From: Milian Wolff Date: Tue, 23 Feb 2016 22:45:45 +0000 (+0100) Subject: Add stacks model to display full backtrace for selection. X-Git-Tag: submit/tizen/20180620.112952^2~223 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=2d11d8e2c50cbd44a3dbd9b7619a193fda7ed002;p=sdk%2Ftools%2Fheaptrack.git Add stacks model to display full backtrace for selection. --- diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt index 2b86a1c..8683694 100644 --- a/gui/CMakeLists.txt +++ b/gui/CMakeLists.txt @@ -24,6 +24,7 @@ add_executable(heaptrack_gui modeltest.cpp parser.cpp flamegraph.cpp + stacksmodel.cpp ${UIFILES} ) @@ -43,4 +44,4 @@ target_link_libraries(heaptrack_gui KChart sharedprint) -install(TARGETS heaptrack_gui ${INSTALL_TARGETS_DEFAULT_ARGS}) \ No newline at end of file +install(TARGETS heaptrack_gui ${INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/gui/gui.cpp b/gui/gui.cpp index 64b0b7f..4667904 100644 --- a/gui/gui.cpp +++ b/gui/gui.cpp @@ -58,16 +58,20 @@ int main(int argc, char** argv) 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 +} diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index e623f83..d874ed0 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -27,6 +27,8 @@ #include #include +#include +#include #include "treemodel.h" #include "treeproxy.h" @@ -34,16 +36,34 @@ #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); @@ -79,6 +99,7 @@ MainWindow::MainWindow(QWidget* parent) 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) { @@ -156,11 +177,53 @@ MainWindow::MainWindow(QWidget* parent) 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(&QSpinBox::valueChanged), + stacksModel, &StacksModel::setStackIndex); + auto fillFromIndex = [stacksModel] (const QModelIndex& current) { + if (!current.isValid()) { + stacksModel->clear(); + } else { + auto proxy = qobject_cast(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) diff --git a/gui/mainwindow.h b/gui/mainwindow.h index eec98d2..d9c83ba 100644 --- a/gui/mainwindow.h +++ b/gui/mainwindow.h @@ -21,6 +21,7 @@ #define MAINWINDOW_H #include +#include namespace Ui { class MainWindow; @@ -44,6 +45,7 @@ public slots: private: QScopedPointer m_ui; Parser* m_parser; + KSharedConfig::Ptr m_config; }; #endif // MAINWINDOW_H diff --git a/gui/mainwindow.ui b/gui/mainwindow.ui index 9946b19..6a6e728 100644 --- a/gui/mainwindow.ui +++ b/gui/mainwindow.ui @@ -6,8 +6,8 @@ 0 0 - 800 - 600 + 1128 + 896 @@ -106,7 +106,7 @@ - 0 + 7 @@ -279,6 +279,56 @@ + + + S&tacks + + + 2 + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Selected Stack: + + + + + + + + + + + + + false + + + true + + + + + + diff --git a/gui/stacksmodel.cpp b/gui/stacksmodel.cpp new file mode 100644 index 0000000..3d165e3 --- /dev/null +++ b/gui/stacksmodel.cpp @@ -0,0 +1,113 @@ +/* + * Copyright 2015 Milian Wolff + * + * 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 + +#include + +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* 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 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 {}; +} diff --git a/gui/stacksmodel.h b/gui/stacksmodel.h new file mode 100644 index 0000000..8d0d9b8 --- /dev/null +++ b/gui/stacksmodel.h @@ -0,0 +1,48 @@ +/* + * Copyright 2015 Milian Wolff + * + * 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 + +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> m_data; + int m_stackIndex = 0; +}; + +#endif // STACKSMODEL_H