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:
Haris Gušić
2021-09-15 18:56:01 +02:00
committed by GitHub
parent a7e88e60de
commit d1428889b9
35 changed files with 1665 additions and 859 deletions

View File

@@ -1,73 +1,73 @@
[General] ;[General]
; Configure which buttons to show after drawing a selection ;; Configure which buttons to show after drawing a selection
; Not easy to set by hand ;; Not easy to set by hand
;buttons=@Variant(\0\0\0\x7f\0\0\0\vQList<int>\0\0\0\0\x14\0\0\0\0\0\0\0\x1\0\0\0\x2\0\0\0\x3\0\0\0\x4\0\0\0\x5\0\0\0\x6\0\0\0\x12\0\0\0\xf\0\0\0\x13\0\0\0\a\0\0\0\b\0\0\0\t\0\0\0\x10\0\0\0\n\0\0\0\v\0\0\0\f\0\0\0\r\0\0\0\xe\0\0\0\x11) ;buttons=@Variant(\0\0\0\x7f\0\0\0\vQList<int>\0\0\0\0\x14\0\0\0\0\0\0\0\x1\0\0\0\x2\0\0\0\x3\0\0\0\x4\0\0\0\x5\0\0\0\x6\0\0\0\x12\0\0\0\xf\0\0\0\x13\0\0\0\a\0\0\0\b\0\0\0\t\0\0\0\x10\0\0\0\n\0\0\0\v\0\0\0\f\0\0\0\r\0\0\0\xe\0\0\0\x11)
;
; List of colors for color picker ;; List of colors for color picker
; The colors are arranged counter-clockwise with the first being set to the right of the cursor ;; The colors are arranged counter-clockwise with the first being set to the right of the cursor
; Colors are any valid hex code or W3C color name ;; Colors are any valid hex code or W3C color name
; "picker" adds a custom color picker ;; "picker" adds a custom color picker
;userColors=#800000, #ff0000, #ffff00, #00ff00, #008000, #00ffff, #0000ff, #ff00ff, #800080, picker ;userColors=#800000, #ff0000, #ffff00, #00ff00, #008000, #00ffff, #0000ff, #ff00ff, #800080, picker
;
; Image Save Path ;; Image Save Path
;savePath= ;savePath=/tmp
;
; Whether the savePath is a fixed path (bool) ;; Whether the savePath is a fixed path (bool)
;savePathFixed=false ;savePathFixed=false
;
; Main UI color ;; Main UI color
; Color is any valid hex code or W3C color name ;; Color is any valid hex code or W3C color name
;uiColor=#740096 ;uiColor=#740096
;
; Contrast UI color ;; Contrast UI color
; Color is any valid hex code or W3C color name ;; Color is any valid hex code or W3C color name
;contrastUiColor=#270032 ;contrastUiColor=#270032
;
; Last used color ;; Last used color
; Color is any valid hex code or W3C color name ;; Color is any valid hex code or W3C color name
;drawColor= ;drawColor=#ff0000
;
; Show the help screen on startup (bool) ;; Show the help screen on startup (bool)
;showHelp=true ;showHelp=true
;
; Show the side panel button (bool) ;; Show the side panel button (bool)
;showSidePanelButton=true ;showSidePanelButton=true
;
; Ignore updates to versions less than this value ;; Ignore updates to versions less than this value
;ignoreUpdateToVersion= ;ignoreUpdateToVersion=
;
; Show desktop notifications (bool) ;; Show desktop notifications (bool)
;showDesktopNotification=true ;showDesktopNotification=true
;
; Filename pattern using C++ strftime formatting ;; Filename pattern using C++ strftime formatting
;filenamePattern=%F_%H-%M ;filenamePattern=%F_%H-%M
;
; Whether the tray icon is disabled (bool) ;; Whether the tray icon is disabled (bool)
;disabledTrayIcon=false ;disabledTrayIcon=false
;
; Last used tool thickness (int) ;; Last used tool thickness (int)
;drawThickness=0 ;drawThickness=1
;
; Keep the App Launcher open after selecting an app (bool) ;; Keep the App Launcher open after selecting an app (bool)
;keepOpenAppLauncher=false ;keepOpenAppLauncher=false
;
; Launch at startup (bool) ;; Launch at startup (bool)
;startupLaunch= ;startupLaunch=true
;
; Opacity of area outside selection (int in range 0-255) ;; Opacity of area outside selection (int in range 0-255)
;contrastOpacity=190 ;contrastOpacity=190
;
; Save image after copy (bool) ;; Save image after copy (bool)
;saveAfterCopy=false ;saveAfterCopy=false
;
; Copy path to image after save (bool) ;; Copy path to image after save (bool)
;copyPathAfterSave=false ;copyPathAfterSave=false
;
; Use JPG format instead of PNG (bool) ;; Use JPG format instead of PNG (bool)
;useJpgForClipboard=false ;useJpgForClipboard=false
;
; Shortcut Settings for all tools ;; Shortcut Settings for all tools
[Shortcuts] ;[Shortcuts]
;TYPE_ARROW=A ;TYPE_ARROW=A
;TYPE_CIRCLE=C ;TYPE_CIRCLE=C
;TYPE_CIRCLECOUNT= ;TYPE_CIRCLECOUNT=

View File

