@@ -31,11 +31,13 @@ endif (OPENGL_FOUND AND GLUT_FOUND)
if (Qt5Widgets_FOUND AND Qt5Network_FOUND)
message(STATUS "libkshark-gui")
- set (ks-guiLib_hdr KsUtils.hpp)
+ set (ks-guiLib_hdr KsUtils.hpp
+ KsWidgetsLib.hpp)
QT5_WRAP_CPP(ks-guiLib_hdr_moc ${ks-guiLib_hdr})
- add_library(kshark-gui SHARED ${ks-guiLib_hdr_moc} KsUtils.cpp)
+ add_library(kshark-gui SHARED ${ks-guiLib_hdr_moc} KsUtils.cpp
+ KsWidgetsLib.cpp)
target_link_libraries(kshark-gui kshark-plot
${CMAKE_DL_LIBS}
new file mode 100644
@@ -0,0 +1,878 @@
+// SPDX-License-Identifier: LGPL-2.1
+
+/*
+ * Copyright (C) 2017 VMware Inc, Yordan Karadzhov <ykaradzhov@vmware.com>
+ */
+
+/**
+ * @file KsWidgetsLib.cpp
+ * @brief Defines small widgets and dialogues used by the KernelShark GUI.
+ */
+
+// KernelShark
+#include "libkshark.h"
+#include "KsUtils.hpp"
+#include "KsCmakeDef.hpp"
+#include "KsPlotTools.hpp"
+#include "KsWidgetsLib.hpp"
+
+/**
+ * @brief Create KsProgressBar.
+ *
+ * @param message: Text to be shown.
+ * @param parent: The parent of this widget.
+ */
+KsProgressBar::KsProgressBar(QString message, QWidget *parent)
+: QWidget(parent),
+ _sb(this),
+ _pb(&_sb) {
+ resize(KS_BROGBAR_WIDTH, KS_BROGBAR_HEIGHT);
+ setWindowTitle("KernelShark");
+ setLayout(new QVBoxLayout);
+
+ _pb.setOrientation(Qt::Horizontal);
+ _pb.setTextVisible(false);
+ _pb.setRange(0, KS_PROGRESS_BAR_MAX);
+ _pb.setValue(1);
+
+ _sb.addPermanentWidget(&_pb, 1);
+
+ layout()->addWidget(new QLabel(message));
+ layout()->addWidget(&_sb);
+
+ setWindowFlags(Qt::WindowStaysOnTopHint);
+
+ show();
+}
+
+/** @brief Set the state of the progressbar.
+ *
+ * @param i: A value ranging from 0 to KS_PROGRESS_BAR_MAX.
+ */
+void KsProgressBar::setValue(int i) {
+ _pb.setValue(i);
+ QApplication::processEvents();
+}
+
+/**
+ * @brief Create KsMessageDialog.
+ *
+ * @param message: Text to be shown.
+ * @param parent: The parent of this widget.
+ */
+KsMessageDialog::KsMessageDialog(QString message, QWidget *parent)
+: QDialog(parent),
+ _text(message, this),
+ _closeButton("Close", this)
+{
+ resize(KS_MSG_DIALOG_WIDTH, KS_MSG_DIALOG_HEIGHT);
+
+ _layout.addWidget(&_text);
+ _layout.addWidget(&_closeButton);
+
+ connect(&_closeButton, &QPushButton::pressed,
+ this, &QWidget::close);
+
+ this->setLayout(&_layout);
+}
+
+/**
+ * @brief Create KsCheckBoxWidget.
+ *
+ * @param name: The name of this widget.
+ * @param parent: The parent of this widget.
+ */
+KsCheckBoxWidget::KsCheckBoxWidget(const QString &name, QWidget *parent)
+: QWidget(parent),
+ _tb(this),
+ _allCb("all", &_tb),
+ _cbWidget(this),
+ _cbLayout(&_cbWidget),
+ _topLayout(this),
+ _name(name),
+ _nameLabel(name + ": ",&_tb)
+{
+ setWindowTitle(_name);
+ setMinimumHeight(SCREEN_HEIGHT / 2);
+
+ connect(&_allCb, &QCheckBox::clicked,
+ this, &KsCheckBoxWidget::_checkAll);
+
+ _cbWidget.setLayout(&_cbLayout);
+
+ _tb.addWidget(&_nameLabel);
+ _tb.addWidget(&_allCb);
+ _topLayout.addWidget(&_tb);
+
+ _topLayout.addWidget(&_cbWidget);
+ _topLayout.setContentsMargins(0, 0, 0, 0);
+
+ setLayout(&_topLayout);
+ _allCb.setCheckState(Qt::Checked);
+}
+
+/**
+ * Set the default state for all checkboxes (including the "all" checkbox).
+ */
+void KsCheckBoxWidget::setDefault(bool st)
+{
+ Qt::CheckState state = Qt::Unchecked;
+
+ if (st)
+ state = Qt::Checked;
+
+ _allCb.setCheckState(state);
+ _checkAll(state);
+}
+
+/** Get a vector containing the indexes of all checked boxes. */
+QVector<int> KsCheckBoxWidget::getCheckedIds()
+{
+ QVector<int> vec;
+ int n = _id.size();
+
+ for (int i = 0; i < n; ++i)
+ if (_checkState(i) == Qt::Checked)
+ vec.append(_id[i]);
+
+ return vec;
+}
+
+/**
+ * @brief Set the state of the checkboxes.
+ *
+ * @param v: Vector containing the bool values for all checkboxes.
+ */
+void KsCheckBoxWidget::set(QVector<bool> v)
+{
+ Qt::CheckState state;
+ int nChecks;
+
+ nChecks = (v.size() < _id.size()) ? v.size() : _id.size();
+
+ /* Start with the "all" checkbox being checked. */
+ _allCb.setCheckState(Qt::Checked);
+ for (int i = 0; i < nChecks; ++i) {
+ if (v[i]) {
+ state = Qt::Checked;
+ } else {
+ /*
+ * At least one checkbox is unchecked. Uncheck
+ * "all" as well.
+ */
+ state = Qt::Unchecked;
+ _allCb.setCheckState(state);
+ }
+
+ _setCheckState(i, state);
+ }
+ _verify();
+}
+
+void KsCheckBoxWidget::_checkAll(bool st)
+{
+ Qt::CheckState state = Qt::Unchecked;
+ int n = _id.size();
+
+ if (st) state = Qt::Checked;
+
+ for (int i = 0; i < n; ++i) {
+ _setCheckState(i, state);
+ }
+
+ _verify();
+}
+
+/**
+ * @brief Create KsCheckBoxDialog.
+ *
+ * @param cbw: A KsCheckBoxWidget to be nested in this dialog.
+ * @param parent: The parent of this widget.
+ */
+KsCheckBoxDialog::KsCheckBoxDialog(KsCheckBoxWidget *cbw, QWidget *parent)
+: QDialog(parent), _checkBoxWidget(cbw),
+ _applyButton("Apply", this),
+ _cancelButton("Cancel", this)
+{
+ int buttonWidth;
+
+ setWindowTitle(cbw->name());
+ _topLayout.addWidget(_checkBoxWidget);
+
+ buttonWidth = STRING_WIDTH("--Cancel--");
+ _applyButton.setFixedWidth(buttonWidth);
+ _cancelButton.setFixedWidth(buttonWidth);
+
+ _buttonLayout.addWidget(&_applyButton);
+ _applyButton.setAutoDefault(false);
+
+ _buttonLayout.addWidget(&_cancelButton);
+ _cancelButton.setAutoDefault(false);
+
+ _buttonLayout.setAlignment(Qt::AlignLeft);
+ _topLayout.addLayout(&_buttonLayout);
+
+ _applyButtonConnection =
+ connect(&_applyButton, &QPushButton::pressed,
+ this, &KsCheckBoxDialog::_applyPress);
+
+ connect(&_applyButton, &QPushButton::pressed,
+ this, &QWidget::close);
+
+ connect(&_cancelButton, &QPushButton::pressed,
+ this, &QWidget::close);
+
+ this->setLayout(&_topLayout);
+}
+
+void KsCheckBoxDialog::_applyPress()
+{
+ QVector<int> vec = _checkBoxWidget->getCheckedIds();
+ emit apply(vec);
+
+ /*
+ * Disconnect _applyButton. This is done in order to protect
+ * against multiple clicks.
+ */
+ disconnect(_applyButtonConnection);
+}
+
+
+/**
+ * @brief Create KsCheckBoxTable.
+ *
+ * @param parent: The parent of this widget.
+ */
+KsCheckBoxTable::KsCheckBoxTable(QWidget *parent)
+: QTableWidget(parent)
+{
+ setShowGrid(false);
+ horizontalHeader()->setDefaultAlignment(Qt::AlignLeft);
+ horizontalHeader()->setStretchLastSection(true);
+ setSelectionBehavior(QAbstractItemView::SelectRows);
+ setEditTriggers(QAbstractItemView::NoEditTriggers);
+ setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ verticalHeader()->setVisible(false);
+
+ connect(this, &QTableWidget::cellDoubleClicked,
+ this, &KsCheckBoxTable::_doubleClicked);
+}
+
+/**
+ * @brief Initialize the table.
+ *
+ * @param headers: The headers of the individual columns.
+ * @param size: The number of rows.
+ */
+void KsCheckBoxTable::init(QStringList headers, int size)
+{
+ QHBoxLayout *cbLayout;
+ QWidget *cbWidget;
+
+ setColumnCount(headers.count());
+ setRowCount(size);
+ setHorizontalHeaderLabels(headers);
+
+ _cb.resize(size);
+
+ for (int i = 0; i < size; ++i) {
+ cbWidget = new QWidget();
+ _cb[i] = new QCheckBox(cbWidget);
+ cbLayout = new QHBoxLayout(cbWidget);
+
+ cbLayout->addWidget(_cb[i]);
+ cbLayout->setAlignment(Qt::AlignCenter);
+ cbLayout->setContentsMargins(0, 0, 0, 0);
+
+ cbWidget->setLayout(cbLayout);
+ setCellWidget(i, 0, cbWidget);
+ }
+}
+
+/** Reimplemented event handler used to receive key press events. */
+void KsCheckBoxTable::keyPressEvent(QKeyEvent *event)
+{
+ if (event->key() == Qt::Key_Return) {
+ for (auto &s: selectedItems()) {
+ if (s->column() == 1)
+ emit changeState(s->row());
+ }
+ }
+
+ QApplication::processEvents();
+ QTableWidget::keyPressEvent(event);
+}
+
+/** Reimplemented event handler used to receive mouse press events. */
+void KsCheckBoxTable::mousePressEvent(QMouseEvent *event)
+{
+ if (event->button() == Qt::RightButton) {
+ for (auto &i: selectedItems())
+ i->setSelected(false);
+
+ return;
+ }
+
+ QApplication::processEvents();
+ QTableWidget::mousePressEvent(event);
+}
+
+void KsCheckBoxTable::_doubleClicked(int row, int col)
+{
+ emit changeState(row);
+ for (auto &i: selectedItems())
+ i->setSelected(false);
+}
+
+/**
+ * @brief Create KsCheckBoxTableWidget.
+ *
+ * @param name: The name of this widget.
+ * @param parent: The parent of this widget.
+ */
+KsCheckBoxTableWidget::KsCheckBoxTableWidget(const QString &name,
+ QWidget *parent)
+: KsCheckBoxWidget(name, parent),
+ _table(this)
+{
+ connect(&_table, &KsCheckBoxTable::changeState,
+ this, &KsCheckBoxTableWidget::_changeState);
+}
+
+/** Initialize the KsCheckBoxTable and its layout. */
+void KsCheckBoxTableWidget::_initTable(QStringList headers, int size)
+{
+ _table.init(headers, size);
+
+ for (auto const & cb: _table._cb) {
+ connect(cb, &QCheckBox::clicked,
+ this, &KsCheckBoxTableWidget::_update);
+ }
+
+ _cbLayout.setContentsMargins(1, 1, 1, 1);
+ _cbLayout.addWidget(&_table);
+}
+
+/** Adjust the size of this widget according to its content. */
+void KsCheckBoxTableWidget::_adjustSize()
+{
+ int width;
+
+ _table.setVisible(false);
+ _table.resizeColumnsToContents();
+ _table.setVisible(true);
+
+ width = _table.horizontalHeader()->length() +
+ FONT_WIDTH * 3 +
+ style()->pixelMetric(QStyle::PM_ScrollBarExtent);
+
+ _cbWidget.resize(width, _cbWidget.height());
+
+ setMinimumWidth(_cbWidget.width() +
+ _cbLayout.contentsMargins().left() +
+ _cbLayout.contentsMargins().right() +
+ _topLayout.contentsMargins().left() +
+ _topLayout.contentsMargins().right());
+}
+
+void KsCheckBoxTableWidget::_update(bool state)
+{
+ /* If a Checkbox is being unchecked. Unchecked "all" as well. */
+ if (!state)
+ _allCb.setCheckState(Qt::Unchecked);
+}
+
+void KsCheckBoxTableWidget::_changeState(int row)
+{
+ if (_table._cb[row]->checkState() == Qt::Checked)
+ _table._cb[row]->setCheckState(Qt::Unchecked);
+ else
+ _table._cb[row]->setCheckState(Qt::Checked);
+
+ _allCb.setCheckState(Qt::Checked);
+ for (auto &c: _table._cb) {
+ if (c->checkState() == Qt::Unchecked) {
+ _allCb.setCheckState(Qt::Unchecked);
+ break;
+ }
+ }
+}
+
+static void update_r(QTreeWidgetItem *item, Qt::CheckState state)
+{
+ int n;
+
+ item->setCheckState(0, state);
+
+ n = item->childCount();
+ for (int i = 0; i < n; ++i)
+ update_r(item->child(i), state);
+}
+
+/**
+ * @brief Create KsCheckBoxTree.
+ *
+ * @param parent: The parent of this widget.
+ */
+KsCheckBoxTree::KsCheckBoxTree(QWidget *parent)
+: QTreeWidget(parent)
+{
+ setColumnCount(2);
+ setHeaderHidden(true);
+ setSelectionBehavior(QAbstractItemView::SelectRows);
+ setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+
+ connect(this, &KsCheckBoxTree::itemDoubleClicked,
+ this, &KsCheckBoxTree::_doubleClicked);
+}
+
+/** Reimplemented event handler used to receive key press events. */
+void KsCheckBoxTree::keyPressEvent(QKeyEvent *event)
+{
+ if (event->key() == Qt::Key_Return) {
+ /* Loop over all selected child items and change
+ * there states. */
+ for (auto &s: selectedItems()) {
+ if(s->childCount()) {
+ if (s->isExpanded())
+ continue;
+ }
+
+ if (s->checkState(0) == Qt::Unchecked)
+ s->setCheckState(0, Qt::Checked);
+ else
+ s->setCheckState(0, Qt::Unchecked);
+
+ if(s->childCount()) {
+ update_r(s, s->checkState(0));
+ }
+ }
+ }
+
+ emit verify();
+ QTreeWidget::keyPressEvent(event);
+}
+
+void KsCheckBoxTree::_doubleClicked(QTreeWidgetItem *item, int col)
+{
+ if (item->checkState(0) == Qt::Unchecked)
+ item->setCheckState(0, Qt::Checked);
+ else
+ item->setCheckState(0, Qt::Unchecked);
+
+ for (auto &i: selectedItems())
+ i->setSelected(false);
+
+ emit itemClicked(item, col);
+}
+
+/** Reimplemented event handler used to receive mouse press events. */
+void KsCheckBoxTree::mousePressEvent(QMouseEvent *event)
+{
+ if (event->button() == Qt::RightButton) {
+ for (auto &i: selectedItems())
+ i->setSelected(false);
+ return;
+ }
+
+ QApplication::processEvents();
+ QTreeWidget::mousePressEvent(event);
+}
+
+/**
+ * @brief Create KsCheckBoxTreeWidget.
+ *
+ * @param name: The name of this widget.
+ * @param parent: The parent of this widget.
+ */
+KsCheckBoxTreeWidget::KsCheckBoxTreeWidget(const QString &name,
+ QWidget *parent)
+: KsCheckBoxWidget(name, parent),
+ _tree(this)
+{
+ connect(&_tree, &KsCheckBoxTree::verify,
+ this, &KsCheckBoxTreeWidget::_verify);
+}
+
+/** Initialize the KsCheckBoxTree and its layout. */
+void KsCheckBoxTreeWidget::_initTree()
+{
+ _tree.setSelectionMode(QAbstractItemView::MultiSelection);
+
+ connect(&_tree, &QTreeWidget::itemClicked,
+ this, &KsCheckBoxTreeWidget::_update);
+
+ _cbLayout.setContentsMargins(1, 1, 1, 1);
+ _cbLayout.addWidget(&_tree);
+}
+
+/** Adjust the size of this widget according to its content. */
+void KsCheckBoxTreeWidget::_adjustSize()
+{
+ int width, n = _tree.topLevelItemCount();
+
+ if (n == 0)
+ return;
+
+ for (int i = 0; i < n; ++i)
+ _tree.topLevelItem(i)->setExpanded(true);
+
+ _tree.resizeColumnToContents(0);
+ if (_tree.topLevelItem(0)->child(0)) {
+ width = _tree.visualItemRect(_tree.topLevelItem(0)->child(0)).width();
+ } else {
+ width = _tree.visualItemRect(_tree.topLevelItem(0)).width();
+ }
+
+ width += FONT_WIDTH*3 + style()->pixelMetric(QStyle::PM_ScrollBarExtent);
+ _cbWidget.resize(width, _cbWidget.height());
+
+ for (int i = 0; i < n; ++i)
+ _tree.topLevelItem(i)->setExpanded(false);
+
+ setMinimumWidth(_cbWidget.width() +
+ _cbLayout.contentsMargins().left() +
+ _cbLayout.contentsMargins().right() +
+ _topLayout.contentsMargins().left() +
+ _topLayout.contentsMargins().right());
+}
+
+void KsCheckBoxTreeWidget::_update(QTreeWidgetItem *item, int column)
+{
+ /* Get the new state of the item. */
+ Qt::CheckState state = item->checkState(0);
+
+ /* Recursively update all items below this one. */
+ update_r(item, state);
+
+ /*
+ * Update all items above this one including the "all"
+ * check box.
+ */
+ _verify();
+}
+
+void KsCheckBoxTreeWidget::_verify()
+{
+ /*
+ * Set the state of the top level items according to the
+ * state of the childs.
+ */
+ QTreeWidgetItem *topItem, *childItem;
+
+ for(int t = 0; t < _tree.topLevelItemCount(); ++t) {
+ topItem = _tree.topLevelItem(t);
+ if (topItem->childCount() == 0)
+ continue;
+
+ topItem->setCheckState(0, Qt::Checked);
+ for (int c = 0; c < topItem->childCount(); ++c) {
+ childItem = topItem->child(c);
+ if (childItem->checkState(0) == Qt::Unchecked)
+ topItem->setCheckState(0, Qt::Unchecked);
+ }
+ }
+
+ _allCb.setCheckState(Qt::Checked);
+ for (auto &c: _cb) {
+ if (c->checkState(0) == Qt::Unchecked) {
+ _allCb.setCheckState(Qt::Unchecked);
+ break;
+ }
+ }
+}
+
+/**
+ * @brief Create KsCPUCheckBoxWidget.
+ *
+ * @param pevent: Page event used to parse the page.
+ * @param parent: The parent of this widget.
+ */
+KsCPUCheckBoxWidget::KsCPUCheckBoxWidget(struct tep_handle *pevent,
+ QWidget *parent)
+: KsCheckBoxTreeWidget("CPUs", parent)
+{
+ int nCPUs(0), height(FONT_HEIGHT * 1.5);
+ KsPlot::Color cpuCol;
+ QString style;
+
+ style = QString("QTreeView::item { height: %1 ;}").arg(height);
+ _tree.setStyleSheet(style);
+
+ _initTree();
+
+ if (pevent)
+ nCPUs = pevent->cpus;
+
+ _id.resize(nCPUs);
+ _cb.resize(nCPUs);
+
+ for (int i = 0; i < nCPUs; ++i) {
+ cpuCol.setRainbowColor(i);
+ QTreeWidgetItem *cpuItem = new QTreeWidgetItem;
+ cpuItem->setText(0, " ");
+ cpuItem->setText(1, QString("CPU %1").arg(i));
+ cpuItem->setCheckState(0, Qt::Checked);
+ cpuItem->setBackgroundColor(0, QColor(cpuCol.r(),
+ cpuCol.g(),
+ cpuCol.b()));
+ _tree.addTopLevelItem(cpuItem);
+ _id[i] = i;
+ _cb[i] = cpuItem;
+ }
+
+ _adjustSize();
+}
+
+/**
+ * @brief Create KsEventsCheckBoxWidget.
+ *
+ * @param pevent: Page event used to parse the page.
+ * @param parent: The parent of this widget.
+ */
+KsEventsCheckBoxWidget::KsEventsCheckBoxWidget(struct tep_handle *pevent,
+ QWidget *parent)
+: KsCheckBoxTreeWidget("Events", parent)
+{
+ QTreeWidgetItem *sysItem, *evtItem;
+ QString sysName, evtName;
+ int nEvts(0), i(0);
+
+ if (pevent)
+ nEvts = pevent->nr_events;
+
+ _initTree();
+ _id.resize(nEvts);
+ _cb.resize(nEvts);
+
+ while (i < nEvts) {
+ sysName = pevent->events[i]->system;
+ sysItem = new QTreeWidgetItem;
+ sysItem->setText(0, sysName);
+ sysItem->setCheckState(0, Qt::Checked);
+ _tree.addTopLevelItem(sysItem);
+
+ while (sysName == pevent->events[i]->system) {
+ evtName = pevent->events[i]->name;
+ evtItem = new QTreeWidgetItem;
+ evtItem->setText(0, evtName);
+ evtItem->setCheckState(0, Qt::Checked);
+ evtItem->setFlags(evtItem->flags() |
+ Qt::ItemIsUserCheckable);
+
+ sysItem->addChild(evtItem);
+
+ _id[i] = pevent->events[i]->id;
+ _cb[i] = evtItem;
+
+ if (++i == nEvts)
+ break;
+ }
+ }
+
+ _tree.sortItems(0, Qt::AscendingOrder);
+ _adjustSize();
+}
+
+/**
+ * @brief Create KsTasksCheckBoxWidget.
+ *
+ * @param pevent: Page event used to parse the page.
+ * @param cond: If True make a "Show Task" widget. Otherwise make "Hide Task".
+ * @param parent: The parent of this widget.
+ */
+KsTasksCheckBoxWidget::KsTasksCheckBoxWidget(struct tep_handle *pevent,
+ bool cond, QWidget *parent)
+: KsCheckBoxTableWidget("Tasks", parent)
+{
+ kshark_context *kshark_ctx(nullptr);
+ QTableWidgetItem *pidItem, *comItem;
+ KsPlot::Color pidCol;
+ QStringList headers;
+ const char *comm;
+ int nTasks;
+
+ if (!kshark_instance(&kshark_ctx))
+ return;
+
+ if (_cond)
+ headers << "Show" << "Pid" << "Task";
+ else
+ headers << "Hide" << "Pid" << "Task";
+
+ _id = KsUtils::getPidList();
+ nTasks = _id.count();
+ _initTable(headers, nTasks);
+
+ for (int i = 0; i < nTasks; ++i) {
+ pidItem = new QTableWidgetItem(tr("%1").arg(_id[i]));
+ _table.setItem(i, 1, pidItem);
+
+ comm = tep_data_comm_from_pid(kshark_ctx->pevent, _id[i]);
+ comItem = new QTableWidgetItem(tr(comm));
+
+ pidItem->setBackgroundColor(QColor(pidCol.r(),
+ pidCol.g(),
+ pidCol.b()));
+
+ if (_id[i] == 0)
+ pidItem->setTextColor(Qt::white);
+
+ _table.setItem(i, 2, comItem);
+
+ pidCol.setRainbowColor(i);
+ }
+
+ _adjustSize();
+}
+
+/**
+ * @brief Create KsPluginCheckBoxWidget.
+ *
+ * @param pluginList: A list of plugin names.
+ * @param parent: The parent of this widget.
+ */
+KsPluginCheckBoxWidget::KsPluginCheckBoxWidget(QStringList pluginList,
+ QWidget *parent)
+: KsCheckBoxTableWidget("Plugins", parent)
+{
+ QTableWidgetItem *nameItem, *infoItem;
+ QStringList headers;
+ int nPlgins;
+
+ headers << "Load" << "Name" << "Info";
+
+ nPlgins = pluginList.count();
+ _initTable(headers, nPlgins);
+ _id.resize(nPlgins);
+
+ for (int i = 0; i < nPlgins; ++i) {
+ nameItem = new QTableWidgetItem(pluginList[i]);
+ _table.setItem(i, 1, nameItem);
+ infoItem = new QTableWidgetItem(" -- ");
+ _table.setItem(i, 2, infoItem);
+ _id[i] = i;
+ }
+
+ _adjustSize();
+}
+
+/**
+ * @brief Create KsQuickEntryMenu.
+ *
+ * @param data: Input location for the KsDataStore object.
+ * @param row: The index of the entry used to initialize the menu.
+ * @param parent: The parent of this widget.
+ */
+KsQuickEntryMenu::KsQuickEntryMenu(KsDataStore *data, size_t row,
+ QWidget *parent)
+: QMenu("Entry menu", parent),
+ _data(data),
+ _row(row),
+ _hideTaskAction(this),
+ _showTaskAction(this),
+ _hideEventAction(this),
+ _showEventAction(this),
+ _addTaskPlotAction(this)
+{
+ QString descr;
+
+ addSection("Quick Filter menu");
+
+ descr = "Hide task [";
+ descr += kshark_get_task_easy(_data->rows()[_row]);
+ descr += "-";
+ descr += QString("%1").arg(_data->rows()[_row]->pid);
+ descr += "]";
+
+ _hideTaskAction.setText(descr);
+
+ connect(&_hideTaskAction, &QAction::triggered,
+ this, &KsQuickEntryMenu::_hideTask);
+
+ addAction(&_hideTaskAction);
+
+ descr = "Show task [";
+ descr += kshark_get_task_easy(_data->rows()[_row]);
+ descr += "-";
+ descr += QString("%1").arg(_data->rows()[_row]->pid);
+ descr += "] only";
+
+ _showTaskAction.setText(descr);
+
+ connect(&_showTaskAction, &QAction::triggered,
+ this, &KsQuickEntryMenu::_showTask);
+
+ addAction(&_showTaskAction);
+
+ descr = "Hide event [";
+ descr += kshark_get_event_name_easy(_data->rows()[_row]);
+ descr += "]";
+
+ _hideEventAction.setText(descr);
+
+ connect(&_hideEventAction, &QAction::triggered,
+ this, &KsQuickEntryMenu::_hideEvent);
+
+ addAction(&_hideEventAction);
+
+ descr = "Show event [";
+ descr += kshark_get_event_name_easy(_data->rows()[_row]);
+ descr += "] only";
+
+ _showEventAction.setText(descr);
+
+ connect(&_showEventAction, &QAction::triggered,
+ this, &KsQuickEntryMenu::_showEvent);
+
+ addAction(&_showEventAction);
+
+ addSection("Quick Plot menu");
+ descr = "Add [";
+ descr += kshark_get_task_easy(_data->rows()[_row]);
+ descr += "-";
+ descr += QString("%1").arg(_data->rows()[_row]->pid);
+ descr += "] plot";
+
+ _addTaskPlotAction.setText(descr);
+
+ connect(&_addTaskPlotAction, &QAction::triggered,
+ this, &KsQuickEntryMenu::_addTaskPlot);
+
+ addAction(&_addTaskPlotAction);
+}
+
+void KsQuickEntryMenu::_hideTask()
+{
+ int pid = kshark_get_pid_easy(_data->rows()[_row]);
+
+ _data->applyNegTaskFilter(QVector<int>(1, pid));
+}
+
+void KsQuickEntryMenu::_showTask()
+{
+ int pid = kshark_get_pid_easy(_data->rows()[_row]);
+
+ _data->applyPosTaskFilter(QVector<int>(1, pid));
+}
+
+void KsQuickEntryMenu::_hideEvent()
+{
+ int eventId = kshark_get_event_id_easy(_data->rows()[_row]);
+
+ _data->applyNegEventFilter(QVector<int>(1, eventId));
+}
+
+void KsQuickEntryMenu::_showEvent()
+{
+ int eventId = kshark_get_event_id_easy(_data->rows()[_row]);
+
+ _data->applyPosEventFilter(QVector<int>(1, eventId));
+}
+
+void KsQuickEntryMenu::_addTaskPlot()
+{
+ int pid = kshark_get_pid_easy(_data->rows()[_row]);
+
+ emit plotTask(pid);
+}
new file mode 100644
@@ -0,0 +1,385 @@
+/* SPDX-License-Identifier: LGPL-2.1 */
+
+/*
+ * Copyright (C) 2017 VMware Inc, Yordan Karadzhov <ykaradzhov@vmware.com>
+ */
+
+ /**
+ * @file KsWidgetsLib.hpp
+ * @brief Defines small widgets and dialogues used by the KernelShark GUI.
+ */
+
+#ifndef _KS_WIDGETS_LIB_H
+#define _KS_WIDGETS_LIB_H
+
+// Qt
+#include <QtWidgets>
+
+/**
+ * The KsProgressBar class provides a visualization of the progress of a
+ * running job.
+ */
+class KsProgressBar : public QWidget
+{
+ Q_OBJECT
+
+ QStatusBar _sb;
+
+ QProgressBar _pb;
+
+public:
+ KsProgressBar(QString message, QWidget *parent = nullptr);
+
+ void setValue(int i);
+};
+
+/** Defines the progress bar's maximum value. */
+#define KS_PROGRESS_BAR_MAX 200
+
+/** The height of the KsProgressBar widget. */
+#define KS_BROGBAR_HEIGHT (FONT_HEIGHT * 5)
+
+/** The width of the KsProgressBar widget. */
+#define KS_BROGBAR_WIDTH (FONT_WIDTH * 50)
+
+/**
+ * The KsMessageDialog class provides a widget showing a message and having
+ * a "Close" button.
+ */
+class KsMessageDialog : public QDialog
+{
+ QVBoxLayout _layout;
+
+ QLabel _text;
+
+ QPushButton _closeButton;
+
+public:
+ explicit KsMessageDialog(QWidget *parent) = delete;
+
+ KsMessageDialog(QString message, QWidget *parent = nullptr);
+};
+
+/** The height of the KsMessageDialog widget. */
+#define KS_MSG_DIALOG_HEIGHT (FONT_HEIGHT * 8)
+
+/** The width of the KsMessageDialog widget. */
+#define KS_MSG_DIALOG_WIDTH (SCREEN_WIDTH / 10)
+
+/**
+ * The KsCheckBoxWidget class is the base class of all CheckBox widget used
+ * by KernelShark.
+ */
+class KsCheckBoxWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ KsCheckBoxWidget(const QString &name = "",
+ QWidget *parent = nullptr);
+
+ /** Get the name of the widget. */
+ QString name() const {return _name;}
+
+ /** Get the state of the "all" checkboxe. */
+ bool all() const
+ {
+ if(_allCb.checkState() == Qt::Checked)
+ return true;
+ return false;
+ }
+
+ void setDefault(bool);
+
+ void set(QVector<bool> v);
+
+ QVector<int> getCheckedIds();
+
+private:
+ QToolBar _tb;
+
+protected:
+ /** The "all" checkboxe. */
+ QCheckBox _allCb;
+
+ /** A vector of Id numbers coupled to each checkboxe. */
+ QVector<int> _id;
+
+ /** A nested widget used to position the checkboxes. */
+ QWidget _cbWidget;
+
+ /** The layout of the nested widget. */
+ QVBoxLayout _cbLayout;
+
+ /** The top level layout of this widget. */
+ QVBoxLayout _topLayout;
+
+ /** The name of this widget. */
+ QString _name;
+
+ /** A label to show the name of the widget. */
+ QLabel _nameLabel;
+
+private:
+ virtual void _setCheckState(int i, Qt::CheckState st) = 0;
+
+ virtual Qt::CheckState _checkState(int i) const = 0;
+
+ virtual void _verify() {};
+
+ void _checkAll(bool);
+};
+
+/**
+ * The KsCheckBoxDialog class is the base class of all CheckBox dialogs
+ * used by KernelShark.
+ */
+class KsCheckBoxDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ KsCheckBoxDialog() = delete;
+
+ KsCheckBoxDialog(KsCheckBoxWidget *cbw, QWidget *parent = nullptr);
+
+signals:
+ /** Signal emitted when the "Apply" button is pressed. */
+ void apply(QVector<int>);
+
+private:
+ void _applyPress();
+
+ QVBoxLayout _topLayout;
+
+ QHBoxLayout _buttonLayout;
+
+ KsCheckBoxWidget *_checkBoxWidget;
+
+ QPushButton _applyButton, _cancelButton;
+
+ QMetaObject::Connection _applyButtonConnection;
+};
+
+/** The KsCheckBoxTable class provides a table of checkboxes. */
+class KsCheckBoxTable : public QTableWidget
+{
+ Q_OBJECT
+public:
+ explicit KsCheckBoxTable(QWidget *parent = nullptr);
+
+ void init(QStringList headers, int size);
+
+ /** A vector of checkboxes. */
+ QVector<QCheckBox*> _cb;
+
+signals:
+ /** Signal emitted when a checkboxes changes state. */
+ void changeState(int row);
+
+protected:
+ void keyPressEvent(QKeyEvent *event) override;
+
+ void mousePressEvent(QMouseEvent *event) override;
+
+private:
+ void _doubleClicked(int row, int col);
+};
+
+/**
+ * The KsCheckBoxTableWidget class provides a widget to hold a table of
+ * checkboxes.
+ */
+class KsCheckBoxTableWidget : public KsCheckBoxWidget
+{
+ Q_OBJECT
+public:
+ KsCheckBoxTableWidget(const QString &name = "",
+ QWidget *parent = nullptr);
+
+protected:
+ void _adjustSize();
+
+ void _initTable(QStringList headers, int size);
+
+ /** The KsCheckBoxTable, shown by this widget. */
+ KsCheckBoxTable _table;
+
+private:
+ void _setCheckState(int i, Qt::CheckState st) override
+ {
+ _table._cb[i]->setCheckState(st);
+ }
+
+ Qt::CheckState _checkState(int i) const override
+ {
+ return _table._cb[i]->checkState();
+ }
+
+ void _update(bool);
+
+ void _changeState(int row);
+};
+
+/** The KsCheckBoxTree class provides a tree of checkboxes. */
+class KsCheckBoxTree : public QTreeWidget
+{
+ Q_OBJECT
+public:
+ explicit KsCheckBoxTree(QWidget *parent = nullptr);
+
+signals:
+ /**
+ * Signal emitted when a checkboxes of the tree changes its state
+ * and the state of all toplevel and child checkboxes has to be
+ * reprocesed.
+ */
+ void verify();
+
+protected:
+ void keyPressEvent(QKeyEvent *event) override;
+
+ void mousePressEvent(QMouseEvent *event) override;
+
+private:
+ void _doubleClicked(QTreeWidgetItem *item, int col);
+};
+
+/**
+ * The KsCheckBoxTreeWidget class provides a widget to hold a tree of
+ * checkboxes.
+ */
+class KsCheckBoxTreeWidget : public KsCheckBoxWidget
+{
+ Q_OBJECT
+public:
+ KsCheckBoxTreeWidget() = delete;
+
+ KsCheckBoxTreeWidget(const QString &name = "",
+ QWidget *parent = nullptr);
+
+protected:
+ void _adjustSize();
+
+ void _initTree();
+
+ /** The KsCheckBoxTree, shown by this widget. */
+ KsCheckBoxTree _tree;
+
+ /** A vector of Tree items (checkboxes). */
+ QVector<QTreeWidgetItem*> _cb;
+
+private:
+ void _setCheckState(int i, Qt::CheckState st) override
+ {
+ _cb[i]->setCheckState(0, st);
+ }
+
+ Qt::CheckState _checkState(int i) const override
+ {
+ return _cb[i]->checkState(0);
+ }
+
+ void _update(QTreeWidgetItem *item, int column);
+
+ void _verify();
+};
+
+/**
+ * The KsCPUCheckBoxWidget class provides a widget for selecting CPU plots to
+ * show.
+ */
+struct KsCPUCheckBoxWidget : public KsCheckBoxTreeWidget
+{
+ KsCPUCheckBoxWidget() = delete;
+
+ KsCPUCheckBoxWidget(struct tep_handle *pe,
+ QWidget *parent = nullptr);
+};
+
+/**
+ * The KsTasksCheckBoxWidget class provides a widget for selecting Tasks
+ * to show or hide.
+ */
+struct KsTasksCheckBoxWidget : public KsCheckBoxTableWidget
+{
+ KsTasksCheckBoxWidget() = delete;
+
+ KsTasksCheckBoxWidget(struct tep_handle *pe,
+ bool cond = true,
+ QWidget *parent = nullptr);
+
+private:
+ /**
+ * A positive condition means that you want to show Tasks and
+ * a negative condition means that you want to hide Tasks.
+ */
+ bool _cond;
+};
+
+/**
+ * The KsEventsCheckBoxWidget class provides a widget for selecting Trace
+ * events to show or hide.
+ */
+struct KsEventsCheckBoxWidget : public KsCheckBoxTreeWidget
+{
+ KsEventsCheckBoxWidget() = delete;
+
+ KsEventsCheckBoxWidget(struct tep_handle *pe,
+ QWidget *parent = nullptr);
+};
+
+/**
+ * The KsPluginCheckBoxWidget class provides a widget for selecting plugins.
+ */
+struct KsPluginCheckBoxWidget : public KsCheckBoxTableWidget
+{
+ KsPluginCheckBoxWidget() = delete;
+
+ KsPluginCheckBoxWidget(QStringList pluginList,
+ QWidget *parent = nullptr);
+};
+
+class KsDataStore;
+class KsGLWidget;
+
+/**
+ * The KsQuickFilterMenu class provides a menu for easy filtering and plotting.
+ * The menu is initialized from a single kshark_entry and uses the content of
+ * this entry to provides quick actions for filtering and plottin.
+ */
+class KsQuickEntryMenu : public QMenu
+{
+ Q_OBJECT
+public:
+ KsQuickEntryMenu() = delete;
+
+ explicit KsQuickEntryMenu(KsDataStore *data,
+ size_t row,
+ QWidget *parent = nullptr);
+
+signals:
+ /** Signal to add a task plot. */
+ void plotTask(int);
+
+private:
+ void _hideTask();
+
+ void _showTask();
+
+ void _hideEvent();
+
+ void _showEvent();
+
+ void _addTaskPlot();
+
+ KsDataStore *_data;
+
+ size_t _row;
+
+ QAction _hideTaskAction, _showTaskAction;
+
+ QAction _hideEventAction, _showEventAction;
+
+ QAction _addTaskPlotAction;
+};
+
+#endif