diff --git a/flameshot.example.ini b/flameshot.example.ini index 72ccdb39..43c566e3 100644 --- a/flameshot.example.ini +++ b/flameshot.example.ini @@ -66,6 +66,9 @@ ;; Copy path to image after save (bool) ;copyPathAfterSave=false ; +;; On successful upload, close the dialog and copy URL to clipboard. +;copyAndCloseAfterUpload=true +; ;; Anti-aliasing image when zoom the pinned image (bool) ;antialiasingPinZoom=true ; diff --git a/src/config/configwindow.cpp b/src/config/configwindow.cpp index 81025de3..c23dcadc 100644 --- a/src/config/configwindow.cpp +++ b/src/config/configwindow.cpp @@ -187,7 +187,7 @@ void ConfigWindow::initErrorIndicator(QWidget* tab, QWidget* widget) qApp->processEvents(); QPoint center = dialog.geometry().center(); - QRect dialogRect(0, 0, 400, 400); + QRect dialogRect(0, 0, 600, 400); dialogRect.moveCenter(center); dialog.setGeometry(dialogRect); diff --git a/src/config/shortcutswidget.cpp b/src/config/shortcutswidget.cpp index 069ea84d..99171788 100644 --- a/src/config/shortcutswidget.cpp +++ b/src/config/shortcutswidget.cpp @@ -38,16 +38,14 @@ ShortcutsWidget::ShortcutsWidget(QWidget* parent) m_layout = new QVBoxLayout(this); m_layout->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); - initShortcuts(); initInfoTable(); + connect(ConfigHandler::getInstance(), + &ConfigHandler::fileChanged, + this, + &ShortcutsWidget::populateInfoTable); show(); } -const QList& ShortcutsWidget::shortcuts() -{ - return m_shortcuts; -} - void ShortcutsWidget::initInfoTable() { m_table = new QTableWidget(this); @@ -56,7 +54,6 @@ void ShortcutsWidget::initInfoTable() 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(); @@ -66,21 +63,35 @@ void ShortcutsWidget::initInfoTable() names << tr("Description") << tr("Key"); m_table->setHorizontalHeaderLabels(names); connect(m_table, - SIGNAL(cellClicked(int, int)), + &QTableWidget::cellClicked, this, - SLOT(slotShortcutCellClicked(int, int))); + &ShortcutsWidget::onShortcutCellClicked); + + // populate with dynamic data + populateInfoTable(); + + // adjust size + m_table->horizontalHeader()->setMinimumSectionSize(200); + m_table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); + m_table->horizontalHeader()->setSizePolicy(QSizePolicy::Expanding, + QSizePolicy::Expanding); + m_table->resizeColumnsToContents(); + m_table->resizeRowsToContents(); +} + +void ShortcutsWidget::populateInfoTable() +{ + loadShortcuts(); + m_table->setRowCount(m_shortcuts.size()); // add content - for (int i = 0; i < shortcuts().size(); ++i) { + for (int i = 0; i < m_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); + const auto 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)); @@ -106,17 +117,9 @@ void ShortcutsWidget::initInfoTable() 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) +void ShortcutsWidget::onShortcutCellClicked(int row, int col) { if (col == 1) { // Ignore non-changable shortcuts @@ -140,38 +143,27 @@ void ShortcutsWidget::slotShortcutCellClicked(int row, int col) 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); + populateInfoTable(); } } delete setShortcutDialog; } } -void ShortcutsWidget::initShortcuts() +void ShortcutsWidget::loadShortcuts() { + m_shortcuts.clear(); auto buttonTypes = CaptureToolButton::getIterableButtonTypes(); // get shortcuts names from capture buttons for (const CaptureTool::Type& t : buttonTypes) { CaptureTool* tool = ToolFactory().CreateTool(t); QString shortcutName = QVariant::fromValue(t).toString(); - if (t != CaptureTool::TYPE_IMAGEUPLOADER) { - appendShortcut(shortcutName, tool->description()); - if (shortcutName == "TYPE_COPY") - m_shortcuts << (QStringList() << "" << tool->description() - << "Left Double-click"); - } + appendShortcut(shortcutName, tool->description()); + if (shortcutName == "TYPE_COPY") + m_shortcuts << (QStringList() << "" << tool->description() + << "Left Double-click"); delete tool; } @@ -219,10 +211,11 @@ void ShortcutsWidget::initShortcuts() void ShortcutsWidget::appendShortcut(const QString& shortcutName, const QString& description) { + QString shortcut = ConfigHandler().shortcut(shortcutName); m_shortcuts << (QStringList() << shortcutName << QObject::tr(description.toStdString().c_str()) - << ConfigHandler().shortcut(shortcutName)); + << shortcut.replace("Return", "Enter")); } #if defined(Q_OS_MACOS) diff --git a/src/config/shortcutswidget.h b/src/config/shortcutswidget.h index 3afeae18..638bff39 100644 --- a/src/config/shortcutswidget.h +++ b/src/config/shortcutswidget.h @@ -18,7 +18,6 @@ class ShortcutsWidget : public QWidget Q_OBJECT public: explicit ShortcutsWidget(QWidget* parent = nullptr); - const QList& shortcuts(); private: void initInfoTable(); @@ -28,7 +27,8 @@ private: #endif private slots: - void slotShortcutCellClicked(int, int); + void populateInfoTable(); + void onShortcutCellClicked(int, int); private: #if (defined(Q_OS_MAC) || defined(Q_OS_MAC64) || defined(Q_OS_MACOS) || \ @@ -40,7 +40,7 @@ private: QVBoxLayout* m_layout; QList m_shortcuts; - void initShortcuts(); + void loadShortcuts(); void appendShortcut(const QString& shortcutName, const QString& description); }; diff --git a/src/utils/confighandler.cpp b/src/utils/confighandler.cpp index 938c33fa..36edd41b 100644 --- a/src/utils/confighandler.cpp +++ b/src/utils/confighandler.cpp @@ -131,7 +131,7 @@ static QMap> recognizedShortcuts = { SHORTCUT("TYPE_SAVE" , "Ctrl+S" ), SHORTCUT("TYPE_ACCEPT" , "Return" ), SHORTCUT("TYPE_EXIT" , "Ctrl+Q" ), - SHORTCUT("TYPE_IMAGEUPLOADER" , "Ctrl+U" ), + SHORTCUT("TYPE_IMAGEUPLOADER" , ), #if !defined(Q_OS_MACOS) SHORTCUT("TYPE_OPEN_APP" , "Ctrl+O" ), #endif @@ -161,6 +161,7 @@ static QMap> recognizedShortcuts = { SHORTCUT("TYPE_SIZEDECREASE" , ), SHORTCUT("TYPE_CIRCLECOUNT" , ), }; + // clang-format on // CLASS CONFIGHANDLER @@ -171,12 +172,14 @@ ConfigHandler::ConfigHandler(bool skipInitialErrorCheck) qApp->organizationName(), qApp->applicationName()) { - - if (m_configWatcher == nullptr) { - if (!skipInitialErrorCheck) { - // check for error on initial call - checkAndHandleError(); - } + static bool wasEverChecked = false; + static bool firstInitialization = true; + if (!skipInitialErrorCheck && !wasEverChecked) { + // check for error on initial call + checkAndHandleError(); + wasEverChecked = true; + } + if (firstInitialization) { // check for error every time the file changes m_configWatcher.reset(new QFileSystemWatcher()); ensureFileWatched(); @@ -201,6 +204,7 @@ ConfigHandler::ConfigHandler(bool skipInitialErrorCheck) } }); } + firstInitialization = false; } /// Serves as an object to which slots can be connected. @@ -363,59 +367,79 @@ QString ConfigHandler::configFilePath() const // GENERIC GETTERS AND SETTERS -bool ConfigHandler::setShortcut(const QString& shortcutName, - const QString& shortutValue) +bool ConfigHandler::setShortcut(const QString& actionName, + const QString& shortcut) { - bool error = false; - m_settings.beginGroup("Shortcuts"); - - QVector reservedShortcuts; - + qDebug() << actionName; + static QVector reservedShortcuts = { #if defined(Q_OS_MACOS) - reservedShortcuts << QKeySequence(Qt::CTRL + Qt::Key_Backspace) - << QKeySequence(Qt::Key_Escape); + Qt::CTRL + Qt::Key_Backspace, + Qt::Key_Escape, #else - reservedShortcuts << QKeySequence(Qt::Key_Backspace) - << QKeySequence(Qt::Key_Escape); + Qt::Key_Backspace, + Qt::Key_Escape, #endif + }; - if (shortutValue.isEmpty()) { - setValue(shortcutName, ""); - } else if (reservedShortcuts.contains(QKeySequence(shortutValue))) { + if (hasError()) { + return false; + } + + bool error = false; + + m_settings.beginGroup("Shortcuts"); + if (shortcut.isEmpty()) { + setValue(actionName, ""); + } else if (reservedShortcuts.contains(QKeySequence(shortcut))) { // do not allow to set reserved shortcuts error = true; } else { + error = false; // Make no difference for Return and Enter keys - QString shortcutItem = shortutValue; - if (shortcutItem == "Enter") { - shortcutItem = QKeySequence(Qt::Key_Return).toString(); - } - - // do not allow to set overlapped shortcuts - foreach (auto currentShortcutName, m_settings.allKeys()) { - if (value(currentShortcutName) == shortcutItem) { - setValue(shortcutName, ""); + QString newShortcut = KeySequence().value(shortcut).toString(); + for (auto& otherAction : m_settings.allKeys()) { + if (actionName == otherAction) { + continue; + } + QString existingShortcut = + KeySequence().value(m_settings.value(otherAction)).toString(); + if (newShortcut == existingShortcut) { error = true; - break; + goto done; } } - if (!error) { - setValue(shortcutName, shortcutItem); - } + m_settings.setValue(actionName, KeySequence().value(shortcut)); } +done: m_settings.endGroup(); return !error; } -QString ConfigHandler::shortcut(const QString& shortcutName) +QString ConfigHandler::shortcut(const QString& actionName) { - return value(QStringLiteral("Shortcuts/") + shortcutName).toString(); + QString setting = "Shortcuts/" + actionName; + QString shortcut = value(setting).toString(); + if (!m_settings.contains(setting)) { + // The action uses a shortcut that is a flameshot default + // (not set explicitly by user) + m_settings.beginGroup("Shortcuts"); + for (auto& otherAction : m_settings.allKeys()) { + if (m_settings.value(otherAction) == shortcut) { + // We found an explicit shortcut - it will take precedence + m_settings.endGroup(); + return {}; + } + } + m_settings.endGroup(); + } + return shortcut; } void ConfigHandler::setValue(const QString& key, const QVariant& value) { assertKeyRecognized(key); if (!hasError()) { + // don't let the file watcher initiate another error check m_skipNextErrorCheck = true; auto val = valueHandler(key)->representation(value); m_settings.setValue(key, val); @@ -444,14 +468,14 @@ QVariant ConfigHandler::value(const QString& key) const return handler->value(val); } -const QSet& ConfigHandler::recognizedGeneralOptions() const +QSet& ConfigHandler::recognizedGeneralOptions() { static QSet options = QSet::fromList(::recognizedGeneralOptions.keys()); return options; } -const QSet& ConfigHandler::recognizedShortcutNames() const +QSet& ConfigHandler::recognizedShortcutNames() { static QSet names = QSet::fromList(recognizedShortcuts.keys()); @@ -515,8 +539,12 @@ bool ConfigHandler::checkUnrecognizedSettings(QTextStream* log) const } /** - * @brief Check if there are multiple shortcuts with the same key binding. + * @brief Check if there are multiple actions with the same shortcut. * @return Whether the config passes this check. + * + * @note It is not considered a conflict if action A uses shortcut S because it + * is the flameshot default (not because the user explicitly configured it), and + * action B uses the same shortcut. */ bool ConfigHandler::checkShortcutConflicts(QTextStream* log) const { @@ -529,12 +557,18 @@ bool ConfigHandler::checkShortcutConflicts(QTextStream* log) const // values stored in variables are useful when running debugger QString value1 = m_settings.value(*key1).toString(), value2 = m_settings.value(*key2).toString(); - if (!value1.isEmpty() && value1 == value2) { + // The check will pass if: + // - one shortcut is empty (the action doesn't use a shortcut) + // - or one of the settings is not found in m_settings, i.e. + // user wants to use flameshot's default shortcut for the action + // - or the shortcuts for both actions are different + if (!(value1.isEmpty() || !m_settings.contains(*key1) || + !m_settings.contains(*key2) || value1 != value2)) { ok = false; if (log == nullptr) { break; - } else if (!reportedInLog.contains(*key1) && - !reportedInLog.contains(*key2)) { + } else if (!reportedInLog.contains(*key1) && // No duplicate + !reportedInLog.contains(*key2)) { // log entries reportedInLog.append(*key1); reportedInLog.append(*key2); *log << QStringLiteral("Shortcut conflict: '%1' and '%2' " @@ -559,8 +593,10 @@ bool ConfigHandler::checkSemantics(QTextStream* log) const QStringList allKeys = m_settings.allKeys(); bool ok = true; for (const QString& key : allKeys) { + // Test if the key is recognized if (!recognizedGeneralOptions().contains(key) && - !recognizedShortcutNames().contains(baseName(key))) { + (!isShortcut(key) || + !recognizedShortcutNames().contains(baseName(key)))) { continue; } QVariant val = m_settings.value(key); @@ -670,10 +706,8 @@ QSharedPointer ConfigHandler::valueHandler( { QSharedPointer handler; if (isShortcut(key)) { - QString _key = key; - _key.replace("Shortcuts/", ""); handler = recognizedShortcuts.value( - _key, QSharedPointer(new KeySequence())); + baseName(key), QSharedPointer(new KeySequence())); } else { // General group handler = ::recognizedGeneralOptions.value(key); } @@ -720,4 +754,5 @@ QString ConfigHandler::baseName(QString key) const bool ConfigHandler::m_hasError = false; bool ConfigHandler::m_errorCheckPending = false; bool ConfigHandler::m_skipNextErrorCheck = false; + QSharedPointer ConfigHandler::m_configWatcher; diff --git a/src/utils/confighandler.h b/src/utils/confighandler.h index d9b4c82e..80459ee9 100644 --- a/src/utils/confighandler.h +++ b/src/utils/confighandler.h @@ -111,14 +111,14 @@ public: QString configFilePath() const; // GENERIC GETTERS AND SETTERS - bool setShortcut(const QString&, const QString&); - QString shortcut(const QString&); + bool setShortcut(const QString& actionName, const QString& shortcut); + QString shortcut(const QString& actionName); void setValue(const QString& key, const QVariant& value); QVariant value(const QString& key) const; // INFO - const QSet& recognizedGeneralOptions() const; - const QSet& recognizedShortcutNames() const; + static QSet& recognizedGeneralOptions(); + static QSet& recognizedShortcutNames(); QSet keysFromGroup(const QString& group) const; // ERROR HANDLING diff --git a/src/utils/valuehandler.cpp b/src/utils/valuehandler.cpp index fe8826ff..83a81b75 100644 --- a/src/utils/valuehandler.cpp +++ b/src/utils/valuehandler.cpp @@ -3,6 +3,7 @@ #include "confighandler.h" #include #include +#include #include #include @@ -151,7 +152,7 @@ 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); + return conversionOk && m_min <= num && num <= m_max; } QVariant BoundedInt::fallback() @@ -214,6 +215,24 @@ QString KeySequence::expected() return QStringLiteral("keyboard shortcut"); } +QVariant KeySequence::representation(const QVariant& val) +{ + QString str(val.toString()); + if (QKeySequence(str) == QKeySequence(Qt::Key_Return)) { + return QStringLiteral("Enter"); + } + return str; +} + +QVariant KeySequence::process(const QVariant& val) +{ + QString str(val.toString()); + if (str == "Enter") { + return QKeySequence(Qt::Key_Return).toString(); + } + return str; +} + // EXISTING DIR bool ExistingDir::check(const QVariant& val) diff --git a/src/utils/valuehandler.h b/src/utils/valuehandler.h index d6d767b6..bbae7c1e 100644 --- a/src/utils/valuehandler.h +++ b/src/utils/valuehandler.h @@ -153,9 +153,12 @@ public: bool check(const QVariant& val) override; QVariant fallback() override; QString expected() override; + QVariant representation(const QVariant& val) override; private: QKeySequence m_fallback; + + QVariant process(const QVariant& val) override; }; class ExistingDir : public ValueHandler diff --git a/src/widgets/capture/capturewidget.cpp b/src/widgets/capture/capturewidget.cpp index 9e58280b..a1dd9f3e 100644 --- a/src/widgets/capture/capturewidget.cpp +++ b/src/widgets/capture/capturewidget.cpp @@ -290,7 +290,6 @@ void CaptureWidget::initButtons() switch (t) { case CaptureTool::TYPE_UNDO: - case CaptureTool::TYPE_IMAGEUPLOADER: case CaptureTool::TYPE_REDO: // nothing to do, just skip non-dynamic buttons with existing // hard coded slots @@ -300,12 +299,12 @@ void CaptureWidget::initButtons() QString shortcut = ConfigHandler().shortcut(QVariant::fromValue(t).toString()); if (!shortcut.isNull()) { - QShortcut* key = - new QShortcut(QKeySequence(shortcut), this); - CaptureWidget* captureWidget = this; - connect(key, &QShortcut::activated, this, [=]() { - captureWidget->setState(b); - }); + auto shortcuts = newShortcut(shortcut, this, nullptr); + for (auto* shortcut : shortcuts) { + connect(shortcut, &QShortcut::activated, this, [=]() { + setState(b); + }); + } } break; } @@ -1269,57 +1268,57 @@ void CaptureWidget::removeToolObject(int index) void CaptureWidget::initShortcuts() { - new QShortcut( + newShortcut( QKeySequence(ConfigHandler().shortcut("TYPE_UNDO")), this, SLOT(undo())); - new QShortcut( + newShortcut( QKeySequence(ConfigHandler().shortcut("TYPE_REDO")), this, SLOT(redo())); - new QShortcut(QKeySequence(ConfigHandler().shortcut("TYPE_TOGGLE_PANEL")), - this, - SLOT(togglePanel())); + newShortcut(QKeySequence(ConfigHandler().shortcut("TYPE_TOGGLE_PANEL")), + this, + SLOT(togglePanel())); - new QShortcut(QKeySequence(ConfigHandler().shortcut("TYPE_RESIZE_LEFT")), - m_selection, - SLOT(resizeLeft())); - new QShortcut(QKeySequence(ConfigHandler().shortcut("TYPE_RESIZE_RIGHT")), - m_selection, - SLOT(resizeRight())); - new QShortcut(QKeySequence(ConfigHandler().shortcut("TYPE_RESIZE_UP")), - m_selection, - SLOT(resizeUp())); - new QShortcut(QKeySequence(ConfigHandler().shortcut("TYPE_RESIZE_DOWN")), - m_selection, - SLOT(resizeDown())); + newShortcut(QKeySequence(ConfigHandler().shortcut("TYPE_RESIZE_LEFT")), + m_selection, + SLOT(resizeLeft())); + newShortcut(QKeySequence(ConfigHandler().shortcut("TYPE_RESIZE_RIGHT")), + m_selection, + SLOT(resizeRight())); + newShortcut(QKeySequence(ConfigHandler().shortcut("TYPE_RESIZE_UP")), + m_selection, + SLOT(resizeUp())); + newShortcut(QKeySequence(ConfigHandler().shortcut("TYPE_RESIZE_DOWN")), + m_selection, + SLOT(resizeDown())); - new QShortcut(QKeySequence(ConfigHandler().shortcut("TYPE_MOVE_LEFT")), - m_selection, - SLOT(moveLeft())); - new QShortcut(QKeySequence(ConfigHandler().shortcut("TYPE_MOVE_RIGHT")), - m_selection, - SLOT(moveRight())); - new QShortcut(QKeySequence(ConfigHandler().shortcut("TYPE_MOVE_UP")), - m_selection, - SLOT(moveUp())); - new QShortcut(QKeySequence(ConfigHandler().shortcut("TYPE_MOVE_DOWN")), - m_selection, - SLOT(moveDown())); + newShortcut(QKeySequence(ConfigHandler().shortcut("TYPE_MOVE_LEFT")), + m_selection, + SLOT(moveLeft())); + newShortcut(QKeySequence(ConfigHandler().shortcut("TYPE_MOVE_RIGHT")), + m_selection, + SLOT(moveRight())); + newShortcut(QKeySequence(ConfigHandler().shortcut("TYPE_MOVE_UP")), + m_selection, + SLOT(moveUp())); + newShortcut(QKeySequence(ConfigHandler().shortcut("TYPE_MOVE_DOWN")), + m_selection, + SLOT(moveDown())); - new QShortcut( + newShortcut( QKeySequence(ConfigHandler().shortcut("TYPE_DELETE_CURRENT_TOOL")), this, SLOT(deleteCurrentTool())); - new QShortcut( + newShortcut( QKeySequence(ConfigHandler().shortcut("TYPE_COMMIT_CURRENT_TOOL")), this, SLOT(commitCurrentTool())); - new QShortcut(QKeySequence(ConfigHandler().shortcut("TYPE_SELECT_ALL")), - this, - SLOT(selectAll())); + newShortcut(QKeySequence(ConfigHandler().shortcut("TYPE_SELECT_ALL")), + this, + SLOT(selectAll())); - new QShortcut(Qt::Key_Escape, this, SLOT(deleteToolWidgetOrClose())); + newShortcut(Qt::Key_Escape, this, SLOT(deleteToolWidgetOrClose())); } void CaptureWidget::deleteCurrentTool() @@ -1507,6 +1506,26 @@ void CaptureWidget::makeChild(QWidget* w) w->installEventFilter(m_eventFilter); } +/** + * @brief Wrapper around `new QShortcut`, properly handling Enter/Return. + */ +QList CaptureWidget::newShortcut(const QKeySequence& key, + QWidget* parent, + const char* slot) +{ + QList shortcuts; + QString strKey = key.toString(); + if (strKey.contains("Enter") || strKey.contains("Return")) { + strKey.replace("Enter", "Return"); + shortcuts << new QShortcut(strKey, parent, slot); + strKey.replace("Return", "Enter"); + shortcuts << new QShortcut(strKey, parent, slot); + } else { + shortcuts << new QShortcut(key, parent, slot); + } + return shortcuts; +} + void CaptureWidget::togglePanel() { m_panel->toggle(); diff --git a/src/widgets/capture/capturewidget.h b/src/widgets/capture/capturewidget.h index e69b7e04..ce267691 100644 --- a/src/widgets/capture/capturewidget.h +++ b/src/widgets/capture/capturewidget.h @@ -26,6 +26,7 @@ class QLabel; class QPaintEvent; class QResizeEvent; class QMouseEvent; +class QShortcut; class QNetworkAccessManager; class QNetworkReply; class ColorPicker; @@ -116,6 +117,10 @@ private: void pushToolToStack(); void makeChild(QWidget* w); + QList newShortcut(const QKeySequence& key, + QWidget* parent, + const char* slot); + void setToolSize(int size); QRect extendedSelection() const;