Implement config checking (#1859)
* Add error handling functions to ConfigHandler Refurbished functions setValue and value which were previously unused. These functions now set/get a setting with error handling. Currently recognizes only errors recognizable by QSettings. * Make use of value and setValue in ConfigHandler Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Add checker for unrecognized general options Extraneous config options in [General] will be reported as errors. Added some placeholder functions to be implemented in future commits. * Introduce keysFromGroup function Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Check shortcut names for duplicates Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Fix notification spam Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Implement shortcut conflict checking Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Fix reading of fallbacks on error If there is a config error, some values would not be loaded correctly. Using the newly implemented function ConfigHandler::contains instead of QSettings::contains solves this issue. These changes reveal u bug that causes a crash on startup. Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Fix crashes introduced in previous commit Because ConfigHandler is a dependency of most other classes, calling functions from those classes inside ConfigHandler caused infinite recursions in some cases. Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Add config file watcher Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Add missing config options Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Fix bug in shortcut conflict detection Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Add error resolved notification Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Add GUI error message overlay Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Add indicator in config window Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Use ConfigHandler::fileChanged in ConfigWindow Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Fix watcher sometimes not firing Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Improve config file watching performance Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Add new way to handle config This is only a fundamental implementation. Future commits will replace everything with this new paradigm. Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Fix getButtons and related functions Also refactored related code to use QList instead of QVector because QSettings does not work well with QVector. Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Make good use of the new way * Implement proper checking for basic types Everything is covered, apart from KeySequence. * Move fallback path to ExistingDir value handler Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Use consistent naming scheme in ConfigHandler Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Implement config getters/setters via macro Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Surround text with tr and clang-format Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Fix colors being saved obfuscated Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Add ValueHandler::represenation Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Move ValueHandler to separate files Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * confighandler.cpp: rename macro CUSTOM to OPTION Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Fix bug with shortcut conflict checker Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Update docs and fix setAllTheButtons Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Handle filenamePattern properly Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Fix failing build due to wrong function name Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Fix QSet error due to Qt version mismatch Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Replace QSharedPointer::get with data for older Qt versions Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Fix failing build on MacOS and ubuntu 18.04 Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Add column headers to recognizedGeneralOptions map Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Fix ubuntu 18.04 error Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Fix false positive when shortcuts empty Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Fix wrong shortcut group prefix Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Implement proper shortcut checking Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Add shortcut map in ConfigHandler Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Move ConfigShortcuts functions to ShortcutsWidget Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Fix minor bugs Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Add fallback scheme: Pictures, HOME, TMP Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Add config --check CLI option Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Add config error log to GUI Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Rename ValueHandler::description to expected * Convert Qt's #AARRGGBB to #RRGGBBAA and vice versa Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Remove obsolete `saveAfterCopyPath` Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Fix errors in example config Also added an additional ; in front of actual comments to differentiate them from commented options. Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Allow special value 'picker' in userColors Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Allow only name, #RRGGBB, and #RRGGBBAA color formats Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com>
This commit is contained in:
@@ -11,10 +11,17 @@
|
||||
#include "src/utils/confighandler.h"
|
||||
#include "src/utils/globalvalues.h"
|
||||
#include "src/utils/pathinfo.h"
|
||||
#include <QApplication>
|
||||
#include <QDialog>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QFileSystemWatcher>
|
||||
#include <QIcon>
|
||||
#include <QKeyEvent>
|
||||
#include <QLabel>
|
||||
#include <QSizePolicy>
|
||||
#include <QTabBar>
|
||||
#include <QTextEdit>
|
||||
#include <QTextStream>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
// ConfigWindow contains the menus where you can configure the application
|
||||
@@ -24,25 +31,18 @@ ConfigWindow::ConfigWindow(QWidget* parent)
|
||||
{
|
||||
// We wrap QTabWidget in a QWidget because of a Qt bug
|
||||
auto layout = new QVBoxLayout(this);
|
||||
m_tabs = new QTabWidget(this);
|
||||
m_tabs->tabBar()->setUsesScrollButtons(false);
|
||||
layout->addWidget(m_tabs);
|
||||
m_tabWidget = new QTabWidget(this);
|
||||
m_tabWidget->tabBar()->setUsesScrollButtons(false);
|
||||
layout->addWidget(m_tabWidget);
|
||||
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
setWindowIcon(QIcon(":img/app/flameshot.svg"));
|
||||
setWindowTitle(tr("Configuration"));
|
||||
|
||||
auto changedSlot = [this](QString s) {
|
||||
QStringList files = m_configWatcher->files();
|
||||
if (!files.contains(s)) {
|
||||
this->m_configWatcher->addPath(s);
|
||||
}
|
||||
emit updateChildren();
|
||||
};
|
||||
m_configWatcher = new QFileSystemWatcher(this);
|
||||
m_configWatcher->addPath(ConfigHandler().configFilePath());
|
||||
connect(
|
||||
m_configWatcher, &QFileSystemWatcher::fileChanged, this, changedSlot);
|
||||
connect(ConfigHandler::getInstance(),
|
||||
&ConfigHandler::fileChanged,
|
||||
this,
|
||||
&ConfigWindow::updateChildren);
|
||||
|
||||
QColor background = this->palette().window().color();
|
||||
bool isDark = ColorUtils::colorIsDark(background);
|
||||
@@ -51,24 +51,40 @@ ConfigWindow::ConfigWindow(QWidget* parent)
|
||||
|
||||
// visuals
|
||||
m_visuals = new VisualsEditor();
|
||||
m_tabs->addTab(
|
||||
m_visuals, QIcon(modifier + "graphics.svg"), tr("Interface"));
|
||||
m_visualsTab = new QWidget();
|
||||
QVBoxLayout* visualsLayout = new QVBoxLayout(m_visualsTab);
|
||||
m_visualsTab->setLayout(visualsLayout);
|
||||
visualsLayout->addWidget(m_visuals);
|
||||
m_tabWidget->addTab(
|
||||
m_visualsTab, QIcon(modifier + "graphics.svg"), tr("Interface"));
|
||||
|
||||
// filename
|
||||
m_filenameEditor = new FileNameEditor();
|
||||
m_tabs->addTab(m_filenameEditor,
|
||||
QIcon(modifier + "name_edition.svg"),
|
||||
tr("Filename Editor"));
|
||||
m_filenameEditorTab = new QWidget();
|
||||
QVBoxLayout* filenameEditorLayout = new QVBoxLayout(m_filenameEditorTab);
|
||||
m_filenameEditorTab->setLayout(filenameEditorLayout);
|
||||
filenameEditorLayout->addWidget(m_filenameEditor);
|
||||
m_tabWidget->addTab(m_filenameEditorTab,
|
||||
QIcon(modifier + "name_edition.svg"),
|
||||
tr("Filename Editor"));
|
||||
|
||||
// general
|
||||
m_generalConfig = new GeneralConf();
|
||||
m_tabs->addTab(
|
||||
m_generalConfig, QIcon(modifier + "config.svg"), tr("General"));
|
||||
m_generalConfigTab = new QWidget();
|
||||
QVBoxLayout* generalConfigLayout = new QVBoxLayout(m_generalConfigTab);
|
||||
m_generalConfigTab->setLayout(generalConfigLayout);
|
||||
generalConfigLayout->addWidget(m_generalConfig);
|
||||
m_tabWidget->addTab(
|
||||
m_generalConfigTab, QIcon(modifier + "config.svg"), tr("General"));
|
||||
|
||||
// shortcuts
|
||||
m_shortcuts = new ShortcutsWidget();
|
||||
m_tabs->addTab(
|
||||
m_shortcuts, QIcon(modifier + "shortcut.svg"), tr("Shortcuts"));
|
||||
m_shortcutsTab = new QWidget();
|
||||
QVBoxLayout* shortcutsLayout = new QVBoxLayout(m_shortcutsTab);
|
||||
m_shortcutsTab->setLayout(shortcutsLayout);
|
||||
shortcutsLayout->addWidget(m_shortcuts);
|
||||
m_tabWidget->addTab(
|
||||
m_shortcutsTab, QIcon(modifier + "shortcut.svg"), tr("Shortcuts"));
|
||||
|
||||
// connect update sigslots
|
||||
connect(this,
|
||||
@@ -83,6 +99,12 @@ ConfigWindow::ConfigWindow(QWidget* parent)
|
||||
&ConfigWindow::updateChildren,
|
||||
m_generalConfig,
|
||||
&GeneralConf::updateComponents);
|
||||
|
||||
// Error indicator (this must come last)
|
||||
initErrorIndicator(m_visualsTab, m_visuals);
|
||||
initErrorIndicator(m_filenameEditorTab, m_filenameEditor);
|
||||
initErrorIndicator(m_generalConfigTab, m_generalConfig);
|
||||
initErrorIndicator(m_shortcutsTab, m_shortcuts);
|
||||
}
|
||||
|
||||
void ConfigWindow::keyPressEvent(QKeyEvent* e)
|
||||
@@ -91,3 +113,84 @@ void ConfigWindow::keyPressEvent(QKeyEvent* e)
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigWindow::initErrorIndicator(QWidget* tab, QWidget* widget)
|
||||
{
|
||||
QLabel* label = new QLabel(tab);
|
||||
QPushButton* btnShowErrors = new QPushButton("Show errors", tab);
|
||||
QHBoxLayout* btnLayout = new QHBoxLayout(tab);
|
||||
|
||||
// Set up label
|
||||
label->setText(tr(
|
||||
"<b>Configuration file has errors. Resolve them before continuing.</b>"));
|
||||
label->setStyleSheet(QStringLiteral(":disabled { color: %1; }")
|
||||
.arg(qApp->palette().color(QPalette::Text).name()));
|
||||
label->setVisible(ConfigHandler().hasError());
|
||||
|
||||
// Set up "Show errors" button
|
||||
btnShowErrors->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
|
||||
btnLayout->addWidget(btnShowErrors);
|
||||
btnShowErrors->setVisible(ConfigHandler().hasError());
|
||||
|
||||
widget->setEnabled(!ConfigHandler().hasError());
|
||||
|
||||
// Add label and button to the parent widget's layout
|
||||
QBoxLayout* layout = static_cast<QBoxLayout*>(tab->layout());
|
||||
if (layout != nullptr) {
|
||||
layout->insertWidget(0, label);
|
||||
layout->insertLayout(1, btnLayout);
|
||||
} else {
|
||||
widget->layout()->addWidget(label);
|
||||
widget->layout()->addWidget(btnShowErrors);
|
||||
}
|
||||
|
||||
// Sigslots
|
||||
connect(ConfigHandler::getInstance(), &ConfigHandler::error, widget, [=]() {
|
||||
widget->setEnabled(false);
|
||||
label->show();
|
||||
btnShowErrors->show();
|
||||
});
|
||||
connect(ConfigHandler::getInstance(),
|
||||
&ConfigHandler::errorResolved,
|
||||
widget,
|
||||
[=]() {
|
||||
widget->setEnabled(true);
|
||||
label->hide();
|
||||
btnShowErrors->hide();
|
||||
});
|
||||
connect(btnShowErrors, &QPushButton::clicked, this, [this]() {
|
||||
// Generate error log message
|
||||
QString str;
|
||||
QTextStream stream(&str);
|
||||
ConfigHandler().checkForErrors(&stream);
|
||||
|
||||
// Set up dialog
|
||||
QDialog dialog;
|
||||
dialog.setWindowTitle(QStringLiteral("Configuration errors"));
|
||||
dialog.setLayout(new QVBoxLayout(&dialog));
|
||||
|
||||
// Add text display
|
||||
QTextEdit* textDisplay = new QTextEdit(&dialog);
|
||||
textDisplay->setPlainText(str);
|
||||
textDisplay->setReadOnly(true);
|
||||
dialog.layout()->addWidget(textDisplay);
|
||||
|
||||
// Add Ok button
|
||||
using BBox = QDialogButtonBox;
|
||||
BBox* buttons = new BBox(BBox::Ok);
|
||||
dialog.layout()->addWidget(buttons);
|
||||
connect(buttons, &QDialogButtonBox::clicked, this, [&dialog]() {
|
||||
dialog.close();
|
||||
});
|
||||
|
||||
dialog.show();
|
||||
|
||||
qApp->processEvents();
|
||||
QPoint center = dialog.geometry().center();
|
||||
QRect dialogRect(0, 0, 400, 400);
|
||||
dialogRect.moveCenter(center);
|
||||
dialog.setGeometry(dialogRect);
|
||||
|
||||
dialog.exec();
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user