mirror of
https://github.com/epasveer/seer.git
synced 2026-08-29 16:40:42 +08:00
58ce8fac72
gdb reports the exit as a *stopped event (reason="exited-*"), so with the Auto checkbox checked the visualizers fired one last refresh on a process that no longer exists, logging "unable to read memory" errors.
699 lines
23 KiB
C++
699 lines
23 KiB
C++
// SPDX-FileCopyrightText: 2021 Ernie Pasveer <epasveer@att.net>
|
|
//
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
#include "SeerMatrixVisualizerWidget.h"
|
|
#include "SeerHelpPageDialog.h"
|
|
#include "SeerUtl.h"
|
|
#include <QtWidgets/QMessageBox>
|
|
#include <QtWidgets/QFileDialog>
|
|
#include <QtWidgets/QToolTip>
|
|
#include <QtGui/QIntValidator>
|
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3)
|
|
#include <QtGui/QGuiApplication>
|
|
#include <QtGui/QStyleHints>
|
|
#endif
|
|
#include <QtPrintSupport/QPrinter>
|
|
#include <QtPrintSupport/QPrintDialog>
|
|
#include <QtCore/QRegularExpression>
|
|
#include <QtCore/QSettings>
|
|
#include <QtCore/QDebug>
|
|
#include <QtGlobal>
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
|
|
SeerMatrixVisualizerWidget::SeerMatrixVisualizerWidget (QWidget* parent) : QWidget(parent) {
|
|
|
|
// Init variables.
|
|
_variableId = Seer::createID(); // Create id's for queries.
|
|
_memoryId = Seer::createID();
|
|
_rowsId = Seer::createID();
|
|
_columnsId = Seer::createID();
|
|
_offsetId = Seer::createID();
|
|
_strideId = Seer::createID();
|
|
|
|
// Set up UI.
|
|
setupUi(this);
|
|
|
|
// Setup the widgets
|
|
setWindowTitle("Seer Matrix Visualizer");
|
|
setAttribute(Qt::WA_DeleteOnClose);
|
|
|
|
matrixDisplayFormatComboBox->setCurrentIndex(0);
|
|
matrixStorageOrderComboBox->setCurrentIndex(0);
|
|
|
|
handleMatrixDisplayFormatComboBox(0);
|
|
handleMatrixStorageOrderComboBox(0);
|
|
|
|
variableNameLineEdit->enableReturnPressedOnClear();
|
|
|
|
// Connect things.
|
|
QObject::connect(refreshToolButton, &QToolButton::clicked, this, &SeerMatrixVisualizerWidget::handleRefreshButton);
|
|
QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerMatrixVisualizerWidget::handleHelpButton);
|
|
QObject::connect(variableNameLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerMatrixVisualizerWidget::handleVariableNameLineEdit);
|
|
QObject::connect(variableNameLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerMatrixVisualizerWidget::handleVariableNameLineEdit);
|
|
QObject::connect(matrixRowsLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerMatrixVisualizerWidget::handleRefreshButton);
|
|
QObject::connect(matrixRowsLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerMatrixVisualizerWidget::handleElementRowsLineEdit);
|
|
QObject::connect(matrixColumnsLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerMatrixVisualizerWidget::handleRefreshButton);
|
|
QObject::connect(matrixColumnsLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerMatrixVisualizerWidget::handleElementColumnsLineEdit);
|
|
QObject::connect(matrixOffsetLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerMatrixVisualizerWidget::handleRefreshButton);
|
|
QObject::connect(matrixOffsetLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerMatrixVisualizerWidget::handleElementOffsetLineEdit);
|
|
QObject::connect(matrixStrideLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerMatrixVisualizerWidget::handleRefreshButton);
|
|
QObject::connect(matrixStrideLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerMatrixVisualizerWidget::handleElementStrideLineEdit);
|
|
QObject::connect(matrixDisplayFormatComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &SeerMatrixVisualizerWidget::handleMatrixDisplayFormatComboBox);
|
|
QObject::connect(matrixStorageOrderComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &SeerMatrixVisualizerWidget::handleMatrixStorageOrderComboBox);
|
|
QObject::connect(matrixTableWidget, &SeerMatrixWidget::dataChanged, this, &SeerMatrixVisualizerWidget::handleDataChanged);
|
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3)
|
|
QObject::connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, &SeerMatrixVisualizerWidget::handleThemeChanged);
|
|
#endif
|
|
|
|
// Colorize icons for theme.
|
|
Seer::colorizeAllIcons(this, Seer::iconColorTheme());
|
|
|
|
// Restore window settings.
|
|
readSettings();
|
|
}
|
|
|
|
SeerMatrixVisualizerWidget::~SeerMatrixVisualizerWidget () {
|
|
}
|
|
|
|
void SeerMatrixVisualizerWidget::setVariableName (const QString& name) {
|
|
|
|
setWindowTitle("Seer Matrix Visualizer - '" + name + "'");
|
|
|
|
variableNameLineEdit->setText(name);
|
|
|
|
if (variableNameLineEdit->text() == "") {
|
|
variableAddressLineEdit->setText("");
|
|
matrixRowsLineEdit->setText("");
|
|
matrixColumnsLineEdit->setText("");
|
|
matrixOffsetLineEdit->setText("");
|
|
matrixStrideLineEdit->setText("");
|
|
|
|
matrixTableWidget->setData(0);
|
|
|
|
return;
|
|
}
|
|
|
|
setVariableAddress("");
|
|
|
|
// Clear old contents.
|
|
QByteArray array;
|
|
bool ok;
|
|
|
|
matrixTableWidget->setData(new SeerMatrixWidget::DataStorageArray(array));
|
|
|
|
if (matrixOffsetLineEdit->text() != "") {
|
|
matrixTableWidget->setAddressOffset(matrixOffsetLineEdit->text().toULong(&ok));
|
|
if (ok == false) {
|
|
qWarning() << "Invalid string for address offset." << matrixOffsetLineEdit->text();
|
|
}
|
|
}else{
|
|
matrixTableWidget->setAddressOffset(0);
|
|
}
|
|
|
|
if (matrixStrideLineEdit->text() != "") {
|
|
matrixTableWidget->setAddressStride(matrixStrideLineEdit->text().toULong(&ok));
|
|
if (ok == false) {
|
|
qWarning() << "Invalid string for address stride." << matrixStrideLineEdit->text();
|
|
}
|
|
}else{
|
|
matrixTableWidget->setAddressStride(1);
|
|
}
|
|
|
|
// Send signal to get variable address.
|
|
emit evaluateVariableExpression(_variableId, variableNameLineEdit->text());
|
|
}
|
|
|
|
QString SeerMatrixVisualizerWidget::variableName () const {
|
|
return variableNameLineEdit->text();
|
|
}
|
|
|
|
void SeerMatrixVisualizerWidget::setVariableAddress (const QString& address) {
|
|
|
|
unsigned long offset = 0;
|
|
bool ok = false;
|
|
|
|
if (address == "") {
|
|
|
|
variableAddressLineEdit->setText("");
|
|
offset = 0;
|
|
|
|
}else{
|
|
|
|
// Test for base10
|
|
if (ok == false) {
|
|
offset = address.toULong(&ok, 10);
|
|
if (ok) {
|
|
variableAddressLineEdit->setText(QString("0x%1").arg(offset, 0, 16, QLatin1Char( '0' )));
|
|
}
|
|
}
|
|
|
|
// Test for base16
|
|
if (ok == false) {
|
|
offset = address.toULong(&ok, 16);
|
|
if (ok) {
|
|
variableAddressLineEdit->setText(QString("0x%1").arg(offset, 0, 16, QLatin1Char( '0' )));
|
|
}
|
|
}
|
|
|
|
if (ok == false) {
|
|
variableAddressLineEdit->setText("not an address");
|
|
offset = 0;
|
|
}
|
|
}
|
|
|
|
matrixTableWidget->setAddressOffset(0);
|
|
}
|
|
|
|
QString SeerMatrixVisualizerWidget::variableAddress () const {
|
|
return variableAddressLineEdit->text();
|
|
}
|
|
|
|
void SeerMatrixVisualizerWidget::setVariableRows (const QString& rows) {
|
|
matrixRowsLineEdit->setText(rows);
|
|
}
|
|
|
|
QString SeerMatrixVisualizerWidget::variableRows () const {
|
|
return matrixRowsLineEdit->text();
|
|
}
|
|
|
|
void SeerMatrixVisualizerWidget::setVariableColumns (const QString& columns) {
|
|
matrixColumnsLineEdit->setText(columns);
|
|
}
|
|
|
|
QString SeerMatrixVisualizerWidget::variableColumns () const {
|
|
return matrixColumnsLineEdit->text();
|
|
}
|
|
|
|
void SeerMatrixVisualizerWidget::setVariableOffset (const QString& offset) {
|
|
matrixOffsetLineEdit->setText(offset);
|
|
}
|
|
|
|
QString SeerMatrixVisualizerWidget::variableOffset () const {
|
|
return matrixOffsetLineEdit->text();
|
|
}
|
|
|
|
void SeerMatrixVisualizerWidget::setVariableStride (const QString& stride) {
|
|
matrixStrideLineEdit->setText(stride);
|
|
}
|
|
|
|
QString SeerMatrixVisualizerWidget::variableStride () const {
|
|
return matrixStrideLineEdit->text();
|
|
}
|
|
|
|
void SeerMatrixVisualizerWidget::handleText (const QString& text) {
|
|
|
|
//qDebug() << text;
|
|
|
|
if (text.contains(QRegularExpression("^([0-9]+)\\^done,value="))) {
|
|
|
|
// 11^done,value="1"
|
|
// 11^done,value="0x7fffffffd538"
|
|
|
|
QString id_text = text.section('^', 0,0);
|
|
|
|
if (id_text.toInt() == _variableId) {
|
|
|
|
QString value_text = Seer::parseFirst(text, "value=", '"', '"', false);
|
|
QString address = "";
|
|
|
|
// Look for an address in the value.
|
|
if (address == "") {
|
|
QRegularExpression re("0[xX][0-9a-fA-F]+");
|
|
QRegularExpressionMatch match = re.match(value_text);
|
|
|
|
if (match.hasMatch()) {
|
|
address = match.captured();
|
|
}
|
|
}
|
|
|
|
// Look for a number in the value.
|
|
if (address == "") {
|
|
QRegularExpression re("[0-9]+");
|
|
QRegularExpressionMatch match = re.match(value_text);
|
|
|
|
if (match.hasMatch()) {
|
|
address = match.captured();
|
|
}
|
|
}
|
|
|
|
// Set the variable address.
|
|
setVariableAddress(address);
|
|
}
|
|
|
|
if (id_text.toInt() == _rowsId) {
|
|
|
|
// Set the memory length.
|
|
QString value_text = Seer::parseFirst(text, "value=", '"', '"', false);
|
|
|
|
setVariableRows(value_text);
|
|
|
|
handleRefreshButton();
|
|
}
|
|
|
|
if (id_text.toInt() == _columnsId) {
|
|
|
|
// Set the memory length.
|
|
QString value_text = Seer::parseFirst(text, "value=", '"', '"', false);
|
|
|
|
setVariableColumns(value_text);
|
|
|
|
handleRefreshButton();
|
|
}
|
|
|
|
if (id_text.toInt() == _offsetId) {
|
|
|
|
// Set the memory offset.
|
|
QString value_text = Seer::parseFirst(text, "value=", '"', '"', false);
|
|
|
|
setVariableOffset(value_text);
|
|
|
|
handleRefreshButton();
|
|
}
|
|
|
|
if (id_text.toInt() == _strideId) {
|
|
|
|
// Set the memory stride.
|
|
QString value_text = Seer::parseFirst(text, "value=", '"', '"', false);
|
|
|
|
setVariableStride(value_text);
|
|
|
|
handleRefreshButton();
|
|
}
|
|
|
|
}else if (text.contains(QRegularExpression("^([0-9]+)\\^done,memory="))) {
|
|
|
|
// 3^done,memory=[{begin="0x0000000000613e70",offset="0x0000000000000000",end="0x0000000000613e71",contents="00"}]
|
|
// 4^done,memory=[{begin="0x0000000000613e70",offset="0x0000000000000000",end="0x0000000000613ed4",contents="000000000000000000000000"}]
|
|
|
|
QString id_text = text.section('^', 0,0);
|
|
|
|
if (id_text.toInt() == _memoryId) {
|
|
|
|
QString memory_text = Seer::parseFirst(text, "memory=", '[', ']', false);
|
|
|
|
QStringList range_list = Seer::parse(memory_text, "", '{', '}', false);
|
|
|
|
// Loop through the memory ranges.
|
|
for ( const auto& range_text : range_list ) {
|
|
|
|
QString contents_text = Seer::parseFirst(range_text, "contents=", '"', '"', false);
|
|
|
|
// Convert hex string to byte array.
|
|
QByteArray array;
|
|
|
|
for (int i = 0; i<contents_text.size(); i += 2) {
|
|
QString num = contents_text.mid(i, 2);
|
|
bool ok = false;
|
|
array.push_back(num.toInt(&ok, 16));
|
|
Q_ASSERT(ok);
|
|
}
|
|
|
|
// Give the byte array to the hex widget.
|
|
bool ok;
|
|
matrixTableWidget->setData(new SeerMatrixWidget::DataStorageArray(array));
|
|
|
|
if (matrixOffsetLineEdit->text() != "") {
|
|
matrixTableWidget->setAddressOffset(matrixOffsetLineEdit->text().toULong(&ok));
|
|
if (ok == false) {
|
|
qWarning() << "Invalid string for address offset." << matrixOffsetLineEdit->text();
|
|
}
|
|
}else{
|
|
matrixTableWidget->setAddressOffset(0);
|
|
}
|
|
|
|
if (matrixStrideLineEdit->text() != "") {
|
|
matrixTableWidget->setAddressStride(matrixStrideLineEdit->text().toULong(&ok));
|
|
if (ok == false) {
|
|
qWarning() << "Invalid string for address stride." << matrixStrideLineEdit->text();
|
|
}
|
|
}else{
|
|
matrixTableWidget->setAddressStride(1);
|
|
}
|
|
|
|
// Set the dimension of the matrix table.
|
|
if (matrixRowsLineEdit->text() != "" && matrixColumnsLineEdit->text() != "") {
|
|
int rows = matrixRowsLineEdit->text().toInt(&ok);
|
|
if (ok == false) {
|
|
qWarning() << "Invalid string for number of rows." << matrixRowsLineEdit->text();
|
|
rows = 0;
|
|
}
|
|
|
|
int columns = matrixColumnsLineEdit->text().toInt(&ok);
|
|
if (ok == false) {
|
|
qWarning() << "Invalid string for number of columns." << matrixColumnsLineEdit->text();
|
|
columns = 0;
|
|
}
|
|
|
|
matrixTableWidget->setDimensions(rows,columns);
|
|
|
|
}else{
|
|
matrixTableWidget->setDimensions(0,0);
|
|
}
|
|
|
|
break; // Take just the first range for now.
|
|
}
|
|
}
|
|
|
|
}else if (text.contains(QRegularExpression("^([0-9]+)\\^error,msg="))) {
|
|
|
|
// 12^error,msg="No symbol \"return\" in current context."
|
|
// 13^error,msg="No symbol \"cout\" in current context."
|
|
// 3^error,msg="Unable to read memory."
|
|
|
|
QString id_text = text.section('^', 0,0);
|
|
|
|
if (id_text.toInt() == _variableId) {
|
|
variableAddressLineEdit->setText( Seer::filterEscapes(Seer::parseFirst(text, "msg=", '"', '"', false)) );
|
|
}
|
|
|
|
if (id_text.toInt() == _memoryId) {
|
|
// Display the error message.
|
|
QString msg_text = Seer::parseFirst(text, "msg=", false);
|
|
|
|
if (msg_text != "") {
|
|
QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text));
|
|
}
|
|
}
|
|
|
|
if (id_text.toInt() == _rowsId) {
|
|
// Display the error message.
|
|
QString msg_text = Seer::parseFirst(text, "msg=", false);
|
|
|
|
QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text));
|
|
|
|
matrixRowsLineEdit->setText("");
|
|
matrixRowsLineEdit->setFocus();
|
|
}
|
|
|
|
if (id_text.toInt() == _columnsId) {
|
|
// Display the error message.
|
|
QString msg_text = Seer::parseFirst(text, "msg=", false);
|
|
|
|
QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text));
|
|
|
|
matrixColumnsLineEdit->setText("");
|
|
matrixColumnsLineEdit->setFocus();
|
|
}
|
|
|
|
if (id_text.toInt() == _offsetId) {
|
|
// Display the error message.
|
|
QString msg_text = Seer::parseFirst(text, "msg=", false);
|
|
|
|
QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text));
|
|
|
|
matrixOffsetLineEdit->setText("");
|
|
matrixOffsetLineEdit->setFocus();
|
|
}
|
|
|
|
if (id_text.toInt() == _strideId) {
|
|
// Display the error message.
|
|
QString msg_text = Seer::parseFirst(text, "msg=", false);
|
|
|
|
QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text));
|
|
|
|
matrixStrideLineEdit->setText("");
|
|
matrixStrideLineEdit->setFocus();
|
|
}
|
|
|
|
// At a stopping point, refresh. Skip the "exited" reasons: the program
|
|
// is gone and reading the matrix would fail with a memory error.
|
|
}else if (text.startsWith("*stopped,reason=\"") && text.startsWith("*stopped,reason=\"exited") == false) {
|
|
|
|
if (autoRefreshCheckBox->isChecked()) {
|
|
handleRefreshButton();
|
|
}
|
|
|
|
}else{
|
|
// Ignore anything else.
|
|
}
|
|
}
|
|
|
|
void SeerMatrixVisualizerWidget::handleRefreshButton () {
|
|
|
|
if (variableNameLineEdit->text() == "") {
|
|
return;
|
|
}
|
|
|
|
if (variableAddressLineEdit->text() == "") {
|
|
return;
|
|
}
|
|
|
|
if (variableAddressLineEdit->text() == "not an address") {
|
|
return;
|
|
}
|
|
|
|
int bytes = matrixRowsLineEdit->text().toInt() * matrixColumnsLineEdit->text().toInt() * Seer::typeBytes(matrixDisplayFormatComboBox->currentText());
|
|
|
|
// qDebug() << "Asking for" << bytes << "bytes of matrix data.";
|
|
|
|
emit evaluateMemoryExpression(_memoryId, variableAddressLineEdit->text(), bytes);
|
|
}
|
|
|
|
void SeerMatrixVisualizerWidget::handleHelpButton () {
|
|
|
|
SeerHelpPageDialog* help = new SeerHelpPageDialog;
|
|
help->loadFile(":/seer/resources/help/MatrixVisualizer.md");
|
|
help->show();
|
|
help->raise();
|
|
}
|
|
|
|
void SeerMatrixVisualizerWidget::handleVariableNameLineEdit () {
|
|
|
|
setVariableName (variableNameLineEdit->text());
|
|
}
|
|
|
|
void SeerMatrixVisualizerWidget::handleElementRowsLineEdit () {
|
|
|
|
// Nothing set? Return.
|
|
if (variableRows() == "") {
|
|
return;
|
|
}
|
|
|
|
// A regular integer? Return.
|
|
QRegularExpression re("[0-9]+");
|
|
QRegularExpressionMatch match = re.match(variableRows());
|
|
|
|
if (match.hasMatch()) {
|
|
return;
|
|
}
|
|
|
|
// Send for the value of the variable.
|
|
emit evaluateVariableExpression(_rowsId, variableRows());
|
|
}
|
|
|
|
void SeerMatrixVisualizerWidget::handleElementColumnsLineEdit () {
|
|
|
|
// Nothing set? Return.
|
|
if (variableColumns() == "") {
|
|
return;
|
|
}
|
|
|
|
// A regular integer? Return.
|
|
QRegularExpression re("[0-9]+");
|
|
QRegularExpressionMatch match = re.match(variableColumns());
|
|
|
|
if (match.hasMatch()) {
|
|
return;
|
|
}
|
|
|
|
// Send for the value of the variable.
|
|
emit evaluateVariableExpression(_columnsId, variableColumns());
|
|
}
|
|
|
|
void SeerMatrixVisualizerWidget::handleElementOffsetLineEdit () {
|
|
|
|
// Nothing set? Return.
|
|
if (variableOffset() == "") {
|
|
return;
|
|
}
|
|
|
|
// A regular integer? Return.
|
|
QRegularExpression re("[0-9]+");
|
|
QRegularExpressionMatch match = re.match(variableOffset());
|
|
|
|
if (match.hasMatch()) {
|
|
return;
|
|
}
|
|
|
|
emit evaluateVariableExpression(_offsetId, variableOffset());
|
|
}
|
|
|
|
void SeerMatrixVisualizerWidget::handleElementStrideLineEdit () {
|
|
|
|
// Nothing set? Return.
|
|
if (variableStride() == "") {
|
|
return;
|
|
}
|
|
|
|
// A regular integer? Return.
|
|
QRegularExpression re("[0-9]+");
|
|
QRegularExpressionMatch match = re.match(variableRows());
|
|
|
|
if (match.hasMatch()) {
|
|
return;
|
|
}
|
|
|
|
// Send for the value of the variable.
|
|
emit evaluateVariableExpression(_strideId, variableStride());
|
|
}
|
|
|
|
void SeerMatrixVisualizerWidget::handleMatrixDisplayFormatComboBox (int index) {
|
|
|
|
//qDebug() << index;
|
|
|
|
if (index == 0) {
|
|
matrixTableWidget->setDataType(SeerMatrixWidget::Int16MatrixType);
|
|
|
|
}else if (index == 1) {
|
|
matrixTableWidget->setDataType(SeerMatrixWidget::Int32MatrixType);
|
|
|
|
}else if (index == 2) {
|
|
matrixTableWidget->setDataType(SeerMatrixWidget::Int64MatrixType);
|
|
|
|
}else if (index == 3) {
|
|
matrixTableWidget->setDataType(SeerMatrixWidget::UInt16MatrixType);
|
|
|
|
}else if (index == 4) {
|
|
matrixTableWidget->setDataType(SeerMatrixWidget::UInt32MatrixType);
|
|
|
|
}else if (index == 5) {
|
|
matrixTableWidget->setDataType(SeerMatrixWidget::UInt64MatrixType);
|
|
|
|
}else if (index == 6) {
|
|
matrixTableWidget->setDataType(SeerMatrixWidget::Float32MatrixType);
|
|
|
|
}else if (index == 7) {
|
|
matrixTableWidget->setDataType(SeerMatrixWidget::Float64MatrixType);
|
|
|
|
}else{
|
|
// Do nothing.
|
|
}
|
|
|
|
handleRefreshButton();
|
|
}
|
|
|
|
void SeerMatrixVisualizerWidget::handleMatrixStorageOrderComboBox (int index) {
|
|
|
|
// Same bytes, only the cell mapping changes, so no memory re-read is needed.
|
|
if (index == 1) {
|
|
matrixTableWidget->setStorageOrder(SeerMatrixWidget::ColumnMajor);
|
|
}else{
|
|
matrixTableWidget->setStorageOrder(SeerMatrixWidget::RowMajor);
|
|
}
|
|
}
|
|
|
|
void SeerMatrixVisualizerWidget::handleDataChanged () {
|
|
|
|
// Update the meta information.
|
|
|
|
// Clear everything.
|
|
countLineEdit->setText("");
|
|
rowsLineEdit->setText("");
|
|
columnsLineEdit->setText("");
|
|
minimumLineEdit->setText("");
|
|
maximumLineEdit->setText("");
|
|
sumLineEdit->setText("");
|
|
averageLineEdit->setText("");
|
|
medianLineEdit->setText("");
|
|
rmsLineEdit->setText("");
|
|
|
|
|
|
// If there's nothing to show, just return.
|
|
if (matrixTableWidget->dataCount() <= 0) {
|
|
return;
|
|
}
|
|
|
|
if (matrixTableWidget->dataValues().count() <= 0) {
|
|
return;
|
|
}
|
|
|
|
// Make a copy of the values for us to play with.
|
|
QVector<double> values = matrixTableWidget->dataValues();
|
|
|
|
// Fill in counts.
|
|
countLineEdit->setText(QString::number(matrixTableWidget->dataCount()));
|
|
rowsLineEdit->setText(QString::number(matrixTableWidget->dataRows()));
|
|
columnsLineEdit->setText(QString::number(matrixTableWidget->dataColumns()));
|
|
|
|
// Calculate statistics.
|
|
double val = 0.0;
|
|
double min = values[0];
|
|
double max = values[0];
|
|
double sum = 0.0;
|
|
double sum2 = 0.0;
|
|
double avg = 0.0;
|
|
double med = 0.0;
|
|
double rms = 0.0;
|
|
|
|
for (int i=0; i<values.size(); i++) {
|
|
|
|
val = values[i];
|
|
|
|
min = std::min(min, val);
|
|
max = std::max(max, val);
|
|
sum += val;
|
|
sum2 += std::pow(val, 2);
|
|
}
|
|
|
|
avg = sum / values.size();
|
|
rms = std::sqrt(sum2 / values.size());
|
|
|
|
// Post them.
|
|
minimumLineEdit->setText(QString::number(min));
|
|
maximumLineEdit->setText(QString::number(max));
|
|
sumLineEdit->setText(QString::number(sum));
|
|
averageLineEdit->setText(QString::number(avg));
|
|
rmsLineEdit->setText(QString::number(rms));
|
|
|
|
// For median, we need to sort the values. So do this last.
|
|
std::sort(values.begin(), values.end());
|
|
|
|
// If the number of elements is odd, the median is the middle element
|
|
if (values.size() % 2 != 0) {
|
|
med = values[values.size() / 2];
|
|
}else{
|
|
double mid1 = values[values.size() / 2 - 1];
|
|
double mid2 = values[values.size() / 2];
|
|
|
|
med = (mid1 + mid2) / 2.0;
|
|
}
|
|
|
|
medianLineEdit->setText(QString::number(med));
|
|
|
|
return;
|
|
}
|
|
|
|
void SeerMatrixVisualizerWidget::handleThemeChanged () {
|
|
|
|
// Colorize icons for theme.
|
|
Seer::colorizeAllIcons(this, Seer::iconColorTheme());
|
|
}
|
|
|
|
void SeerMatrixVisualizerWidget::writeSettings() {
|
|
|
|
QSettings settings;
|
|
|
|
settings.beginGroup("matrixvisualizerwindow"); {
|
|
settings.setValue("size", size());
|
|
} settings.endGroup();
|
|
}
|
|
|
|
void SeerMatrixVisualizerWidget::readSettings() {
|
|
|
|
QSettings settings;
|
|
|
|
settings.beginGroup("matrixvisualizerwindow"); {
|
|
resize(settings.value("size", QSize(800, 400)).toSize());
|
|
} settings.endGroup();
|
|
}
|
|
|
|
void SeerMatrixVisualizerWidget::resizeEvent (QResizeEvent* event) {
|
|
|
|
writeSettings();
|
|
|
|
QWidget::resizeEvent(event);
|
|
}
|
|
|