modeltest.cpp
parser.cpp
flamegraph.cpp
+ stacksmodel.cpp
${UIFILES}
)
KChart
sharedprint)
-install(TARGETS heaptrack_gui ${INSTALL_TARGETS_DEFAULT_ARGS})
\ No newline at end of file
+install(TARGETS heaptrack_gui ${INSTALL_TARGETS_DEFAULT_ARGS})
parser.process(app);
aboutData.processCommandLine(&parser);
- foreach (const QString &file, parser.positionalArguments()) {
- MainWindow* window = new MainWindow;
- window->loadFile(file);
+ auto createWindow = [] () -> MainWindow* {
+ auto window = new MainWindow;
+ window->setAttribute(Qt::WA_DeleteOnClose);
window->show();
+ return window;
+ };
+
+ foreach (const QString &file, parser.positionalArguments()) {
+ createWindow()->loadFile(file);
}
if (parser.positionalArguments().isEmpty()) {
- MainWindow* window = new MainWindow;
- window->show();
+ createWindow();
}
return app.exec();
-}
\ No newline at end of file
+}
#include <QFileDialog>
#include <QStatusBar>
+#include <KConfigGroup>
+#include <QDebug>
#include "treemodel.h"
#include "treeproxy.h"
#include "chartmodel.h"
#include "chartproxy.h"
#include "histogrammodel.h"
+#include "stacksmodel.h"
using namespace std;
+namespace {
+const int MAINWINDOW_VERSION = 1;
+namespace Config {
+namespace Groups {
+const char MainWindow[] = "MainWindow";
+}
+namespace Entries {
+const char State[] = "State";
+}
+}
+}
+
MainWindow::MainWindow(QWidget* parent)
: QMainWindow(parent)
, m_ui(new Ui::MainWindow)
, m_parser(new Parser(this))
+ , m_config(KSharedConfig::openConfig(QStringLiteral("heaptrack_gui")))
{
m_ui->setupUi(this);
+ auto group = m_config->group(Config::Groups::MainWindow);
+ auto state = group.readEntry(Config::Entries::State, QByteArray());
+ restoreState(state, MAINWINDOW_VERSION);
+
m_ui->pages->setCurrentWidget(m_ui->openPage);
// TODO: proper progress report
m_ui->loadingProgress->setMinimum(0);
statusBar()->addWidget(m_ui->progressLabel, 1);
statusBar()->addWidget(m_ui->loadingProgress);
m_ui->pages->setCurrentWidget(m_ui->resultsPage);
+ m_ui->stacksDock->setVisible(true);
});
connect(m_parser, &Parser::topDownDataAvailable,
this, [=] (const TreeData& data) {
auto openFile = KStandardAction::open(this, SLOT(openFile()), this);
m_ui->openFile->setDefaultAction(openFile);
+ auto stacksModel = new StacksModel(this);
+ m_ui->stacksTree->setModel(stacksModel);
+ m_ui->stacksTree->setRootIsDecorated(false);
+ auto updateStackSpinner = [this] (int stacks) {
+ m_ui->stackSpinner->setMinimum(min(stacks, 1));
+ m_ui->stackSpinner->setSuffix(i18n(" / %1", stacks));
+ m_ui->stackSpinner->setMaximum(stacks);
+ };
+ updateStackSpinner(0);
+ connect(stacksModel, &StacksModel::stacksFound,
+ this, updateStackSpinner);
+ connect(m_ui->stackSpinner, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
+ stacksModel, &StacksModel::setStackIndex);
+ auto fillFromIndex = [stacksModel] (const QModelIndex& current) {
+ if (!current.isValid()) {
+ stacksModel->clear();
+ } else {
+ auto proxy = qobject_cast<const TreeProxy*>(current.model());
+ Q_ASSERT(proxy);
+ auto leaf = proxy->mapToSource(current);
+ stacksModel->fillFromIndex(leaf);
+ }
+ };
+ connect(m_ui->bottomUpResults->selectionModel(), &QItemSelectionModel::currentChanged,
+ this, fillFromIndex);
+ connect(m_ui->topDownResults->selectionModel(), &QItemSelectionModel::currentChanged,
+ this, fillFromIndex);
+ connect(m_ui->tabWidget, &QTabWidget::currentChanged, this, [this, fillFromIndex] (int tabIndex) {
+ const auto widget = m_ui->tabWidget->widget(tabIndex);
+ const bool showDocks = (widget == m_ui->topDownTab || widget == m_ui->bottomUpTab);
+ m_ui->stacksDock->setVisible(showDocks);
+ if (showDocks) {
+ auto tree = (widget == m_ui->topDownTab) ? m_ui->topDownResults : m_ui->bottomUpResults;
+ fillFromIndex(tree->selectionModel()->currentIndex());
+ }
+ });
+ m_ui->stacksDock->setVisible(false);
+ m_ui->stacksDock->setFeatures(QDockWidget::DockWidgetMovable);
+
setWindowTitle(i18n("Heaptrack"));
}
MainWindow::~MainWindow()
{
+ auto state = saveState(MAINWINDOW_VERSION);
+ auto group = m_config->group(Config::Groups::MainWindow);
+ group.writeEntry(Config::Entries::State, state);
}
void MainWindow::loadFile(const QString& file)
#define MAINWINDOW_H
#include <QMainWindow>
+#include <KSharedConfig>
namespace Ui {
class MainWindow;
private:
QScopedPointer<Ui::MainWindow> m_ui;
Parser* m_parser;
+ KSharedConfig::Ptr m_config;
};
#endif // MAINWINDOW_H
<rect>
<x>0</x>
<y>0</y>
- <width>800</width>
- <height>600</height>
+ <width>1128</width>
+ <height>896</height>
</rect>
</property>
<property name="windowTitle">
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
- <number>0</number>
+ <number>7</number>
</property>
<widget class="QWidget" name="bottomUpTab">
<attribute name="title">
</item>
</layout>
</widget>
+ <widget class="QDockWidget" name="stacksDock">
+ <property name="windowTitle">
+ <string>S&tacks</string>
+ </property>
+ <attribute name="dockWidgetArea">
+ <number>2</number>
+ </attribute>
+ <widget class="QWidget" name="stacksDockContents">
+ <layout class="QVBoxLayout" name="verticalLayout_5">
+ <item>
+ <widget class="QWidget" name="widget_3" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_5">
+ <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="QLabel" name="stackSpinnerLabel">
+ <property name="text">
+ <string>Selected Stack:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="stackSpinner"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTreeView" name="stacksTree">
+ <property name="rootIsDecorated">
+ <bool>false</bool>
+ </property>
+ <property name="uniformRowHeights">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
</widget>
<customwidgets>
<customwidget>
--- /dev/null
+/*
+ * Copyright 2015 Milian Wolff <mail@milianw.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * 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, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stacksmodel.h"
+#include "treemodel.h"
+
+#include <KLocalizedString>
+
+#include <QDebug>
+
+StacksModel::StacksModel(QObject* parent)
+ : QAbstractListModel(parent)
+{
+}
+
+StacksModel::~StacksModel() = default;
+
+void StacksModel::setStackIndex(int index)
+{
+ beginResetModel();
+ m_stackIndex = index - 1;
+ endResetModel();
+}
+
+static void findLeafs(const QModelIndex& index, QVector<QModelIndex>* leafs)
+{
+ int rows = index.model()->rowCount(index);
+ if (!rows) {
+ leafs->append(index);
+ return;
+ }
+ for (int i = 0; i < rows; ++i) {
+ findLeafs(index.child(i, 0), leafs);
+ }
+}
+
+void StacksModel::fillFromIndex(const QModelIndex& index)
+{
+ if (index.column() != 0) {
+ // only the first column has children
+ fillFromIndex(index.sibling(index.row(), 0));
+ return;
+ }
+
+ QVector<QModelIndex> leafs;
+ findLeafs(index, &leafs);
+
+ beginResetModel();
+ m_data.clear();
+ m_data.resize(leafs.size());
+ m_stackIndex = 0;
+ int stackIndex = 0;
+ foreach (QModelIndex leaf, leafs) {
+ auto& stack = m_data[stackIndex];
+ while (leaf.isValid()) {
+ stack << leaf.sibling(leaf.row(), TreeModel::LocationColumn);
+ leaf = leaf.parent();
+ }
+ std::reverse(stack.begin(), stack.end());
+ ++stackIndex;
+ }
+ endResetModel();
+
+ emit stacksFound(m_data.size());
+}
+
+void StacksModel::clear()
+{
+ beginResetModel();
+ m_data.clear();
+ endResetModel();
+ emit stacksFound(0);
+}
+
+int StacksModel::rowCount(const QModelIndex& parent) const
+{
+ if (parent.isValid() || m_data.isEmpty()) {
+ return 0;
+ }
+ return m_data.value(m_stackIndex).size();
+}
+
+QVariant StacksModel::data(const QModelIndex& index, int role) const
+{
+ if (!hasIndex(index.row(), index.column(), index.parent())) {
+ return {};
+ }
+ return m_data.value(m_stackIndex).value(index.row()).data(role);
+}
+
+QVariant StacksModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (section == 0 && role == Qt::DisplayRole && orientation == Qt::Horizontal) {
+ return i18n("Backtrace");
+ }
+ return {};
+}
--- /dev/null
+/*
+ * Copyright 2015 Milian Wolff <mail@milianw.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * 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, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef STACKSMODEL_H
+#define STACKSMODEL_H
+
+#include <QAbstractListModel>
+
+class StacksModel : public QAbstractListModel
+{
+ Q_OBJECT
+public:
+ explicit StacksModel(QObject* parent = nullptr);
+ ~StacksModel();
+
+ void setStackIndex(int index);
+ void fillFromIndex(const QModelIndex& leaf);
+ void clear();
+
+ int rowCount(const QModelIndex& parent) const override;
+ QVariant data(const QModelIndex& index, int role) const override;
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
+
+signals:
+ void stacksFound(int stacks);
+
+private:
+ QVector<QVector<QModelIndex>> m_data;
+ int m_stackIndex = 0;
+};
+
+#endif // STACKSMODEL_H