Files
flameshot/src/config/shortcutswidget.cpp
Haris Gušić d1428889b9 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>
2021-09-15 11:56:01 -05:00

236 lines
8.1 KiB
C++

// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2020 Yurii Puchkov at Namecheap & Contributors
#include "shortcutswidget.h"
#include "capturetool.h"
#include "setshortcutwidget.h"
#include "src/core/qguiappcurrentscreen.h"
#include <QHeaderView>
#include <QIcon>
#include <QKeyEvent>
#include <QLabel>
#include <QStringList>
#include <QTableWidget>
#include <QVBoxLayout>
#include <QVector>
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
#include <QCursor>
#include <QRect>
#include <QScreen>
#endif
ShortcutsWidget::ShortcutsWidget(QWidget* parent)
: QWidget(parent)
{
setAttribute(Qt::WA_DeleteOnClose);
setWindowIcon(QIcon(":img/app/flameshot.svg"));
setWindowTitle(tr("Hot Keys"));
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
QRect position = frameGeometry();
QScreen* screen = QGuiAppCurrentScreen().currentScreen();
position.moveCenter(screen->availableGeometry().center());
move(position.topLeft());
#endif
m_layout = new QVBoxLayout(this);
m_layout->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
initShortcuts();
initInfoTable();
show();
}
const QList<QStringList>& ShortcutsWidget::shortcuts()
{
return m_shortcuts;
}
void ShortcutsWidget::initInfoTable()
{
m_table = new QTableWidget(this);
m_table->setToolTip(tr("Available shortcuts in the screen capture mode."));
m_layout->addWidget(m_table);
m_table->setColumnCount(2);
m_table->setRowCount(m_shortcuts.size());
m_table->setSelectionMode(QAbstractItemView::NoSelection);
m_table->setFocusPolicy(Qt::NoFocus);
m_table->verticalHeader()->hide();
// header creation
QStringList names;
names << tr("Description") << tr("Key");
m_table->setHorizontalHeaderLabels(names);
connect(m_table,
SIGNAL(cellClicked(int, int)),
this,
SLOT(slotShortcutCellClicked(int, int)));
// add content
for (int i = 0; i < shortcuts().size(); ++i) {
const auto current_shortcut = m_shortcuts.at(i);
const auto identifier = current_shortcut.at(0);
const auto description = current_shortcut.at(1);
const auto default_key_sequence = current_shortcut.at(2);
m_table->setItem(i, 0, new QTableWidgetItem(description));
const auto key_sequence = identifier.isEmpty()
? default_key_sequence
: m_config.shortcut(identifier);
#if defined(Q_OS_MACOS)
QTableWidgetItem* item =
new QTableWidgetItem(nativeOSHotKeyText(key_sequence));
#else
QTableWidgetItem* item = new QTableWidgetItem(key_sequence);
#endif
item->setTextAlignment(Qt::AlignCenter);
m_table->setItem(i, 1, item);
if (identifier.isEmpty()) {
QFont font;
font.setBold(true);
item->setFont(font);
item->setFlags(item->flags() ^ Qt::ItemIsEnabled);
m_table->item(i, 1)->setFont(font);
}
}
// Read-only table items
for (int x = 0; x < m_table->rowCount(); ++x) {
for (int y = 0; y < m_table->columnCount(); ++y) {
QTableWidgetItem* item = m_table->item(x, y);
item->setFlags(item->flags() ^ Qt::ItemIsEditable);
}
}
// adjust size
m_table->resizeColumnsToContents();
m_table->resizeRowsToContents();
m_table->horizontalHeader()->setMinimumSectionSize(200);
m_table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
m_table->horizontalHeader()->setSizePolicy(QSizePolicy::Expanding,
QSizePolicy::Expanding);
}
void ShortcutsWidget::slotShortcutCellClicked(int row, int col)
{
if (col == 1) {
// Ignore non-changable shortcuts
if (Qt::ItemIsEnabled !=
(Qt::ItemIsEnabled & m_table->item(row, col)->flags())) {
return;
}
SetShortcutDialog* setShortcutDialog = new SetShortcutDialog();
if (0 != setShortcutDialog->exec()) {
QString shortcutName = m_shortcuts.at(row).at(0);
QKeySequence shortcutValue = setShortcutDialog->shortcut();
// set no shortcut is Backspace
#if defined(Q_OS_MACOS)
if (shortcutValue == QKeySequence(Qt::CTRL + Qt::Key_Backspace)) {
shortcutValue = QKeySequence("");
}
#else
if (shortcutValue == QKeySequence(Qt::Key_Backspace)) {
shortcutValue = QKeySequence("");
}
#endif
if (m_config.setShortcut(shortcutName, shortcutValue.toString())) {
#if defined(Q_OS_MACOS)
QTableWidgetItem* item = new QTableWidgetItem(
nativeOSHotKeyText(shortcutValue.toString()));
#else
QTableWidgetItem* item =
new QTableWidgetItem(shortcutValue.toString());
#endif
item->setTextAlignment(Qt::AlignCenter);
item->setFlags(item->flags() ^ Qt::ItemIsEditable);
m_table->setItem(row, col, item);
}
}
delete setShortcutDialog;
}
}
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)
const QString& ShortcutsWidget::nativeOSHotKeyText(const QString& text)
{
m_res = text;
m_res.replace("Ctrl+", "");
m_res.replace("Alt+", "");
m_res.replace("Meta+", "");
m_res.replace("Shift+", "");
return m_res;
}
#endif