diff mbox series

[v3,3/4] kernel-shark-qt: Add Widgets Lib

Message ID 20181011165713.15257-4-ykaradzhov@vmware.com (mailing list archive)
State Accepted
Headers show
Series Add basic components to be used by the Qt GUI | expand

Commit Message

Yordan Karadzhov Oct. 11, 2018, 4:57 p.m. UTC
From: Yordan Karadzhov (VMware) <y.karadz@gmail.com>

This patch defines various small widgets and dialogues to be used by
the KernelShark GUI.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 kernel-shark-qt/src/CMakeLists.txt   |   6 +-
 kernel-shark-qt/src/KsWidgetsLib.cpp | 881 +++++++++++++++++++++++++++
 kernel-shark-qt/src/KsWidgetsLib.hpp | 385 ++++++++++++
 3 files changed, 1270 insertions(+), 2 deletions(-)
 create mode 100644 kernel-shark-qt/src/KsWidgetsLib.cpp
 create mode 100644 kernel-shark-qt/src/KsWidgetsLib.hpp
diff mbox series

Patch

diff --git a/kernel-shark-qt/src/CMakeLists.txt b/kernel-shark-qt/src/CMakeLists.txt
index e897e9a..2ac79ca 100644
--- a/kernel-shark-qt/src/CMakeLists.txt
+++ b/kernel-shark-qt/src/CMakeLists.txt
@@ -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}
diff --git a/kernel-shark-qt/src/KsWidgetsLib.cpp b/kernel-shark-qt/src/KsWidgetsLib.cpp
new file mode 100644
index 0000000..f7fca09
--- /dev/null
+++ b/kernel-shark-qt/src/KsWidgetsLib.cpp
@@ -0,0 +1,881 @@ 
+// 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 tep: Trace event parseer.
+ * @param parent: The parent of this widget.
+ */
+KsCPUCheckBoxWidget::KsCPUCheckBoxWidget(struct tep_handle *tep,
+					 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 (tep)
+		nCPUs = tep_get_cpus(tep);
+
+	_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 tep: Trace event parseer.
+ * @param parent: The parent of this widget.
+ */
+KsEventsCheckBoxWidget::KsEventsCheckBoxWidget(struct tep_handle *tep,
+					       QWidget *parent)
+: KsCheckBoxTreeWidget("Events", parent)
+{
+	QTreeWidgetItem *sysItem, *evtItem;
+	tep_event_format **events(nullptr);
+	QString sysName, evtName;
+	int nEvts(0), i(0);
+
+	if (tep) {
+		nEvts = tep_get_events_count(tep);
+		events = tep_list_events(tep, TEP_EVENT_SORT_SYSTEM);
+	}
+
+	_initTree();
+	_id.resize(nEvts);
+	_cb.resize(nEvts);
+
+	while (i < nEvts) {
+		sysName = events[i]->system;
+		sysItem = new QTreeWidgetItem;
+		sysItem->setText(0, sysName);
+		sysItem->setCheckState(0, Qt::Checked);
+		_tree.addTopLevelItem(sysItem);
+
+		while (sysName == events[i]->system) {
+			evtName = 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] = 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);
+}
diff --git a/kernel-shark-qt/src/KsWidgetsLib.hpp b/kernel-shark-qt/src/KsWidgetsLib.hpp
new file mode 100644
index 0000000..b9ba35a
--- /dev/null
+++ b/kernel-shark-qt/src/KsWidgetsLib.hpp
@@ -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