Re: [PATCH 3/4] kernel-shark-qt: Add Widgets Lib

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon,  8 Oct 2018 18:16:28 +0300
Yordan Karadzhov <y.karadz@xxxxxxxxx> wrote:

> From: Yordan Karadzhov <ykaradzhov@xxxxxxxxxx>
> 
> This patch defines various small widgets and dialogues to be used by
> the KernelShark GUI.
> 
> Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@xxxxxxxxx>
> ---
>  kernel-shark-qt/src/CMakeLists.txt   |   6 +-
>  kernel-shark-qt/src/KsWidgetsLib.cpp | 873 +++++++++++++++++++++++++++
>  kernel-shark-qt/src/KsWidgetsLib.hpp | 370 ++++++++++++
>  3 files changed, 1247 insertions(+), 2 deletions(-)
>  create mode 100644 kernel-shark-qt/src/KsWidgetsLib.cpp
>  create mode 100644 kernel-shark-qt/src/KsWidgetsLib.hpp
> 
> 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..c6ae266
> --- /dev/null
> +++ b/kernel-shark-qt/src/KsWidgetsLib.cpp
> @@ -0,0 +1,873 @@
> +// SPDX-License-Identifier: LGPL-2.1
> +
> +/*
> + * Copyright (C) 2017 VMware Inc, Yordan Karadzhov <y.karadz@xxxxxxxxx>
> + */
> +
> +/**
> + *  @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(FONT_WIDTH * 50, FONT_HEIGHT * 5);

Where did the magic numbers 50 and 5 come from?

Can we make them into macros that define what they are.

> +	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(SCREEN_WIDTH / 10, FONT_HEIGHT * 8);

Same here with 10 and 8.

> +
> +	_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),
> +  _allCb("all", this),
> +  _cbWidget(this),
> +  _cbLayout(&_cbWidget),
> +  _topLayout(this),
> +  _name(name),
> +  _nameLabel(name + ":  ")
> +{
> +	setWindowTitle(_name);
> +	setMinimumHeight(SCREEN_HEIGHT / 2);
> +
> +	connect(&_allCb,	&QCheckBox::clicked,
> +		this,		&KsCheckBoxWidget::_checkAll);
> +
> +	_cbWidget.setLayout(&_cbLayout);
> +
> +	QToolBar *tb = new QToolBar(this);
> +
> +	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. */

The above comment format needs to be fixed.

> +	_verify();
> +}
> +
> +void KsCheckBoxTreeWidget::_verify()
> +{
> +	/* Set the state of the top level items according to the
> +	* state of the childs. */

The above one too.

-- Steve

> +	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;
> +		}
> +	}
> +}
> +



[Index of Archives]     [Linux USB Development]     [Linux USB Development]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux