[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: [massif-visualizer] app: Implementation of multiple document interface.
From: Arnold Dumas <contact () arnolddumas ! com>
Date: 2013-11-04 18:17:48
Message-ID: E1VdOii-0001fw-4a () scm ! kde ! org
[Download RAW message or body]
Git commit 52ea510803f685e60580a9373fce340339a4919b by Arnold Dumas.
Committed on 04/11/2013 at 18:14.
Pushed by arnolddumas into branch 'master'.
Implementation of multiple document interface.
REVIEW: 113523
M +1 -0 app/CMakeLists.txt
A +541 -0 app/documentwidget.cpp [License: GPL (v2/3)]
A +179 -0 app/documentwidget.h [License: GPL (v2/3)]
M +5 -8 app/main.cpp
M +241 -509 app/mainwindow.cpp
M +20 -42 app/mainwindow.h
M +19 -90 app/mainwindow.ui
http://commits.kde.org/massif-visualizer/52ea510803f685e60580a9373fce340339a4919b
diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt
index 31290f6..086839a 100644
--- a/app/CMakeLists.txt
+++ b/app/CMakeLists.txt
@@ -14,6 +14,7 @@ set(massif-visualizer_SRCS
main.cpp
mainwindow.cpp
configdialog.cpp
+ documentwidget.cpp
)
kde4_add_kcfg_files(massif-visualizer_SRCS massif-visualizer-settings.kcfgc)
diff --git a/app/documentwidget.cpp b/app/documentwidget.cpp
new file mode 100644
index 0000000..ec854b1
--- /dev/null
+++ b/app/documentwidget.cpp
@@ -0,0 +1,541 @@
+/*
+ This file is part of Massif Visualizer
+
+ Copyright 2010 Milian Wolff <mail@milianw.de>
+ Copyright 2013 Arnold Dumas <contact@arnolddumas.com>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License or (at your option) version 3 or any later version
+ accepted by the membership of KDE e.V. (or its successor approved
+ by the membership of KDE e.V.), which shall act as a proxy
+ defined in Section 14 of version 3 of the license.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "documentwidget.h"
+
+using namespace Massif;
+using namespace KDChart;
+
+void markPeak(Plotter* p, const QModelIndex& peak, quint64 cost, const QPen& \
foreground) +{
+ DataValueAttributes dataAttributes = p->dataValueAttributes(peak);
+ dataAttributes.setDataLabel(prettyCost(cost));
+ dataAttributes.setVisible(true);
+
+ MarkerAttributes a = dataAttributes.markerAttributes();
+ a.setMarkerSize(QSizeF(2, 2));
+ a.setPen(foreground);
+ a.setMarkerStyle(KDChart::MarkerAttributes::MarkerCircle);
+ a.setVisible(true);
+ dataAttributes.setMarkerAttributes(a);
+
+ TextAttributes txtAttrs = dataAttributes.textAttributes();
+ txtAttrs.setPen(foreground);
+ dataAttributes.setTextAttributes(txtAttrs);
+
+ BackgroundAttributes bkgAtt = dataAttributes.backgroundAttributes();
+ QBrush brush = p->model()->data(peak, DatasetBrushRole).value<QBrush>();
+ QColor c = brush.color();
+ c.setAlpha(127);
+ brush.setColor(c);
+ brush.setStyle(Qt::CrossPattern);
+ bkgAtt.setBrush(brush);
+ bkgAtt.setVisible(true);
+ dataAttributes.setBackgroundAttributes(bkgAtt);
+
+ p->setDataValueAttributes(peak, dataAttributes);
+}
+
+DocumentWidget::DocumentWidget(QWidget* parent) :
+ QWidget(parent), m_chart(new Chart(this))
+ , m_header(new QLabel(this))
+ , m_totalDiagram(0)
+ , m_totalCostModel(new TotalCostModel(m_chart))
+ , m_detailedDiagram(0)
+ , m_detailedCostModel(new DetailedCostModel(m_chart))
+ , m_legend(new Legend(m_chart))
+ , m_dataTreeModel(new DataTreeModel(m_chart))
+ , m_dataTreeFilterModel(new FilteredDataTreeModel(m_dataTreeModel))
+ , m_data(0)
+#ifdef HAVE_KGRAPHVIEWER
+ , m_graphViewerPart(0)
+ , m_graphViewer(0)
+ , m_dotGenerator(0)
+#endif
+ , m_stackedWidget(new QStackedWidget(this))
+ , m_displayTabWidget(new QTabWidget(m_stackedWidget))
+ , m_loadingMessage(0)
+ , m_loadingProgressBar(0)
+ , m_stopParserButton(0)
+ , m_isLoaded(false)
+{
+ // for axis labels to fit
+ m_chart->setGlobalLeadingRight(10);
+ m_chart->setGlobalLeadingLeft(10);
+ m_chart->setGlobalLeadingTop(20);
+ m_chart->setContextMenuPolicy(Qt::CustomContextMenu);
+
+ m_legend->setPosition(Position(KDChartEnums::PositionFloating));
+ m_legend->setTitleText("");
+ m_legend->setAlignment(Qt::AlignVCenter | Qt::AlignLeft);
+ m_legend->setSortOrder(Qt::DescendingOrder);
+
+ m_chart->addLegend(m_legend);
+
+ //NOTE: this has to be set _after_ the legend was added to the chart...
+ TextAttributes att = m_legend->textAttributes();
+ att.setAutoShrink(true);
+ att.setFontSize(Measure(12));
+ QFont font("monospace");
+ font.setStyleHint(QFont::TypeWriter);
+ att.setFont(font);
+ m_legend->setTextAttributes(att);
+ m_legend->setTextAlignment(Qt::AlignLeft);
+ m_legend->hide();
+
+ // Set m_stackedWidget as the main widget.
+ setLayout(new QGridLayout(this));
+ layout()->addWidget(m_stackedWidget);
+
+ // First widget : displayPage
+ m_displayTabWidget->setTabPosition(QTabWidget::South);
+ QWidget* memoryConsumptionWidget = new QWidget(m_displayTabWidget);
+ memoryConsumptionWidget->setLayout(new QVBoxLayout(memoryConsumptionWidget));
+ memoryConsumptionWidget->layout()->addWidget(m_header);
+ memoryConsumptionWidget->layout()->addWidget(m_chart);
+ m_displayTabWidget->addTab(memoryConsumptionWidget, i18n("&Evolution of Memory \
Consumption")); +
+#ifdef HAVE_KGRAPHVIEWER
+ KLibFactory *factory = KLibLoader::self()->factory("kgraphviewerpart");
+ if (factory) {
+ m_graphViewerPart = factory->create<KParts::ReadOnlyPart>(this);
+ if (m_graphViewerPart) {
+ m_graphViewer = qobject_cast< KGraphViewer::KGraphViewerInterface* \
>(m_graphViewerPart); + QWidget* dotGraphWidget = new \
> QWidget(m_displayTabWidget);
+ dotGraphWidget->setLayout(new QGridLayout(dotGraphLayout));
+ dotGraphWidget->layout()->addWidget(m_graphViewerPart->widget());
+ m_displayTabWidget->addTab(dotGraphWidget, i18n("&Detailed Snapshot \
Analysis")); + connect(m_graphViewerPart, SIGNAL(graphLoaded()), this, \
SLOT(slotGraphLoaded())); +
+ connect(m_displayTabWidget, SIGNAL(currentChanged(int)),
+ this, SLOT(slotTabChanged(int)));
+ slotTabChanged(m_displayTabWidget->currentIndex());
+ }
+ }
+#endif
+
+ m_stackedWidget->addWidget(m_displayTabWidget);
+
+ // Second widget : loadingPage
+ QWidget* loadingPage = new QWidget(m_stackedWidget);
+ QVBoxLayout* verticalLayout = new QVBoxLayout(loadingPage);
+ QSpacerItem* upperSpacerItem = new QSpacerItem(20, 247, QSizePolicy::Minimum, \
QSizePolicy::Expanding); + verticalLayout->addItem(upperSpacerItem);
+
+ m_loadingMessage = new QLabel(loadingPage);
+ m_loadingMessage->setText(i18n("loading..."));
+ m_loadingMessage->setAlignment(Qt::AlignCenter);
+ verticalLayout->addWidget(m_loadingMessage);
+
+ m_loadingProgressBar = new QProgressBar(loadingPage);
+ m_loadingProgressBar->setValue(24);
+ m_loadingProgressBar->setRange(0, 0);
+ verticalLayout->addWidget(m_loadingProgressBar);
+
+ QWidget* stopParserWidget = new QWidget(loadingPage);
+ stopParserWidget->setLayoutDirection(Qt::LeftToRight);
+ QHBoxLayout* stopParserWidgetLayout = new QHBoxLayout(stopParserWidget);
+ m_stopParserButton = new QToolButton(stopParserWidget);
+ m_stopParserButton->setObjectName(QString::fromUtf8("stopParsing"));
+ m_stopParserButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
+ m_stopParserButton->setIcon(KIcon("process-stop"));
+ m_stopParserButton->setIconSize(QSize(48, 48));
+ connect(m_stopParserButton, SIGNAL(clicked()),
+ this, SLOT(slotEmitStopParserSignal()));
+ stopParserWidgetLayout->addWidget(m_stopParserButton);
+ verticalLayout->addWidget(stopParserWidget);
+
+ QSpacerItem* bottomSpacerItem = new QSpacerItem(20, 230, QSizePolicy::Minimum, \
QSizePolicy::Expanding); + verticalLayout->addItem(bottomSpacerItem);
+ m_stackedWidget->addWidget(loadingPage);
+
+ // By default we show the loadingPage.
+ m_stackedWidget->setCurrentIndex(1);
+}
+
+DocumentWidget::~DocumentWidget()
+{
+ if (m_data) {
+
+#ifdef HAVE_KGRAPHVIEWER
+ if (m_dotGenerator) {
+ if (m_dotGenerator->isRunning()) {
+ disconnect(m_dotGenerator.data(), 0, this, 0);
+ connect(m_dotGenerator.data(), SIGNAL(finished()),
+ m_dotGenerator.data(), SLOT(deleteLater()));
+ m_dotGenerator->cancel();
+ m_dotGenerator.take();
+ }
+ m_dotGenerator.reset();
+ }
+ if (m_graphViewer) {
+ m_graphViewerPart->closeUrl();
+ m_zoomIn->setEnabled(false);
+ m_zoomOut->setEnabled(false);
+ m_focusExpensive->setEnabled(false);
+ }
+ m_lastDotItem.first = 0;
+ m_lastDotItem.second = 0;
+#endif
+
+ m_chart->replaceCoordinatePlane(new CartesianCoordinatePlane);
+ m_legend->removeDiagrams();
+ m_legend->hide();
+ m_header->setText("");
+
+ foreach(CartesianAxis* axis, m_detailedDiagram->axes()) {
+ m_detailedDiagram->takeAxis(axis);
+ delete axis;
+ }
+ m_detailedDiagram->deleteLater();
+ m_detailedDiagram = 0;
+
+ foreach(CartesianAxis* axis, m_totalDiagram->axes()) {
+ m_totalDiagram->takeAxis(axis);
+ delete axis;
+ }
+ m_totalDiagram->deleteLater();
+ m_totalDiagram = 0;
+
+ m_dataTreeModel->setSource(0);
+ m_dataTreeFilterModel->setFilter("");
+ m_detailedCostModel->setSource(0);
+ m_totalCostModel->setSource(0);
+
+ delete m_data;
+ m_data = 0;
+ m_file.clear();
+ }
+}
+
+KUrl DocumentWidget::file() const
+{
+ return m_file;
+}
+
+FileData* DocumentWidget::data() const
+{
+ return m_data;
+}
+
+Chart* DocumentWidget::chart() const
+{
+ return m_chart;
+}
+
+Plotter* DocumentWidget::totalDiagram() const
+{
+ return m_totalDiagram;
+}
+
+
+TotalCostModel* DocumentWidget::totalCostModel() const
+{
+ return m_totalCostModel;
+}
+
+Plotter* DocumentWidget::detailedDiagram() const
+{
+ return m_detailedDiagram;
+}
+
+DetailedCostModel* DocumentWidget::detailedCostModel() const
+{
+ return m_detailedCostModel;
+}
+
+DataTreeModel* DocumentWidget::dataTreeModel() const
+{
+ return m_dataTreeModel;
+}
+
+FilteredDataTreeModel* DocumentWidget::dataTreeFilterModel() const
+{
+ return m_dataTreeFilterModel;
+}
+
+#ifdef HAVE_KGRAPHVIEWER
+ KGraphViewer::KGraphViewerInterface* DocumentWidget::graphViewer()
+ {
+ return m_graphViewer;
+ }
+#endif
+
+bool DocumentWidget::isLoaded() const
+{
+ return m_isLoaded;
+}
+
+void DocumentWidget::parserFinished(const KUrl& file, FileData* data)
+{
+ Q_ASSERT(data->peak());
+
+ kDebug() << "loaded massif file:" << file;
+ qDebug() << "description:" << data->description();
+ qDebug() << "command:" << data->cmd();
+ qDebug() << "time unit:" << data->timeUnit();
+ qDebug() << "snapshots:" << data->snapshots().size();
+ qDebug() << "peak: snapshot #" << data->peak()->number() << "after" << \
QString("%1%2").arg(data->peak()->time()).arg(data->timeUnit()); + qDebug() << \
"peak cost:" << prettyCost(data->peak()->memHeap()) << " heap" + \
<< prettyCost(data->peak()->memHeapExtra()) << " heap extra" + \
<< prettyCost(data->peak()->memStacks()) << " stacks"; +
+ m_data = data;
+ m_file = file;
+
+ #ifdef HAVE_KGRAPHVIEWER
+ if (m_graphViewer) {
+ showDotGraph(QPair<TreeLeafItem*,SnapshotItem*>(0, m_data->peak()));
+ }
+ #endif
+
+ //BEGIN KDChart
+ KColorScheme scheme(QPalette::Active, KColorScheme::Window);
+ QPen foreground(scheme.foreground().color());
+
+ //Begin Legend
+ BackgroundAttributes bkgAtt = m_legend->backgroundAttributes();
+ QColor background = \
scheme.background(KColorScheme::AlternateBackground).color(); + \
background.setAlpha(200); + bkgAtt.setBrush(QBrush(background));
+ bkgAtt.setVisible(true);
+ m_legend->setBackgroundAttributes(bkgAtt);
+ TextAttributes txtAttrs = m_legend->textAttributes();
+ txtAttrs.setPen(foreground);
+ m_legend->setTextAttributes(txtAttrs);
+
+ m_header->setAlignment(Qt::AlignCenter);
+ updateHeader();
+
+ //BEGIN TotalDiagram
+ m_totalDiagram = new Plotter;
+ m_totalDiagram->setAntiAliasing(true);
+
+ CartesianAxis* bottomAxis = new CartesianAxis(m_totalDiagram);
+ TextAttributes axisTextAttributes = bottomAxis->textAttributes();
+ axisTextAttributes.setPen(foreground);
+ axisTextAttributes.setFontSize(Measure(10));
+ bottomAxis->setTextAttributes(axisTextAttributes);
+ TextAttributes axisTitleTextAttributes = bottomAxis->titleTextAttributes();
+ axisTitleTextAttributes.setPen(foreground);
+ axisTitleTextAttributes.setFontSize(Measure(12));
+ bottomAxis->setTitleTextAttributes(axisTitleTextAttributes);
+ bottomAxis->setTitleText(i18n("time in %1", m_data->timeUnit()));
+ bottomAxis->setPosition ( CartesianAxis::Bottom );
+ m_totalDiagram->addAxis(bottomAxis);
+
+ CartesianAxis* rightAxis = new CartesianAxis(m_totalDiagram);
+ rightAxis->setTextAttributes(axisTextAttributes);
+ rightAxis->setTitleTextAttributes(axisTitleTextAttributes);
+ rightAxis->setTitleText(i18n("memory heap size in kilobytes"));
+ rightAxis->setPosition ( CartesianAxis::Right );
+ m_totalDiagram->addAxis(rightAxis);
+
+ m_totalCostModel->setSource(m_data);
+ m_totalDiagram->setModel(m_totalCostModel);
+
+ CartesianCoordinatePlane* coordinatePlane = \
dynamic_cast<CartesianCoordinatePlane*>(m_chart->coordinatePlane()); + \
Q_ASSERT(coordinatePlane); + coordinatePlane->addDiagram(m_totalDiagram);
+
+ GridAttributes gridAttributes = coordinatePlane->gridAttributes(Qt::Horizontal);
+ gridAttributes.setAdjustBoundsToGrid(false, false);
+ coordinatePlane->setGridAttributes(Qt::Horizontal, gridAttributes);
+
+ m_legend->addDiagram(m_totalDiagram);
+
+ m_detailedDiagram = new Plotter;
+ m_detailedDiagram->setAntiAliasing(true);
+ m_detailedDiagram->setType(KDChart::Plotter::Stacked);
+
+ m_detailedCostModel->setSource(m_data);
+ m_detailedDiagram->setModel(m_detailedCostModel);
+
+ updatePeaks();
+
+ m_chart->coordinatePlane()->addDiagram(m_detailedDiagram);
+
+ m_legend->addDiagram(m_detailedDiagram);
+ m_legend->show();
+
+ m_dataTreeModel->setSource(m_data);
+ m_isLoaded = true;
+
+ // Switch to the display page and notify that everything is setup.
+ m_stackedWidget->setCurrentIndex(0);
+ emit loadingFinished();
+}
+
+void DocumentWidget::setDetailedDiagramHidden(bool hidden)
+{
+ m_detailedDiagram->setHidden(hidden);
+}
+
+void DocumentWidget::setDetailedDiagramVisible(bool visible)
+{
+ m_detailedDiagram->setVisible(visible);
+}
+
+void DocumentWidget::setTotalDiagramHidden(bool hidden)
+{
+ m_totalDiagram->setHidden(hidden);
+}
+
+void DocumentWidget::setTotalDiagramVisible(bool visible)
+{
+ m_totalDiagram->setVisible(visible);
+}
+
+void DocumentWidget::setProgress(int value)
+{
+ m_loadingProgressBar->setValue(value);
+}
+
+void DocumentWidget::setRange(int minimum, int maximum)
+{
+ m_loadingProgressBar->setRange(minimum, maximum);
+}
+
+void DocumentWidget::setLoadingMessage(const QString& message)
+{
+ m_loadingMessage->setText(message);
+}
+
+void DocumentWidget::slotEmitStopParserSignal()
+{
+ emit stopParser();
+}
+
+void DocumentWidget::updateHeader()
+{
+ const QString app = m_data->cmd().split(' ', QString::SkipEmptyParts).first();
+
+ m_header->setText(QString("<b>%1</b><br /><i>%2</i>")
+ .arg(i18n("Memory consumption of %1", app))
+ .arg(i18n("Peak of %1 at snapshot #%2", \
prettyCost(m_data->peak()->cost()), m_data->peak()->number())) + );
+ m_header->setToolTip(i18n("Command: %1\nValgrind Options: %2", m_data->cmd(), \
m_data->description())); +}
+
+void DocumentWidget::updatePeaks()
+{
+ KColorScheme scheme(QPalette::Active, KColorScheme::Window);
+ QPen foreground(scheme.foreground().color());
+
+ if (m_data->peak()) {
+ const QModelIndex peak = m_totalCostModel->peak();
+ Q_ASSERT(peak.isValid());
+ markPeak(m_totalDiagram, peak, m_data->peak()->cost(), foreground);
+ }
+ updateDetailedPeaks();
+}
+
+void DocumentWidget::updateDetailedPeaks()
+{
+ KColorScheme scheme(QPalette::Active, KColorScheme::Window);
+ QPen foreground(scheme.foreground().color());
+
+ QMap< QModelIndex, TreeLeafItem* > peaks = m_detailedCostModel->peaks();
+ QMap< QModelIndex, TreeLeafItem* >::const_iterator it = peaks.constBegin();
+ while (it != peaks.constEnd()) {
+ const QModelIndex peak = it.key();
+ Q_ASSERT(peak.isValid());
+ markPeak(m_detailedDiagram, peak, it.value()->cost(), foreground);
+ ++it;
+ }
+}
+
+#ifdef HAVE_KGRAPHVIEWER
+void MainWindow::slotTabChanged(int index)
+{
+ toolBar("chartToolBar")->setVisible(index == 0);
+ foreach(QAction* action, toolBar("chartToolBar")->actions()) {
+ action->setEnabled(m_data && index == 0);
+ }
+ toolBar("callgraphToolBar")->setVisible(index == 1);
+ foreach(QAction* action, toolBar("callgraphToolBar")->actions()) {
+ action->setEnabled(m_data && index == 1);
+ }
+ if (index == 1) {
+ // if we parsed a dot graph we might want to show it now
+ showDotGraph();
+ }
+}
+
+void MainWindow::showDotGraph(const QPair<TreeLeafItem*, SnapshotItem*>& item)
+{
+ if (item == m_lastDotItem) {
+ return;
+ }
+ m_lastDotItem = item;
+
+ Q_ASSERT(m_graphViewer);
+
+ kDebug() << "new dot graph requested" << item;
+ if (m_dotGenerator) {
+ kDebug() << "existing generator is running:" << m_dotGenerator->isRunning();
+ if (m_dotGenerator->isRunning()) {
+ disconnect(m_dotGenerator.data(), 0, this, 0);
+ connect(m_dotGenerator.data(), SIGNAL(finished()),
+ m_dotGenerator.data(), SLOT(deleteLater()));
+ m_dotGenerator->cancel();
+ m_dotGenerator.take();
+ }
+ m_dotGenerator.reset();
+ }
+ if (!item.first && !item.second) {
+ return;
+ }
+ if (item.second) {
+ m_dotGenerator.reset(new DotGraphGenerator(item.second, m_data->timeUnit(), \
this)); + } else {
+ m_dotGenerator.reset(new DotGraphGenerator(item.first, m_data->timeUnit(), \
this)); + }
+ connect(m_dotGenerator.data(), SIGNAL(finished()), SLOT(showDotGraph()));
+ m_dotGenerator->start();
+}
+
+void MainWindow::showDotGraph()
+{
+ if (!m_dotGenerator || !m_graphViewerPart || \
!m_graphViewerPart->widget()->isVisible()) { + return;
+ }
+ kDebug() << "show dot graph in output file" << m_dotGenerator->outputFile();
+ if (!m_dotGenerator->outputFile().isEmpty() && m_graphViewerPart->url() != \
KUrl(m_dotGenerator->outputFile())) { + \
m_graphViewerPart->openUrl(KUrl(m_dotGenerator->outputFile())); + }
+}
+
+void MainWindow::slotGraphLoaded()
+{
+ Q_ASSERT(m_graphViewer);
+
+ if (!m_dotGenerator) {
+ return;
+ }
+ m_graphViewer->setZoomFactor(0.75);
+ m_graphViewer->setPannerPosition(KGraphViewer::KGraphViewerInterface::BottomRight);
+ m_graphViewer->setPannerEnabled(true);
+ m_graphViewer->centerOnNode(m_dotGenerator->mostCostIntensiveGraphvizId());
+}
+#endif
diff --git a/app/documentwidget.h b/app/documentwidget.h
new file mode 100644
index 0000000..4e27762
--- /dev/null
+++ b/app/documentwidget.h
@@ -0,0 +1,179 @@
+/*
+ This file is part of Massif Visualizer
+
+ Copyright 2010 Milian Wolff <mail@milianw.de>
+ Copyright 2013 Arnold Dumas <contact@arnolddumas.com>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License or (at your option) version 3 or any later version
+ accepted by the membership of KDE e.V. (or its successor approved
+ by the membership of KDE e.V.), which shall act as a proxy
+ defined in Section 14 of version 3 of the license.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DOCUMENTWIDGET_H
+#define DOCUMENTWIDGET_H
+
+#include "documentwidget.h"
+
+#include "KDChartChart"
+#include "KDChartGridAttributes"
+#include "KDChartHeaderFooter"
+#include "KDChartCartesianCoordinatePlane"
+#include "KDChartPlotter"
+#include "KDChartLegend"
+#include "KDChartDataValueAttributes"
+#include "KDChartBackgroundAttributes"
+
+#include "massifdata/filedata.h"
+#include "massifdata/parser.h"
+#include "massifdata/parseworker.h"
+#include "massifdata/snapshotitem.h"
+#include "massifdata/treeleafitem.h"
+#include "massifdata/util.h"
+
+#include "visualizer/totalcostmodel.h"
+#include "visualizer/detailedcostmodel.h"
+#include "visualizer/datatreemodel.h"
+#include "visualizer/filtereddatatreemodel.h"
+#include "visualizer/dotgraphgenerator.h"
+
+#include "massif-visualizer-settings.h"
+#include "configdialog.h"
+
+#include <KStandardAction>
+#include <KColorScheme>
+#include <KParts/Part>
+#include <KLibFactory>
+#include <KLibLoader>
+#include <KLocalizedString>
+
+#include <QLabel>
+#include <QProgressBar>
+#include <QSortFilterProxyModel>
+#include <QStackedWidget>
+#include <QStringListModel>
+#include <QTabWidget>
+#include <QToolButton>
+
+#ifdef HAVE_KGRAPHVIEWER
+#include <kgraphviewer_interface.h>
+#endif
+
+namespace KDChart {
+class Chart;
+class HeaderFooter;
+class Plotter;
+class CartesianAxis;
+class Legend;
+class BarDiagram;
+}
+
+namespace KParts {
+class ReadOnlyPart;
+}
+
+#ifdef HAVE_KGRAPHVIEWER
+namespace KGraphViewer {
+class KGraphViewerInterface;
+}
+#endif
+
+class DocumentWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit DocumentWidget(QWidget* parent = 0);
+ ~DocumentWidget();
+
+ void updateHeader();
+ void updatePeaks();
+
+ KUrl file() const;
+ Massif::FileData* data() const;
+ KDChart::Chart* chart() const;
+ KDChart::Plotter* totalDiagram() const;
+ Massif::TotalCostModel* totalCostModel() const;
+ KDChart::Plotter* detailedDiagram() const;
+ Massif::DetailedCostModel* detailedCostModel() const;
+ Massif::DataTreeModel* dataTreeModel() const;
+ Massif::FilteredDataTreeModel* dataTreeFilterModel() const;
+
+#ifdef HAVE_KGRAPHVIEWER
+ KGraphViewer::KGraphViewerInterface* graphViewer();
+#endif
+
+ bool isLoaded() const;
+
+signals:
+ void stopParser();
+ void loadingFinished();
+
+public slots:
+ void parserFinished(const KUrl& file, Massif::FileData* data);
+
+ void setDetailedDiagramHidden(bool hidden);
+ void setDetailedDiagramVisible(bool visible);
+
+ void setTotalDiagramHidden(bool hidden);
+ void setTotalDiagramVisible(bool visible);
+
+ void setProgress(int value);
+ void setRange(int minimum, int maximum);
+ void setLoadingMessage(const QString& message);
+
+private slots:
+ void slotEmitStopParserSignal();
+
+#ifdef HAVE_KGRAPHVIEWER
+ void showDotGraph();
+ void showDotGraph(const QPair<TreeLeafItem*, SnapshotItem*>& item);
+ void slotTabChanged(int index);
+ void slotGraphLoaded();
+#endif
+
+private:
+ void updateDetailedPeaks();
+
+ KDChart::Chart* m_chart;
+ QLabel* m_header;
+ KDChart::Plotter* m_totalDiagram;
+ Massif::TotalCostModel* m_totalCostModel;
+
+ KDChart::Plotter* m_detailedDiagram;
+ Massif::DetailedCostModel* m_detailedCostModel;
+
+ KDChart::Legend* m_legend;
+
+ Massif::DataTreeModel* m_dataTreeModel;
+ Massif::FilteredDataTreeModel* m_dataTreeFilterModel;
+ Massif::FileData* m_data;
+ KUrl m_file;
+
+ QStackedWidget* m_stackedWidget;
+ QTabWidget* m_displayTabWidget;
+ QLabel* m_loadingMessage;
+ QProgressBar* m_loadingProgressBar;
+ QToolButton* m_stopParserButton;
+ bool m_isLoaded;
+
+#ifdef HAVE_KGRAPHVIEWER
+ KParts::ReadOnlyPart* m_graphViewerPart;
+ KGraphViewer::KGraphViewerInterface* m_graphViewer;
+ QScopedPointer<DotGraphGenerator> m_dotGenerator;
+ QPair<TreeLeafItem*, SnapshotItem*> m_lastDotItem;
+#endif
+};
+
+#endif // DOCUMENTWIDGET_H
diff --git a/app/main.cpp b/app/main.cpp
index be938b4..3e70f67 100644
--- a/app/main.cpp
+++ b/app/main.cpp
@@ -47,15 +47,12 @@ int main( int argc, char *argv[] )
KCmdLineArgs* args = KCmdLineArgs::parsedArgs();
KApplication app;
- for ( int i = 0; i < args->count(); ++i ) {
- Massif::MainWindow* window = new Massif::MainWindow;
+ Massif::MainWindow* window = new Massif::MainWindow;
+
+ for (int i = 0; i < args->count(); ++i) {
window->openFile(args->url(i));
- window->show();
- }
- if (!args->count()) {
- // at least one window has to be shown...
- Massif::MainWindow* window = new Massif::MainWindow;
- window->show();
}
+
+ window->show();
return app.exec();
}
diff --git a/app/mainwindow.cpp b/app/mainwindow.cpp
index b33ff60..792ead3 100644
--- a/app/mainwindow.cpp
+++ b/app/mainwindow.cpp
@@ -2,6 +2,7 @@
This file is part of Massif Visualizer
Copyright 2010 Milian Wolff <mail@milianw.de>
+ Copyright 2013 Arnold Dumas <contact@arnolddumas.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -66,7 +67,6 @@
#include <QPrinter>
#include <QPrintDialog>
-#include <KDebug>
#include <KMessageBox>
#ifdef HAVE_KGRAPHVIEWER
@@ -76,64 +76,17 @@
using namespace Massif;
using namespace KDChart;
-//BEGIN Helper Functions
-void markPeak(Plotter* p, const QModelIndex& peak, quint64 cost, const QPen& \
foreground)
-{
- DataValueAttributes dataAttributes = p->dataValueAttributes(peak);
- dataAttributes.setDataLabel(prettyCost(cost));
- dataAttributes.setVisible(true);
-
- MarkerAttributes a = dataAttributes.markerAttributes();
- a.setMarkerSize(QSizeF(2, 2));
- a.setPen(foreground);
- a.setMarkerStyle(KDChart::MarkerAttributes::MarkerCircle);
- a.setVisible(true);
- dataAttributes.setMarkerAttributes(a);
-
- TextAttributes txtAttrs = dataAttributes.textAttributes();
- txtAttrs.setPen(foreground);
- dataAttributes.setTextAttributes(txtAttrs);
-
- BackgroundAttributes bkgAtt = dataAttributes.backgroundAttributes();
- QBrush brush = p->model()->data(peak, DatasetBrushRole).value<QBrush>();
- QColor c = brush.color();
- c.setAlpha(127);
- brush.setColor(c);
- brush.setStyle(Qt::CrossPattern);
- bkgAtt.setBrush(brush);
- bkgAtt.setVisible(true);
- dataAttributes.setBackgroundAttributes(bkgAtt);
-
- p->setDataValueAttributes(peak, dataAttributes);
-}
-
+// Helper function
KConfigGroup allocatorConfig()
{
return KGlobal::config()->group("Allocators");
}
-//END Helper Functions
-
MainWindow::MainWindow(QWidget* parent, Qt::WindowFlags f)
- : KParts::MainWindow(parent, f), m_chart(new Chart(this)), m_header(new \
QLabel(this)) + : KParts::MainWindow(parent, f)
, m_toggleTotal(0)
- , m_totalDiagram(0)
- , m_totalCostModel(new TotalCostModel(m_chart))
- , m_toggleDetailed(0)
- , m_detailedDiagram(0)
- , m_detailedCostModel(new DetailedCostModel(m_chart))
- , m_legend(new Legend(m_chart))
- , m_dataTreeModel(new DataTreeModel(m_chart))
- , m_dataTreeFilterModel(new FilteredDataTreeModel(m_dataTreeModel))
- , m_data(0)
, m_selectPeak(0)
, m_recentFiles(0)
- , m_changingSelections(false)
-#ifdef HAVE_KGRAPHVIEWER
- , m_graphViewerPart(0)
- , m_graphViewer(0)
- , m_dotGenerator(0)
-#endif
, m_zoomIn(0)
, m_zoomOut(0)
, m_focusExpensive(0)
@@ -144,65 +97,35 @@ MainWindow::MainWindow(QWidget* parent, Qt::WindowFlags f)
, m_newAllocator(0)
, m_removeAllocator(0)
, m_shortenTemplates(0)
- , m_parseWorker(new ParseWorker)
{
ui.setupUi(this);
setWindowTitle(i18n("Massif Visualizer"));
- // for axis labels to fit
- m_chart->setGlobalLeadingRight(10);
- m_chart->setGlobalLeadingLeft(10);
- m_chart->setGlobalLeadingTop(20);
- connect(m_chart, SIGNAL(customContextMenuRequested(QPoint)),
- this, SLOT(chartContextMenuRequested(QPoint)));
- m_chart->setContextMenuPolicy(Qt::CustomContextMenu);
-
- m_legend->setPosition(Position(KDChartEnums::PositionFloating));
- m_legend->setTitleText("");
- m_legend->setAlignment(Qt::AlignVCenter | Qt::AlignLeft);
- m_legend->setSortOrder(Qt::DescendingOrder);
-
- m_chart->addLegend(m_legend);
-
- //NOTE: this has to be set _after_ the legend was added to the chart...
- TextAttributes att = m_legend->textAttributes();
- att.setAutoShrink(true);
- att.setFontSize( Measure(12) );
- QFont font("monospace");
- font.setStyleHint(QFont::TypeWriter);
- att.setFont(font);
- m_legend->setTextAttributes(att);
- m_legend->setTextAlignment(Qt::AlignLeft);
- m_legend->hide();
-
- ui.plotterTab->layout()->addWidget(m_header);
- ui.plotterTab->layout()->addWidget(m_chart);
-
//BEGIN KGraphViewer
-
bool haveGraphViewer = false;
+ // NOTE: just check if kgraphviewer is available at runtime.
+ // The former logic has been moved to DocumentWidget constructor.
#ifdef HAVE_KGRAPHVIEWER
KLibFactory *factory = KLibLoader::self()->factory("kgraphviewerpart");
if (factory) {
- m_graphViewerPart = factory->create<KParts::ReadOnlyPart>(this);
- if (m_graphViewerPart) {
- m_graphViewer = qobject_cast< KGraphViewer::KGraphViewerInterface* \
>(m_graphViewerPart);
- ui.dotGraphTab->layout()->addWidget(m_graphViewerPart->widget());
- connect(m_graphViewerPart, SIGNAL(graphLoaded()), this, \
SLOT(slotGraphLoaded())); + if (factory->create<KParts::ReadOnlyPart>(this)) {
haveGraphViewer = true;
}
}
#endif
- //END KGraphViewer
- connect(ui.filterDataTree, SIGNAL(textChanged(QString)),
- m_dataTreeFilterModel, SLOT(setFilter(QString)));
- ui.dataTreeView->setModel(m_dataTreeFilterModel);
- connect(ui.dataTreeView->selectionModel(), \
SIGNAL(currentChanged(QModelIndex,QModelIndex)),
- this, SLOT(treeSelectionChanged(QModelIndex,QModelIndex)));
+ if (!haveGraphViewer) {
+ // cleanup UI when we installed with kgraphviewer but it's not available at \
runtime + KToolBar* callgraphToolbar = toolBar("callgraphToolBar");
+ removeToolBar(callgraphToolbar);
+ delete callgraphToolbar;
+ }
+ //END KGraphViewer
+ connect(ui.documents, SIGNAL(currentChanged(int)),
+ this, SLOT(documentChanged()));
//BEGIN custom allocators
tabifyDockWidget(ui.allocatorDock, ui.dataTreeDock);
@@ -236,60 +159,28 @@ MainWindow::MainWindow(QWidget* parent, Qt::WindowFlags f)
setupGUI(StandardWindowOptions(Default ^ StatusBar));
statusBar()->hide();
- if (haveGraphViewer) {
-#ifdef HAVE_KGRAPHVIEWER
- connect(ui.tabWidget, SIGNAL(currentChanged(int)),
- this, SLOT(slotTabChanged(int)));
- slotTabChanged(ui.tabWidget->currentIndex());
-#endif
- } else {
- // cleanup UI when we installed with kgraphviewer but it's not available at \
runtime
- KToolBar* callgraphToolbar = toolBar("callgraphToolBar");
- removeToolBar(callgraphToolbar);
- delete callgraphToolbar;
- int i = ui.stackedWidget->addWidget(ui.plotterTab);
- ui.stackedWidget->setCurrentIndex(i);
- ui.stackedWidget->removeWidget(ui.displayPage);
- delete ui.displayPage;
- ui.displayPage = ui.plotterTab;
- }
-
// open page
ui.stackedWidget->setCurrentWidget(ui.openPage);
-
- // threaded parser
- QThread* thread = new QThread(this);
- thread->start();
- m_parseWorker->moveToThread(thread);
- connect(m_parseWorker, SIGNAL(finished(KUrl, Massif::FileData*)),
- this, SLOT(parserFinished(KUrl, Massif::FileData*)));
- connect(m_parseWorker, SIGNAL(error(QString, QString)),
- this, SLOT(parserError(QString, QString)));
- connect(m_parseWorker, SIGNAL(progressRange(int, int)),
- ui.loadingProgress, SLOT(setRange(int,int)));
- connect(m_parseWorker, SIGNAL(progress(int)),
- ui.loadingProgress, SLOT(setValue(int)));
}
MainWindow::~MainWindow()
{
- m_parseWorker->stop();
- m_parseWorker->deleteLater();
- m_parseWorker->thread()->quit();
- m_parseWorker->thread()->wait();
- closeFile();
+ while (ui.documents->count()) {
+ closeCurrentFile();
+ }
+
m_recentFiles->saveEntries(KGlobal::config()->group( QString() ));
}
void MainWindow::setupActions()
{
KAction* openFile = KStandardAction::open(this, SLOT(openFile()), \
actionCollection());
- KAction* reload = KStandardAction::redisplay(this, SLOT(reload()), \
actionCollection()); + KAction* reload = KStandardAction::redisplay(this, \
SLOT(reloadCurrentFile()), actionCollection()); \
actionCollection()->addAction("file_reload", reload);
m_recentFiles = KStandardAction::openRecent(this, SLOT(openFile(KUrl)), \
actionCollection()); m_recentFiles->loadEntries(KGlobal::config()->group( QString() \
));
- m_close = KStandardAction::close(this, SLOT(closeFile()), actionCollection());
+ m_close = KStandardAction::close(this, SLOT(closeCurrentFile()), \
actionCollection()); m_close->setEnabled(false);
m_print = KStandardAction::print(this, SLOT(showPrintPreviewDialog()), \
actionCollection()); @@ -327,8 +218,9 @@ void MainWindow::setupActions()
connect(m_toggleDetailed, SIGNAL(toggled(bool)), SLOT(showDetailedGraph(bool)));
actionCollection()->addAction("toggle_detailed", m_toggleDetailed);
+ // If the toolbar is still there, kgraphviewer is available at runtime.
#ifdef HAVE_KGRAPHVIEWER
- if (m_graphViewer) {
+ if (!toolBar("callgraphToolBar")) {
m_zoomIn = KStandardAction::zoomIn(this, SLOT(zoomIn()), \
actionCollection()); actionCollection()->addAction("zoomIn", m_zoomIn);
m_zoomOut = KStandardAction::zoomOut(this, SLOT(zoomOut()), \
actionCollection()); @@ -395,10 +287,6 @@ void MainWindow::setupActions()
ui.openFile->setDefaultAction(openFile);
ui.openFile->setText(i18n("Open Massif Data File"));
ui.openFile->setIconSize(QSize(48, 48));
-
- //load page actions
- ui.stopParsing->setDefaultAction(m_stopParser);
- ui.stopParsing->setIconSize(QSize(48, 48));
}
void MainWindow::preferences()
@@ -421,179 +309,136 @@ void MainWindow::settingsChanged()
Settings::self()->writeConfig();
- if (m_data) {
- updateHeader();
- updatePeaks();
+ if (ui.documents->count()) {
+ currentDocument()->updateHeader();
+ currentDocument()->updatePeaks();
}
ui.dataTreeView->viewport()->update();
}
void MainWindow::openFile()
{
- QString file = KFileDialog::getOpenFileName(KUrl("kfiledialog:///massif-visualizer"),
+ QStringList files = \
KFileDialog::getOpenFileNames(KUrl("kfiledialog:///massif-visualizer"),
\
QString("application/x-valgrind-massif"),
this, i18n("Open Massif Output \
File"));
- if (!file.isEmpty()) {
- openFile(KUrl(file));
+
+ foreach (KUrl file, files) {
+ openFile(file);
}
}
-void MainWindow::reload()
+void MainWindow::reloadCurrentFile()
{
- if (m_currentFile.isValid()) {
- // copy to prevent madness
- openFile(KUrl(m_currentFile));
+ if (currentDocument()->file().isValid()) {
+ openFile(KUrl(currentDocument()->file()));
}
}
void MainWindow::stopParser()
{
- m_parseWorker->stop();
+ Q_ASSERT(currentDocument());
+ ParseWorker* parseWorker = m_documentsParseWorkers.take(currentDocument());
+
+ parseWorker->stop();
+ parseWorker->deleteLater();
+ parseWorker->thread()->quit();
+ parseWorker->thread()->wait();
+
m_stopParser->setEnabled(false);
- ui.stackedWidget->setCurrentWidget(ui.openPage);
}
void MainWindow::openFile(const KUrl& file)
{
Q_ASSERT(file.isValid());
- if (m_data) {
- closeFile();
- }
- stopParser();
+ // give the progress bar one last chance to update
+ QApplication::processEvents();
- m_stopParser->setEnabled(true);
- ui.stackedWidget->setCurrentWidget(ui.loadingPage);
- ui.loadingProgress->setRange(0, 0);
- ui.loadingMessage->setText(i18n("loading file <i>%1</i>...", file.pathOrUrl()));
+ int indexToInsert = -1, i = 0;
- m_parseWorker->parse(file, m_allocatorModel->stringList());
-}
+ // Is file already opened ?
+ while (indexToInsert == -1 && i < ui.documents->count()) {
+ if (qobject_cast<DocumentWidget*>(ui.documents->widget(i))->file() == file) \
{ + indexToInsert = i;
+ }
-void MainWindow::parserFinished(const KUrl& file, FileData* data)
-{
- // give the progress bar one last chance to update
- QApplication::processEvents();
+ ++i;
+ }
- m_data = data;
- m_currentFile = file;
+ DocumentWidget* documentWidget = new DocumentWidget;
+ documentWidget->setLoadingMessage(i18n("loading file <i>%1</i>...", \
file.pathOrUrl()));
- Q_ASSERT(m_data->peak());
+ // Create dedicated thread for this document.
+ ParseWorker* parseWorker = new ParseWorker;
+ QThread* thread = new QThread(this);
+ thread->start();
+ parseWorker->moveToThread(thread);
+ // Register thread in the hash map.
+ m_documentsParseWorkers.insert(documentWidget, parseWorker);
+
+ if (indexToInsert != -1) {
+ // Remove existing instance of the file.
+ ui.documents->setCurrentIndex(indexToInsert);
+ closeCurrentFile();
+ // Insert the new tab at the correct position.
+ ui.documents->insertTab(indexToInsert, documentWidget, file.fileName());
+ } else {
+ ui.documents->addTab(documentWidget, file.fileName());
+ }
+ connect(parseWorker, SIGNAL(finished(KUrl, Massif::FileData*)),
+ documentWidget, SLOT(parserFinished(KUrl, Massif::FileData*)));
+ connect(parseWorker, SIGNAL(error(QString, QString)),
+ this, SLOT(parserError(QString, QString)));
+ connect(parseWorker, SIGNAL(progressRange(int, int)),
+ documentWidget, SLOT(setRange(int,int)));
+ connect(parseWorker, SIGNAL(progress(int)),
+ documentWidget, SLOT(setProgress(int)));
+ connect(documentWidget, SIGNAL(loadingFinished()),
+ this, SLOT(parserFinished()));
+
+ parseWorker->parse(file, m_allocatorModel->stringList());
+
+ m_stopParser->setEnabled(true);
m_close->setEnabled(true);
- m_print->setEnabled(true);
+ m_recentFiles->addUrl(file);
+ ui.stackedWidget->setCurrentWidget(ui.displayPage);
+}
+
+void MainWindow::parserFinished()
+{
+ DocumentWidget* documentWidget = qobject_cast<DocumentWidget*>(sender());
+ m_changingSelections.insert(documentWidget, false);
- kDebug() << "loaded massif file:" << m_currentFile;
- qDebug() << "description:" << m_data->description();
- qDebug() << "command:" << m_data->cmd();
- qDebug() << "time unit:" << m_data->timeUnit();
- qDebug() << "snapshots:" << m_data->snapshots().size();
- qDebug() << "peak: snapshot #" << m_data->peak()->number() << "after" << \
QString("%1%2").arg(m_data->peak()->time()).arg(m_data->timeUnit());
- qDebug() << "peak cost:" << prettyCost(m_data->peak()->memHeap()) << " heap"
- << prettyCost(m_data->peak()->memHeapExtra()) << " heap \
extra"
- << prettyCost(m_data->peak()->memStacks()) << " \
stacks";
-
- //BEGIN DotGraph
#ifdef HAVE_KGRAPHVIEWER
- if (m_graphViewer) {
- showDotGraph(QPair<TreeLeafItem*,SnapshotItem*>(0, m_data->peak()));
+ if (documentWidget->graphViewer()) {
m_zoomIn->setEnabled(true);
m_zoomOut->setEnabled(true);
m_focusExpensive->setEnabled(true);
}
#endif
- //BEGIN KDChart
- KColorScheme scheme(QPalette::Active, KColorScheme::Window);
- QPen foreground(scheme.foreground().color());
-
- //Begin Legend
- BackgroundAttributes bkgAtt = m_legend->backgroundAttributes();
- QColor background = \
scheme.background(KColorScheme::AlternateBackground).color();
- background.setAlpha(200);
- bkgAtt.setBrush(QBrush(background));
- bkgAtt.setVisible(true);
- m_legend->setBackgroundAttributes(bkgAtt);
- TextAttributes txtAttrs = m_legend->textAttributes();
- txtAttrs.setPen(foreground);
- m_legend->setTextAttributes(txtAttrs);
-
- //BEGIN Header
- {
- m_header->setAlignment(Qt::AlignCenter);
- updateHeader();
- }
-
- setWindowTitle(i18n("Massif Visualizer - evaluation of %1 (%2)", m_data->cmd(), \
m_currentFile.fileName())); + \
ui.dataTreeView->setModel(documentWidget->dataTreeFilterModel());
- //BEGIN TotalDiagram
- m_totalDiagram = new Plotter;
- m_toggleTotal->setEnabled(true);
- m_totalDiagram->setAntiAliasing(true);
-
- CartesianAxis* bottomAxis = new CartesianAxis(m_totalDiagram);
- TextAttributes axisTextAttributes = bottomAxis->textAttributes();
- axisTextAttributes.setPen(foreground);
- axisTextAttributes.setFontSize(Measure(10));
- bottomAxis->setTextAttributes(axisTextAttributes);
- TextAttributes axisTitleTextAttributes = bottomAxis->titleTextAttributes();
- axisTitleTextAttributes.setPen(foreground);
- axisTitleTextAttributes.setFontSize(Measure(12));
- bottomAxis->setTitleTextAttributes(axisTitleTextAttributes);
- bottomAxis->setTitleText(i18n("time in %1", m_data->timeUnit()));
- bottomAxis->setPosition ( CartesianAxis::Bottom );
- m_totalDiagram->addAxis(bottomAxis);
-
- CartesianAxis* rightAxis = new CartesianAxis(m_totalDiagram);
- rightAxis->setTextAttributes(axisTextAttributes);
- rightAxis->setTitleTextAttributes(axisTitleTextAttributes);
- rightAxis->setTitleText(i18n("memory heap size in kilobytes"));
- rightAxis->setPosition ( CartesianAxis::Right );
- m_totalDiagram->addAxis(rightAxis);
-
- m_totalCostModel->setSource(m_data);
- m_totalDiagram->setModel(m_totalCostModel);
-
- CartesianCoordinatePlane* coordinatePlane = \
dynamic_cast<CartesianCoordinatePlane*>(m_chart->coordinatePlane());
- Q_ASSERT(coordinatePlane);
- coordinatePlane->addDiagram(m_totalDiagram);
-
- GridAttributes gridAttributes = coordinatePlane->gridAttributes(Qt::Horizontal);
- gridAttributes.setAdjustBoundsToGrid(false, false);
- coordinatePlane->setGridAttributes(Qt::Horizontal, gridAttributes);
-
- m_legend->addDiagram(m_totalDiagram);
- connect(m_totalDiagram, SIGNAL(clicked(QModelIndex)),
+ connect(documentWidget->totalDiagram(), SIGNAL(clicked(QModelIndex)),
this, SLOT(totalItemClicked(QModelIndex)));
-
- //BEGIN DetailedDiagram
- m_detailedDiagram = new Plotter;
- m_toggleDetailed->setEnabled(true);
- m_detailedDiagram->setAntiAliasing(true);
- m_detailedDiagram->setType(KDChart::Plotter::Stacked);
-
- m_detailedCostModel->setSource(m_data);
- m_detailedDiagram->setModel(m_detailedCostModel);
-
- updatePeaks();
-
- m_chart->coordinatePlane()->addDiagram(m_detailedDiagram);
- connect(m_detailedDiagram, SIGNAL(clicked(QModelIndex)),
+ connect(documentWidget->detailedDiagram(), SIGNAL(clicked(QModelIndex)),
this, SLOT(detailedItemClicked(QModelIndex)));
+ connect(documentWidget->chart(), SIGNAL(customContextMenuRequested(QPoint)),
+ this, SLOT(chartContextMenuRequested(QPoint)));
+ connect(ui.filterDataTree, SIGNAL(textChanged(QString)),
+ documentWidget->dataTreeFilterModel(), SLOT(setFilter(QString)));
+ connect(ui.dataTreeView->selectionModel(), \
SIGNAL(currentChanged(QModelIndex,QModelIndex)), + this, \
SLOT(treeSelectionChanged(QModelIndex,QModelIndex)));
- m_legend->addDiagram(m_detailedDiagram);
-
- //BEGIN Legend
- m_legend->show();
-
- //BEGIN TreeView
- m_dataTreeModel->setSource(m_data);
+ m_print->setEnabled(true);
+ m_toggleDetailed->setEnabled(true);
+ m_toggleTotal->setEnabled(true);
m_selectPeak->setEnabled(true);
+ actionCollection()->action("file_reload")->setEnabled(true);
- //BEGIN RecentFiles
- m_recentFiles->addUrl(m_currentFile);
-
- ui.stackedWidget->setCurrentWidget(ui.displayPage);
+ // Update the window title once the document is fully loaded.
+ updateWindowTitle();
}
void MainWindow::parserError(const QString& title, const QString& error)
@@ -601,340 +446,186 @@ void MainWindow::parserError(const QString& title, const \
QString& error) KMessageBox::error(this, error, title);
}
-void MainWindow::updateHeader()
-{
- const QString app = m_data->cmd().split(' ', QString::SkipEmptyParts).first();
-
- m_header->setText(QString("<b>%1</b><br /><i>%2</i>")
- .arg(i18n("Memory consumption of %1", app))
- .arg(i18n("Peak of %1 at snapshot #%2", \
prettyCost(m_data->peak()->cost()), m_data->peak()->number()))
- );
- m_header->setToolTip(i18n("Command: %1\nValgrind Options: %2", m_data->cmd(), \
m_data->description()));
-}
-
void MainWindow::treeSelectionChanged(const QModelIndex& now, const QModelIndex& \
before) {
- if (m_changingSelections || !m_data) {
+ if (currentChangingSelections() || !ui.documents->count()) {
return;
}
if (now == before) {
return;
}
- m_changingSelections = true;
+ setCurrentChangingSelections(true);
- const QPair< TreeLeafItem*, SnapshotItem* >& item = \
m_dataTreeModel->itemForIndex(
- m_dataTreeFilterModel->mapToSource(now)
+ const QPair< TreeLeafItem*, SnapshotItem* >& item = \
currentDocument()->dataTreeModel()->itemForIndex( + \
currentDocument()->dataTreeFilterModel()->mapToSource(now) );
if (now.parent().isValid()) {
- m_detailedCostModel->setSelection(m_detailedCostModel->indexForItem(item));
- m_totalCostModel->setSelection(QModelIndex());
+ currentDocument()->detailedCostModel()->setSelection(currentDocument()->detailedCostModel()->indexForItem(item));
+ currentDocument()->totalCostModel()->setSelection(QModelIndex());
} else {
- m_totalCostModel->setSelection(m_totalCostModel->indexForItem(item));
- m_detailedCostModel->setSelection(QModelIndex());
+ currentDocument()->totalCostModel()->setSelection(currentDocument()->totalCostModel()->indexForItem(item));
+ currentDocument()->detailedCostModel()->setSelection(QModelIndex());
}
- m_chart->update();
+ currentDocument()->chart()->update();
+
#ifdef HAVE_KGRAPHVIEWER
- if (m_graphViewer) {
- showDotGraph(item);
+ if (currentDocument()->graphViewer()) {
+ currendDocument()->showDotGraph(item);
}
#endif
- m_changingSelections = false;
+ setCurrentChangingSelections(false);
}
void MainWindow::detailedItemClicked(const QModelIndex& idx)
{
- if (m_changingSelections || !m_data) {
+ if (currentChangingSelections() || !ui.documents->count()) {
return;
}
- m_changingSelections = true;
+ setCurrentChangingSelections(true);
- m_detailedCostModel->setSelection(idx);
- m_totalCostModel->setSelection(QModelIndex());
+ currentDocument()->detailedCostModel()->setSelection(idx);
+ currentDocument()->totalCostModel()->setSelection(QModelIndex());
// hack: the ToolTip will only be queried by KDChart and that one uses the
// left index, but we want it to query the right one
- const QModelIndex _idx = m_detailedCostModel->index(idx.row() + 1, idx.column(), \
idx.parent()); + const QModelIndex _idx = \
currentDocument()->detailedCostModel()->index(idx.row() + 1, idx.column(), \
idx.parent()); ui.dataTreeView->selectionModel()->clearSelection();
- QPair< TreeLeafItem*, SnapshotItem* > item = \
m_detailedCostModel->itemForIndex(_idx);
- const QModelIndex& newIndex = m_dataTreeFilterModel->mapFromSource(
- m_dataTreeModel->indexForItem(item)
+ QPair< TreeLeafItem*, SnapshotItem* > item = \
currentDocument()->detailedCostModel()->itemForIndex(_idx); + const QModelIndex& \
newIndex = currentDocument()->dataTreeFilterModel()->mapFromSource( + \
currentDocument()->dataTreeModel()->indexForItem(item) );
ui.dataTreeView->selectionModel()->setCurrentIndex(newIndex, \
QItemSelectionModel::Select | QItemSelectionModel::Rows);
ui.dataTreeView->scrollTo(ui.dataTreeView->selectionModel()->currentIndex());
- m_chart->update();
+ currentDocument()->chart()->update();
+
#ifdef HAVE_KGRAPHVIEWER
- if (m_graphViewer) {
- showDotGraph(item);
+ if (currentDocument()->graphViewer()) {
+ currentDocument()->showDotGraph(item);
}
#endif
- m_changingSelections = false;
+ setCurrentChangingSelections(false);
}
void MainWindow::totalItemClicked(const QModelIndex& idx_)
{
- if (m_changingSelections || !m_data) {
+ if (currentChangingSelections() || !ui.documents->count()) {
return;
}
- m_changingSelections = true;
+ setCurrentChangingSelections(true);
QModelIndex idx = idx_.model()->index(idx_.row() + 1, idx_.column(), \
idx_.parent());
- m_detailedCostModel->setSelection(QModelIndex());
- m_totalCostModel->setSelection(idx);
+ currentDocument()->detailedCostModel()->setSelection(QModelIndex());
+ currentDocument()->totalCostModel()->setSelection(idx);
- QPair< TreeLeafItem*, SnapshotItem* > item = \
m_totalCostModel->itemForIndex(idx); + QPair< TreeLeafItem*, SnapshotItem* > item \
= currentDocument()->totalCostModel()->itemForIndex(idx);
ui.dataTreeView->selectionModel()->clearSelection();
- const QModelIndex& newIndex = m_dataTreeFilterModel->mapFromSource(
- m_dataTreeModel->indexForItem(item)
+ const QModelIndex& newIndex = \
currentDocument()->dataTreeFilterModel()->mapFromSource( + \
currentDocument()->dataTreeModel()->indexForItem(item) );
ui.dataTreeView->selectionModel()->setCurrentIndex(newIndex, \
QItemSelectionModel::Select | QItemSelectionModel::Rows);
ui.dataTreeView->scrollTo(ui.dataTreeView->selectionModel()->currentIndex());
- m_chart->update();
+ currentDocument()->chart()->update();
- m_changingSelections = false;
+ setCurrentChangingSelections(false);
}
-void MainWindow::closeFile()
+void MainWindow::closeCurrentFile()
{
- if (!m_data) {
- return;
- }
-
- ui.stackedWidget->setCurrentWidget(ui.openPage);
-
-#ifdef HAVE_KGRAPHVIEWER
- if (m_dotGenerator) {
- if (m_dotGenerator->isRunning()) {
- disconnect(m_dotGenerator.data(), 0, this, 0);
- connect(m_dotGenerator.data(), SIGNAL(finished()),
- m_dotGenerator.data(), SLOT(deleteLater()));
- m_dotGenerator->cancel();
- m_dotGenerator.take();
- }
- m_dotGenerator.reset();
- }
- if (m_graphViewer) {
- m_graphViewerPart->closeUrl();
- m_zoomIn->setEnabled(false);
- m_zoomOut->setEnabled(false);
- m_focusExpensive->setEnabled(false);
- }
- m_lastDotItem.first = 0;
- m_lastDotItem.second = 0;
-#endif
-
- m_close->setEnabled(false);
- m_print->setEnabled(false);
-
- kDebug() << "closing file";
-
- m_chart->replaceCoordinatePlane(new CartesianCoordinatePlane);
- m_legend->removeDiagrams();
- m_legend->hide();
- m_header->setText("");
-
- m_toggleDetailed->setEnabled(false);
- m_toggleDetailed->setChecked(true);
- foreach(CartesianAxis* axis, m_detailedDiagram->axes()) {
- m_detailedDiagram->takeAxis(axis);
- delete axis;
- }
- delete m_detailedDiagram;
- m_detailedDiagram = 0;
+ stopParser();
- m_toggleTotal->setEnabled(false);
- m_toggleTotal->setChecked(true);
- foreach(CartesianAxis* axis, m_totalDiagram->axes()) {
- m_totalDiagram->takeAxis(axis);
- delete axis;
+ // Tab is now removed
+ int tabToCloseIndex = ui.documents->currentIndex();
+ m_changingSelections.remove(currentDocument());
+ m_documentsParseWorkers.remove(currentDocument());
+ ui.documents->widget(tabToCloseIndex)->deleteLater();
+ ui.documents->removeTab(tabToCloseIndex);
+
+ if (!ui.documents->count()) {
+ actionCollection()->action("file_reload")->setEnabled(false);
+ m_close->setEnabled(false);
+ m_print->setEnabled(false);
+ m_toggleDetailed->setEnabled(false);
+ m_toggleTotal->setEnabled(false);
+ m_selectPeak->setEnabled(false);
+ ui.stackedWidget->setCurrentWidget(ui.openPage);
+ ui.stackedWidget->setCurrentWidget(ui.openPage);
+ } else {
+ // Display the remaining(s) file(s).
+ ui.stackedWidget->setCurrentWidget(ui.displayPage);
}
- delete m_totalDiagram;
- m_totalDiagram = 0;
-
- m_dataTreeModel->setSource(0);
- m_dataTreeFilterModel->setFilter("");
- m_detailedCostModel->setSource(0);
- m_totalCostModel->setSource(0);
-
- m_selectPeak->setEnabled(false);
-
- delete m_data;
- m_data = 0;
- m_currentFile.clear();
-
- setWindowTitle(i18n("Massif Visualizer"));
}
void MainWindow::showDetailedGraph(bool show)
{
- Q_ASSERT(m_data);
- Q_ASSERT(m_detailedDiagram);
- m_detailedDiagram->setHidden(!show);
- m_toggleDetailed->setChecked(show);
- m_chart->update();
-}
-
-void MainWindow::showTotalGraph(bool show)
-{
- Q_ASSERT(m_data);
- Q_ASSERT(m_totalDiagram);
- m_totalDiagram->setHidden(!show);
- m_toggleTotal->setChecked(show);
- m_chart->update();
-}
-
-#ifdef HAVE_KGRAPHVIEWER
-void MainWindow::slotTabChanged(int index)
-{
- toolBar("chartToolBar")->setVisible(index == 0);
- foreach(QAction* action, toolBar("chartToolBar")->actions()) {
- action->setEnabled(m_data && index == 0);
- }
- toolBar("callgraphToolBar")->setVisible(index == 1);
- foreach(QAction* action, toolBar("callgraphToolBar")->actions()) {
- action->setEnabled(m_data && index == 1);
- }
- if (index == 1) {
- // if we parsed a dot graph we might want to show it now
- showDotGraph();
- }
-}
-
-void MainWindow::showDotGraph(const QPair<TreeLeafItem*, SnapshotItem*>& item)
-{
- if (item == m_lastDotItem) {
- return;
+ if (ui.documents->count()) {
+ currentDocument()->detailedDiagram()->setHidden(!show);
+ m_toggleDetailed->setChecked(show);
+ currentDocument()->chart()->update();
}
- m_lastDotItem = item;
-
- Q_ASSERT(m_graphViewer);
-
- kDebug() << "new dot graph requested" << item;
- if (m_dotGenerator) {
- kDebug() << "existing generator is running:" << m_dotGenerator->isRunning();
- if (m_dotGenerator->isRunning()) {
- disconnect(m_dotGenerator.data(), 0, this, 0);
- connect(m_dotGenerator.data(), SIGNAL(finished()),
- m_dotGenerator.data(), SLOT(deleteLater()));
- m_dotGenerator->cancel();
- m_dotGenerator.take();
- }
- m_dotGenerator.reset();
- }
- if (!item.first && !item.second) {
- return;
- }
- if (item.second) {
- m_dotGenerator.reset(new DotGraphGenerator(item.second, m_data->timeUnit(), \
this));
- } else {
- m_dotGenerator.reset(new DotGraphGenerator(item.first, m_data->timeUnit(), \
this));
- }
- connect(m_dotGenerator.data(), SIGNAL(finished()), SLOT(showDotGraph()));
- m_dotGenerator->start();
}
-void MainWindow::showDotGraph()
+void MainWindow::showTotalGraph(bool show)
{
- if (!m_dotGenerator || !m_graphViewerPart || \
!m_graphViewerPart->widget()->isVisible()) {
- return;
- }
- kDebug() << "show dot graph in output file" << m_dotGenerator->outputFile();
- if (!m_dotGenerator->outputFile().isEmpty() && m_graphViewerPart->url() != \
KUrl(m_dotGenerator->outputFile())) {
- m_graphViewerPart->openUrl(KUrl(m_dotGenerator->outputFile()));
+ if (ui.documents->count()) {
+ currentDocument()->totalDiagram()->setHidden(!show);
+ m_toggleTotal->setChecked(show);
+ currentDocument()->chart()->update();
}
}
-void MainWindow::slotGraphLoaded()
-{
- Q_ASSERT(m_graphViewer);
-
- if (!m_dotGenerator) {
- return;
- }
- m_graphViewer->setZoomFactor(0.75);
- m_graphViewer->setPannerPosition(KGraphViewer::KGraphViewerInterface::BottomRight);
- m_graphViewer->setPannerEnabled(true);
- m_graphViewer->centerOnNode(m_dotGenerator->mostCostIntensiveGraphvizId());
-}
+#ifdef HAVE_KGRAPHVIEWER
void MainWindow::zoomIn()
{
- Q_ASSERT(m_graphViewer);
+ Q_ASSERT(currentDocument()->graphViewer());
- m_graphViewer->zoomIn();
+ currentDocument()->graphViewer()->zoomIn();
}
void MainWindow::zoomOut()
{
- Q_ASSERT(m_graphViewer);
+ Q_ASSERT(currentDocument()->graphViewer());
- m_graphViewer->zoomOut();
+ currentDocument()->graphViewer()->zoomOut();
}
void MainWindow::focusExpensiveGraphNode()
{
- Q_ASSERT(m_graphViewer);
+ Q_ASSERT(currentDocument()->graphViewer());
- m_graphViewer->centerOnNode(m_dotGenerator->mostCostIntensiveGraphvizId());
+ currentDocument()->graphViewer()->centerOnNode(m_dotGenerator->mostCostIntensiveGraphvizId());
}
#endif
void MainWindow::selectPeakSnapshot()
{
- Q_ASSERT(m_data);
+ Q_ASSERT(currentDocument());
ui.dataTreeView->selectionModel()->clearSelection();
ui.dataTreeView->selectionModel()->setCurrentIndex(
- m_dataTreeFilterModel->mapFromSource(
- m_dataTreeModel->indexForSnapshot(m_data->peak())
- ), QItemSelectionModel::Select | QItemSelectionModel::Rows
+ currentDocument()->dataTreeFilterModel()->mapFromSource(
+ currentDocument()->dataTreeModel()->indexForSnapshot(currentDocument()->data()->peak())),
+ QItemSelectionModel::Select | QItemSelectionModel::Rows
);
}
void MainWindow::setStackNum(int num)
{
- if (m_detailedCostModel) {
- m_detailedCostModel->setMaximumDatasetCount(num);
- updateDetailedPeaks();
- }
-}
-
-void MainWindow::updatePeaks()
-{
- KColorScheme scheme(QPalette::Active, KColorScheme::Window);
- QPen foreground(scheme.foreground().color());
-
- if (m_data->peak()) {
- const QModelIndex peak = m_totalCostModel->peak();
- Q_ASSERT(peak.isValid());
- markPeak(m_totalDiagram, peak, m_data->peak()->cost(), foreground);
- }
- updateDetailedPeaks();
-}
-
-void MainWindow::updateDetailedPeaks()
-{
- KColorScheme scheme(QPalette::Active, KColorScheme::Window);
- QPen foreground(scheme.foreground().color());
-
- QMap< QModelIndex, TreeLeafItem* > peaks = m_detailedCostModel->peaks();
- QMap< QModelIndex, TreeLeafItem* >::const_iterator it = peaks.constBegin();
- while (it != peaks.constEnd()) {
- const QModelIndex peak = it.key();
- Q_ASSERT(peak.isValid());
- markPeak(m_detailedDiagram, peak, it.value()->cost(), foreground);
- ++it;
+ if (ui.documents->count()) {
+ currentDocument()->detailedCostModel()->setMaximumDatasetCount(num);
+ currentDocument()->updatePeaks();
}
}
@@ -952,8 +643,8 @@ void MainWindow::allocatorsChanged()
}
cfg.sync();
- if (m_data) {
- reload();
+ if (ui.documents->count()) {
+ reloadCurrentFile();
}
}
@@ -1005,7 +696,7 @@ void MainWindow::allocatorViewContextMenuRequested(const QPoint& \
pos)
void MainWindow::dataTreeContextMenuRequested(const QPoint& pos)
{
- const QModelIndex idx = m_dataTreeFilterModel->mapToSource(
+ const QModelIndex idx = currentDocument()->dataTreeFilterModel()->mapToSource(
ui.dataTreeView->indexAt(pos));
if (!idx.isValid()) {
return;
@@ -1017,7 +708,7 @@ void MainWindow::dataTreeContextMenuRequested(const QPoint& pos)
}
QMenu menu;
- TreeLeafItem* item = m_dataTreeModel->itemForIndex(idx).first;
+ TreeLeafItem* item = \
currentDocument()->dataTreeModel()->itemForIndex(idx).first; Q_ASSERT(item);
prepareActions(&menu, item);
menu.exec(ui.dataTreeView->mapToGlobal(pos));
@@ -1025,16 +716,16 @@ void MainWindow::dataTreeContextMenuRequested(const QPoint& \
pos)
void MainWindow::chartContextMenuRequested(const QPoint& pos)
{
- const QPoint dPos = m_detailedDiagram->mapFromGlobal(m_chart->mapToGlobal(pos));
+ const QPoint dPos = \
currentDocument()->detailedDiagram()->mapFromGlobal(currentDocument()->chart()->mapToGlobal(pos));
- const QModelIndex idx = m_detailedDiagram->indexAt(dPos);
+ const QModelIndex idx = currentDocument()->detailedDiagram()->indexAt(dPos);
if (!idx.isValid()) {
return;
}
// hack: the ToolTip will only be queried by KDChart and that one uses the
// left index, but we want it to query the right one
- const QModelIndex _idx = m_detailedCostModel->index(idx.row() + 1, idx.column(), \
idx.parent());
- QPair< TreeLeafItem*, SnapshotItem* > item = \
m_detailedCostModel->itemForIndex(_idx); + const QModelIndex _idx = \
currentDocument()->detailedCostModel()->index(idx.row() + 1, idx.column(), \
idx.parent()); + QPair< TreeLeafItem*, SnapshotItem* > item = \
currentDocument()->detailedCostModel()->itemForIndex(_idx);
if (!item.first) {
return;
@@ -1043,7 +734,7 @@ void MainWindow::chartContextMenuRequested(const QPoint& pos)
QMenu menu;
menu.addAction(m_markCustomAllocator);
prepareActions(&menu, item.first);
- menu.exec(m_detailedDiagram->mapToGlobal(dPos));
+ menu.exec(currentDocument()->detailedDiagram()->mapToGlobal(dPos));
}
void MainWindow::prepareActions(QMenu* menu, TreeLeafItem* item)
@@ -1067,12 +758,12 @@ void MainWindow::prepareActions(QMenu* menu, TreeLeafItem* \
item)
void MainWindow::slotHideFunction()
{
- m_detailedCostModel->hideFunction(m_hideFunction->data().value<TreeLeafItem*>());
+ currentDocument()->detailedCostModel()->hideFunction(m_hideFunction->data().value<TreeLeafItem*>());
}
void MainWindow::slotHideOtherFunctions()
{
- m_detailedCostModel->hideOtherFunctions(m_hideOtherFunctions->data().value<TreeLeafItem*>());
+ currentDocument()->detailedCostModel()->hideOtherFunctions(m_hideOtherFunctions->data().value<TreeLeafItem*>());
}
void MainWindow::slotShortenTemplates(bool shorten)
@@ -1087,7 +778,7 @@ void MainWindow::slotShortenTemplates(bool shorten)
void MainWindow::showPrintPreviewDialog()
{
- Q_ASSERT(m_data);
+ Q_ASSERT(ui.documents->count());
QPrinter printer;
QPrintPreviewDialog *ppd = new QPrintPreviewDialog(&printer, this);
@@ -1102,8 +793,49 @@ void MainWindow::printFile(QPrinter *printer)
{
QPainter painter;
painter.begin(printer);
- m_chart->paint(&painter, printer->pageRect());
+ currentDocument()->chart()->paint(&painter, printer->pageRect());
painter.end();
}
+void MainWindow::updateWindowTitle()
+{
+ if (ui.documents->count() && currentDocument()->isLoaded()) {
+ setWindowTitle(i18n("Massif Visualizer - evaluation of %1 (%2)", \
currentDocument()->data()->cmd(), currentDocument()->file().fileName())); + } else \
{ + setWindowTitle(i18n("Massif Visualizer"));
+ }
+}
+
+DocumentWidget* MainWindow::currentDocument() const
+{
+ return qobject_cast<DocumentWidget*>(ui.documents->currentWidget());
+}
+
+void MainWindow::documentChanged()
+{
+ updateWindowTitle();
+
+ if (ui.documents->count() && currentDocument()->isLoaded()) {
+
+ ui.dataTreeView->setModel(currentDocument()->dataTreeFilterModel());
+
+ // FIXME (arnold): this connection shouldn't be necessary
+ connect(ui.dataTreeView->selectionModel(), \
SIGNAL(currentChanged(QModelIndex,QModelIndex)), + this, \
SLOT(treeSelectionChanged(QModelIndex,QModelIndex))); +
+ m_toggleDetailed->setChecked(!currentDocument()->detailedDiagram()->isHidden());
+ m_toggleTotal->setChecked(!currentDocument()->totalDiagram()->isHidden());
+ }
+}
+
+bool MainWindow::currentChangingSelections() const
+{
+ return m_changingSelections[currentDocument()];
+}
+
+void MainWindow::setCurrentChangingSelections(bool changingSelections)
+{
+ m_changingSelections[currentDocument()] = changingSelections;
+}
+
#include "mainwindow.moc"
diff --git a/app/mainwindow.h b/app/mainwindow.h
index 2acc6a8..6d9693f 100644
--- a/app/mainwindow.h
+++ b/app/mainwindow.h
@@ -2,6 +2,7 @@
This file is part of Massif Visualizer
Copyright 2010 Milian Wolff <mail@milianw.de>
+ Copyright 2013 Arnold Dumas <contact@arnolddumas.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -28,9 +29,9 @@
#include <QPrintPreviewDialog>
#include "ui_mainwindow.h"
+#include "documentwidget.h"
class QStringListModel;
-class QLabel;
namespace KDChart {
class Chart;
@@ -41,18 +42,14 @@ class Legend;
class BarDiagram;
}
-namespace KParts {
-class ReadOnlyPart;
-}
-
class KAction;
class KRecentFilesAction;
+#ifdef HAVE_KGRAPHVIEWER
namespace KGraphViewer {
-
class KGraphViewerInterface;
-
}
+#endif
namespace Massif {
@@ -60,9 +57,7 @@ class ParseWorker;
class FileData;
class DetailedCostModel;
class TotalCostModel;
-class DataTreeModel;
class FilteredDataTreeModel;
-class DotGraphGenerator;
class SnapshotItem;
class TreeLeafItem;
@@ -78,7 +73,7 @@ public:
public slots:
/**
- * Open a dialog to pick a massif output file to display.
+ * Open a dialog to pick a massif output file(s) to display.
*/
void openFile();
@@ -90,12 +85,12 @@ public slots:
/**
* reload currently opened file
*/
- void reload();
+ void reloadCurrentFile();
/**
* Close currently opened file.
*/
- void closeFile();
+ void closeCurrentFile();
/**
* Depending on @p show, the total cost graph is shown or hidden.
@@ -127,10 +122,9 @@ private slots:
void selectPeakSnapshot();
void setStackNum(int num);
+ void documentChanged();
+
#ifdef HAVE_KGRAPHVIEWER
- void showDotGraph();
- void slotTabChanged(int index);
- void slotGraphLoaded();
void zoomIn();
void zoomOut();
void focusExpensiveGraphNode();
@@ -153,44 +147,28 @@ private slots:
void slotShortenTemplates(bool);
void stopParser();
- void parserFinished(const KUrl& file, Massif::FileData* data);
+ void parserFinished();
void parserError(const QString& title, const QString& error);
private:
- void showDotGraph(const QPair<TreeLeafItem*, SnapshotItem*>& item);
- void updateHeader();
- void updatePeaks();
void updateDetailedPeaks();
+ void updateWindowTitle();
void prepareActions(QMenu* menu, TreeLeafItem* item);
+ // Helper
+ DocumentWidget* currentDocument() const;
+
Ui::MainWindow ui;
- KDChart::Chart* m_chart;
- QLabel* m_header;
- KAction* m_toggleTotal;
- KDChart::Plotter* m_totalDiagram;
- TotalCostModel* m_totalCostModel;
+ KAction* m_toggleTotal;
KAction* m_toggleDetailed;
- KDChart::Plotter* m_detailedDiagram;
- DetailedCostModel* m_detailedCostModel;
-
- KDChart::Legend* m_legend;
-
- DataTreeModel* m_dataTreeModel;
- FilteredDataTreeModel* m_dataTreeFilterModel;
- FileData* m_data;
- KUrl m_currentFile;
KAction* m_selectPeak;
-
KRecentFilesAction* m_recentFiles;
- bool m_changingSelections;
-#ifdef HAVE_KGRAPHVIEWER
- KParts::ReadOnlyPart* m_graphViewerPart;
- KGraphViewer::KGraphViewerInterface* m_graphViewer;
- QScopedPointer<DotGraphGenerator> m_dotGenerator;
- QPair<TreeLeafItem*, SnapshotItem*> m_lastDotItem;
-#endif
+ QHash<DocumentWidget*, bool> m_changingSelections;
+ bool currentChangingSelections() const;
+ void setCurrentChangingSelections(bool changingSelections);
+
KAction* m_zoomIn;
KAction* m_zoomOut;
KAction* m_focusExpensive;
@@ -208,7 +186,7 @@ private:
KAction* m_shortenTemplates;
- ParseWorker* m_parseWorker;
+ QHash<DocumentWidget*, ParseWorker*> m_documentsParseWorkers;
};
}
diff --git a/app/mainwindow.ui b/app/mainwindow.ui
index 8ac4119..4fda1a6 100644
--- a/app/mainwindow.ui
+++ b/app/mainwindow.ui
@@ -12,38 +12,33 @@
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout_4">
- <property name="margin">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QStackedWidget" name="stackedWidget">
+ <property name="currentIndex">
+ <number>1</number>
+ </property>
<widget class="QWidget" name="displayPage">
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
- <widget class="QTabWidget" name="tabWidget">
+ <widget class="QTabWidget" name="documents">
<property name="currentIndex">
- <number>0</number>
+ <number>-1</number>
+ </property>
+ <property name="documentMode">
+ <bool>true</bool>
</property>
- <widget class="QWidget" name="plotterTab">
- <attribute name="title">
- <string>&Evolution of Memory Consumption</string>
- </attribute>
- <layout class="QVBoxLayout" name="verticalLayout_2">
- <property name="margin">
- <number>0</number>
- </property>
- </layout>
- </widget>
- <widget class="QWidget" name="dotGraphTab">
- <attribute name="title">
- <string>&Detailed Snapshot Analysis</string>
- </attribute>
- <layout class="QVBoxLayout" name="verticalLayout_3">
- <property name="margin">
- <number>0</number>
- </property>
- </layout>
- </widget>
</widget>
</item>
</layout>
@@ -94,72 +89,6 @@
</item>
</layout>
</widget>
- <widget class="QWidget" name="loadingPage">
- <layout class="QVBoxLayout" name="verticalLayout_8">
- <item>
- <spacer name="verticalSpacer_3">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>247</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <widget class="QLabel" name="loadingMessage">
- <property name="text">
- <string notr="true">loading...</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignCenter</set>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QProgressBar" name="loadingProgress">
- <property name="value">
- <number>24</number>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QWidget" name="widget_3" native="true">
- <property name="layoutDirection">
- <enum>Qt::LeftToRight</enum>
- </property>
- <layout class="QHBoxLayout" name="horizontalLayout_3">
- <item>
- <widget class="QToolButton" name="stopParsing">
- <property name="text">
- <string>...</string>
- </property>
- <property name="toolButtonStyle">
- <enum>Qt::ToolButtonTextUnderIcon</enum>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <spacer name="verticalSpacer_4">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>230</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
</widget>
</item>
</layout>
@@ -170,7 +99,7 @@
<x>0</x>
<y>0</y>
<width>800</width>
- <height>22</height>
+ <height>19</height>
</rect>
</property>
</widget>
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic