| // 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. | 
 |  */ | 
 |  | 
 | // C | 
 | #include <unistd.h> | 
 |  | 
 | // KernelShark | 
 | #include "libkshark-tepdata.h" | 
 | #include "KsCmakeDef.hpp" | 
 | #include "KsPlotTools.hpp" | 
 | #include "KsWidgetsLib.hpp" | 
 |  | 
 | namespace KsWidgetsLib | 
 | { | 
 |  | 
 | /** | 
 |  * @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), | 
 |   _notDone(false) { | 
 | 	setWindowTitle("KernelShark"); | 
 | 	setLayout(new QVBoxLayout); | 
 | 	setFixedHeight(KS_PROGBAR_HEIGHT); | 
 | 	setFixedWidth(KS_PROGBAR_WIDTH); | 
 | 	_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(); | 
 | } | 
 |  | 
 | /** Destroy the KsProgressBar object. */ | 
 | KsProgressBar::~KsProgressBar() | 
 | { | 
 | 	_notDone = false; | 
 | 	usleep(10000); | 
 | } | 
 |  | 
 | /** @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(); | 
 | } | 
 |  | 
 | /** Show continuous work. */ | 
 | void KsProgressBar::workInProgress() | 
 | { | 
 | 	int progress, inc; | 
 | 	bool inv = false; | 
 |  | 
 | 	progress = inc = 5; | 
 | 	_notDone = true; | 
 | 	while (_notDone) { | 
 | 		if (progress > KS_PROGRESS_BAR_MAX || | 
 | 		    progress <= 0) { | 
 | 			inc = -inc; | 
 | 			inv = !inv; | 
 | 			_pb.setInvertedAppearance(inv); | 
 | 		} | 
 |  | 
 | 		setValue(progress); | 
 | 		progress += inc; | 
 | 		usleep(30000); | 
 | 	} | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Create KsWorkInProgress. | 
 |  * | 
 |  * @param parent: The parent of this widget. | 
 |  */ | 
 | KsWorkInProgress::KsWorkInProgress(QWidget *parent) | 
 | : QWidget(parent), | 
 |   _icon(this), | 
 |   _message("work in progress", this) | 
 | { | 
 | 	QIcon statusIcon = QIcon::fromTheme("dialog-warning"); | 
 | 	_icon.setPixmap(statusIcon.pixmap(.8 * FONT_HEIGHT)); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Show the "work in progress" notification. | 
 |  * | 
 |  * @param w: Data Work identifier. | 
 |  */ | 
 | void KsWorkInProgress::show(KsDataWork w) | 
 | { | 
 | 	_works.insert(w); | 
 | 	if (_works.size() == 1) { | 
 | 		_icon.show(); | 
 | 		_message.show(); | 
 |  | 
 | 		if (w != KsDataWork::RenderGL && | 
 | 		    w != KsDataWork::ResizeGL) | 
 | 			QApplication::processEvents(); | 
 | 	} | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Hide the "work in progress" notification. | 
 |  * | 
 |  * @param w: Data Work identifier. | 
 |  */ | 
 | void KsWorkInProgress::hide(KsDataWork w) | 
 | { | 
 | 	_works.remove(w); | 
 | 	if (_works.isEmpty()) { | 
 | 		_icon.hide(); | 
 | 		_message.hide(); | 
 |  | 
 | 		if (w != KsDataWork::RenderGL && | 
 | 		    w != KsDataWork::ResizeGL) | 
 | 			QApplication::processEvents(); | 
 | 	} | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Returns True the "work in progress" notification is active. | 
 |  *	  Otherwise False. | 
 |  * | 
 |  * @param w: Data Work identifier. | 
 |  */ | 
 | bool KsWorkInProgress::isBusy(KsDataWork w) const | 
 | { | 
 | 	if (w == KsDataWork::AnyWork) | 
 | 		return _works.isEmpty()? false : true; | 
 |  | 
 | 	return _works.contains(w)? true : false; | 
 | } | 
 |  | 
 | /** Add the KsWorkInProgress widget to a given Status Bar. */ | 
 | void KsWorkInProgress::addToStatusBar(QStatusBar *sb) | 
 | { | 
 | 	sb->addPermanentWidget(&_icon); | 
 | 	sb->addPermanentWidget(&_message); | 
 | 	_icon.hide(); | 
 | 	_message.hide(); | 
 | } | 
 |  | 
 | /** | 
 |  * @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 Launch a File exists dialog. Use this function to ask the user | 
 |  * before overwriting an existing file. | 
 |  * | 
 |  * @param fileName: the name of the file. | 
 |  * | 
 |  * @returns True if the user wants to overwrite the file. Otherwise | 
 |  */ | 
 | bool fileExistsDialog(QString fileName) | 
 | { | 
 | 	QString msg("A file "); | 
 | 	QMessageBox msgBox; | 
 |  | 
 | 	msg += fileName; | 
 | 	msg += " already exists."; | 
 | 	msgBox.setText(msg); | 
 | 	msgBox.setInformativeText("Do you want to replace it?"); | 
 |  | 
 | 	msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Cancel); | 
 | 	msgBox.setDefaultButton(QMessageBox::Cancel); | 
 |  | 
 | 	return (msgBox.exec() == QMessageBox::Save); | 
 | } | 
 |  | 
 | /** Create KsTimeOffsetDialog. */ | 
 | KsTimeOffsetDialog::KsTimeOffsetDialog(QWidget *parent) : QDialog(parent) | 
 | { | 
 | 	kshark_context *kshark_ctx(nullptr); | 
 | 	QVector<int> streamIds; | 
 | 	QString streamName; | 
 | 	int64_t max_ofst; | 
 |  | 
 | 	auto lamApply = [&] (double val) { | 
 | 		int sd = _streamCombo.currentData().toInt(); | 
 | 		emit apply(sd, val); | 
 | 		close(); | 
 | 	}; | 
 |  | 
 | 	if (!kshark_instance(&kshark_ctx)) | 
 | 		return; | 
 |  | 
 | 	this->setLayout(new QVBoxLayout); | 
 |  | 
 | 	streamIds = KsUtils::getStreamIdList(kshark_ctx); | 
 | 	if (streamIds.size() > 1) { | 
 | 		for (auto const &sd: streamIds) | 
 | 			if (sd != 0) { | 
 | 				streamName = KsUtils::streamDescription(kshark_ctx->stream[sd]); | 
 | 				_streamCombo.addItem(streamName); | 
 | 			} | 
 |  | 
 | 		layout()->addWidget(&_streamCombo); | 
 | 	} | 
 |  | 
 | 	_input.setInputMode(QInputDialog::DoubleInput); | 
 | 	 max_ofst = (int64_t) 1 << 60; | 
 | 	_input.setDoubleRange(-max_ofst, max_ofst); | 
 | 	_input.setDoubleDecimals(3); | 
 | 	_input.setLabelText("Offset [usec]:"); | 
 | 	_setDefault(_streamCombo.currentIndex()); | 
 |  | 
 | 	layout()->addWidget(&_input); | 
 |  | 
 | 	connect(&_input,	&QInputDialog::doubleValueSelected, | 
 | 		lamApply); | 
 |  | 
 | 	connect(&_input,	&QDialog::rejected, | 
 | 		this,		&QWidget::close); | 
 |  | 
 | 	connect(&_streamCombo,	&QComboBox::currentIndexChanged, | 
 | 		this,		&KsTimeOffsetDialog::_setDefault); | 
 |  | 
 | 	show(); | 
 | } | 
 |  | 
 | void KsTimeOffsetDialog::_setDefault(int) { | 
 | 	int sd = _streamCombo.currentData().toInt(); | 
 | 	kshark_context *kshark_ctx(nullptr); | 
 | 	struct kshark_data_stream *stream; | 
 | 	double offset; | 
 |  | 
 | 	if (!kshark_instance(&kshark_ctx)) | 
 | 		return; | 
 |  | 
 | 	stream = kshark_get_data_stream(kshark_ctx, sd); | 
 | 	if (!stream) | 
 | 		return; | 
 |  | 
 | 	if (!stream->calib_array) { | 
 | 		stream->calib = kshark_offset_calib; | 
 | 		stream->calib_array = | 
 | 			(int64_t *) calloc(1, sizeof(int64_t)); | 
 | 		stream->calib_array_size = 1; | 
 | 	} | 
 |  | 
 | 	offset = stream->calib_array[0] * 1e-3; | 
 | 	_input.setDoubleValue(offset); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Static function that starts a KsTimeOffsetDialog and returns value | 
 |  *	  selected by the user. | 
 |  * | 
 |  * @param dataFile: The name of the trace file to which the Time Offset will | 
 |  *		    apply. To be shown by the dialog. | 
 |  * @param ok: Output location to a success flag. True if the user has pressed | 
 |  *	      "Apply". | 
 |  */ | 
 | double KsTimeOffsetDialog::getValueNanoSec(QString dataFile, bool *ok) | 
 | { | 
 | 	KsTimeOffsetDialog dialog; | 
 | 	int64_t ofst(0); | 
 | 	int sd(-1); | 
 |  | 
 | 	*ok = false; | 
 |  | 
 | 	auto lamGetOffset = [&] (int stream_id, double ms) { | 
 | 		ofst = ms * 1000; | 
 | 		sd = stream_id; | 
 | 		*ok = true; | 
 | 	}; | 
 |  | 
 | 	connect(&dialog, &KsTimeOffsetDialog::apply, lamGetOffset); | 
 | 	dialog._streamCombo.hide(); | 
 | 	dialog._input.setLabelText(dataFile + "\nOffset [usec]:"); | 
 | 	dialog.exec(); | 
 |  | 
 | 	return ofst; | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Create KsCheckBoxWidget. | 
 |  * | 
 |  * @param sd: Data stream identifier. | 
 |  * @param name: The name of this widget. | 
 |  * @param parent: The parent of this widget. | 
 |  */ | 
 | KsCheckBoxWidget::KsCheckBoxWidget(int sd, const QString &name, | 
 | 				   QWidget *parent) | 
 | : QWidget(parent), | 
 |   _userInput(false), | 
 |   _sd(sd), | 
 |   _allCb("all"), | 
 |   _cbWidget(this), | 
 |   _cbLayout(&_cbWidget), | 
 |   _topLayout(this), | 
 |   _allCbAction(nullptr), | 
 |   _streamLabel("", this), | 
 |   _name(name), | 
 |   _nameLabel(name + ":  ") | 
 | { | 
 | 	setWindowTitle(_name); | 
 | 	setMinimumHeight(SCREEN_HEIGHT / 2); | 
 | 	setMinimumWidth(FONT_WIDTH * 20); | 
 |  | 
 | 	auto lamCheckAll = [this] (bool s) { | 
 | 		_userInput = true; | 
 | 		_checkAll(s); | 
 | 	}; | 
 |  | 
 | 	connect(&_allCb,	&QCheckBox::clicked, | 
 | 				lamCheckAll); | 
 |  | 
 | 	_cbWidget.setLayout(&_cbLayout); | 
 |  | 
 | 	_setStream(sd); | 
 | 	if (!_streamLabel.text().isEmpty()) | 
 | 		_topLayout.addWidget(&_streamLabel); | 
 |  | 
 | 	_tb.addWidget(&_nameLabel); | 
 | 	_allCbAction = _tb.addWidget(&_allCb); | 
 |  | 
 | 	_topLayout.addWidget(&_tb); | 
 | 	_topLayout.addWidget(&_cbWidget); | 
 |  | 
 | 	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); | 
 | } | 
 |  | 
 | /** Set the stream Id of the widget. */ | 
 | void KsCheckBoxWidget::_setStream(int8_t sd) | 
 | { | 
 | 	kshark_context *kshark_ctx(nullptr); | 
 | 	kshark_data_stream *stream; | 
 |  | 
 | 	if (!kshark_instance(&kshark_ctx)) | 
 | 		return; | 
 |  | 
 | 	_sd = sd; | 
 | 	stream = kshark_get_data_stream(kshark_ctx, sd); | 
 | 	if (!stream) | 
 | 		return; | 
 |  | 
 | 	_streamName = KsUtils::streamDescription(stream); | 
 |  | 
 | 	KsUtils::setElidedText(&_streamLabel, _streamName, | 
 | 			       Qt::ElideLeft, width()); | 
 | 	QApplication::processEvents(); | 
 | } | 
 |  | 
 | /** 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; | 
 | } | 
 |  | 
 | /** Get a vector containing the state of all checkboxes. */ | 
 | QVector<int> KsCheckBoxWidget::getStates() | 
 | { | 
 | 	int n = _id.size(); | 
 | 	QVector<int> vec(n); | 
 |  | 
 | 	for (int i = 0; i < n; ++i) | 
 | 		vec[i] = !!_checkState(i); | 
 |  | 
 | 	return vec; | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Set the state of the checkboxes. | 
 |  * | 
 |  * @param v: Vector containing the state values for all checkboxes. | 
 |  */ | 
 | void KsCheckBoxWidget::set(QVector<int> 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 cbws: A vector of KsCheckBoxWidgets to be nested in this dialog. | 
 |  * @param parent: The parent of this widget. | 
 |  */ | 
 | KsCheckBoxDialog::KsCheckBoxDialog(QVector<KsCheckBoxWidget *> cbws, QWidget *parent) | 
 | : QDialog(parent), | 
 |   _applyIds(true), | 
 |   _checkBoxWidgets(cbws), | 
 |   _applyButton("Apply", this), | 
 |   _cancelButton("Cancel", this) | 
 | { | 
 | 	int buttonWidth; | 
 |  | 
 | 	if (!cbws.isEmpty()) | 
 | 		setWindowTitle(cbws[0]->name()); | 
 |  | 
 | 	for (auto const &w: _checkBoxWidgets) | 
 | 		_cbLayout.addWidget(w); | 
 | 	_topLayout.addLayout(&_cbLayout); | 
 |  | 
 | 	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; | 
 |  | 
 | 	/* | 
 | 	 * Disconnect _applyButton. This is done in order to protect | 
 | 	 * against multiple clicks. | 
 | 	 */ | 
 | 	disconnect(_applyButtonConnection); | 
 |  | 
 | 	_preApplyAction(); | 
 |  | 
 | 	for (auto const &w: _checkBoxWidgets) { | 
 | 		if (!w->_userInput) | 
 | 			continue; | 
 |  | 
 | 		if (_applyIds) | 
 | 			vec = w->getCheckedIds(); | 
 | 		else | 
 | 			vec = w->getStates(); | 
 | 		emit apply(w->sd(), vec); | 
 | 	} | 
 |  | 
 | 	_postApplyAction(); | 
 | } | 
 |  | 
 | /** | 
 |  * @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 sd: Data stream identifier. | 
 |  * @param name: The name of this widget. | 
 |  * @param parent: The parent of this widget. | 
 |  */ | 
 | KsCheckBoxTableWidget::KsCheckBoxTableWidget(int sd, const QString &name, | 
 | 					     QWidget *parent) | 
 | : KsCheckBoxWidget(sd, 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); | 
 |  | 
 | 	_userInput = true; | 
 | } | 
 |  | 
 | 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; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	_userInput = true; | 
 | } | 
 |  | 
 | 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 sd: Data stream identifier. | 
 |  * @param name: The name of this widget. | 
 |  * @param parent: The parent of this widget. | 
 |  */ | 
 | KsCheckBoxTreeWidget::KsCheckBoxTreeWidget(int sd, const QString &name, | 
 | 					   QWidget *parent) | 
 | : KsCheckBoxWidget(sd, name, parent), | 
 |   _tree(this) | 
 | { | 
 | 	connect(&_tree,		&KsCheckBoxTree::verify, | 
 | 		this,		&KsCheckBoxTreeWidget::_verify); | 
 |  | 
 | 	auto lamSetUserInput = [this] (QTreeWidgetItem *, int) { | 
 | 		_userInput = true; | 
 | 	}; | 
 |  | 
 | 	connect(&_tree,		&QTreeWidget::itemClicked, | 
 | 				lamSetUserInput); | 
 | } | 
 |  | 
 | /** 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 stream: Input location for a Data stream pointer. | 
 |  * @param parent: The parent of this widget. | 
 |  */ | 
 | KsCPUCheckBoxWidget::KsCPUCheckBoxWidget(kshark_data_stream *stream, QWidget *parent) | 
 | : KsCheckBoxTreeWidget(stream->stream_id, "CPUs", parent), | 
 |   _hideEmpty("hide empty") | 
 | { | 
 | 	int height(FONT_HEIGHT * 1.5); | 
 | 	KsPlot::ColorTable colors; | 
 | 	QString style; | 
 |  | 
 | 	_hideEmpty.setCheckState(Qt::Checked); | 
 | 	_tb.addSeparator(); | 
 | 	_tb.addWidget(&_hideEmpty); | 
 |  | 
 | 	auto lamHideEmpty = [this, stream] (bool hide) { | 
 | 		QTreeWidgetItem *item; | 
 | 		bool isIdle; | 
 |  | 
 | 		for(int cpu = 0; cpu < stream->n_cpus; ++cpu) { | 
 | 			item = _tree.topLevelItem(cpu); | 
 | 			if (hide) { | 
 | 				isIdle = kshark_hash_id_find(stream->idle_cpus, cpu); | 
 | 				item->setHidden(isIdle); | 
 | 			} else { | 
 | 				item->setHidden(false); | 
 | 			} | 
 | 		} | 
 | 	}; | 
 |  | 
 | 	connect(&_hideEmpty,	&QCheckBox::clicked, | 
 | 				lamHideEmpty); | 
 |  | 
 | 	style = QString("QTreeView::item { height: %1 ;}").arg(height); | 
 | 	_tree.setStyleSheet(style); | 
 |  | 
 | 	_initTree(); | 
 |  | 
 | 	_id.resize(stream->n_cpus); | 
 | 	_cb.resize(stream->n_cpus); | 
 | 	colors = KsPlot::CPUColorTable(); | 
 |  | 
 | 	for (int i = 0; i < stream->n_cpus; ++i) { | 
 | 		QTreeWidgetItem *cpuItem = new QTreeWidgetItem; | 
 | 		cpuItem->setText(0, "  "); | 
 | 		cpuItem->setText(1, QString("CPU %1").arg(i)); | 
 | 		cpuItem->setCheckState(0, Qt::Checked); | 
 | 		cpuItem->setBackground(0, QColor(colors[i].r(), | 
 | 						 colors[i].g(), | 
 | 						 colors[i].b())); | 
 | 		_tree.addTopLevelItem(cpuItem); | 
 | 		_id[i] = i; | 
 | 		_cb[i] = cpuItem; | 
 | 	} | 
 |  | 
 | 	lamHideEmpty(true); | 
 | 	_adjustSize(); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Create KsEventsCheckBoxWidget. | 
 |  * | 
 |  * @param stream: Input location for a Data stream pointer. | 
 |  * @param parent: The parent of this widget. | 
 |  */ | 
 | KsEventsCheckBoxWidget::KsEventsCheckBoxWidget(kshark_data_stream *stream, | 
 | 					       QWidget *parent) | 
 | : KsCheckBoxTreeWidget(stream->stream_id, "Events", parent) | 
 | { | 
 | 	QVector<int> eventIds = KsUtils::getEventIdList(stream->stream_id); | 
 |  | 
 | 	_initTree(); | 
 | 	if(!stream->n_events || eventIds.isEmpty()) | 
 | 		return; | 
 |  | 
 | 	_id.resize(stream->n_events); | 
 | 	_cb.resize(stream->n_events); | 
 |  | 
 | 	if (kshark_is_tep(stream)) | 
 | 		_makeTepEventItems(stream, eventIds); | 
 | 	else | 
 | 		_makeItems(stream, eventIds); | 
 | } | 
 |  | 
 | void KsEventsCheckBoxWidget::_makeItems(kshark_data_stream *stream, | 
 | 					QVector<int> eventIds) | 
 | { | 
 | 	QTreeWidgetItem *evtItem; | 
 | 	QString evtName; | 
 |  | 
 | 	for (int i = 0; i < stream->n_events; ++i) { | 
 | 		evtName = KsUtils::getEventName(stream->stream_id, | 
 | 						eventIds[i]); | 
 | 		evtItem = new QTreeWidgetItem; | 
 | 		evtItem->setText(0, evtName); | 
 | 		evtItem->setCheckState(0, Qt::Checked); | 
 | 		evtItem->setFlags(evtItem->flags() | | 
 | 				  Qt::ItemIsUserCheckable); | 
 | 		_tree.addTopLevelItem(evtItem); | 
 | 		_cb[i] = evtItem; | 
 | 	} | 
 | } | 
 |  | 
 | void KsEventsCheckBoxWidget::_makeTepEventItems(kshark_data_stream *stream, | 
 | 						QVector<int> eventIds) | 
 | { | 
 | 	QTreeWidgetItem *sysItem, *evtItem; | 
 | 	QString sysName, evtName; | 
 | 	QStringList name; | 
 | 	int i(0); | 
 |  | 
 | 	while (i < stream->n_events) { | 
 | 		name = KsUtils::getTepEvtName(stream->stream_id, | 
 | 					      eventIds[i]); | 
 | 		sysName = name[0]; | 
 | 		sysItem = new QTreeWidgetItem; | 
 | 		sysItem->setText(0, sysName); | 
 | 		sysItem->setCheckState(0, Qt::Checked); | 
 | 		_tree.addTopLevelItem(sysItem); | 
 |  | 
 | 		while (sysName == name[0]) { | 
 | 			evtName = name[1]; | 
 | 			evtItem = new QTreeWidgetItem; | 
 | 			evtItem->setText(0, evtName); | 
 | 			evtItem->setCheckState(0, Qt::Checked); | 
 | 			evtItem->setFlags(evtItem->flags() | | 
 | 					  Qt::ItemIsUserCheckable); | 
 |  | 
 | 			sysItem->addChild(evtItem); | 
 |  | 
 | 			_id[i] = eventIds[i]; | 
 | 			_cb[i] = evtItem; | 
 | 			if (++i == stream->n_events) | 
 | 				break; | 
 |  | 
 | 			name = KsUtils::getTepEvtName(stream->stream_id, | 
 | 						      eventIds[i]); | 
 | 		} | 
 | 	} | 
 |  | 
 | 	_tree.sortItems(0, Qt::AscendingOrder); | 
 | 	_adjustSize(); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Get a list of all checked events. If the whole system is selected | 
 |  *	  (the top level checkbox is checked), only the name of the system is | 
 |  *	  added to the list. | 
 |  * | 
 |  * @param option: If True, "-e" is added as prefix to each element of the list. | 
 |  * | 
 |  * @returns A list of checked events or systems. | 
 |  */ | 
 | QStringList KsEventsCheckBoxWidget::getCheckedEvents(bool option) | 
 | { | 
 | 	QTreeWidgetItem *sysItem, *evtItem; | 
 | 	QStringList list; | 
 | 	QString optStr; | 
 | 	int nSys, nEvts; | 
 |  | 
 | 	if (option) | 
 | 		optStr = "-e"; | 
 |  | 
 | 	nSys = _tree.topLevelItemCount(); | 
 | 	for(int t = 0; t < nSys; ++t) { | 
 | 		sysItem = _tree.topLevelItem(t); | 
 | 		if (sysItem->checkState(0) == Qt::Checked) { | 
 | 			list << optStr + sysItem->text(0); | 
 | 		} else { | 
 | 			nEvts = sysItem->childCount(); | 
 | 			for (int c = 0; c < nEvts; ++c) { | 
 | 				evtItem = sysItem->child(c); | 
 | 				if (evtItem->checkState(0) == Qt::Checked) { | 
 | 					list << optStr + | 
 | 						sysItem->text(0) + | 
 | 						":" + | 
 | 						evtItem->text(0); | 
 | 				} | 
 | 			} | 
 | 		} | 
 | 	} | 
 |  | 
 | 	return list; | 
 | } | 
 |  | 
 | /** Remove a System from the Checkbox tree. */ | 
 | void KsEventsCheckBoxWidget::removeSystem(QString name) { | 
 | 	auto itemList = _tree.findItems(name, Qt::MatchFixedString, 0); | 
 | 	int index; | 
 |  | 
 | 	if (itemList.isEmpty()) | 
 | 		return; | 
 |  | 
 | 	index = _tree.indexOfTopLevelItem(itemList[0]); | 
 | 	if (index >= 0) | 
 | 		_tree.takeTopLevelItem(index); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Create KsTasksCheckBoxWidget. | 
 |  * | 
 |  * @param stream: Input location for a Data stream pointer. | 
 |  * @param cond: If True make a "Show Task" widget. Otherwise make "Hide Task". | 
 |  * @param parent: The parent of this widget. | 
 |  */ | 
 | KsTasksCheckBoxWidget::KsTasksCheckBoxWidget(kshark_data_stream *stream, | 
 | 					     bool cond, QWidget *parent) | 
 | : KsCheckBoxTableWidget(stream->stream_id, "Tasks", parent), | 
 |   _cond(cond) | 
 | { | 
 | 	QTableWidgetItem *pidItem, *comItem; | 
 | 	KsPlot::ColorTable colors; | 
 | 	QStringList headers; | 
 | 	kshark_entry entry; | 
 | 	const char *comm; | 
 | 	int nTasks, pid; | 
 |  | 
 | 	if (_cond) | 
 | 		headers << "Show" << "Pid" << "Task"; | 
 | 	else | 
 | 		headers << "Hide" << "Pid" << "Task"; | 
 |  | 
 | 	_id = KsUtils::getPidList(stream->stream_id); | 
 | 	nTasks = _id.count(); | 
 | 	_initTable(headers, nTasks); | 
 | 	colors = KsPlot::taskColorTable(); | 
 | 	entry.stream_id = stream->stream_id; | 
 | 	entry.visible = 0xff; | 
 | 	for (int i = 0; i < nTasks; ++i) { | 
 | 		entry.pid = pid = _id[i]; | 
 | 		pidItem = new QTableWidgetItem(tr("%1").arg(pid)); | 
 | 		_table.setItem(i, 1, pidItem); | 
 |  | 
 | 		comm = kshark_get_task(&entry); | 
 |  | 
 | 		comItem = new QTableWidgetItem(tr(comm)); | 
 |  | 
 | 		pidItem->setBackground(QColor(colors[pid].r(), | 
 | 					      colors[pid].g(), | 
 | 					      colors[pid].b())); | 
 |  | 
 | 		if (_id[i] == 0) | 
 | 			pidItem->setForeground(Qt::white); | 
 |  | 
 | 		_table.setItem(i, 2, comItem); | 
 | 	} | 
 |  | 
 | 	_adjustSize(); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Create KsPluginCheckBoxWidget. | 
 |  * | 
 |  * @param sd: Data stream identifier. | 
 |  * @param pluginList: A list of plugin names. | 
 |  * @param parent: The parent of this widget. | 
 |  */ | 
 | KsPluginCheckBoxWidget::KsPluginCheckBoxWidget(int sd, QStringList pluginList, | 
 | 					       QWidget *parent) | 
 | : KsCheckBoxTableWidget(sd, "Manage 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) { | 
 | 		if (pluginList[i].size() < 30) { | 
 | 			nameItem = new QTableWidgetItem(pluginList[i]); | 
 | 		} else { | 
 | 			QLabel l; | 
 | 			KsUtils::setElidedText(&l, pluginList[i], | 
 | 					       Qt::ElideLeft, | 
 | 					       FONT_WIDTH * 30); | 
 | 			nameItem = new QTableWidgetItem(l.text()); | 
 | 		} | 
 |  | 
 | 		_table.setItem(i, 1, nameItem); | 
 | 		infoItem = new QTableWidgetItem(" -- "); | 
 | 		_table.setItem(i, 2, infoItem); | 
 | 		_id[i] = i; | 
 | 	} | 
 |  | 
 | 	_adjustSize(); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Set the "Info" field inside the table of the widget. | 
 |  * | 
 |  * @param row: The row number in the table. | 
 |  * @param info: The "Info" string to be shown. | 
 |  */ | 
 | void KsPluginCheckBoxWidget::setInfo(int row, QString info) | 
 | { | 
 | 	QTableWidgetItem *infoItem = _table.item(row, 2); | 
 | 	infoItem->setText(info); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Set the "Active" field inside the table of the widget. | 
 |  * | 
 |  * @param rows: The row numbers in the table. | 
 |  * @param a: Are those plugins active. | 
 |  */ | 
 | void KsPluginCheckBoxWidget::setActive(QVector<int> rows, bool a) | 
 | { | 
 | 	for (auto const &r: rows) { | 
 | 		QTableWidgetItem *infoItem = _table.item(r, 2); | 
 | 		if (a) { | 
 | 			infoItem->setText("- Active"); | 
 | 			infoItem->setForeground(QBrush(QColor(0, 220, 80))); | 
 | 		} else { | 
 | 			infoItem->setText("- Not Active"); | 
 | 			infoItem->setForeground(QBrush(QColor(255, 50, 50))); | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | void KsPluginsCheckBoxDialog::_postApplyAction() | 
 | { | 
 | 	emit _data->updateWidgets(_data); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Create KsDStreamCheckBoxWidget. | 
 |  * | 
 |  * @param parent: The parent of this widget. | 
 |  */ | 
 | KsDStreamCheckBoxWidget::KsDStreamCheckBoxWidget(QWidget *parent) | 
 | : KsCheckBoxTableWidget(-1, "Select Data stream", parent) | 
 | { | 
 | 	kshark_context *kshark_ctx(nullptr); | 
 | 	kshark_data_stream *stream; | 
 | 	QTableWidgetItem *nameItem; | 
 | 	QVector<int> streamIds; | 
 | 	QStringList headers; | 
 | 	int nStreams; | 
 |  | 
 | 	if (!kshark_instance(&kshark_ctx)) | 
 | 		return; | 
 |  | 
 | 	headers << "Apply" << "To stream"; | 
 | 	streamIds = KsUtils::getStreamIdList(kshark_ctx); | 
 | 	nStreams = streamIds.size(); | 
 | 	_initTable(headers, nStreams); | 
 | 	_id.resize(nStreams); | 
 |  | 
 | 	for (int i = 0; i < nStreams; ++i) { | 
 | 		stream = kshark_ctx->stream[streamIds[i]]; | 
 | 		QString name = KsUtils::streamDescription(stream); | 
 | 		if (name.size() < 40) { | 
 | 			nameItem = new QTableWidgetItem(name); | 
 | 		} else { | 
 | 			QLabel l; | 
 | 			KsUtils::setElidedText(&l, name, | 
 | 					       Qt::ElideLeft, | 
 | 					       FONT_WIDTH * 40); | 
 | 			nameItem = new QTableWidgetItem(l.text()); | 
 | 		} | 
 |  | 
 | 		_table.setItem(i, 1, nameItem); | 
 | 		_id[i] = stream->stream_id; | 
 | 	} | 
 |  | 
 | 	_adjustSize(); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Create KsEventFieldSelectWidget. | 
 |  * | 
 |  * @param parent: The parent of this widget. | 
 |  */ | 
 | KsEventFieldSelectWidget::KsEventFieldSelectWidget(QWidget *parent) | 
 | : QWidget(parent), | 
 |   _streamLabel("Data stream", this), | 
 |   _eventLabel("Event (type in for searching)", this), | 
 |   _fieldLabel("Field", this) | 
 | { | 
 | 	auto lamAddLine = [&] { | 
 | 		QFrame* line = new QFrame(); | 
 | 		QSpacerItem *spacer = new QSpacerItem(1, FONT_HEIGHT / 2, | 
 | 						      QSizePolicy::Expanding, | 
 | 						      QSizePolicy::Minimum); | 
 | 		line->setFrameShape(QFrame::HLine); | 
 | 		line->setFrameShadow(QFrame::Sunken); | 
 | 		_topLayout.addSpacerItem(spacer); | 
 | 		_topLayout.addWidget(line); | 
 | 	}; | 
 |  | 
 | 	_topLayout.addWidget(&_streamLabel); | 
 | 	_topLayout.addWidget(&_streamComboBox); | 
 |  | 
 | 	/* | 
 | 	 * Using the old Signal-Slot syntax because QComboBox::currentIndexChanged | 
 | 	 * has overloads. | 
 | 	 */ | 
 | 	connect(&_streamComboBox,	&QComboBox::currentIndexChanged, | 
 | 		this,			&KsEventFieldSelectWidget::_streamChanged); | 
 |  | 
 | 	lamAddLine(); | 
 |  | 
 | 	_topLayout.addWidget(&_eventLabel); | 
 | 	_topLayout.addWidget(&_eventComboBox); | 
 | 	_eventComboBox.setEditable(true); | 
 | 	_eventComboBox.view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); | 
 | 	_eventComboBox.setMaxVisibleItems(25); | 
 |  | 
 | 	/* | 
 | 	 * Using the old Signal-Slot syntax because QComboBox::currentIndexChanged | 
 | 	 * has overloads. | 
 | 	 */ | 
 | 	connect(&_eventComboBox,	&QComboBox::currentIndexChanged, | 
 | 		this,			&KsEventFieldSelectWidget::_eventChanged); | 
 |  | 
 | 	lamAddLine(); | 
 |  | 
 | 	_topLayout.addWidget(&_fieldLabel); | 
 | 	_topLayout.addWidget(&_fieldComboBox); | 
 |  | 
 | 	lamAddLine(); | 
 |  | 
 | 	setLayout(&_topLayout); | 
 | } | 
 |  | 
 | /** Populate the Data stream selection combo box. */ | 
 | void KsEventFieldSelectWidget::setStreamCombo() | 
 | { | 
 | 	kshark_context *kshark_ctx(NULL); | 
 | 	kshark_data_stream *stream; | 
 | 	QVector<int> streamIds; | 
 |  | 
 | 	if (!kshark_instance(&kshark_ctx)) | 
 | 		return; | 
 |  | 
 | 	streamIds = KsUtils::getStreamIdList(kshark_ctx); | 
 | 	for (auto const &sd: streamIds) { | 
 | 		stream = kshark_ctx->stream[sd]; | 
 | 		if (_streamComboBox.findData(sd) < 0) | 
 | 			_streamComboBox.addItem(KsUtils::streamDescription(stream), sd); | 
 | 	} | 
 | } | 
 |  | 
 | void KsEventFieldSelectWidget::_streamChanged(int) | 
 | { | 
 | 	int sd = _streamComboBox.currentData().toInt(); | 
 | 	QVector<int> eventIds = KsUtils::getEventIdList(sd); | 
 | 	QStringList evtsList; | 
 |  | 
 | 	_eventComboBox.clear(); | 
 |  | 
 | 	for (auto const &eid: eventIds) | 
 | 		evtsList << KsUtils::getEventName(sd, eid); | 
 |  | 
 | 	std::sort(evtsList.begin(), evtsList.end()); | 
 | 	_eventComboBox.addItems(evtsList); | 
 | } | 
 |  | 
 | void KsEventFieldSelectWidget::_eventChanged(int) | 
 | { | 
 | 	int sd = _streamComboBox.currentData().toInt(); | 
 | 	QString evtName = _eventComboBox.currentText(); | 
 | 	int eventId = KsUtils::getEventId(sd, evtName); | 
 | 	QStringList fieldsList = KsUtils::getEventFieldsList(sd, eventId); | 
 |  | 
 | 	auto lamIsValide = [&] (const QString &f) { | 
 | 		return KsUtils::getEventFieldType(sd, eventId, f) == | 
 | 		       KS_INVALID_FIELD; | 
 | 	}; | 
 |  | 
 | 	_fieldComboBox.clear(); | 
 |  | 
 | 	fieldsList.erase(std::remove_if(fieldsList.begin(), fieldsList.end(), | 
 | 					lamIsValide), fieldsList.end()); | 
 |  | 
 | 	if (fieldsList.isEmpty()) | 
 | 		return; | 
 |  | 
 | 	std::sort(fieldsList.begin(), fieldsList.end()); | 
 |  | 
 | 	_fieldComboBox.addItems(fieldsList); | 
 | } | 
 |  | 
 | }; // KsWidgetsLib |