@@ -59,7 +59,7 @@ void ButtonListView::updateActiveButtons(QListWidgetItem* item)
CaptureToolButton::getPriorityByButton(b); CaptureToolButton::getPriorityByButton(b);
}); });
} else { } else {
m_listButtons.remove(m_listButtons.indexOf(bType)); m_listButtons.removeOne(bType);
} }
ConfigHandler().setButtons(m_listButtons); ConfigHandler().setButtons(m_listButtons);
} }
@@ -85,7 +85,7 @@ void ButtonListView::selectAll()
void ButtonListView::updateComponents() void ButtonListView::updateComponents()
{ {
m_listButtons = ConfigHandler().getButtons(); m_listButtons = ConfigHandler().buttons();
auto listTypes = CaptureToolButton::getIterableButtonTypes(); auto listTypes = CaptureToolButton::getIterableButtonTypes();
for (int i = 0; i < this->count(); ++i) { for (int i = 0; i < this->count(); ++i) {
QListWidgetItem* item = this->item(i); QListWidgetItem* item = this->item(i);

View File

@@ -22,7 +22,7 @@ protected:
void initButtonList(); void initButtonList();
private: private:
QVector<CaptureToolButton::ButtonType> m_listButtons; QList<CaptureToolButton::ButtonType> m_listButtons;
QMap<QString, CaptureToolButton::ButtonType> m_buttonTypeByName; QMap<QString, CaptureToolButton::ButtonType> m_buttonTypeByName;
void updateActiveButtons(QListWidgetItem*); void updateActiveButtons(QListWidgetItem*);

View File

@@ -11,10 +11,17 @@
#include "src/utils/confighandler.h" #include "src/utils/confighandler.h"
#include "src/utils/globalvalues.h" #include "src/utils/globalvalues.h"
#include "src/utils/pathinfo.h" #include "src/utils/pathinfo.h"
#include <QApplication>
#include <QDialog>
#include <QDialogButtonBox>
#include <QFileSystemWatcher> #include <QFileSystemWatcher>
#include <QIcon> #include <QIcon>
#include <QKeyEvent> #include <QKeyEvent>
#include <QLabel>
#include <QSizePolicy>
#include <QTabBar> #include <QTabBar>
#include <QTextEdit>
#include <QTextStream>
#include <QVBoxLayout> #include <QVBoxLayout>
// ConfigWindow contains the menus where you can configure the application // 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 // We wrap QTabWidget in a QWidget because of a Qt bug
auto layout = new QVBoxLayout(this); auto layout = new QVBoxLayout(this);
m_tabs = new QTabWidget(this); m_tabWidget = new QTabWidget(this);
m_tabs->tabBar()->setUsesScrollButtons(false); m_tabWidget->tabBar()->setUsesScrollButtons(false);
layout->addWidget(m_tabs); layout->addWidget(m_tabWidget);
setAttribute(Qt::WA_DeleteOnClose); setAttribute(Qt::WA_DeleteOnClose);
setWindowIcon(QIcon(":img/app/flameshot.svg")); setWindowIcon(QIcon(":img/app/flameshot.svg"));
setWindowTitle(tr("Configuration")); setWindowTitle(tr("Configuration"));
auto changedSlot = [this](QString s) { connect(ConfigHandler::getInstance(),
QStringList files = m_configWatcher->files(); &ConfigHandler::fileChanged,
if (!files.contains(s)) { this,
this->m_configWatcher->addPath(s); &ConfigWindow::updateChildren);
}
emit updateChildren();
};
m_configWatcher = new QFileSystemWatcher(this);
m_configWatcher->addPath(ConfigHandler().configFilePath());
connect(
m_configWatcher, &QFileSystemWatcher::fileChanged, this, changedSlot);
QColor background = this->palette().window().color(); QColor background = this->palette().window().color();
bool isDark = ColorUtils::colorIsDark(background); bool isDark = ColorUtils::colorIsDark(background);
@@ -51,24 +51,40 @@ ConfigWindow::ConfigWindow(QWidget* parent)
// visuals // visuals
m_visuals = new VisualsEditor(); m_visuals = new VisualsEditor();
m_tabs->addTab( m_visualsTab = new QWidget();
m_visuals, QIcon(modifier + "graphics.svg"), tr("Interface")); 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 // filename
m_filenameEditor = new FileNameEditor(); m_filenameEditor = new FileNameEditor();
m_tabs->addTab(m_filenameEditor, m_filenameEditorTab = new QWidget();
QIcon(modifier + "name_edition.svg"), QVBoxLayout* filenameEditorLayout = new QVBoxLayout(m_filenameEditorTab);
tr("Filename Editor")); m_filenameEditorTab->setLayout(filenameEditorLayout);
filenameEditorLayout->addWidget(m_filenameEditor);
m_tabWidget->addTab(m_filenameEditorTab,
QIcon(modifier + "name_edition.svg"),
tr("Filename Editor"));
// general // general
m_generalConfig = new GeneralConf(); m_generalConfig = new GeneralConf();
m_tabs->addTab( m_generalConfigTab = new QWidget();
m_generalConfig, QIcon(modifier + "config.svg"), tr("General")); 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 // shortcuts
m_shortcuts = new ShortcutsWidget(); m_shortcuts = new ShortcutsWidget();
m_tabs->addTab( m_shortcutsTab = new QWidget();
m_shortcuts, QIcon(modifier + "shortcut.svg"), tr("Shortcuts")); 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 update sigslots
connect(this, connect(this,
@@ -83,6 +99,12 @@ ConfigWindow::ConfigWindow(QWidget* parent)
&ConfigWindow::updateChildren, &ConfigWindow::updateChildren,
m_generalConfig, m_generalConfig,
&GeneralConf::updateComponents); &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) void ConfigWindow::keyPressEvent(QKeyEvent* e)
@@ -91,3 +113,84 @@ void ConfigWindow::keyPressEvent(QKeyEvent* e)
close(); 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();
});
}

View File

@@ -10,6 +10,7 @@ class ShortcutsWidget;
class GeneralConf; class GeneralConf;
class QFileSystemWatcher; class QFileSystemWatcher;
class VisualsEditor; class VisualsEditor;
class QWidget;
class ConfigWindow : public QWidget class ConfigWindow : public QWidget
{ {
@@ -24,10 +25,19 @@ protected:
void keyPressEvent(QKeyEvent*); void keyPressEvent(QKeyEvent*);
private: private:
QTabWidget* m_tabs; QTabWidget* m_tabWidget;
FileNameEditor* m_filenameEditor; FileNameEditor* m_filenameEditor;
QWidget* m_filenameEditorTab;
ShortcutsWidget* m_shortcuts; ShortcutsWidget* m_shortcuts;
QWidget* m_shortcutsTab;
GeneralConf* m_generalConfig; GeneralConf* m_generalConfig;
QWidget* m_generalConfigTab;
VisualsEditor* m_visuals; VisualsEditor* m_visuals;
QFileSystemWatcher* m_configWatcher; QWidget* m_visualsTab;
void initErrorIndicator(QWidget* tab, QWidget* widget);
}; };

View File

@@ -103,7 +103,7 @@ void FileNameEditor::showParsedPattern(const QString& p)
void FileNameEditor::resetName() void FileNameEditor::resetName()
{ {
m_nameEditor->setText(ConfigHandler().filenamePatternValue()); m_nameEditor->setText(ConfigHandler().filenamePattern());
} }
void FileNameEditor::addToNameEditor(QString s) void FileNameEditor::addToNameEditor(QString s)
@@ -114,6 +114,6 @@ void FileNameEditor::addToNameEditor(QString s)
void FileNameEditor::updateComponents() void FileNameEditor::updateComponents()
{ {
m_nameEditor->setText(ConfigHandler().filenamePatternValue()); m_nameEditor->setText(ConfigHandler().filenamePattern());
m_outputLabel->setText(m_nameHandler->parsedPattern()); m_outputLabel->setText(m_nameHandler->parsedPattern());
} }

View File

@@ -42,7 +42,7 @@ GeneralConf::GeneralConf(QWidget* parent)
initCopyPathAfterSave(); initCopyPathAfterSave();
initUseJpgForClipboard(); initUseJpgForClipboard();
initSaveAfterCopy(); initSaveAfterCopy();
initUploadHistoryMaxSize(); inituploadHistoryMax();
initUndoLimit(); initUndoLimit();
m_layout->addStretch(); m_layout->addStretch();
@@ -55,31 +55,27 @@ GeneralConf::GeneralConf(QWidget* parent)
void GeneralConf::_updateComponents(bool allowEmptySavePath) void GeneralConf::_updateComponents(bool allowEmptySavePath)
{ {
ConfigHandler config; ConfigHandler config;
m_helpMessage->setChecked(config.showHelpValue()); m_helpMessage->setChecked(config.showHelp());
m_sidePanelButton->setChecked(config.showSidePanelButtonValue()); m_sidePanelButton->setChecked(config.showSidePanelButton());
m_sysNotifications->setChecked(config.desktopNotificationValue()); m_sysNotifications->setChecked(config.showDesktopNotification());
m_autostart->setChecked(config.startupLaunchValue()); m_autostart->setChecked(config.startupLaunch());
m_copyAndCloseAfterUpload->setChecked( m_copyAndCloseAfterUpload->setChecked(config.copyAndCloseAfterUpload());
config.copyAndCloseAfterUploadEnabled()); m_saveAfterCopy->setChecked(config.saveAfterCopy());
m_saveAfterCopy->setChecked(config.saveAfterCopyValue()); m_copyPathAfterSave->setChecked(config.copyPathAfterSave());
m_copyPathAfterSave->setChecked(config.copyPathAfterSaveEnabled());
m_useJpgForClipboard->setChecked(config.useJpgForClipboard()); m_useJpgForClipboard->setChecked(config.useJpgForClipboard());
m_historyConfirmationToDelete->setChecked( m_historyConfirmationToDelete->setChecked(
config.historyConfirmationToDelete()); config.historyConfirmationToDelete());
m_checkForUpdates->setChecked(config.checkForUpdates()); m_checkForUpdates->setChecked(config.checkForUpdates());
m_showStartupLaunchMessage->setChecked(config.showStartupLaunchMessage()); m_showStartupLaunchMessage->setChecked(config.showStartupLaunchMessage());
m_screenshotPathFixedCheck->setChecked(config.savePathFixed()); m_screenshotPathFixedCheck->setChecked(config.savePathFixed());
m_uploadHistoryMaxSize->setValue(config.uploadHistoryMaxSizeValue()); m_uploadHistoryMax->setValue(config.uploadHistoryMax());
m_undoLimit->setValue(config.undoLimit()); m_undoLimit->setValue(config.undoLimit());
if (allowEmptySavePath || !config.savePath().isEmpty()) { if (allowEmptySavePath || !config.savePath().isEmpty()) {
m_savePath->setText(config.savePath()); m_savePath->setText(config.savePath());
} else {
ConfigHandler().setSavePath(
QStandardPaths::writableLocation(QStandardPaths::PicturesLocation));
} }
#if defined(Q_OS_LINUX) || defined(Q_OS_UNIX) #if defined(Q_OS_LINUX) || defined(Q_OS_UNIX)
m_showTray->setChecked(!config.disabledTrayIconValue()); m_showTray->setChecked(!config.disabledTrayIcon());
#endif #endif
} }
@@ -100,7 +96,7 @@ void GeneralConf::showSidePanelButtonChanged(bool checked)
void GeneralConf::showDesktopNotificationChanged(bool checked) void GeneralConf::showDesktopNotificationChanged(bool checked)
{ {
ConfigHandler().setDesktopNotification(checked); ConfigHandler().setShowDesktopNotification(checked);
} }
void GeneralConf::showTrayIconChanged(bool checked) void GeneralConf::showTrayIconChanged(bool checked)
@@ -344,7 +340,7 @@ void GeneralConf::initCopyAndCloseAfterUpload()
m_scrollAreaLayout->addWidget(m_copyAndCloseAfterUpload); m_scrollAreaLayout->addWidget(m_copyAndCloseAfterUpload);
connect(m_copyAndCloseAfterUpload, &QCheckBox::clicked, [](bool checked) { connect(m_copyAndCloseAfterUpload, &QCheckBox::clicked, [](bool checked) {
ConfigHandler().setCopyAndCloseAfterUploadEnabled(checked); ConfigHandler().setCopyAndCloseAfterUpload(checked);
}); });
} }
@@ -368,10 +364,6 @@ void GeneralConf::initSaveAfterCopy()
QHBoxLayout* pathLayout = new QHBoxLayout(); QHBoxLayout* pathLayout = new QHBoxLayout();
QString path = ConfigHandler().savePath(); QString path = ConfigHandler().savePath();
if (path.isEmpty()) {
path =
QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
}
m_savePath = new QLineEdit(path, this); m_savePath = new QLineEdit(path, this);
m_savePath->setDisabled(true); m_savePath->setDisabled(true);
QString foreground = this->palette().windowText().color().name(); QString foreground = this->palette().windowText().color().name();
@@ -401,7 +393,7 @@ void GeneralConf::historyConfirmationToDelete(bool checked)
ConfigHandler().setHistoryConfirmationToDelete(checked); ConfigHandler().setHistoryConfirmationToDelete(checked);
} }
void GeneralConf::initUploadHistoryMaxSize() void GeneralConf::inituploadHistoryMax()
{ {
QGroupBox* box = new QGroupBox(tr("Latest Uploads Max Size")); QGroupBox* box = new QGroupBox(tr("Latest Uploads Max Size"));
box->setFlat(true); box->setFlat(true);
@@ -410,22 +402,22 @@ void GeneralConf::initUploadHistoryMaxSize()
QVBoxLayout* vboxLayout = new QVBoxLayout(); QVBoxLayout* vboxLayout = new QVBoxLayout();
box->setLayout(vboxLayout); box->setLayout(vboxLayout);
m_uploadHistoryMaxSize = new QSpinBox(this); m_uploadHistoryMax = new QSpinBox(this);
m_uploadHistoryMaxSize->setMaximum(50); m_uploadHistoryMax->setMaximum(50);
QString foreground = this->palette().windowText().color().name(); QString foreground = this->palette().windowText().color().name();
m_uploadHistoryMaxSize->setStyleSheet( m_uploadHistoryMax->setStyleSheet(
QStringLiteral("color: %1").arg(foreground)); QStringLiteral("color: %1").arg(foreground));
connect(m_uploadHistoryMaxSize, connect(m_uploadHistoryMax,
SIGNAL(valueChanged(int)), SIGNAL(valueChanged(int)),
this, this,
SLOT(uploadHistoryMaxSizeChanged(int))); SLOT(uploadHistoryMaxChanged(int)));
vboxLayout->addWidget(m_uploadHistoryMaxSize); vboxLayout->addWidget(m_uploadHistoryMax);
} }
void GeneralConf::uploadHistoryMaxSizeChanged(int max) void GeneralConf::uploadHistoryMaxChanged(int max)
{ {
ConfigHandler().setUploadHistoryMaxSize(max); ConfigHandler().setUploadHistoryMax(max);
} }
void GeneralConf::initUndoLimit() void GeneralConf::initUndoLimit()
@@ -479,10 +471,6 @@ void GeneralConf::saveAfterCopyChanged(bool checked)
void GeneralConf::changeSavePath() void GeneralConf::changeSavePath()
{ {
QString path = ConfigHandler().savePath(); QString path = ConfigHandler().savePath();
if (path.isEmpty()) {
path =
QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
}
path = chooseFolder(path); path = chooseFolder(path);
if (!path.isEmpty()) { if (!path.isEmpty()) {
m_savePath->setText(path); m_savePath->setText(path);
@@ -496,7 +484,7 @@ void GeneralConf::initCopyPathAfterSave()
m_copyPathAfterSave->setToolTip(tr("Copy file path after save")); m_copyPathAfterSave->setToolTip(tr("Copy file path after save"));
m_scrollAreaLayout->addWidget(m_copyPathAfterSave); m_scrollAreaLayout->addWidget(m_copyPathAfterSave);
connect(m_copyPathAfterSave, &QCheckBox::clicked, [](bool checked) { connect(m_copyPathAfterSave, &QCheckBox::clicked, [](bool checked) {
ConfigHandler().setCopyPathAfterSaveEnabled(checked); ConfigHandler().setCopyPathAfterSave(checked);
}); });
} }

View File

@@ -30,7 +30,7 @@ private slots:
void checkForUpdatesChanged(bool checked); void checkForUpdatesChanged(bool checked);
void autostartChanged(bool checked); void autostartChanged(bool checked);
void historyConfirmationToDelete(bool checked); void historyConfirmationToDelete(bool checked);
void uploadHistoryMaxSizeChanged(int max); void uploadHistoryMaxChanged(int max);
void undoLimit(int limit); void undoLimit(int limit);
void saveAfterCopyChanged(bool checked); void saveAfterCopyChanged(bool checked);
void changeSavePath(); void changeSavePath();
@@ -49,7 +49,7 @@ private:
void initShowDesktopNotification(); void initShowDesktopNotification();
void initShowTrayIcon(); void initShowTrayIcon();
void initHistoryConfirmationToDelete(); void initHistoryConfirmationToDelete();
void initUploadHistoryMaxSize(); void inituploadHistoryMax();
void initUndoLimit(); void initUndoLimit();
void initConfigButtons(); void initConfigButtons();
void initCheckForUpdates(); void initCheckForUpdates();
@@ -84,6 +84,6 @@ private:
QCheckBox* m_screenshotPathFixedCheck; QCheckBox* m_screenshotPathFixedCheck;
QCheckBox* m_historyConfirmationToDelete; QCheckBox* m_historyConfirmationToDelete;
QCheckBox* m_useJpgForClipboard; QCheckBox* m_useJpgForClipboard;
QSpinBox* m_uploadHistoryMaxSize; QSpinBox* m_uploadHistoryMax;
QSpinBox* m_undoLimit; QSpinBox* m_undoLimit;
}; };

