diff --git a/src/SeerAboutDialog.cpp b/src/SeerAboutDialog.cpp index c2b597f..d7e5f6f 100644 --- a/src/SeerAboutDialog.cpp +++ b/src/SeerAboutDialog.cpp @@ -6,8 +6,10 @@ #include "SeerUtl.h" #include #include +#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) #include #include +#endif #include #include #include @@ -18,7 +20,9 @@ SeerAboutDialog::SeerAboutDialog (QWidget* parent) : QDialog(parent) { setupUi(this); // Handle when theme is changed. Change the color of all icons. +#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) QObject::connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, &SeerAboutDialog::handleThemeChanged); +#endif // Get the About text from the resource. QFile file(":/seer/resources/ABOUT.md"); diff --git a/src/SeerArrayVisualizerWidget.cpp b/src/SeerArrayVisualizerWidget.cpp index 52995e5..9fce3cf 100644 --- a/src/SeerArrayVisualizerWidget.cpp +++ b/src/SeerArrayVisualizerWidget.cpp @@ -13,8 +13,10 @@ #include #include #include +#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) #include #include +#endif #include #include #include @@ -106,7 +108,9 @@ SeerArrayVisualizerWidget::SeerArrayVisualizerWidget (QWidget* parent) : QWidget QObject::connect(labelsCheckBox, &QCheckBox::clicked, this, &SeerArrayVisualizerWidget::handleLabelsCheckBox); QObject::connect(lineTypeButtonGroup, QOverload::of(&QButtonGroup::idClicked), this, &SeerArrayVisualizerWidget::handleLineTypeButtonGroup); QObject::connect(printPushButton, &QPushButton::clicked, arrayChartView, &QZoomChartView::printView); +#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) QObject::connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, &SeerArrayVisualizerWidget::handleThemeChanged); +#endif // Colorize icons for theme. Seer::colorizeAllIcons(this); diff --git a/src/SeerConfigDialog.cpp-main b/src/SeerConfigDialog.cpp-main new file mode 100644 index 0000000..43da16d --- /dev/null +++ b/src/SeerConfigDialog.cpp-main @@ -0,0 +1,587 @@ +// SPDX-FileCopyrightText: 2021 Ernie Pasveer +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "SeerConfigDialog.h" +#include "SeerUtl.h" +#include +#include +#include +#include +#include +#include +#include +#include + +SeerConfigDialog::SeerConfigDialog(QWidget* parent) : QDialog(parent) { + + // Set up the UI. + setupUi(this); + + // Setup the widgets + QSize size(96, 84); + int spacing = 12; + + contentsListWidget->setViewMode(QListView::IconMode); + contentsListWidget->setIconSize(size); + contentsListWidget->setMovement(QListView::Static); + contentsListWidget->setSpacing(spacing); + contentsListWidget->setFixedWidth(size.width()+(spacing*3)); + contentsListWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + QPushButton* resetButton = buttonBox->button(QDialogButtonBox::Reset); + if (resetButton) { + resetButton->setToolTip("Reset configuration for the current page to initial settings."); + } + + QPushButton* okButton = buttonBox->button(QDialogButtonBox::Ok); + if (okButton) { + okButton->setToolTip("Accept configuration changes to all pages."); + } + + QPushButton* cancelButton = buttonBox->button(QDialogButtonBox::Cancel); + if (cancelButton) { + cancelButton->setToolTip("Discard configuration changes to all pages."); + } + + // Create pages. + _seerConfigPage = new SeerSeerConfigPage; + _gdbConfigPage = new SeerGdbConfigPage; + _editorConfigPage = new SeerEditorConfigPage; + _sourceConfigPage = new SeerSourceConfigPage; + _assemblyConfigPage = new SeerAssemblyConfigPage; + _keysConfigPage = new SeerKeysConfigPage; + _rrConfigPage = new SeerRRConfigPage; + + // Add the pages to the stacked widget. + pagesStackedWidget->addWidget(_seerConfigPage); + pagesStackedWidget->addWidget(_gdbConfigPage); + pagesStackedWidget->addWidget(_editorConfigPage); + pagesStackedWidget->addWidget(_sourceConfigPage); + pagesStackedWidget->addWidget(_assemblyConfigPage); + pagesStackedWidget->addWidget(_keysConfigPage); + pagesStackedWidget->addWidget(_rrConfigPage); + + // Create icons. + QListWidgetItem* configSeerButton = new QListWidgetItem(contentsListWidget); + configSeerButton->setIcon(QIcon(":/seer/resources/icons/hicolor/128x128/seergdb.png")); + configSeerButton->setText(tr("Seer")); + configSeerButton->setTextAlignment(Qt::AlignHCenter); + configSeerButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + + QListWidgetItem* configGdbButton = new QListWidgetItem(contentsListWidget); + configGdbButton->setIcon(QIcon(":/seer/resources/icons-icons/gdb.png")); + configGdbButton->setText(tr("GDB")); + configGdbButton->setTextAlignment(Qt::AlignHCenter); + configGdbButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + + QListWidgetItem* configEditorButton = new QListWidgetItem(contentsListWidget); + configEditorButton->setIcon(QIcon(":/seer/resources/icons-icons/editor.png")); + configEditorButton->setText(tr("Editor")); + configEditorButton->setTextAlignment(Qt::AlignHCenter); + configEditorButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + + QListWidgetItem* configSourceButton = new QListWidgetItem(contentsListWidget); + configSourceButton->setIcon(QIcon(":/seer/resources/thenounproject/source.svg")); + configSourceButton->setText(tr("Source")); + configSourceButton->setTextAlignment(Qt::AlignHCenter); + configSourceButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + + QListWidgetItem* configAssemblyButton = new QListWidgetItem(contentsListWidget); + configAssemblyButton->setIcon(QIcon(":/seer/resources/thenounproject/assembly.svg")); + configAssemblyButton->setText(tr("Assembly")); + configAssemblyButton->setTextAlignment(Qt::AlignHCenter); + configAssemblyButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + + QListWidgetItem* configKeysButton = new QListWidgetItem(contentsListWidget); + configKeysButton->setIcon(QIcon(":/seer/resources/thenounproject/keyboard.svg")); + configKeysButton->setText(tr("Keys")); + configKeysButton->setTextAlignment(Qt::AlignHCenter); + configKeysButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + + QListWidgetItem* configRRButton = new QListWidgetItem(contentsListWidget); + configRRButton->setIcon(QIcon(":/seer/resources/icons/hicolor/256x256/rr.png")); + configRRButton->setText(tr("RR")); + configRRButton->setTextAlignment(Qt::AlignHCenter); + configRRButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + + // Connect things. + connect(contentsListWidget, &QListWidget::currentItemChanged, this, &SeerConfigDialog::handleChangePage); + connect(buttonBox, &QDialogButtonBox::clicked, this, &SeerConfigDialog::handleButtonClicked); + + // Colorize icons for theme. + Seer::colorizeAllIcons(this); + Seer::colorizeListWidgetItemIcon(configSeerButton, QSize(128,128)); + Seer::colorizeListWidgetItemIcon(configGdbButton, QSize(128,128)); + Seer::colorizeListWidgetItemIcon(configEditorButton, QSize(128,128)); + Seer::colorizeListWidgetItemIcon(configSourceButton, QSize(128,128)); + Seer::colorizeListWidgetItemIcon(configAssemblyButton, QSize(128,128)); + Seer::colorizeListWidgetItemIcon(configKeysButton, QSize(128,128)); + // Seer::colorizeListWidgetItemIcon(configRRButton, QSize(128,128)); // Don't change. It's a multi-colored icon. + + // Set to first page. + contentsListWidget->setCurrentRow(0); +} + +SeerConfigDialog::~SeerConfigDialog() { +} + +void SeerConfigDialog::setSeerConsoleMode (const QString& mode) { + + _seerConfigPage->setConsoleMode(mode); +} + +QString SeerConfigDialog::seerConsoleMode () const { + + return _seerConfigPage->consoleMode(); +} + +void SeerConfigDialog::setSeerConsoleScrollLines (int count) { + + _seerConfigPage->setConsoleScrollLines(count); +} + +int SeerConfigDialog::seerConsoleScrollLines () const { + + return _seerConfigPage->consoleScrollLines(); +} +void SeerConfigDialog::setSeerRememberWindowSizes (bool flag) { + + _seerConfigPage->setRememberWindowSizes(flag); +} + +bool SeerConfigDialog::seerRememberWindowSizes () const { + + return _seerConfigPage->rememberWindowSizes(); +} + +void SeerConfigDialog::setSeerRememberManualCommandCount (int count) { + + _seerConfigPage->setRememberManualCommandCount(count); +} + +int SeerConfigDialog::seerRememberManualCommandCount () const { + + return _seerConfigPage->rememberManualCommandCount(); +} + +void SeerConfigDialog::setSeerClearManualCommandHistory (bool flag) { + + _seerConfigPage->setClearManualCommandHistory(flag); +} + +bool SeerConfigDialog::seerClearManualCommandHistory () const { + + return _seerConfigPage->clearManualCommandHistory(); +} + +void SeerConfigDialog::setGdbLauncher (const QString& launcher) { + + _gdbConfigPage->setGdbLauncher(launcher); +} + +QString SeerConfigDialog::gdbLauncher () const { + + return _gdbConfigPage->gdbLauncher(); +} + +void SeerConfigDialog::setGdbProgram (const QString& program) { + + _gdbConfigPage->setGdbProgram(program); +} + +QString SeerConfigDialog::gdbProgram () const { + + return _gdbConfigPage->gdbProgram(); +} + +void SeerConfigDialog::setGdbArguments (const QString& arguments) { + + _gdbConfigPage->setGdbArguments(arguments); +} + +QString SeerConfigDialog::gdbArguments () const { + + return _gdbConfigPage->gdbArguments(); +} + +void SeerConfigDialog::setGdbAsyncMode (bool flag) { + + _gdbConfigPage->setGdbAsyncMode(flag); +} + +bool SeerConfigDialog::gdbAsyncMode () const { + + return _gdbConfigPage->gdbAsyncMode(); +} + +void SeerConfigDialog::setGdbNonStopMode (bool flag) { + + _gdbConfigPage->setGdbNonStopMode(flag); +} + +bool SeerConfigDialog::gdbNonStopMode () const { + + return _gdbConfigPage->gdbNonStopMode(); +} + +void SeerConfigDialog::setGdbHandleTerminatingException (bool flag) { + + _gdbConfigPage->setGdbHandleTerminatingException(flag); +} + +bool SeerConfigDialog::gdbHandleTerminatingException () const { + + return _gdbConfigPage->gdbHandleTerminatingException(); +} + +void SeerConfigDialog::setGdbRandomizeStartAddress (bool flag) { + + _gdbConfigPage->setGdbRandomizeStartAddress(flag); +} + +bool SeerConfigDialog::gdbRandomizeStartAddress () const { + + return _gdbConfigPage->gdbRandomizeStartAddress(); +} + +void SeerConfigDialog::setGdbEnablePrettyPrinting (bool flag) { + + _gdbConfigPage->setGdbEnablePrettyPrinting(flag); +} + +bool SeerConfigDialog::gdbEnablePrettyPrinting () const { + + return _gdbConfigPage->gdbEnablePrettyPrinting(); +} + +void SeerConfigDialog::setGdbRemoteTargetType (const QString& type) { + + _gdbConfigPage->setGdbRemoteTargetType(type); +} + +QString SeerConfigDialog::gdbRemoteTargetType () const { + + return _gdbConfigPage->gdbRemoteTargetType(); +} + +void SeerConfigDialog::setGdbArchitectureType (const QString& type) { + + _gdbConfigPage->setGdbArchitectureType(type); +} + +QString SeerConfigDialog::gdbArchitectureType () const { + + return _gdbConfigPage->gdbArchitectureType(); +} + +void SeerConfigDialog::setEditorFont (const QFont& font) { + + _editorConfigPage->setEditorFont(font); +} + +const QFont& SeerConfigDialog::editorFont () const { + + return _editorConfigPage->editorFont(); +} + +void SeerConfigDialog::setEditorTabSize (int spaces) { + + _editorConfigPage->setEditorTabSize(spaces); +} + +int SeerConfigDialog::editorTabSize () const { + + return _editorConfigPage->editorTabSize(); +} + +void SeerConfigDialog::setEditorHighlighterSettings (const SeerHighlighterSettings& settings) { + + _editorConfigPage->setHighlighterSettings(settings); +} + +const SeerHighlighterSettings& SeerConfigDialog::editorHighlighterSettings () const { + + return _editorConfigPage->highlighterSettings(); +} + +void SeerConfigDialog::setEditorHighlighterEnabled (bool flag) { + + _editorConfigPage->setHighlighterEnabled(flag); +} + +bool SeerConfigDialog::editorHighlighterEnabled () const { + + return _editorConfigPage->highlighterEnabled(); +} + +void SeerConfigDialog::setExternalEditorCommand (const QString& externalEditorCommand) { + + _editorConfigPage->setExternalEditorCommand(externalEditorCommand); +} + +QString SeerConfigDialog::externalEditorCommand () const { + + return _editorConfigPage->externalEditorCommand(); +} + +void SeerConfigDialog::setEditorAutoSourceReload (bool flag) { + + _editorConfigPage->setAutoSourceReload(flag); +} + +bool SeerConfigDialog::editorAutoSourceReload () const { + + return _editorConfigPage->autoSourceReload(); +} + +void SeerConfigDialog::setSourceAlternateDirectories (const QStringList& alternateDirectories) { + + _sourceConfigPage->setAlternateDirectories(alternateDirectories); +} + +QStringList SeerConfigDialog::sourceAlternateDirectories () const { + + return _sourceConfigPage->alternateDirectories(); +} + +void SeerConfigDialog::setSourceIgnoreFilePatterns (const QStringList& filePatterns) { + + _sourceConfigPage->setIgnoreFilePatterns(filePatterns); +} + +QStringList SeerConfigDialog::sourceIgnoreFilePatterns () const { + + return _sourceConfigPage->ignoreFilePatterns(); +} + +void SeerConfigDialog::setSourceMiscFilePatterns (const QStringList& filePatterns) { + + _sourceConfigPage->setMiscFilePatterns(filePatterns); +} + +QStringList SeerConfigDialog::sourceMiscFilePatterns () const { + + return _sourceConfigPage->miscFilePatterns(); +} + +void SeerConfigDialog::setSourceSourceFilePatterns (const QStringList& filePatterns) { + + _sourceConfigPage->setSourceFilePatterns(filePatterns); +} + +QStringList SeerConfigDialog::sourceSourceFilePatterns () const { + + return _sourceConfigPage->sourceFilePatterns(); +} + +void SeerConfigDialog::setSourceHeaderFilePatterns (const QStringList& filePatterns) { + + _sourceConfigPage->setHeaderFilePatterns(filePatterns); +} + +QStringList SeerConfigDialog::sourceHeaderFilePatterns () const { + + return _sourceConfigPage->headerFilePatterns(); +} + +void SeerConfigDialog::setAssemblyShowAssemblyTabOnStartupMode (const QString& mode) { + + _assemblyConfigPage->setShowAssemblyTabOnStartupMode(mode); +} + +QString SeerConfigDialog::assemblyShowAssemblyTabOnStartupMode () const { + + return _assemblyConfigPage->showAssemblyTabOnStartupMode(); +} + +void SeerConfigDialog::setAssemblyKeepAssemblyTabOnTop (bool flag) { + + _assemblyConfigPage->setKeepAssemblyTabOnTop(flag); +} + +bool SeerConfigDialog::assemblyKeepAssemblyTabOnTop () const { + + return _assemblyConfigPage->keepAssemblyTabOnTop(); +} + +void SeerConfigDialog::setAssemblyDisassemblyFlavor (const QString& flavor) { + + _assemblyConfigPage->setDisassemblyFlavor(flavor); +} + +QString SeerConfigDialog::assemblyDisassemblyFlavor () const { + + return _assemblyConfigPage->disassemblyFlavor(); +} + +void SeerConfigDialog::setAssemblySymbolDemagling (const QString& onoff) { + + _assemblyConfigPage->setSymbolDemagling(onoff); +} + +QString SeerConfigDialog::assemblySymbolDemagling () const { + + return _assemblyConfigPage->symbolDemagling(); +} + +void SeerConfigDialog::setAssemblyShowAddressColumn (bool flag) { + + _assemblyConfigPage->setShowAddressColumn(flag); +} + +bool SeerConfigDialog::assemblyShowAddressColumn () const { + + return _assemblyConfigPage->showAddressColumn(); +} + +void SeerConfigDialog::setAssemblyShowOffsetColumn (bool flag) { + + _assemblyConfigPage->setShowOffsetColumn(flag); +} + +bool SeerConfigDialog::assemblyShowOffsetColumn () const { + + return _assemblyConfigPage->showOffsetColumn(); +} + +void SeerConfigDialog::setAssemblyShowOpcodeColumn (bool flag) { + + _assemblyConfigPage->setShowOpcodeColumn(flag); +} + +bool SeerConfigDialog::assemblyShowOpcodeColumn () const { + + return _assemblyConfigPage->showOpcodeColumn(); +} + +void SeerConfigDialog::setAssemblyShowSourceLines (bool flag) { + + _assemblyConfigPage->setShowSourceLines(flag); +} + +bool SeerConfigDialog::assemblyShowSourceLines () const { + + return _assemblyConfigPage->showSourceLines(); +} + +void SeerConfigDialog::setAssemblyRegisterFormat (const QString& format) { + + _assemblyConfigPage->setRegisterFormat(format); +} + +QString SeerConfigDialog::assemblyRegisterFormat () const { + + return _assemblyConfigPage->registerFormat(); +} + +void SeerConfigDialog::setAssemblyDisassemblyMode (const QString& mode, int bytes) { + + _assemblyConfigPage->setDisassemblyMode(mode, bytes); +} + +QString SeerConfigDialog::assemblyDisassemblyMode () const { + + return _assemblyConfigPage->disassemblyMode(); +} + +int SeerConfigDialog::assemblyDisassemblyBytes () const { + + return _assemblyConfigPage->disassemblyBytes(); +} + +void SeerConfigDialog::setKeySettings (const SeerKeySettings& settings) { + + _keysConfigPage->setKeySettings(settings); +} + +SeerKeySettings SeerConfigDialog::keySettings () const { + + return _keysConfigPage->keySettings(); +} + +void SeerConfigDialog::setRRProgram (const QString& program) { + + _rrConfigPage->setRRProgram(program); +} + +QString SeerConfigDialog::rrProgram () const { + + return _rrConfigPage->rrProgram(); +} + +void SeerConfigDialog::setRRArguments (const QString& arguments) { + + _rrConfigPage->setRRArguments(arguments); +} + +QString SeerConfigDialog::rrArguments () const { + + return _rrConfigPage->rrArguments(); +} + +void SeerConfigDialog::setRRGdbArguments (const QString& arguments) { + + _rrConfigPage->setGdbArguments(arguments); +} + +QString SeerConfigDialog::rrGdbArguments () const { + + return _rrConfigPage->gdbArguments(); +} + +void SeerConfigDialog::handleChangePage(QListWidgetItem* current, QListWidgetItem* previous) { + + if (!current) { + current = previous; + } + + pagesStackedWidget->setCurrentIndex(contentsListWidget->row(current)); +} + +void SeerConfigDialog::handleButtonClicked (QAbstractButton* button) { + + // Handle resetting the config pages if "Reset" is clicked. + if (buttonBox->buttonRole(button) == QDialogButtonBox::ResetRole) { + + QString itemLabel = contentsListWidget->currentItem()->text(); + + int result = QMessageBox::warning(this, "Seer", + QString("Reset settings for the '") + itemLabel + "' tab?", + QMessageBox::Ok|QMessageBox::Cancel, QMessageBox::Cancel); + + if (result != QMessageBox::Ok) { + return; + } + + if (itemLabel == "GDB") { + + _gdbConfigPage->reset(); + + }else if (itemLabel == "Editor") { + + _editorConfigPage->reset(); + + }else if (itemLabel == "Source") { + + _sourceConfigPage->reset(); + + }else if (itemLabel == "Assembly") { + + _assemblyConfigPage->reset(); + + }else if (itemLabel == "Keys") { + + _keysConfigPage->reset(); + + }else if (itemLabel == "Seer") { + + _seerConfigPage->reset(); + + }else if (itemLabel == "RR") { + + _rrConfigPage->reset(); + } + } +} + diff --git a/src/SeerEditorManagerWidget.cpp b/src/SeerEditorManagerWidget.cpp index 92eb7be..db48835 100644 --- a/src/SeerEditorManagerWidget.cpp +++ b/src/SeerEditorManagerWidget.cpp @@ -12,8 +12,10 @@ #include #include #include +#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) #include #include +#endif #include #include #include @@ -89,7 +91,9 @@ SeerEditorManagerWidget::SeerEditorManagerWidget (QWidget* parent) : QWidget(par QObject::connect(fileCloseToolButton, &QToolButton::clicked, this, &SeerEditorManagerWidget::handleFileCloseToolButtonClicked); QObject::connect(textSearchToolButton, &QToolButton::clicked, this, &SeerEditorManagerWidget::handleTextSearchToolButtonClicked); QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerEditorManagerWidget::handleHelpToolButtonClicked); +#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) QObject::connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, &SeerEditorManagerWidget::handleThemeChanged); +#endif // Add combination shortcut for re-open closed file (Ctrl + Shift + T) QShortcut *shortcut = new QShortcut(QKeySequence("Ctrl+Shift+T"), this); diff --git a/src/SeerGdbMonitorWidget.cpp b/src/SeerGdbMonitorWidget.cpp index 4f13d9b..0c1c279 100644 --- a/src/SeerGdbMonitorWidget.cpp +++ b/src/SeerGdbMonitorWidget.cpp @@ -11,8 +11,10 @@ #include #include #include +#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) #include #include +#endif #include #include #include @@ -60,7 +62,9 @@ SeerGdbMonitorWidget::SeerGdbMonitorWidget (QWidget* parent) : QWidget(parent) { QObject::connect(printToolButton, &QToolButton::clicked, this, &SeerGdbMonitorWidget::handlePrintButton); QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerGdbMonitorWidget::handleHelpButton); QObject::connect(macroButtonGroup, &QButtonGroup::buttonClicked, this, &SeerGdbMonitorWidget::handleMacroToolButtonClicked); +#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) QObject::connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, &SeerGdbMonitorWidget::handleThemeChanged); +#endif // Colorize icons for theme. Seer::colorizeAllIcons(this); diff --git a/src/SeerHighlighterSettings.cpp b/src/SeerHighlighterSettings.cpp index 5faa197..418a88a 100644 --- a/src/SeerHighlighterSettings.cpp +++ b/src/SeerHighlighterSettings.cpp @@ -3,8 +3,10 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerHighlighterSettings.h" +#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) #include #include +#endif SeerHighlighterSettings::SeerHighlighterSettings () { } @@ -129,6 +131,7 @@ SeerHighlighterSettings SeerHighlighterSettings::populate (const QString& themeN if (themeName == "auto") { +#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) // Get the current color scheme Qt::ColorScheme colorScheme = QGuiApplication::styleHints()->colorScheme(); @@ -137,6 +140,9 @@ SeerHighlighterSettings SeerHighlighterSettings::populate (const QString& themeN }else{ return SeerHighlighterSettings::populate_light(); } +#else + return SeerHighlighterSettings::populate_light(); +#endif }else if (themeName == "light") { return SeerHighlighterSettings::populate_light(); diff --git a/src/SeerImageVisualizerWidget.cpp b/src/SeerImageVisualizerWidget.cpp index fa2af2b..8882c51 100644 --- a/src/SeerImageVisualizerWidget.cpp +++ b/src/SeerImageVisualizerWidget.cpp @@ -8,8 +8,10 @@ #include #include #include +#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) #include #include +#endif #include #include #include @@ -47,7 +49,9 @@ SeerImageVisualizerWidget::SeerImageVisualizerWidget (QWidget* parent) : QWidget QObject::connect(formatComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerImageVisualizerWidget::handleFormatComboBox); QObject::connect(printToolButton, &QToolButton::clicked, this, &SeerImageVisualizerWidget::handlePrintButton); QObject::connect(saveToolButton, &QToolButton::clicked, this, &SeerImageVisualizerWidget::handleSaveButton); +#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) QObject::connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, &SeerImageVisualizerWidget::handleThemeChanged); +#endif // Colorize icons for theme. Seer::colorizeAllIcons(this); diff --git a/src/SeerMainWindow.cpp b/src/SeerMainWindow.cpp index ebaa463..3ef9185 100644 --- a/src/SeerMainWindow.cpp +++ b/src/SeerMainWindow.cpp @@ -16,8 +16,10 @@ #include #include #include +#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) #include #include +#endif #include #include #include @@ -227,7 +229,9 @@ SeerMainWindow::SeerMainWindow(QWidget* parent) : QMainWindow(parent) { QObject::connect(gdbWidget->gdbMonitor(), &GdbMonitor::caretTextOutput, this, &SeerMainWindow::handleStatusChanged); // Handle when theme is changed. Change the color of all icons. +#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) QObject::connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, &SeerMainWindow::handleThemeChanged); +#endif // Colorize icons for theme. Seer::colorizeAllIcons(this); diff --git a/src/SeerMatrixVisualizerWidget.cpp b/src/SeerMatrixVisualizerWidget.cpp index 85ca90f..bdfcc40 100644 --- a/src/SeerMatrixVisualizerWidget.cpp +++ b/src/SeerMatrixVisualizerWidget.cpp @@ -9,8 +9,10 @@ #include #include #include +#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) #include #include +#endif #include #include #include @@ -58,7 +60,9 @@ SeerMatrixVisualizerWidget::SeerMatrixVisualizerWidget (QWidget* parent) : QWidg QObject::connect(matrixStrideLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerMatrixVisualizerWidget::handleElementStrideLineEdit); QObject::connect(matrixDisplayFormatComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerMatrixVisualizerWidget::handleMatrixDisplayFormatComboBox); QObject::connect(matrixTableWidget, &SeerMatrixWidget::dataChanged, this, &SeerMatrixVisualizerWidget::handleDataChanged); +#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) QObject::connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, &SeerMatrixVisualizerWidget::handleThemeChanged); +#endif // Colorize icons for theme. Seer::colorizeAllIcons(this); diff --git a/src/SeerMemoryVisualizerWidget.cpp b/src/SeerMemoryVisualizerWidget.cpp index ff38ff9..4bc30fd 100644 --- a/src/SeerMemoryVisualizerWidget.cpp +++ b/src/SeerMemoryVisualizerWidget.cpp @@ -8,8 +8,10 @@ #include #include #include +#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) #include #include +#endif #include #include #include @@ -72,7 +74,9 @@ SeerMemoryVisualizerWidget::SeerMemoryVisualizerWidget (QWidget* parent) : QWidg QObject::connect(columnCountSpinBox, QOverload::of(&QSpinBox::valueChanged), this, &SeerMemoryVisualizerWidget::handleColumnCountSpinBox); QObject::connect(printToolButton, &QToolButton::clicked, this, &SeerMemoryVisualizerWidget::handlePrintButton); QObject::connect(saveToolButton, &QToolButton::clicked, this, &SeerMemoryVisualizerWidget::handleSaveButton); +#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) QObject::connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, &SeerMemoryVisualizerWidget::handleThemeChanged); +#endif // Colorize icons for theme. Seer::colorizeAllIcons(this); diff --git a/src/SeerStructVisualizerWidget.cpp b/src/SeerStructVisualizerWidget.cpp index 0f13ab3..aae5465 100644 --- a/src/SeerStructVisualizerWidget.cpp +++ b/src/SeerStructVisualizerWidget.cpp @@ -9,8 +9,10 @@ #include #include #include +#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) #include #include +#endif #include #include #include @@ -46,7 +48,9 @@ SeerStructVisualizerWidget::SeerStructVisualizerWidget (QWidget* parent) : QWidg QObject::connect(variableTreeWidget, &QTreeWidget::itemEntered, this, &SeerStructVisualizerWidget::handleItemEntered); QObject::connect(variableTreeWidget, &QTreeWidget::itemExpanded, this, &SeerStructVisualizerWidget::handleItemExpanded); QObject::connect(variableTreeWidget, &QTreeWidget::itemCollapsed, this, &SeerStructVisualizerWidget::handleItemExpanded); +#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) QObject::connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, &SeerStructVisualizerWidget::handleThemeChanged); +#endif // Colorize icons for theme. Seer::colorizeAllIcons(this); diff --git a/src/SeerUtl.cpp b/src/SeerUtl.cpp index 5ec5f9e..6aaa47a 100644 --- a/src/SeerUtl.cpp +++ b/src/SeerUtl.cpp @@ -13,8 +13,10 @@ #include #include #include +#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) #include #include +#endif #include #include #include @@ -1383,6 +1385,7 @@ namespace Seer { void colorizeAllIcons (QWidget* parent, const QSize& size) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) if (parent == nullptr) { return; } @@ -1434,10 +1437,12 @@ namespace Seer { }else{ QApplication::setWindowIcon(Seer::colorizeIcon(QIcon(":/seer/resources/icons/hicolor/64x64/seergdb.png"), QColor("black"), size)); } +#endif } void colorizeListWidgetItemIcon (QListWidgetItem* item, const QSize& size) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) if (item == nullptr) { return; } @@ -1450,10 +1455,12 @@ namespace Seer { }else{ item->setIcon(Seer::colorizeIcon(item->icon(), QColor("black"), size)); } +#endif } void colorizeChartViewItem (QChartView* item) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) if (item == nullptr) { return; } @@ -1472,10 +1479,12 @@ namespace Seer { }else{ chart->setTheme(QChart::ChartThemeLight); } +#endif } QIcon colorizeIcon (const QIcon& icon, const QSize& size) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) // Get the current color scheme Qt::ColorScheme colorScheme = QGuiApplication::styleHints()->colorScheme(); @@ -1484,29 +1493,36 @@ namespace Seer { }else{ return Seer::colorizeIcon(icon, QColor("black"), size); } +#else + return icon; +#endif } QIcon colorizeIcon (const QIcon& icon, const QColor& color, const QSize& size) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) // Get the pixmap from the icon QPixmap pixmap = icon.pixmap(size); // Create a new pixmap with the same size and format (preserves alpha) - QPixmap whitePixmap(pixmap.size()); - whitePixmap.fill(Qt::transparent); + QPixmap coloredPixmap(pixmap.size()); + coloredPixmap.fill(Qt::transparent); - QPainter painter(&whitePixmap); + QPainter painter(&coloredPixmap); // Draw the original pixmap painter.drawPixmap(0, 0, pixmap); // Use CompositionMode_SourceIn to colorize while keeping alpha painter.setCompositionMode(QPainter::CompositionMode_SourceIn); - painter.fillRect(whitePixmap.rect(), color); + painter.fillRect(coloredPixmap.rect(), color); painter.end(); - return QIcon(whitePixmap); + return QIcon(coloredPixmap); +#else + return icon; +#endif } } diff --git a/src/SeerUtl.cpp-main b/src/SeerUtl.cpp-main new file mode 100644 index 0000000..5ec5f9e --- /dev/null +++ b/src/SeerUtl.cpp-main @@ -0,0 +1,1512 @@ +// SPDX-FileCopyrightText: 2021 Ernie Pasveer +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "SeerUtl.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Comment out for now. I don't want to include boost because +// that would impact people try to compile Seer. Qt6 offer +// a 'stacktrace' function. OpenSuse may be slow in adoption. +// For now, comment it out and use when needed. +// #include + +#include +#include + +// +// Increment this with every release on GitHub. +// See scripts/change_versionnumber +// +#define SEER_VERSION "2.8beta" + +namespace Seer { + + QString version () { + return SEER_VERSION + QString(" (Qt") + QT_VERSION_STR + ")"; + } + + QString filterBareNewLines (const QString& str) { + + // Remove bare (not inside quotes) '\n' substrings. + // Maybe extra spaces after '\n'. + // "{\n B = 1,\n C = 0,\n D = \"asd\",\n E = std::vector of length 1, capacity 64 = {true}\n}" + // "{B = 1, C = 0, D = \"asd\", E = std::vector of length 1, capacity 64 = {true}}" + + QString tmp; + qsizetype anchor=0; + qsizetype curr=0; + qsizetype end=str.length(); + + // Loop through string a character at a time. + while (curr < end) { + + // Found a '\n' substring. Deal with it. + if (str.mid(curr,2) == "\\n") { + + // Append the good bits before the '\n'. + tmp.append(str.mid(anchor,curr-anchor)); + curr += 2; + + // Skip trailing spaces, if any, after '\n'. + while (curr < end) { + if (str.at(curr) == ' ') { + curr++; + }else{ + break; + } + } + + anchor = curr; + + // Other character. Skip it. + }else{ + curr++; + } + } + + // Anything left to deal with? + if (curr > anchor) { + tmp.append(str.mid(anchor,curr-anchor)); + anchor = curr; + } + + return tmp; + } + + QString filterEscapes (const QString& str) { + + // Remove one level of '\'. + // value="\"'Treasure' by Lucillius\\n\\n\\tbut theirs.\\n\"" + + QString tmp; + bool escaped = false; + + for (int i=0; i 0) { + r.remove(i, len); + r.insert(i, value); + }else{ + f = false; // Not expanded. + break; + } + } + + while (true) { + + QRegularExpressionMatch match = env_re2.match(r); + + if (match.hasMatch() == false) { + break; + } + + qsizetype i = match.capturedStart(); + qsizetype len = match.capturedLength(); + QString capstr = match.captured(); + QString envstr = capstr.mid(1,capstr.length()-1); + + QByteArray value(qgetenv(envstr.toLatin1().data())); + + if (value.size() > 0) { + r.remove(i, len); + r.insert(i, value); + }else{ + f = false; // Not expanded. + break; + } + } + + if (ok) { + *ok = f; + } + + return r; + } + + QStringList parse (const QString& str, const QString& search, QChar startBracket, QChar endBracket, bool includeSearchString) { + + // + // str = "^done,stack-args=[frame={level=\"0\",args=[{name=\"message\",value=\"\\\"Hello, World!\\\"\"}]},frame={level=\"1\",args=[{name=\"argc\",value=\"1\"},{name=\"argv\",value=\"0x7fffffffd5b8\"}]}]" + // search = "frame=" + // startBracket = '{' + // endBracket = '}' + // + + QStringList list; + QString searchWord = search + startBracket; // 'frame={' + int from = 0; + + while (1) { + + // Look for the next occurance of the search word. + int index = str.indexOf(searchWord,from); + if (index < 0) { // If not found, we're done. + break; + } + + // Set things up to look for the matching end bracket. + int start = index + search.size() + 1; // Positioned after 'frame={' + int end = start + 1; + int bracketLevel = 1; // Start with one start bracket already encountered. + + for (end=start; end= 0) { + if (str[end-1] == '\\') { + escaped = true; + } + } + + if (startBracket != endBracket) { // Do this test if brackets are not the same character. + if (str[end] == startBracket && escaped == false) { // Encountered another start bracket, increment the level. + bracketLevel++; + } + } + + if (str[end] == endBracket && escaped == false) { // Encountered an end bracket, decrement the level. + bracketLevel--; + + if (bracketLevel == 0) { // If the level is 0, we're done. + break; + } + } + } + + // Are things valid? + if (bracketLevel != 0) { // No matching bracket. + break; + } + + if (end > str.size()) { // The end is past the end of the string. + break; + } + + // Build the string. + QString tmp; + + if (includeSearchString) { + tmp = search + startBracket + str.mid(start, end-start) + endBracket; + }else{ + tmp = str.mid(start, end-start); + } + + // Add it to the list. + list.append(tmp); + + // Go back for more + from = end + 1; + } + + // Return the list. + return list; + } + + QString parseFirst (const QString& str, const QString& search, QChar startBracket, QChar endBracket, bool includeSearchString) { + + QStringList list = Seer::parse(str, search, startBracket, endBracket, includeSearchString); + + if (list.size() == 0) { + return QString(); + } + + return list.front(); + } + + QString parseFirst (const QString& str, const QString& search, bool includeSearchString) { + + QString match; + + // Look for the next occurance of the search word. + int index = str.indexOf(search,0); + if (index < 0) { // If not found, we're done. + return match; + } + + // Set things up to look for the matching end bracket. + int start = index + search.size() + 0; // Position after 'msg=' + int end = str.size(); + + if (includeSearchString) { + match = search + str.mid(start, end-start); + }else{ + match = str.mid(start, end-start); + } + + return match; + } + + + bool hasBookends (const QString& str, QChar startBracket, QChar endBracket) { + + if (str.startsWith(startBracket) && str.endsWith(endBracket)) { + return true; + } + + return false; + } + + + QString filterBookends (const QString& str, QChar startBracket, QChar endBracket) { + + // If the string starts with and ends with the bracket characters, then return + // the text between the brackets. + if (str.startsWith(startBracket) && str.endsWith(endBracket)) { + return str.mid(1,str.size()-2); + } + + // Otherwise, return the orginal string. + return str; + } + + QStringList filterBookends (const QStringList& strings, QChar startBracket, QChar endBracket) { + + QStringList list; + + // For a list of strings, remove the bookends, if possible. + for (int i=0; i, \"hildTest 2000-", '0' , "1", '0' , "330324377377377177000000004", '0' , "test\", '000' , \"325377377\", child = {childId = -9864, childString = \"\"}} + + enum STATE{ + START = 0, + SCANNING = 1, + FOUND = 2, + IGNORE = 3, + }; + QStringList list; + int index = 0; + int start = 0; + int end = 0; + int previousComma= 0; + STATE state = START; + + while (index < str.length()) + { + // Handle "=" + if (str[index] == '=') { + if (state == SCANNING) // looking for 2nd '=' + { + // state = FOUND; + end = previousComma; + QString field = str.mid(start, end-start); + list.append(field.trimmed()); + start = previousComma + 1; + } + if (state == START) // looking for 2nd '=' + { + state = SCANNING; + + } + } + + if (str[index] == startBracket) + { + state = IGNORE; + } + + if (str[index] == endBracket) + { + state = SCANNING; + } + + if (str[index] == ',' && state != IGNORE) { + previousComma = index; + } + + // The last + if (index == str.length() - 1) + { + QString field = str.mid(start, index); + list.append(field.trimmed()); + } + index++; + } + return list; + } + + // + // Parse an array, turn it to QList + // + + QStringList parseArray (const QString& parentName, const QString& str) + { + // Input: {age = 1, name = "1st_child"}, {age = 2, name = "2nd_child"} + // Output: QStringList : parentName[0] = {age = 1, name = "1st_child"}, parentName[1] = {age = 1, name = "1st_child"} + + QStringList list; + int index = 0; + int cntStartBracket = 0; + int cntEndBracket = 0; + int start = 0; + int cnt = 0; + + while (index < str.length()) + { + if (str[index] == '{') + { + if (cntStartBracket == cntEndBracket) + start = index; + cntStartBracket++; + } + if (str[index] == '}') + { + // Check to see if character after it is ",". Otherwise, it probably trash character. + if (index + 1 < str.length()) + { + if (str[index + 1] == '}' || str[index + 1] == ',' || index + 1 == str.length() ) + { + cntEndBracket++; + if (cntStartBracket == cntEndBracket) + { + QString field = str.mid(start, index + 1 - start); + field = parentName + "[" + QString::number(cnt) + "] = " + field; + list.append(field.trimmed()); + cntStartBracket = 0; cntEndBracket = 0; + cnt++; + } + } + } + else if (index + 1 == str.length()) + { + // The last element + cntEndBracket++; + if (cntStartBracket == cntEndBracket) + { + QString field = str.mid(start, index + 1 - start); + field = parentName + "[" + QString::number(cnt) + "] = " + field; + list.append(field.trimmed()); + cntStartBracket = 0; cntEndBracket = 0; + cnt++; + } + } + } + index ++; + } + return list; + } + + QMap createKeyValueMap (const QStringList& list, QChar separator) { + + QMap map; + + for (const auto& i : list) { + QStringPair pair = parseNameValue(i, separator); + + map[pair.first] = pair.second; + } + + return map; + } + + // + // + // + + QStringPair parseNameValue (const QString& str, QChar separator) { + + // name = "Pasveer, Ernie" + // + // pair.first = name + // pair.second = "Pasveer, Ernie" + // + + QStringPair pair; + int index = 0; + int state = 0; + int start = 0; + int end = 0; + bool inquotes = false; + + while (index < str.length()) { + + // Handle start of field. + if (state == 0) { // Start of field. + start = index; + end = index; + state = 1; // Look for end of field (a command or eol). + + continue; + } + + // Handle end of field. + if (state == 1) { + + // Handle """ + if (str[index] == '"') { + if (inquotes == false) { + inquotes = true; + }else{ + inquotes = false; + } + + index++; continue; + } + + // Handle "=" separator. + if (str[index] == separator) { + + if (inquotes) { + index++; continue; + } + + // Extract the two fields. index is at the "=". + end = index; + + QString one = str.mid(start, end-start); + QString two = str.mid(end+1); + + pair = QStringPair(one.trimmed(),two.trimmed()); + + state = 0; // Look for the next field. + + break; + } + + // Handle any other character. + index++; continue; + } + + qDebug() << "Bad state!"; + index++; continue; + } + + // Handle if no "=" separator. + if (state == 1) { + pair = QStringPair(str.trimmed(),QString()); + } + + return pair; + } + + // + // Quote certain characters in a string. + // + // "hello" => \"hello\" + // + QString quoteChars (const QString& str, const QString& chars) { + + QString string; + + for (int i=0; i= 0x060000 + + QRegularExpression re = QRegularExpression::fromWildcard(pattern, Qt::CaseInsensitive, QRegularExpression::UnanchoredWildcardConversion); + +#else + // With Qt5, 'wildcardToRegularExpression' needs a "/*" at the start of 'pattern' + // if 'string' start with a "/". + //if (string[0] == '/') { + // if (pattern[0] != '/') { + // pattern = "/*/" + pattern; + // } + //} + + // This pattern needs to be converted from a glob to a regex. + // All '*' are replaced with '.*' + // The pattern is terminated with a '$', if it doesn't have one. + pattern.replace("*", ".*"); + + //if (string[0] != '/') { + // if (pattern.back() != '$') { + // pattern += '$'; + // } + //} + + // qDebug() << pattern << string; + + // QRegularExpression re = QRegularExpression(QRegularExpression::wildcardToRegularExpression(pattern)); + QRegularExpression re = QRegularExpression(pattern); +#endif + + if (re.match(string).hasMatch()) { + return true; + } + } + + return false; + } + + bool hasWildcards (const QString& str) { + return (str.indexOf('*') >= 0) || (str.indexOf('?') >= 0); + } + + QString elideText (const QString& str, Qt::TextElideMode mode, int length) { + + QString leftElide("... "); + QString middleElide(" ... "); + QString rightElide(" ..."); + + // The string is fine. Just return it. + if (str.length() <= length) { + return str; + } + + // The string is too long but don't add elide. + if (mode == Qt::ElideNone) { + return str.left(length); + } + + // The string is too long. Add elilde on the left. + if (mode == Qt::ElideLeft) { + return leftElide + str.right(length); + } + + // The string is too long. Add elilde on the right. + if (mode == Qt::ElideRight) { + return str.left(length) + rightElide; + } + + // The string is too long. Add elilde in the middle. + if (mode == Qt::ElideRight) { + int halve = length / 2; + return str.left(halve) + middleElide + str.right(halve); + } + + // Bad mode. Just return the string. + return str; + } + + // Split a string on words. Double "quoted strings" + // act as one word. + QStringList split (const QString& str) { + + QRegularExpression re("[^\\s\"']+|\"([^\"]*)\"|'([^']*)'"); + QStringList list; + + QRegularExpressionMatchIterator i = re.globalMatch(str); + while (i.hasNext()) { + QRegularExpressionMatch match = i.next(); + + QString word; + if (match.captured(2) != "") { + word = match.captured(2); + }else if (match.captured(1) != "") { + word = match.captured(1); + }else if (match.captured(0) != "") { + word = match.captured(0); + } + + if (word != "") { + list << word; + } + } + + return list; + } + + // + // + // + + static int Next_ID = 1; + static std::mutex ID_mutex; + + int createID () { + + std::lock_guard guard(ID_mutex); + + int id = Next_ID; + + Next_ID++; + + return id; + } + + unsigned char ebcdicToAscii (unsigned char byte) { + + static const unsigned char ebcdicToAsciiTable[256] = { + 46, 46, 46, 46, 46, 46, 46, 46, // 0 + 46, 46, 46, 46, 46, 46, 46, 46, // 8 + 46, 46, 46, 46, 46, 46, 46, 46, // 16 + 46, 46, 46, 46, 46, 46, 46, 46, // 24 + 46, 46, 46, 46, 46, 46, 46, 46, // 32 + 46, 46, 46, 46, 46, 46, 46, 46, // 40 + 46, 46, 46, 46, 46, 46, 46, 46, // 48 + 46, 46, 46, 46, 46, 46, 46, 46, // 56 + 32, 46, 46, 46, 46, 46, 46, 46, // 64 + 46, 46, 91, 46, 60, 40, 43, 33, // 72 + 38, 46, 46, 46, 46, 46, 46, 46, // 80 + 46, 46, 33, 36, 42, 41, 59, 94, // 88 + 45, 47, 46, 46, 46, 46, 46, 46, // 96 + 46, 46, 124, 44, 37, 95, 62, 63, // 104 + 46, 46, 46, 46, 46, 46, 46, 46, // 112 + 46, 96, 58, 35, 64, 39, 61, 34, // 120 + 46, 97, 98, 99, 100, 101, 102, 103, // 128 + 104, 105, 46, 46, 46, 46, 46, 46, // 136 + 46, 106, 107, 108, 109, 110, 111, 112, // 144 + 113, 114, 46, 46, 46, 46, 46, 46, // 152 + 46, 126, 115, 116, 117, 118, 119, 120, // 160 + 121, 122, 46, 46, 46, 46, 46, 46, // 168 + 46, 46, 46, 46, 46, 46, 46, 46, // 176 + 46, 46, 46, 46, 46, 46, 46, 46, // 184 + 123, 65, 66, 67, 68, 69, 70, 71, // 192 + 72, 73, 46, 46, 46, 46, 46, 46, // 200 + 125, 74, 75, 76, 77, 78, 79, 80, // 208 + 81, 82, 46, 46, 46, 46, 46, 46, // 216 + 92, 46, 83, 84, 85, 86, 87, 88, // 224 + 89, 90, 46, 46, 46, 46, 46, 46, // 232 + 48, 49, 50, 51, 52, 53, 54, 55, // 240 + 56, 57, 46, 46, 46, 46, 46, 46 // 248 + }; + + return ebcdicToAsciiTable[byte]; + } + + unsigned char ucharToAscii (unsigned char byte) { + + static const unsigned char ucharToAsciiTable[256] = { + 46, 46, 46, 46, 46, 46, 46, 46, // 0 + 46, 46, 46, 46, 46, 46, 46, 46, // 8 + 46, 46, 46, 46, 46, 46, 46, 46, // 16 + 46, 46, 46, 46, 46, 46, 46, 46, // 24 + 32, 33, 34, 35, 36, 37, 38, 39, // 32 + 40, 41, 42, 43, 44, 45, 46, 47, // 40 + 48, 49, 50, 51, 52, 53, 54, 55, // 48 + 56, 57, 58, 59, 60, 61, 62, 63, // 56 + 64, 65, 66, 67, 68, 69, 70, 71, // 64 + 72, 73, 74, 75, 76, 77, 78, 79, // 72 + 80, 81, 82, 83, 84, 85, 86, 87, // 80 + 88, 89, 90, 91, 92, 93, 94, 95, // 88 + 96, 97, 98, 99, 100, 101, 102, 103, // 96 + 104, 105, 106, 107, 108, 109, 110, 111, // 104 + 112, 113, 114, 115, 116, 117, 118, 119, // 112 + 120, 121, 122, 123, 124, 125, 126, 46, // 120 + 46, 46, 46, 46, 46, 46, 46, 46, // 128 + 46, 46, 46, 46, 46, 46, 46, 46, // 136 + 46, 46, 46, 46, 46, 46, 46, 46, // 144 + 46, 46, 46, 46, 46, 46, 46, 46, // 152 + 46, 46, 46, 46, 46, 46, 46, 46, // 160 + 46, 46, 46, 46, 46, 46, 46, 46, // 168 + 46, 46, 46, 46, 46, 46, 46, 46, // 176 + 46, 46, 46, 46, 46, 46, 46, 46, // 184 + 46, 46, 46, 46, 46, 46, 46, 46, // 192 + 46, 46, 46, 46, 46, 46, 46, 46, // 200 + 46, 46, 46, 46, 46, 46, 46, 46, // 208 + 46, 46, 46, 46, 46, 46, 46, 46, // 216 + 46, 46, 46, 46, 46, 46, 46, 46, // 224 + 46, 46, 46, 46, 46, 46, 46, 46, // 232 + 46, 46, 46, 46, 46, 46, 46, 46, // 240 + 46, 46, 46, 46, 46, 46, 46, 46 // 248 + }; + + return ucharToAsciiTable[byte]; + } + + QString ucharToHex (const QVector& bytes, int from, int count) { + + QString str; + + str.reserve(count*2+4); + + for (int i=from; i= bytes.size()) { + break; + } + + quint8 decimal = bytes[i]; + QString hex = QString("%1").arg(decimal, 2, 16, QLatin1Char('0')); + + str += hex; + } + + return str; + } + + QString ucharToOctal (const QVector& bytes, int from, int count) { + + QString str; + + str.reserve(count*3+4); + + for (int i=from; i= bytes.size()) { + break; + } + + quint8 decimal = bytes[i]; + QString octal = QString("%1").arg(decimal, 3, 8, QLatin1Char('0')); + + str += octal; + } + + return str; + } + + QString ucharToAscii (const QVector& bytes, int from, int count) { + + QString str; + + str.reserve(count); + + for (int i=from; i= bytes.size()) { + break; + } + + quint8 decimal = bytes[i]; + QString ascii = QChar(Seer::ucharToAscii(decimal)); + + str += ascii; + } + + return str; + } + + QString ucharToUShort (const QVector& bytes, int from, int count) { + + QString str; + + for (int i=0; i= bytes.size()) { + break; + } + + quint16 decimal = *(quint16*)(bytes.data()+from); + QString val = QString("%1").arg(decimal); + + if (i != 0) { + str += " "; + } + + str += val; + from += sizeof(quint16); + } + + return str; + } + + QString ucharToShort (const QVector& bytes, int from, int count) { + + QString str; + + for (int i=0; i= bytes.size()) { + break; + } + + qint16 decimal = *(qint16*)(bytes.data()+from); + QString val = QString("%1").arg(decimal); + + if (i != 0) { + str += " "; + } + + str += val; + from += sizeof(qint16); + } + + return str; + } + + QString ucharToUInt (const QVector& bytes, int from, int count) { + + QString str; + + for (int i=0; i= bytes.size()) { + break; + } + + quint32 decimal = *(quint32*)(bytes.data()+from); + QString val = QString("%1").arg(decimal); + + if (i != 0) { + str += " "; + } + + str += val; + from += sizeof(quint32); + } + + return str; + } + + QString ucharToInt (const QVector& bytes, int from, int count) { + + QString str; + + for (int i=0; i= bytes.size()) { + break; + } + + qint32 decimal = *(qint32*)(bytes.data()+from); + QString val = QString("%1").arg(decimal); + + if (i != 0) { + str += " "; + } + + str += val; + from += sizeof(qint32); + } + + return str; + } + + QString ucharToULong (const QVector& bytes, int from, int count) { + + QString str; + + for (int i=0; i= bytes.size()) { + break; + } + + quint64 decimal = *(quint64*)(bytes.data()+from); + QString val = QString("%1").arg(decimal); + + if (i != 0) { + str += " "; + } + + str += val; + from += sizeof(quint64); + } + + return str; + } + + QString ucharToLong (const QVector& bytes, int from, int count) { + + QString str; + + for (int i=0; i= bytes.size()) { + break; + } + + qint64 decimal = *(qint64*)(bytes.data()+from); + QString val = QString("%1").arg(decimal); + + if (i != 0) { + str += " "; + } + + str += val; + from += sizeof(qint64); + } + + return str; + } + + QString ucharToFloat (const QVector& bytes, int from, int count) { + + QString str; + + for (int i=0; i= bytes.size()) { + break; + } + + float real = *(float*)(bytes.data()+from); + QString val = QString("%1").arg(real); + + if (i != 0) { + str += " "; + } + + str += val; + from += sizeof(float); + } + + return str; + } + + QString ucharToDouble (const QVector& bytes, int from, int count) { + + QString str; + + for (int i=0; i= bytes.size()) { + break; + } + + double real = *(double*)(bytes.data()+from); + QString val = QString("%1").arg(real); + + if (i != 0) { + str += " "; + } + + str += val; + from += sizeof(double); + } + + return str; + } + + int typeBytes (const QString& type) { + + if (type == "int8" || type == "uint8") { + return 1; + }else if (type == "int16" || type == "uint16") { + return 2; + }else if (type == "int32" || type == "uint32") { + return 4; + }else if (type == "int64" || type == "uint64") { + return 8; + }else if (type == "float32") { + return 4; + }else if (type == "float64") { + return 8; + }else{ + qWarning() << "Bad data type:" << type; + return 0; + } + } + + bool readFile (const QString& filename, QStringList& lines) { + + // Empty the list + lines = QStringList(); + + // Open the file. + QFile file(filename); + + if (file.open(QIODevice::ReadOnly) == false) { + qDebug() << "Can't open:" << filename; + return false; + } + + // Read the file line-by-line and build up the string list. + while (file.atEnd() == false) { + + QString line = file.readLine(); + line.chop(1); + lines.append(line); + } + + file.close(); + + // All good. + return true; + } + + QString unescape (const QString& str) { + + QString result; + bool quoted = false; + + // Maybe reserve `str.length()` bytes in result, so that it will not allocate during `push_back()` + result.reserve(str.length()); + + // Loop through each character in 'str'. Look for a '\'. + for (int i=0; i= str.length()) { + // Nope, just add it. + result.push_back(str[i]); + break; + } + + // If the following character is another '\', skip the first one. + // This removes one level of '\'. + if (str[i+1] == QChar('\\')) { + continue; + } + + // Treat the following character as an escaped character. + // Unescape it. (Is that even a word?) + switch(str[i+1].unicode()) { + // We don't want to unescape things that are in double quotes. + // So keep track of that. (Not the more fool proof implementation). + case QChar('\"').unicode(): + result.push_back(QChar('\"')); + if (quoted) { + quoted = false; + }else{ + quoted = true; + } + break; + case QChar('n').unicode(): + if (quoted == false) { + result.push_back(QChar('\n')); + }else{ + result.push_back(QChar('\\')); + result.push_back(str[i+1]); + } + break; + case QChar('\'').unicode(): + if (quoted == false) { + result.push_back(QChar('\'')); + }else{ + result.push_back(QChar('\\')); + result.push_back(str[i+1]); + } + break; + case QChar('\\').unicode(): + if (quoted == false) { + result.push_back(QChar('\\')); + }else{ + result.push_back(QChar('\\')); + result.push_back(str[i+1]); + } + break; + case QChar('t').unicode(): + if (quoted == false) { + result.push_back(QChar('\t')); + }else{ + result.push_back(QChar('\\')); + result.push_back(str[i+1]); + } + break; + // and so on for \a, \b, \e, \f, \r, \t, \v + // maybe handle octal, hexadecimal ASCII and Unicode forms, but probably in the more distant future + // ... + default: + // unknown escape sequence — do not escape it — I think it is reasonable default + result.push_back(QChar('\\')); + result.push_back(str[i+1]); + break; + } + i++; + + // Normal character. Just add it. + }else{ + result.push_back(str[i]); + } + } + + return result; + } + + void printStackTrace () { + // Capture and print the stack trace using Boost.Stacktrace. + // See comments at top. + // std::cout << "Stack trace:\n" << boost::stacktrace::stacktrace() << std::endl; + } + + // Check if directory and file exist, otherwise, raise a notification + bool isFileExistNotify (const QString& filename) { + if (QFile::exists(filename)) { + return true; + } else { + QMessageBox::warning(nullptr, "Seer", QString("File %1 doesn't exist.").arg(filename), QMessageBox::Ok); + return false; + } + } + + bool isDirExistNotify (const QString& dirname) { + if (QDir(dirname).exists()) { + return true; + } else { + QMessageBox::warning(nullptr, "Seer", QString("Directory %1 doesn't exist.").arg(dirname), QMessageBox::Ok); + return false; + } + } + + void colorizeAllIcons (QWidget* parent, const QSize& size) { + + if (parent == nullptr) { + return; + } + + // Get the current color scheme + Qt::ColorScheme colorScheme = QGuiApplication::styleHints()->colorScheme(); + + // Look for all button types. + const auto buttons = parent->findChildren(); + + for (QAbstractButton* button : buttons) { + + if (colorScheme == Qt::ColorScheme::Dark) { + button->setIcon(Seer::colorizeIcon(button->icon(), QColor("white"), size)); + }else{ + button->setIcon(Seer::colorizeIcon(button->icon(), QColor("black"), size)); + } + } + + // Look for all menu types. + const auto menus = parent->findChildren(); + + for (QMenu* menu : menus) { + + if (colorScheme == Qt::ColorScheme::Dark) { + menu->setIcon(Seer::colorizeIcon(menu->icon(), QColor("white"), size)); + }else{ + menu->setIcon(Seer::colorizeIcon(menu->icon(), QColor("black"), size)); + } + } + + // Look for all action types. + const auto actions = parent->findChildren(); + + for (QAction* action : actions) { + + if (colorScheme == Qt::ColorScheme::Dark) { + action->setIcon(Seer::colorizeIcon(action->icon(), QColor("white"), size)); + }else{ + action->setIcon(Seer::colorizeIcon(action->icon(), QColor("black"), size)); + } + } + + // Look for the app's titlebar icon. + // XXX Doesn't work! + // XXX Titlebar icon remains the same. It doesn't change. Don't know why. + if (colorScheme == Qt::ColorScheme::Dark) { + QApplication::setWindowIcon(Seer::colorizeIcon(QIcon(":/seer/resources/icons/hicolor/64x64/seergdb.png"), QColor("white"), size)); + }else{ + QApplication::setWindowIcon(Seer::colorizeIcon(QIcon(":/seer/resources/icons/hicolor/64x64/seergdb.png"), QColor("black"), size)); + } + } + + void colorizeListWidgetItemIcon (QListWidgetItem* item, const QSize& size) { + + if (item == nullptr) { + return; + } + + // Get the current color scheme + Qt::ColorScheme colorScheme = QGuiApplication::styleHints()->colorScheme(); + + if (colorScheme == Qt::ColorScheme::Dark) { + item->setIcon(Seer::colorizeIcon(item->icon(), QColor("white"), size)); + }else{ + item->setIcon(Seer::colorizeIcon(item->icon(), QColor("black"), size)); + } + } + + void colorizeChartViewItem (QChartView* item) { + + if (item == nullptr) { + return; + } + + QChart* chart = item->chart(); + + if (chart == nullptr) { + return; + } + + // Get the current color scheme + Qt::ColorScheme colorScheme = QGuiApplication::styleHints()->colorScheme(); + + if (colorScheme == Qt::ColorScheme::Dark) { + chart->setTheme(QChart::ChartThemeDark); + }else{ + chart->setTheme(QChart::ChartThemeLight); + } + } + + QIcon colorizeIcon (const QIcon& icon, const QSize& size) { + + // Get the current color scheme + Qt::ColorScheme colorScheme = QGuiApplication::styleHints()->colorScheme(); + + if (colorScheme == Qt::ColorScheme::Dark) { + return Seer::colorizeIcon(icon, QColor("white"), size); + }else{ + return Seer::colorizeIcon(icon, QColor("black"), size); + } + } + + QIcon colorizeIcon (const QIcon& icon, const QColor& color, const QSize& size) { + + // Get the pixmap from the icon + QPixmap pixmap = icon.pixmap(size); + + // Create a new pixmap with the same size and format (preserves alpha) + QPixmap whitePixmap(pixmap.size()); + whitePixmap.fill(Qt::transparent); + + QPainter painter(&whitePixmap); + + // Draw the original pixmap + painter.drawPixmap(0, 0, pixmap); + + // Use CompositionMode_SourceIn to colorize while keeping alpha + painter.setCompositionMode(QPainter::CompositionMode_SourceIn); + painter.fillRect(whitePixmap.rect(), color); + + painter.end(); + + return QIcon(whitePixmap); + } +} + diff --git a/src/SeerVarVisualizerWidget.cpp b/src/SeerVarVisualizerWidget.cpp index afb48d6..e9278b0 100644 --- a/src/SeerVarVisualizerWidget.cpp +++ b/src/SeerVarVisualizerWidget.cpp @@ -11,8 +11,10 @@ #include #include #include +#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) #include #include +#endif #include #include #include @@ -83,7 +85,9 @@ SeerVarVisualizerWidget::SeerVarVisualizerWidget (QWidget* parent) : QWidget(par QObject::connect(collapseSelectedToolButton, &QToolButton::clicked, this, &SeerVarVisualizerWidget::handleCollapseSelected); QObject::connect(editDelegate, &QAllowEditDelegate::editingStarted, this, &SeerVarVisualizerWidget::handleIndexEditingStarted); QObject::connect(editDelegate, &QAllowEditDelegate::editingFinished, this, &SeerVarVisualizerWidget::handleIndexEditingFinished); +#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) QObject::connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, &SeerVarVisualizerWidget::handleThemeChanged); +#endif // Colorize icons for theme. Seer::colorizeAllIcons(this);