View File

@@ -2,9 +2,9 @@
// SPDX-FileCopyrightText: 2020 Yurii Puchkov at Namecheap & Contributors // SPDX-FileCopyrightText: 2020 Yurii Puchkov at Namecheap & Contributors
#include "shortcutswidget.h" #include "shortcutswidget.h"
#include "capturetool.h"
#include "setshortcutwidget.h" #include "setshortcutwidget.h"
#include "src/core/qguiappcurrentscreen.h" #include "src/core/qguiappcurrentscreen.h"
#include "src/utils/configshortcuts.h"
#include <QHeaderView> #include <QHeaderView>
#include <QIcon> #include <QIcon>
#include <QKeyEvent> #include <QKeyEvent>
@@ -37,13 +37,12 @@ ShortcutsWidget::ShortcutsWidget(QWidget* parent)
m_layout = new QVBoxLayout(this); m_layout = new QVBoxLayout(this);
m_layout->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); m_layout->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
m_shortcuts = ConfigShortcuts().captureShortcutsDefault( initShortcuts();
CaptureToolButton::getIterableButtonTypes());
initInfoTable(); initInfoTable();
show(); show();
} }
const QVector<QStringList>& ShortcutsWidget::shortcuts() const QList<QStringList>& ShortcutsWidget::shortcuts()
{ {
return m_shortcuts; return m_shortcuts;
} }
@@ -158,6 +157,71 @@ void ShortcutsWidget::slotShortcutCellClicked(int row, int col)
} }
} }
void ShortcutsWidget::initShortcuts()
{
auto buttons = CaptureToolButton::getIterableButtonTypes();
// get shortcuts names from capture buttons
for (const CaptureToolButton::ButtonType& t : buttons) {
CaptureToolButton* b = new CaptureToolButton(t, nullptr);
QString shortcutName = QVariant::fromValue(t).toString();
if (shortcutName != "TYPE_IMAGEUPLOADER") {
appendShortcut(shortcutName, b->tool()->description());
}
delete b;
}
// additional tools that don't have their own buttons
appendShortcut("TYPE_TOGGLE_PANEL", "Toggle side panel");
appendShortcut("TYPE_RESIZE_LEFT", "Resize selection left 1px");
appendShortcut("TYPE_RESIZE_RIGHT", "Resize selection right 1px");
appendShortcut("TYPE_RESIZE_UP", "Resize selection up 1px");
appendShortcut("TYPE_RESIZE_DOWN", "Resize selection down 1px");
appendShortcut("TYPE_SELECT_ALL", "Select entire screen");
appendShortcut("TYPE_MOVE_LEFT", "Move selection left 1px");
appendShortcut("TYPE_MOVE_RIGHT", "Move selection right 1px");
appendShortcut("TYPE_MOVE_UP", "Move selection up 1px");
appendShortcut("TYPE_MOVE_DOWN", "Move selection down 1px");
appendShortcut("TYPE_COMMIT_CURRENT_TOOL", "Commit text in text area");
appendShortcut("TYPE_DELETE_CURRENT_TOOL", "Delete current tool");
// non-editable shortcuts have an empty shortcut name
m_shortcuts << (QStringList() << "" << QObject::tr("Quit capture")
<< QKeySequence(Qt::Key_Escape).toString());
// Global hotkeys
#if defined(Q_OS_MACOS)
m_shortcuts << (QStringList()
<< "" << QObject::tr("Screenshot history") << "⇧⌘⌥H");
m_shortcuts << (QStringList()
<< "" << QObject::tr("Capture screen") << "⇧⌘⌥4");
#elif defined(Q_OS_WIN)
m_shortcuts << (QStringList() << "" << QObject::tr("Screenshot history")
<< "Shift+Print Screen");
m_shortcuts << (QStringList()
<< "" << QObject::tr("Capture screen") << "Print Screen");
#else
// TODO - Linux doesn't support global shortcuts for (XServer and Wayland),
// possibly it will be solved in the QHotKey library later. So it is
// disabled for now.
#endif
m_shortcuts << (QStringList()
<< "" << QObject::tr("Show color picker") << "Right Click");
m_shortcuts << (QStringList()
<< "" << QObject::tr("Change the tool's thickness")
<< "Mouse Wheel");
}
void ShortcutsWidget::appendShortcut(const QString& shortcutName,
const QString& description)
{
m_shortcuts << (QStringList()
<< shortcutName
<< QObject::tr(description.toStdString().c_str())
<< ConfigHandler().shortcut(shortcutName));
}
#if defined(Q_OS_MACOS) #if defined(Q_OS_MACOS)
const QString& ShortcutsWidget::nativeOSHotKeyText(const QString& text) const QString& ShortcutsWidget::nativeOSHotKeyText(const QString& text)
{ {

View File

@@ -18,7 +18,7 @@ class ShortcutsWidget : public QWidget
Q_OBJECT Q_OBJECT
public: public:
explicit ShortcutsWidget(QWidget* parent = nullptr); explicit ShortcutsWidget(QWidget* parent = nullptr);
const QVector<QStringList>& shortcuts(); const QList<QStringList>& shortcuts();
private: private:
void initInfoTable(); void initInfoTable();
@@ -38,7 +38,11 @@ private:
ConfigHandler m_config; ConfigHandler m_config;
QTableWidget* m_table; QTableWidget* m_table;
QVBoxLayout* m_layout; QVBoxLayout* m_layout;
QVector<QStringList> m_shortcuts; QList<QStringList> m_shortcuts;
void initShortcuts();
void appendShortcut(const QString& shortcutName,
const QString& description);
}; };
#endif // HOTKEYSCONFIG_H #endif // HOTKEYSCONFIG_H

View File

@@ -37,8 +37,8 @@ UIcolorEditor::UIcolorEditor(QWidget* parent)
void UIcolorEditor::updateComponents() void UIcolorEditor::updateComponents()
{ {
ConfigHandler config; ConfigHandler config;
m_uiColor = config.uiMainColorValue(); m_uiColor = config.uiColor();
m_contrastColor = config.uiContrastColorValue(); m_contrastColor = config.contrastUiColor();
m_buttonContrast->setColor(m_contrastColor); m_buttonContrast->setColor(m_contrastColor);
m_buttonMainColor->setColor(m_uiColor); m_buttonMainColor->setColor(m_uiColor);
if (m_lastButtonPressed == m_buttonMainColor) { if (m_lastButtonPressed == m_buttonMainColor) {
@@ -53,9 +53,9 @@ void UIcolorEditor::updateUIcolor()
{ {
ConfigHandler config; ConfigHandler config;
if (m_lastButtonPressed == m_buttonMainColor) { if (m_lastButtonPressed == m_buttonMainColor) {
config.setUIMainColor(m_uiColor); config.setUiColor(m_uiColor);
} else { } else {
config.setUIContrastColor(m_contrastColor); config.setContrastUiColor(m_contrastColor);
} }
} }

View File

@@ -21,7 +21,7 @@ void VisualsEditor::updateComponents()
{ {
m_buttonList->updateComponents(); m_buttonList->updateComponents();
m_colorEditor->updateComponents(); m_colorEditor->updateComponents();
int opacity = ConfigHandler().contrastOpacityValue(); int opacity = ConfigHandler().contrastOpacity();
m_opacitySlider->setMapedValue(0, opacity, 255); m_opacitySlider->setMapedValue(0, opacity, 255);
} }
@@ -50,7 +50,7 @@ void VisualsEditor::initOpacitySlider()
m_layout->addWidget(label); m_layout->addWidget(label);
m_layout->addLayout(localLayout); m_layout->addLayout(localLayout);
int opacity = ConfigHandler().contrastOpacityValue(); int opacity = ConfigHandler().contrastOpacity();
m_opacitySlider->setMapedValue(0, opacity, 255); m_opacitySlider->setMapedValue(0, opacity, 255);
} }

View File

@@ -66,7 +66,7 @@ Controller::Controller()
// init tray icon // init tray icon
#if defined(Q_OS_LINUX) || defined(Q_OS_UNIX) #if defined(Q_OS_LINUX) || defined(Q_OS_UNIX)
if (!ConfigHandler().disabledTrayIconValue()) { if (!ConfigHandler().disabledTrayIcon()) {
enableTrayIcon(); enableTrayIcon();
} }
#elif defined(Q_OS_WIN) #elif defined(Q_OS_WIN)

View File

@@ -165,6 +165,8 @@ int main(int argc, char* argv[])
{ "a", "autostart" }, { "a", "autostart" },
QObject::tr("Enable or disable run at startup"), QObject::tr("Enable or disable run at startup"),
QStringLiteral("bool")); QStringLiteral("bool"));
CommandOption checkOption(
"check", QObject::tr("Check the configuration for errors"));
CommandOption showHelpOption( CommandOption showHelpOption(
{ "s", "showhelp" }, { "s", "showhelp" },
QObject::tr("Show the help message in the capture mode"), QObject::tr("Show the help message in the capture mode"),
@@ -270,7 +272,8 @@ int main(int argc, char* argv[])
trayOption, trayOption,
showHelpOption, showHelpOption,
mainColorOption, mainColorOption,
contrastColorOption }, contrastColorOption,
checkOption },
configArgument); configArgument);
// Parse // Parse
if (!parser.parse(app.arguments())) { if (!parser.parse(app.arguments())) {
@@ -447,8 +450,19 @@ int main(int argc, char* argv[])
bool help = parser.isSet(showHelpOption); bool help = parser.isSet(showHelpOption);
bool mainColor = parser.isSet(mainColorOption); bool mainColor = parser.isSet(mainColorOption);
bool contrastColor = parser.isSet(contrastColorOption); bool contrastColor = parser.isSet(contrastColorOption);
bool check = parser.isSet(checkOption);
bool someFlagSet = bool someFlagSet =
(filename || tray || help || mainColor || contrastColor); (filename || tray || help || mainColor || contrastColor || check);
if (check) {
QTextStream stream(stderr);
bool ok = ConfigHandler(true).checkForErrors(&stream);
if (ok) {
stream << QStringLiteral("No errors detected.\n");
goto finish;
} else {
return 1;
}
}
ConfigHandler config; ConfigHandler config;
if (autostart) { if (autostart) {
QDBusMessage m = QDBusMessage::createMethodCall( QDBusMessage m = QDBusMessage::createMethodCall(
@@ -506,12 +520,12 @@ int main(int argc, char* argv[])
if (mainColor) { if (mainColor) {
QString colorCode = parser.value(mainColorOption); QString colorCode = parser.value(mainColorOption);
QColor parsedColor(colorCode); QColor parsedColor(colorCode);
config.setUIMainColor(parsedColor); config.setUiColor(parsedColor);
} }
if (contrastColor) { if (contrastColor) {
QString colorCode = parser.value(contrastColorOption); QString colorCode = parser.value(contrastColorOption);
QColor parsedColor(colorCode); QColor parsedColor(colorCode);
config.setUIContrastColor(parsedColor); config.setContrastUiColor(parsedColor);
} }
// Open gui when no options // Open gui when no options

View File

@@ -47,7 +47,7 @@ ImgurUploader::ImgurUploader(const QPixmap& capture, QWidget* parent)
#endif #endif
m_spinner = new LoadSpinner(this); m_spinner = new LoadSpinner(this);
m_spinner->setColor(ConfigHandler().uiMainColorValue()); m_spinner->setColor(ConfigHandler().uiColor());
m_spinner->start(); m_spinner->start();
m_infoLabel = new QLabel(tr("Uploading Image")); m_infoLabel = new QLabel(tr("Uploading Image"));
@@ -94,7 +94,7 @@ void ImgurUploader::handleReply(QNetworkReply* reply)
imageName = history.packFileName("imgur", deleteToken, imageName); imageName = history.packFileName("imgur", deleteToken, imageName);
history.save(m_pixmap, imageName); history.save(m_pixmap, imageName);
if (ConfigHandler().copyAndCloseAfterUploadEnabled()) { if (ConfigHandler().copyAndCloseAfterUpload()) {
SystemNotification().sendMessage( SystemNotification().sendMessage(
QObject::tr("URL copied to clipboard.")); QObject::tr("URL copied to clipboard."));
QApplication::clipboard()->setText(m_imageURL.toString()); QApplication::clipboard()->setText(m_imageURL.toString());

View File

@@ -42,7 +42,7 @@ AppLauncherWidget::AppLauncherWidget(const QPixmap& p, QWidget* parent)
setWindowIcon(QIcon(":img/app/flameshot.svg")); setWindowIcon(QIcon(":img/app/flameshot.svg"));
setWindowTitle(tr("Open With")); setWindowTitle(tr("Open With"));
m_keepOpen = ConfigHandler().keepOpenAppLauncherValue(); m_keepOpen = ConfigHandler().keepOpenAppLauncher();
QString dirLocal = QDir::homePath() + "/.local/share/applications/"; QString dirLocal = QDir::homePath() + "/.local/share/applications/";
QDir appsDirLocal(dirLocal); QDir appsDirLocal(dirLocal);
@@ -57,7 +57,7 @@ AppLauncherWidget::AppLauncherWidget(const QPixmap& p, QWidget* parent)
m_terminalCheckbox = new QCheckBox(tr("Launch in terminal"), this); m_terminalCheckbox = new QCheckBox(tr("Launch in terminal"), this);
m_keepOpenCheckbox = new QCheckBox(tr("Keep open after selection"), this); m_keepOpenCheckbox = new QCheckBox(tr("Keep open after selection"), this);
m_keepOpenCheckbox->setChecked(ConfigHandler().keepOpenAppLauncherValue()); m_keepOpenCheckbox->setChecked(ConfigHandler().keepOpenAppLauncher());
connect(m_keepOpenCheckbox, connect(m_keepOpenCheckbox,
&QCheckBox::clicked, &QCheckBox::clicked,
this, this,

View File

@@ -19,8 +19,8 @@ PinWidget::PinWidget(const QPixmap& pixmap, QWidget* parent)
setAttribute(Qt::WA_TranslucentBackground); setAttribute(Qt::WA_TranslucentBackground);
ConfigHandler conf; ConfigHandler conf;
m_baseColor = conf.uiMainColorValue(); m_baseColor = conf.uiColor();
m_hoverColor = conf.uiContrastColorValue(); m_hoverColor = conf.contrastUiColor();
m_layout = new QVBoxLayout(this); m_layout = new QVBoxLayout(this);
const int margin = this->margin(); const int margin = this->margin();

View File

@@ -5,7 +5,7 @@ target_sources(
filenamehandler.h filenamehandler.h
screengrabber.h screengrabber.h
systemnotification.h systemnotification.h
configshortcuts.h valuehandler.h
request.h request.h
strfparse.h strfparse.h
) )
@@ -16,6 +16,7 @@ target_sources(
screengrabber.cpp screengrabber.cpp
confighandler.cpp confighandler.cpp
systemnotification.cpp systemnotification.cpp
valuehandler.cpp
screenshotsaver.cpp screenshotsaver.cpp
dbusutils.cpp dbusutils.cpp
globalvalues.cpp globalvalues.cpp
@@ -24,7 +25,6 @@ target_sources(
pathinfo.cpp pathinfo.cpp
colorutils.cpp colorutils.cpp
history.cpp history.cpp
configshortcuts.cpp
strfparse.cpp strfparse.cpp
request.cpp request.cpp
) )

File diff suppressed because it is too large Load Diff

View File

@@ -9,121 +9,141 @@
#include <QVariant> #include <QVariant>
#include <QVector> #include <QVector>
class ConfigHandler class QFileSystemWatcher;
class ValueHandler;
template<class T>
class QSharedPointer;
class QTextStream;
/**
* Declare and implement a getter for a config option. `KEY` is the option key
* as it appears in the config file, `TYPE` is the C++ type. At the same time
* `KEY` is the name of the generated getter function.
*/
#define CONFIG_GETTER(KEY, TYPE) \
TYPE KEY() { return value(QStringLiteral(#KEY)).value<TYPE>(); }
/**
* Declare and implement a setter for a config option. `FUNC` is the name of the
* generated function, `KEY` is the option key as it appears in the config file
* and `TYPE` is the C++ type.
*/
#define CONFIG_SETTER(FUNC, KEY, TYPE) \
void FUNC(const TYPE& value) \
{ \
setValue(QStringLiteral(#KEY), QVariant::fromValue(value)); \
}
/**
* Combines the functionality of `CONFIG_GETTER` and `CONFIG_SETTER`. `GETFUNC`
* is simultaneously the name of the getter function and the option key as it
* appears in the config file. `SETFUNC` is the name of the setter function.
* `TYPE` is the C++ type of the value.
*/
#define CONFIG_GETTER_SETTER(GETFUNC, SETFUNC, TYPE) \
CONFIG_GETTER(GETFUNC, TYPE) \
CONFIG_SETTER(SETFUNC, GETFUNC, TYPE)
class ConfigHandler : public QObject
{ {
Q_OBJECT
public: public:
explicit ConfigHandler(); explicit ConfigHandler(bool skipInitialErrorCheck = false);
QVector<CaptureToolButton::ButtonType> getButtons(); static ConfigHandler* getInstance();
void setButtons(const QVector<CaptureToolButton::ButtonType>&);
QVector<QColor> getUserColors(); // Definitions of getters and setters for config options
// Some special cases are implemented regularly, without the macro
// NOTE: When adding new options, make sure to add an entry in
// recognizedGeneralOptions in the cpp file.
CONFIG_GETTER_SETTER(userColors, setUserColors, QVector<QColor>);
CONFIG_GETTER_SETTER(savePath, setSavePath, QString)
CONFIG_GETTER_SETTER(savePathFixed, setSavePathFixed, bool)
CONFIG_GETTER_SETTER(uiColor, setUiColor, QColor)
CONFIG_GETTER_SETTER(contrastUiColor, setContrastUiColor, QColor)
CONFIG_GETTER_SETTER(drawColor, setDrawColor, QColor)
CONFIG_GETTER_SETTER(fontFamily, setFontFamily, QString)
CONFIG_GETTER_SETTER(showHelp, setShowHelp, bool)
CONFIG_GETTER_SETTER(showSidePanelButton, setShowSidePanelButton, bool)
CONFIG_GETTER_SETTER(showDesktopNotification,
setShowDesktopNotification,
bool)
CONFIG_GETTER_SETTER(filenamePattern, setFilenamePattern, QString)
CONFIG_GETTER_SETTER(disabledTrayIcon, setDisabledTrayIcon, bool)
CONFIG_GETTER_SETTER(drawThickness, setDrawThickness, int)
CONFIG_GETTER_SETTER(drawFontSize, setDrawFontSize, int)
CONFIG_GETTER_SETTER(keepOpenAppLauncher, setKeepOpenAppLauncher, bool)
CONFIG_GETTER_SETTER(checkForUpdates, setCheckForUpdates, bool)
CONFIG_GETTER_SETTER(showStartupLaunchMessage,
setShowStartupLaunchMessage,
bool)
CONFIG_GETTER_SETTER(contrastOpacity, setContrastOpacity, int)
CONFIG_GETTER_SETTER(copyAndCloseAfterUpload,
setCopyAndCloseAfterUpload,
bool)
CONFIG_GETTER_SETTER(historyConfirmationToDelete,
setHistoryConfirmationToDelete,
bool)
CONFIG_GETTER_SETTER(uploadHistoryMax, setUploadHistoryMax, int)
CONFIG_GETTER_SETTER(saveAfterCopy, setSaveAfterCopy, bool)
CONFIG_GETTER_SETTER(copyPathAfterSave, setCopyPathAfterSave, bool)
CONFIG_GETTER_SETTER(useJpgForClipboard, setUseJpgForClipboard, bool)
CONFIG_GETTER_SETTER(ignoreUpdateToVersion,
setIgnoreUpdateToVersion,
QString)
CONFIG_GETTER_SETTER(undoLimit, setUndoLimit, int)
CONFIG_GETTER_SETTER(buttons,
setButtons,
QList<CaptureToolButton::ButtonType>)
QString savePath(); // SPECIAL CASES
void setSavePath(const QString&); bool startupLaunch();
bool savePathFixed();
void setSavePathFixed(bool);
QColor uiMainColorValue();
void setUIMainColor(const QColor&);
QColor uiContrastColorValue();
void setUIContrastColor(const QColor&);
QColor drawColorValue();
void setDrawColor(const QColor&);
void setFontFamily(const QString&);
const QString& fontFamily();
bool showHelpValue();
void setShowHelp(const bool);
bool showSidePanelButtonValue();
void setShowSidePanelButton(const bool);
bool desktopNotificationValue();
void setDesktopNotification(const bool);
QString filenamePatternDefault();
QString filenamePatternValue();
void setFilenamePattern(const QString&);
bool disabledTrayIconValue();
void setDisabledTrayIcon(const bool);
int drawThicknessValue();
void setDrawThickness(const int);
int drawFontSizeValue();
void setDrawFontSize(const int);
bool keepOpenAppLauncherValue();
void setKeepOpenAppLauncher(const bool);
bool checkForUpdates();
void setCheckForUpdates(const bool);
bool verifyLaunchFile();
bool startupLaunchValue();
void setStartupLaunch(const bool); void setStartupLaunch(const bool);
QString saveAsFileExtension();
bool showStartupLaunchMessage(); CONFIG_SETTER(setSaveAsFileExtension, setSaveAsFileExtension, QString)
void setShowStartupLaunchMessage(const bool);
int contrastOpacityValue();
void setContrastOpacity(const int);
bool copyAndCloseAfterUploadEnabled();
void setCopyAndCloseAfterUploadEnabled(const bool);
bool historyConfirmationToDelete();
void setHistoryConfirmationToDelete(const bool save);
int uploadHistoryMaxSizeValue();
void setUploadHistoryMaxSize(const int);
bool saveAfterCopyValue();
void setSaveAfterCopy(const bool);
bool copyPathAfterSaveEnabled();
void setCopyPathAfterSaveEnabled(const bool);
bool useJpgForClipboard() const;
void setUseJpgForClipboard(const bool);
void setSaveAsFileExtension(const QString& extension);
QString getSaveAsFileExtension();
void setDefaultSettings();
void setAllTheButtons(); void setAllTheButtons();
void setIgnoreUpdateToVersion(const QString& text); // DEFAULTS
QString ignoreUpdateToVersion(); QString filenamePatternDefault();
void setDefaultSettings();
void setUndoLimit(int value);
int undoLimit();
bool setShortcut(const QString&, const QString&);
const QString& shortcut(const QString&);
QString configFilePath() const; QString configFilePath() const;
void setValue(const QString& group, // GENERIC GETTERS AND SETTERS
const QString& key, bool setShortcut(const QString&, const QString&);
const QVariant& value); QString shortcut(const QString&);
QVariant& value(const QString& group, const QString& key); void setValue(const QString& key, const QVariant& value);
QVariant value(const QString& key) const;
// INFO
const QSet<QString>& recognizedGeneralOptions() const;
const QSet<QString>& recognizedShortcutNames() const;
QSet<QString> keysFromGroup(const QString& group) const;
// ERROR HANDLING
bool checkForErrors(QTextStream* log = nullptr) const;
bool checkUnrecognizedSettings(QTextStream* log = nullptr) const;
bool checkShortcutConflicts(QTextStream* log = nullptr) const;
bool checkSemantics(QTextStream* log = nullptr) const;
void checkAndHandleError() const;
void setErrorState(bool error) const;
bool hasError() const;
QString errorMessage() const;
signals:
void error() const;
void errorResolved() const;
void fileChanged() const;
private: private:
QString m_strRes; mutable QSettings m_settings;
QVariant m_varRes;
QSettings m_settings;
QVector<QStringList> m_shortcuts;
bool normalizeButtons(QVector<int>&); static bool m_hasError, m_errorCheckPending, m_skipNextErrorCheck;
static QSharedPointer<QFileSystemWatcher> m_configWatcher;
QVector<CaptureToolButton::ButtonType> fromIntToButton( void ensureFileWatched() const;
const QVector<int>& l); QSharedPointer<ValueHandler> valueHandler(const QString& key) const;
QVector<int> fromButtonToInt( void assertKeyRecognized(const QString& key) const;
const QVector<CaptureToolButton::ButtonType>& l); bool isShortcut(const QString& key) const;
QString baseName(QString key) const;
}; };

View File

@@ -1,26 +0,0 @@
#ifndef CONFIGSHORTCUTS_H
#define CONFIGSHORTCUTS_H
#include "src/widgets/capture/capturetoolbutton.h"
#include <QKeySequence>
#include <QString>
#include <QStringList>
#include <QVector>
class ConfigShortcuts
{
public:
ConfigShortcuts();
const QVector<QStringList>& captureShortcutsDefault(
const QVector<CaptureToolButton::ButtonType>& buttons);
const QKeySequence& captureShortcutDefault(const QString& buttonType);
private:
QVector<QStringList> m_shortcuts;
QKeySequence m_ks;
void addShortcut(const QString& shortcutName, const QString& description);
};
#endif // CONFIGSHORTCUTS_H

View File

@@ -27,7 +27,7 @@ FileNameHandler::FileNameHandler(QObject* parent)
QString FileNameHandler::parsedPattern() QString FileNameHandler::parsedPattern()
{ {
return parseFilename(ConfigHandler().filenamePatternValue()); return parseFilename(ConfigHandler().filenamePattern());
} }
QString FileNameHandler::parseFilename(const QString& name) QString FileNameHandler::parseFilename(const QString& name)

View File

@@ -57,7 +57,7 @@ const QList<QString>& History::history()
QDir::Files, QDir::Files,
QDir::Time); QDir::Time);
int cnt = 0; int cnt = 0;
int max = ConfigHandler().uploadHistoryMaxSizeValue(); int max = ConfigHandler().uploadHistoryMax();
m_thumbs.clear(); m_thumbs.clear();
foreach (QString fileName, images) { foreach (QString fileName, images) {
if (++cnt <= max) { if (++cnt <= max) {

View File

@@ -58,7 +58,7 @@ void ScreenshotSaver::saveToClipboard(const QPixmap& capture)
{ {
// If we are able to properly save the file, save the file and copy to // If we are able to properly save the file, save the file and copy to
// clipboard. // clipboard.
if ((ConfigHandler().saveAfterCopyValue()) && if ((ConfigHandler().saveAfterCopy()) &&
(!ConfigHandler().savePath().isEmpty())) { (!ConfigHandler().savePath().isEmpty())) {
saveToFilesystem(capture, saveToFilesystem(capture,
ConfigHandler().savePath(), ConfigHandler().savePath(),
@@ -126,7 +126,7 @@ QString ScreenshotSaver::ShowSaveFileDialog(QWidget* parent,
mimeTypeList.append(mimeType); mimeTypeList.append(mimeType);
dialog.setMimeTypeFilters(mimeTypeList); dialog.setMimeTypeFilters(mimeTypeList);
QString suffix = ConfigHandler().getSaveAsFileExtension(); QString suffix = ConfigHandler().saveAsFileExtension();
QString defaultMimeType = QString defaultMimeType =
QMimeDatabase().mimeTypeForFile("image" + suffix).name(); QMimeDatabase().mimeTypeForFile("image" + suffix).name();
dialog.selectMimeTypeFilter(defaultMimeType); dialog.selectMimeTypeFilter(defaultMimeType);
@@ -179,7 +179,7 @@ bool ScreenshotSaver::saveToFilesystemGUI(const QPixmap& capture)
QString msg = QObject::tr("Capture saved as ") + savePath; QString msg = QObject::tr("Capture saved as ") + savePath;
if (config.copyPathAfterSaveEnabled()) { if (config.copyPathAfterSave()) {
msg = msg =
QObject::tr("Capture is saved and copied to the clipboard as ") + QObject::tr("Capture is saved and copied to the clipboard as ") +
savePath; savePath;
@@ -190,7 +190,7 @@ bool ScreenshotSaver::saveToFilesystemGUI(const QPixmap& capture)
Controller::getInstance()->sendCaptureSaved( Controller::getInstance()->sendCaptureSaved(
m_id, QFileInfo(savePath).canonicalFilePath()); m_id, QFileInfo(savePath).canonicalFilePath());
if (config.copyPathAfterSaveEnabled()) { if (config.copyPathAfterSave()) {
QApplication::clipboard()->setText(savePath); QApplication::clipboard()->setText(savePath);
} }

View File

@@ -35,7 +35,7 @@ void SystemNotification::sendMessage(const QString& text,
const QString& savePath, const QString& savePath,
const int timeout) const int timeout)
{ {
if (!ConfigHandler().desktopNotificationValue()) { if (!ConfigHandler().showDesktopNotification()) {
return; return;
} }

413
src/utils/valuehandler.cpp Normal file
View File

@@ -0,0 +1,413 @@
#include "valuehandler.h"
#include "confighandler.h"
#include <QColor>
#include <QFileInfo>
#include <QStandardPaths>
#include <QVariant>
// VALUE HANDLER
QVariant ValueHandler::value(const QVariant& val)
{
if (!val.isValid() || !check(val)) {
return fallback();
} else {
return process(val);
}
}
QVariant ValueHandler::fallback()
{
return QVariant();
}
QVariant ValueHandler::representation(const QVariant& val)
{
return val.toString();
}
QString ValueHandler::expected()
{
return {};
}
QVariant ValueHandler::process(const QVariant& val)
{
return val;
}
// BOOL
Bool::Bool(bool def)
: m_def(def)
{}
bool Bool::check(const QVariant& val)
{
QString str = val.toString();
if (str != "true" && str != "false") {
return false;
}
return true;
}
QVariant Bool::fallback()
{
return m_def;
}
QString Bool::expected()
{
return QStringLiteral("true or false");
}
// STRING
String::String(const QString& def)
: m_def(def)
{}
bool String::check(const QVariant&)
{
return true;
}
QVariant String::fallback()
{
return m_def;
}
QString String::expected()
{
return QStringLiteral("string");
}
// COLOR
Color::Color(const QColor& def)
: m_def(def)
{}
bool Color::check(const QVariant& val)
{
QString str = val.toString();
// Disable #RGB, #RRRGGGBBB and #RRRRGGGGBBBB formats that QColor supports
return QColor::isValidColor(str) &&
(str[0] != '#' ||
(str.length() != 4 && str.length() != 10 && str.length() != 13));
}
QVariant Color::process(const QVariant& val)
{
QString str = val.toString();
QColor color(str);
if (str.length() == 9 && str[0] == '#') {
// Convert #RRGGBBAA (flameshot) to #AARRGGBB (QColor)
int blue = color.blue();
color.setBlue(color.green());
color.setGreen(color.red());
color.setRed(color.alpha());
color.setAlpha(blue);
}
return color;
}
QVariant Color::fallback()
{
return m_def;
}
QVariant Color::representation(const QVariant& val)
{
QString str = val.toString();
QColor color(str);
if (str.length() == 9 && str[0] == '#') {
// Convert #AARRGGBB (QColor) to #RRGGBBAA (flameshot)
int alpha = color.alpha();
color.setAlpha(color.red());
color.setRed(color.green());
color.setGreen(color.blue());
color.setBlue(alpha);
}
return color.name();
}
QString Color::expected()
{
return QStringLiteral("color name or hex value");
}
// BOUNDED INT
BoundedInt::BoundedInt(int min, int max, int def)
: m_min(min)
, m_max(max)
, m_def(def)
{}
bool BoundedInt::check(const QVariant& val)
{
QString str = val.toString();
bool conversionOk;
int num = str.toInt(&conversionOk);
return conversionOk && (m_max < m_min || num <= m_max);
}
QVariant BoundedInt::fallback()
{
return m_def;
}
QString BoundedInt::expected()
{
return QStringLiteral("number between %1 and %2").arg(m_min).arg(m_max);
}
// LOWER BOUNDED INT
LowerBoundedInt::LowerBoundedInt(int min, int def)
: m_min(min)
, m_def(def)
{}
bool LowerBoundedInt::check(const QVariant& val)
{
QString str = val.toString();
bool conversionOk;
int num = str.toInt(&conversionOk);
return conversionOk && num >= m_min;
}
QVariant LowerBoundedInt::fallback()
{
return m_def;
}
QString LowerBoundedInt::expected()
{
return QStringLiteral("number >= %1").arg(m_min);
}
// KEY SEQUENCE
KeySequence::KeySequence(const QKeySequence& fallback)
: m_fallback(fallback)
{}
bool KeySequence::check(const QVariant& val)
{
QString str = val.toString();
if (!str.isEmpty() && QKeySequence(str).toString().isEmpty()) {
return false;
}
return true;
}
QVariant KeySequence::fallback()
{
return m_fallback;
}
QString KeySequence::expected()
{
return QStringLiteral("keyboard shortcut");
}
// EXISTING DIR
bool ExistingDir::check(const QVariant& val)
{
if (!val.canConvert(QVariant::String) || val.toString().isEmpty()) {
return false;
}
QFileInfo info(val.toString());
return info.isDir() && info.exists();
}
QVariant ExistingDir::fallback()
{
using SP = QStandardPaths;
for (auto location :
{ SP::PicturesLocation, SP::HomeLocation, SP::TempLocation }) {
QString path = SP::writableLocation(location);
if (QFileInfo(path).isDir()) {
return path;
}
}
return {};
}
QString ExistingDir::expected()
{
return QStringLiteral("existing directory");
}
// FILENAME PATTERN
bool FilenamePattern::check(const QVariant&)
{
return true;
}
QVariant FilenamePattern::fallback()
{
return ConfigHandler().filenamePatternDefault();
}
QVariant FilenamePattern::process(const QVariant& val)
{
QString str = val.toString();
return !str.isEmpty() ? val : fallback();
}
QString FilenamePattern::expected()
{
return QStringLiteral("please edit using the GUI");
}
// BUTTON LIST
using BType = CaptureToolButton::ButtonType;
using BList = QList<BType>;
bool ButtonList::check(const QVariant& val)
{
using CTB = CaptureToolButton;
auto allButtons = CTB::getIterableButtonTypes();
for (int btn : val.value<QList<int>>()) {
if (!allButtons.contains(static_cast<CTB::ButtonType>(btn))) {
return false;
}
}
return true;
}
// Helper
void sortButtons(BList& buttons)
{
std::sort(buttons.begin(), buttons.end(), [](BType a, BType b) {
return CaptureToolButton::getPriorityByButton(a) <
CaptureToolButton::getPriorityByButton(b);
});
}
QVariant ButtonList::process(const QVariant& val)
{
QList<int> intButtons = val.value<QList<int>>();
auto buttons = ButtonList::fromIntList(intButtons);
sortButtons(buttons);
return QVariant::fromValue(buttons);
}
QVariant ButtonList::fallback()
{
auto buttons = CaptureToolButton::getIterableButtonTypes();
buttons.removeOne(CaptureToolButton::TYPE_SIZEDECREASE);
buttons.removeOne(CaptureToolButton::TYPE_SIZEINCREASE);
sortButtons(buttons);
return QVariant::fromValue(buttons);
}
QVariant ButtonList::representation(const QVariant& val)
{
auto intList = toIntList(val.value<BList>());
normalizeButtons(intList);
return QVariant::fromValue(intList);
}
QString ButtonList::expected()
{
return QStringLiteral("please don't edit by hand");
}
QList<CaptureToolButton::ButtonType> ButtonList::fromIntList(
const QList<int>& l)
{
QList<CaptureToolButton::ButtonType> buttons;
buttons.reserve(l.size());
for (auto const i : l)
buttons << static_cast<CaptureToolButton::ButtonType>(i);
return buttons;
}
QList<int> ButtonList::toIntList(const QList<CaptureToolButton::ButtonType>& l)
{
QList<int> buttons;
buttons.reserve(l.size());
for (auto const i : l)
buttons << static_cast<int>(i);
return buttons;
}
bool ButtonList::normalizeButtons(QList<int>& buttons)
{
QList<int> listTypesInt =
toIntList(CaptureToolButton::getIterableButtonTypes());
bool hasChanged = false;
for (int i = 0; i < buttons.size(); i++) {
if (!listTypesInt.contains(buttons.at(i))) {
buttons.removeAt(i);
hasChanged = true;
}
}
return hasChanged;
}
// USER COLORS
bool UserColors::check(const QVariant& val)
{
if (!val.isValid()) {
return true;
}
if (!val.canConvert(QVariant::StringList)) {
return false;
}
for (const QString& str : val.toStringList()) {
if (!QColor::isValidColor(str) && str != "picker") {
return false;
}
}
return true;
}
QVariant UserColors::process(const QVariant& val)
{
QStringList strColors = val.toStringList();
if (strColors.isEmpty()) {
return fallback();
}
QVector<QColor> colors;
colors.reserve(strColors.size());
for (const QString& str : strColors) {
if (str != "picker") {
colors.append(QColor(str));
} else {
colors.append(QColor());
}
}
return QVariant::fromValue(colors);
}
QVariant UserColors::fallback()
{
return QVariant::fromValue(QVector<QColor>{ Qt::darkRed,
Qt::red,
Qt::yellow,
Qt::green,
Qt::darkGreen,
Qt::cyan,
Qt::blue,
Qt::magenta,
Qt::darkMagenta,
QColor() });
}
QString UserColors::expected()
{
return QStringLiteral("list of colors separated by comma");
}

197
src/utils/valuehandler.h Normal file
View File

@@ -0,0 +1,197 @@
#pragma once
#include "src/widgets/capture/capturetoolbutton.h"
#include <QColor>
#include <QList>
#include <QString>
class QVariant;
/**
* @brief Handles the value of a configuration option (abstract class).
*
* Each configuration option is represented as a `QVariant`. If the option was
* not specified in a config file, the `QVariant` will be invalid.
*
* Each option will usually be handled in three different ways:
* - have its value checked for semantic errors (type, format, etc).
* @see ValueHandler::check
* - have its value (that was taken from the config file) adapted for proper
* use.
* @see ValueHandler::value
* - provided a fallback value in case: the config does not explicitly specify
* it, or the config contains an error and is globally falling back to
* defaults.
* @see ValueHandler::fallback.
* - some options may want to be stored in the config file in a different way
* than the default one provided by `QVariant`.
* @see ValueHandler::representation
*
* @note Please see the documentation of the functions to learn when you should
* override each.
*
*/
class ValueHandler
{
public:
/**
* @brief Check the value semantically.
* @param val The value that was read from the config file
* @return Whether the value is correct
* @note The function should presume that `val.isValid()` is true.
*/
virtual bool check(const QVariant& val) = 0;
/**
* @brief Adapt the value for proper use.
* @param val The value that was read from the config file
* @return The modified value
*
* If the value is invalid (unspecified in the config) or does not pass
* `check`, the fallback will be returned. Otherwise the value is processed
* by `process` and then returned.
*
* @note Cannot be overriden
* @see fallback, process
*/
QVariant value(const QVariant& val);
/**
* @brief Fallback value (default value).
*/
virtual QVariant fallback();
/**
* @brief Return the representaion of the value in the config file.
*
* Override this if you want to write the value in a different format than
* the one provided by `QVariant`.
*/
virtual QVariant representation(const QVariant& val);
/**
* @brief The expected value (descriptive).
* Used when reporting configuration errors.
*/
virtual QString expected();
protected:
/**
* @brief Process a value, presuming it is a valid `QVariant`.
* @param val The value that was read from the config file
* @return The processed value
* @note You will usually want to override this. In rare cases, you may want
* to override `value`.
*/
virtual QVariant process(const QVariant& val);
};
class Bool : public ValueHandler
{
public:
Bool(bool def);
bool check(const QVariant& val) override;
QVariant fallback() override;
QString expected() override;
private:
bool m_def;
};
class String : public ValueHandler
{
public:
String(const QString& def);
bool check(const QVariant&) override;
QVariant fallback() override;
QString expected() override;
private:
QString m_def;
};
class Color : public ValueHandler
{
public:
Color(const QColor& def);
bool check(const QVariant& val) override;
QVariant process(const QVariant& val) override;
QVariant fallback() override;
QVariant representation(const QVariant& val) override;
QString expected() override;
private:
QColor m_def;
};
class BoundedInt : public ValueHandler
{
public:
BoundedInt(int min, int max, int def);
bool check(const QVariant& val) override;
virtual QVariant fallback() override;
QString expected() override;
private:
int m_min, m_max, m_def;
};
class LowerBoundedInt : public ValueHandler
{
public:
LowerBoundedInt(int min, int def);
bool check(const QVariant& val) override;
QVariant fallback() override;
QString expected() override;
private:
int m_min, m_def;
};
class KeySequence : public ValueHandler
{
public:
KeySequence(const QKeySequence& fallback = {});
bool check(const QVariant& val) override;
QVariant fallback() override;
QString expected() override;
private:
QKeySequence m_fallback;
};
class ExistingDir : public ValueHandler
{
bool check(const QVariant& val) override;
QVariant fallback() override;
QString expected() override;
};
class FilenamePattern : public ValueHandler
{
bool check(const QVariant&) override;
QVariant fallback() override;
QVariant process(const QVariant&) override;
QString expected() override;
};
class ButtonList : public ValueHandler
{
public:
bool check(const QVariant& val) override;
QVariant process(const QVariant& val) override;
QVariant fallback() override;
QVariant representation(const QVariant& val) override;
QString expected() override;
// UTILITY FUNCTIONS
static QList<CaptureToolButton::ButtonType> fromIntList(const QList<int>&);
static QList<int> toIntList(const QList<CaptureToolButton::ButtonType>& l);
static bool normalizeButtons(QList<int>& buttons);
};
class UserColors : public ValueHandler
{
bool check(const QVariant& val) override;
QVariant process(const QVariant& val) override;
QVariant fallback() override;
QString expected() override;
};

View File

@@ -72,4 +72,4 @@ void CaptureButton::setColor(const QColor& c)
setStyleSheet(styleSheet()); setStyleSheet(styleSheet());
} }
QColor CaptureButton::m_mainColor = ConfigHandler().uiMainColorValue(); QColor CaptureButton::m_mainColor = ConfigHandler().uiColor();

View File

@@ -81,8 +81,7 @@ void CaptureToolButton::updateIcon()
setIconSize(size() * 0.6); setIconSize(size() * 0.6);
} }
QVector<CaptureToolButton::ButtonType> QList<CaptureToolButton::ButtonType> CaptureToolButton::getIterableButtonTypes()
CaptureToolButton::getIterableButtonTypes()
{ {
return iterableButtonTypes; return iterableButtonTypes;
} }
@@ -123,7 +122,7 @@ void CaptureToolButton::setColor(const QColor& c)
updateIcon(); updateIcon();
} }
QColor CaptureToolButton::m_mainColor = ConfigHandler().uiMainColorValue(); QColor CaptureToolButton::m_mainColor = ConfigHandler().uiColor();
static std::map<CaptureToolButton::ButtonType, int> buttonTypeOrder static std::map<CaptureToolButton::ButtonType, int> buttonTypeOrder
{ {
@@ -163,31 +162,30 @@ int CaptureToolButton::getPriorityByButton(CaptureToolButton::ButtonType b)
: it->second; : it->second;
} }
QVector<CaptureToolButton::ButtonType> QList<CaptureToolButton::ButtonType> CaptureToolButton::iterableButtonTypes = {
CaptureToolButton::iterableButtonTypes = { CaptureToolButton::TYPE_PENCIL,
CaptureToolButton::TYPE_PENCIL, CaptureToolButton::TYPE_DRAWER,
CaptureToolButton::TYPE_DRAWER, CaptureToolButton::TYPE_ARROW,
CaptureToolButton::TYPE_ARROW, CaptureToolButton::TYPE_SELECTION,
CaptureToolButton::TYPE_SELECTION, CaptureToolButton::TYPE_RECTANGLE,
CaptureToolButton::TYPE_RECTANGLE, CaptureToolButton::TYPE_CIRCLE,
CaptureToolButton::TYPE_CIRCLE, CaptureToolButton::TYPE_MARKER,
CaptureToolButton::TYPE_MARKER, CaptureToolButton::TYPE_TEXT,
CaptureToolButton::TYPE_TEXT, CaptureToolButton::TYPE_PIXELATE,
CaptureToolButton::TYPE_PIXELATE, CaptureToolButton::TYPE_INVERT,
CaptureToolButton::TYPE_INVERT, CaptureToolButton::TYPE_SELECTIONINDICATOR,
CaptureToolButton::TYPE_CIRCLECOUNT, CaptureToolButton::TYPE_MOVESELECTION,
CaptureToolButton::TYPE_SELECTIONINDICATOR, CaptureToolButton::TYPE_UNDO,
CaptureToolButton::TYPE_MOVESELECTION, CaptureToolButton::TYPE_REDO,
CaptureToolButton::TYPE_UNDO, CaptureToolButton::TYPE_COPY,
CaptureToolButton::TYPE_REDO, CaptureToolButton::TYPE_SAVE,
CaptureToolButton::TYPE_COPY, CaptureToolButton::TYPE_EXIT,
CaptureToolButton::TYPE_SAVE, CaptureToolButton::TYPE_IMAGEUPLOADER,
CaptureToolButton::TYPE_EXIT,
CaptureToolButton::TYPE_IMAGEUPLOADER,
#if !defined(Q_OS_MACOS) #if !defined(Q_OS_MACOS)
CaptureToolButton::TYPE_OPEN_APP, CaptureToolButton::TYPE_OPEN_APP,
#endif #endif
CaptureToolButton::TYPE_PIN, CaptureToolButton::TYPE_PIN,
CaptureToolButton::TYPE_SIZEINCREASE, CaptureToolButton::TYPE_CIRCLECOUNT,
CaptureToolButton::TYPE_SIZEDECREASE, CaptureToolButton::TYPE_SIZEINCREASE,
}; CaptureToolButton::TYPE_SIZEDECREASE,
};

View File

@@ -51,7 +51,7 @@ public:
explicit CaptureToolButton(const ButtonType, QWidget* parent = nullptr); explicit CaptureToolButton(const ButtonType, QWidget* parent = nullptr);
~CaptureToolButton(); ~CaptureToolButton();
static QVector<CaptureToolButton::ButtonType> getIterableButtonTypes(); static QList<CaptureToolButton::ButtonType> getIterableButtonTypes();
static int getPriorityByButton(CaptureToolButton::ButtonType); static int getPriorityByButton(CaptureToolButton::ButtonType);
QString name() const; QString name() const;
@@ -64,7 +64,7 @@ public:
protected: protected:
void mousePressEvent(QMouseEvent* e) override; void mousePressEvent(QMouseEvent* e) override;
static QVector<ButtonType> iterableButtonTypes; static QList<ButtonType> iterableButtonTypes;
CaptureTool* m_tool; CaptureTool* m_tool;

View File

@@ -29,6 +29,8 @@
#include <QApplication> #include <QApplication>
#include <QDateTime> #include <QDateTime>
#include <QDesktopWidget> #include <QDesktopWidget>
#include <QFontMetrics>
#include <QLabel>
#include <QPaintEvent> #include <QPaintEvent>
#include <QPainter> #include <QPainter>
#include <QScreen> #include <QScreen>
@@ -56,6 +58,8 @@ CaptureWidget::CaptureWidget(uint id,
, m_captureDone(false) , m_captureDone(false)
, m_previewEnabled(true) , m_previewEnabled(true)
, m_adjustmentButtonPressed(false) , m_adjustmentButtonPressed(false)
, m_configError(false)
, m_configErrorResolved(false)
, m_activeButton(nullptr) , m_activeButton(nullptr)
, m_activeTool(nullptr) , m_activeTool(nullptr)
, m_toolWidget(nullptr) , m_toolWidget(nullptr)
@@ -85,9 +89,9 @@ CaptureWidget::CaptureWidget(uint id,
this, this,
&CaptureWidget::childLeave); &CaptureWidget::childLeave);
setAttribute(Qt::WA_DeleteOnClose); setAttribute(Qt::WA_DeleteOnClose);
m_opacity = m_config.contrastOpacityValue(); m_opacity = m_config.contrastOpacity();
m_uiColor = m_config.uiMainColorValue(); m_uiColor = m_config.uiColor();
m_contrastUiColor = m_config.uiContrastColorValue(); m_contrastUiColor = m_config.contrastUiColor();
setMouseTracking(true); setMouseTracking(true);
initContext(savePath, fullScreen); initContext(savePath, fullScreen);
initShortcuts(); initShortcuts();
@@ -200,10 +204,25 @@ CaptureWidget::CaptureWidget(uint id,
initPanel(); initPanel();
m_config.checkAndHandleError();
if (m_config.hasError()) {
m_configError = true;
}
connect(ConfigHandler::getInstance(), &ConfigHandler::error, this, [=]() {
m_configError = true;
m_configErrorResolved = false;
update();
});
connect(
ConfigHandler::getInstance(), &ConfigHandler::errorResolved, this, [=]() {
m_configError = false;
m_configErrorResolved = true;
update();
});
OverlayMessage::init(this, OverlayMessage::init(this,
QGuiAppCurrentScreen().currentScreen()->geometry()); QGuiAppCurrentScreen().currentScreen()->geometry());
if (m_config.showHelpValue()) { if (m_config.showHelp()) {
OverlayMessage::push( OverlayMessage::push(
tr("Select an area with the mouse, or press Esc to exit." tr("Select an area with the mouse, or press Esc to exit."
"\nPress Enter to capture the screen." "\nPress Enter to capture the screen."
@@ -225,7 +244,7 @@ CaptureWidget::~CaptureWidget()
void CaptureWidget::initButtons() void CaptureWidget::initButtons()
{ {
auto allButtonTypes = CaptureToolButton::getIterableButtonTypes(); auto allButtonTypes = CaptureToolButton::getIterableButtonTypes();
auto visibleButtonTypes = m_config.getButtons(); auto visibleButtonTypes = m_config.buttons();
QVector<CaptureToolButton*> vectorButtons; QVector<CaptureToolButton*> vectorButtons;
// Add all buttons but hide those that were disabled in the Interface config // Add all buttons but hide those that were disabled in the Interface config
@@ -376,6 +395,10 @@ void CaptureWidget::paintEvent(QPaintEvent* paintEvent)
// draw inactive region // draw inactive region
drawInactiveRegion(&painter); drawInactiveRegion(&painter);
if (m_configError || m_configErrorResolved) {
drawConfigErrorMessage(&painter);
}
} }
void CaptureWidget::showColorPicker(const QPoint& pos) void CaptureWidget::showColorPicker(const QPoint& pos)
@@ -683,8 +706,7 @@ void CaptureWidget::mouseMoveEvent(QMouseEvent* e)
m_buttonHandler->show(); m_buttonHandler->show();
} }
} }
} else if (m_activeButton && m_activeButton->tool() && } else if (m_activeButton && m_activeButton->tool()) {
m_activeButton->tool()->showMousePreview()) {
update(); update();
} else { } else {
if (!m_selection->isVisible()) { if (!m_selection->isVisible()) {
@@ -705,7 +727,7 @@ void CaptureWidget::mouseReleaseEvent(QMouseEvent* e)
} }
m_colorPicker->hide(); m_colorPicker->hide();
if (!m_context.color.isValid()) { if (!m_context.color.isValid()) {
m_context.color = ConfigHandler().drawColorValue(); m_context.color = ConfigHandler().drawColor();
m_panel->show(); m_panel->show();
} }
} else if (m_mouseIsClicked) { } else if (m_mouseIsClicked) {
@@ -907,11 +929,11 @@ void CaptureWidget::moveEvent(QMoveEvent* e)
void CaptureWidget::initContext(const QString& savePath, bool fullscreen) void CaptureWidget::initContext(const QString& savePath, bool fullscreen)
{ {
m_context.color = m_config.drawColorValue(); m_context.color = m_config.drawColor();
m_context.savePath = savePath; m_context.savePath = savePath;
m_context.widgetOffset = mapToGlobal(QPoint(0, 0)); m_context.widgetOffset = mapToGlobal(QPoint(0, 0));
m_context.mousePos = mapFromGlobal(QCursor::pos()); m_context.mousePos = mapFromGlobal(QCursor::pos());
m_context.thickness = m_config.drawThicknessValue(); m_context.thickness = m_config.drawThickness();
m_context.fullscreen = fullscreen; m_context.fullscreen = fullscreen;
} }
@@ -934,7 +956,7 @@ void CaptureWidget::initPanel()
#endif #endif
} }
if (ConfigHandler().showSidePanelButtonValue()) { if (ConfigHandler().showSidePanelButton()) {
auto* panelToggleButton = auto* panelToggleButton =
new OrientablePushButton(tr("Tool Settings"), this); new OrientablePushButton(tr("Tool Settings"), this);
makeChild(panelToggleButton); makeChild(panelToggleButton);
@@ -1107,9 +1129,9 @@ void CaptureWidget::loadDrawThickness()
if ((m_activeButton && m_activeButton->tool() && if ((m_activeButton && m_activeButton->tool() &&
m_activeButton->tool()->type() == ToolType::TEXT) || m_activeButton->tool()->type() == ToolType::TEXT) ||
(m_activeTool && m_activeTool->type() == ToolType::TEXT)) { (m_activeTool && m_activeTool->type() == ToolType::TEXT)) {
m_context.thickness = m_config.drawFontSizeValue(); m_context.thickness = m_config.drawFontSize();
} else { } else {
m_context.thickness = m_config.drawThicknessValue(); m_context.thickness = m_config.drawThickness();
} }
emit m_sidePanel->thicknessChanged(m_context.thickness); emit m_sidePanel->thicknessChanged(m_context.thickness);
} }
@@ -1670,6 +1692,28 @@ QRect CaptureWidget::extendedRect(const QRect& r) const
r.height() * devicePixelRatio); r.height() * devicePixelRatio);
} }
void CaptureWidget::drawConfigErrorMessage(QPainter* painter)
{
QString msg;
if (m_configError) {
msg = ConfigHandler().errorMessage();
} else if (m_configErrorResolved) {
msg = tr("Configuration error resolved. Launch `flameshot "
"gui` again to apply it.");
}
auto textRect = painter->fontMetrics().boundingRect(msg);
int w = textRect.width(), h = textRect.height();
textRect = { size().width() - w, size().height() - h, w + 100, h + 100 };
QScreen* currentScreen = QGuiAppCurrentScreen().currentScreen();
if (!textRect.contains(QCursor::pos(currentScreen))) {
QColor textColor(Qt::white);
painter->setPen(textColor);
painter->drawText(textRect, msg);
}
}
void CaptureWidget::drawInactiveRegion(QPainter* painter) void CaptureWidget::drawInactiveRegion(QPainter* painter)
{ {
QColor overlayColor(0, 0, 0, m_opacity); QColor overlayColor(0, 0, 0, m_opacity);

View File

@@ -22,6 +22,7 @@
#include <QUndoStack> #include <QUndoStack>
#include <QWidget> #include <QWidget>
class QLabel;
class QPaintEvent; class QPaintEvent;
class QResizeEvent; class QResizeEvent;
class QMouseEvent; class QMouseEvent;
@@ -131,6 +132,7 @@ private:
QRect extendedSelection() const; QRect extendedSelection() const;
QRect extendedRect(const QRect& r) const; QRect extendedRect(const QRect& r) const;
void drawConfigErrorMessage(QPainter* painter);
void drawInactiveRegion(QPainter* painter); void drawInactiveRegion(QPainter* painter);
void drawToolsData(bool updateLayersPanel = true, void drawToolsData(bool updateLayersPanel = true,
bool drawSelection = false); bool drawSelection = false);
@@ -161,6 +163,8 @@ private:
bool m_captureDone; bool m_captureDone;
bool m_previewEnabled; bool m_previewEnabled;
bool m_adjustmentButtonPressed; bool m_adjustmentButtonPressed;
bool m_configError;
bool m_configErrorResolved;
UpdateNotificationWidget* m_updateNotificationWidget; UpdateNotificationWidget* m_updateNotificationWidget;
quint64 m_lastMouseWheel; quint64 m_lastMouseWheel;

View File

@@ -11,12 +11,12 @@ ColorPicker::ColorPicker(QWidget* parent)
: QWidget(parent) : QWidget(parent)
{ {
ConfigHandler config; ConfigHandler config;
m_colorList = config.getUserColors(); m_colorList = config.userColors();
m_colorAreaSize = GlobalValues::buttonBaseSize() * 0.6; m_colorAreaSize = GlobalValues::buttonBaseSize() * 0.6;
setMouseTracking(true); setMouseTracking(true);
// save the color values in member variables for faster access // save the color values in member variables for faster access
m_uiColor = config.uiMainColorValue(); m_uiColor = config.uiColor();
m_drawColor = config.drawColorValue(); m_drawColor = config.drawColor();
// extraSize represents the extra space needed for the highlight of the // extraSize represents the extra space needed for the highlight of the
// selected color. // selected color.
const int extraSize = 6; const int extraSize = 6;

View File

@@ -16,7 +16,7 @@ NotifierBox::NotifierBox(QWidget* parent)
m_timer->setSingleShot(true); m_timer->setSingleShot(true);
m_timer->setInterval(600); m_timer->setInterval(600);
connect(m_timer, &QTimer::timeout, this, &NotifierBox::hide); connect(m_timer, &QTimer::timeout, this, &NotifierBox::hide);
m_bgColor = ConfigHandler().uiMainColorValue(); m_bgColor = ConfigHandler().uiColor();
m_foregroundColor = m_foregroundColor =
(ColorUtils::colorIsDark(m_bgColor) ? Qt::white : Qt::black); (ColorUtils::colorIsDark(m_bgColor) ? Qt::white : Qt::black);
m_bgColor.setAlpha(180); m_bgColor.setAlpha(180);

View File

@@ -66,7 +66,7 @@ void OverlayMessage::paintEvent(QPaintEvent*)
QRectF bRect = boundingRect(); QRectF bRect = boundingRect();
bRect.moveTo(0, 0); bRect.moveTo(0, 0);
QColor rectColor(ConfigHandler().uiMainColorValue()); QColor rectColor(ConfigHandler().uiColor());
rectColor.setAlpha(180); rectColor.setAlpha(180);
QColor textColor( QColor textColor(
(ColorUtils::colorIsDark(rectColor) ? Qt::white : Qt::black)); (ColorUtils::colorIsDark(rectColor) ? Qt::white : Qt::black));