diff --git a/src/plugins/coreplugin/actionmanager/commandmappings.cpp b/src/plugins/coreplugin/actionmanager/commandmappings.cpp index a27fac24bde..94cb436d6db 100644 --- a/src/plugins/coreplugin/actionmanager/commandmappings.cpp +++ b/src/plugins/coreplugin/actionmanager/commandmappings.cpp @@ -82,24 +82,6 @@ public: importButton = new QPushButton(CommandMappings::tr("Import..."), groupBox); exportButton = new QPushButton(CommandMappings::tr("Export..."), groupBox); - targetEditGroup = new QGroupBox(CommandMappings::tr("Target Identifier"), parent); - targetEditGroup->setEnabled(false); - - targetEdit = new FancyLineEdit(targetEditGroup); - targetEdit->setAutoHideButton(FancyLineEdit::Right, true); - targetEdit->setPlaceholderText(QString()); - targetEdit->setFiltering(true); - targetEdit->setValidationFunction([this](FancyLineEdit *, QString *) { - return !q->hasConflicts(); - }); - - resetButton = new QPushButton(targetEditGroup); - resetButton->setToolTip(CommandMappings::tr("Reset to default.")); - resetButton->setText(CommandMappings::tr("Reset")); - - QLabel *infoLabel = new QLabel(targetEditGroup); - infoLabel->setTextFormat(Qt::RichText); - QHBoxLayout *hboxLayout1 = new QHBoxLayout(); hboxLayout1->addWidget(defaultButton); hboxLayout1->addStretch(); @@ -114,25 +96,9 @@ public: vboxLayout1->addWidget(commandList); vboxLayout1->addLayout(hboxLayout1); - targetLabel = new QLabel(CommandMappings::tr("Target:")); - - QHBoxLayout *hboxLayout2 = new QHBoxLayout(); - hboxLayout2->addWidget(targetLabel); - hboxLayout2->addWidget(targetEdit); - hboxLayout2->addWidget(resetButton); - - QVBoxLayout *vboxLayout2 = new QVBoxLayout(targetEditGroup); - vboxLayout2->addLayout(hboxLayout2); - vboxLayout2->addWidget(infoLabel); - QVBoxLayout *vboxLayout = new QVBoxLayout(parent); vboxLayout->addWidget(groupBox); - vboxLayout->addWidget(targetEditGroup); - q->connect(targetEdit, &FancyLineEdit::buttonClicked, - q, &CommandMappings::removeTargetIdentifier); - q->connect(resetButton, &QPushButton::clicked, - q, &CommandMappings::resetTargetIdentifier); q->connect(exportButton, &QPushButton::clicked, q, &CommandMappings::exportAction); q->connect(importButton, &QPushButton::clicked, @@ -145,9 +111,7 @@ public: q->connect(filterEdit, &FancyLineEdit::textChanged, q, &CommandMappings::filterChanged); q->connect(commandList, &QTreeWidget::currentItemChanged, - q, &CommandMappings::commandChanged); - q->connect(targetEdit, &FancyLineEdit::textChanged, - q, &CommandMappings::targetIdentifierChanged); + q, &CommandMappings::currentCommandChanged); new HeaderViewStretcher(commandList->header(), 1); } @@ -160,10 +124,6 @@ public: QPushButton *defaultButton; QPushButton *importButton; QPushButton *exportButton; - QGroupBox *targetEditGroup; - QLabel *targetLabel; - FancyLineEdit *targetEdit; - QPushButton *resetButton; }; } // namespace Internal @@ -189,41 +149,16 @@ QTreeWidget *CommandMappings::commandList() const return d->commandList; } -QLineEdit *CommandMappings::targetEdit() const -{ - return d->targetEdit; -} - void CommandMappings::setPageTitle(const QString &s) { d->groupBox->setTitle(s); } -void CommandMappings::setTargetLabelText(const QString &s) -{ - d->targetLabel->setText(s); -} - -void CommandMappings::setTargetEditTitle(const QString &s) -{ - d->targetEditGroup->setTitle(s); -} - void CommandMappings::setTargetHeader(const QString &s) { d->commandList->setHeaderLabels(QStringList() << tr("Command") << tr("Label") << s); } -void CommandMappings::commandChanged(QTreeWidgetItem *current) -{ - if (!current || !current->data(0, Qt::UserRole).isValid()) { - d->targetEdit->clear(); - d->targetEditGroup->setEnabled(false); - return; - } - d->targetEditGroup->setEnabled(true); -} - void CommandMappings::filterChanged(const QString &f) { for (int i = 0; i < d->commandList->topLevelItemCount(); ++i) { @@ -232,11 +167,6 @@ void CommandMappings::filterChanged(const QString &f) } } -bool CommandMappings::hasConflicts() const -{ - return true; -} - bool CommandMappings::filter(const QString &filterString, QTreeWidgetItem *item) { bool visible = filterString.isEmpty(); @@ -275,7 +205,12 @@ void CommandMappings::setModified(QTreeWidgetItem *item , bool modified) QString CommandMappings::filterText() const { - return d->filterEdit ? d->filterEdit->text() : QString(); + return d->filterEdit->text(); +} + +void CommandMappings::setFilterText(const QString &text) +{ + d->filterEdit->setText(text); } } // namespace Core diff --git a/src/plugins/coreplugin/actionmanager/commandmappings.h b/src/plugins/coreplugin/actionmanager/commandmappings.h index dba27989d98..4d7081d48ee 100644 --- a/src/plugins/coreplugin/actionmanager/commandmappings.h +++ b/src/plugins/coreplugin/actionmanager/commandmappings.h @@ -54,15 +54,11 @@ class CORE_EXPORT CommandMappings : public QWidget public: CommandMappings(QWidget *parent = 0); ~CommandMappings(); - virtual bool hasConflicts() const; -protected slots: +signals: + void currentCommandChanged(QTreeWidgetItem *current); protected: - virtual void removeTargetIdentifier() = 0; - virtual void resetTargetIdentifier() = 0; - virtual void targetIdentifierChanged() = 0; - virtual void defaultAction() = 0; virtual void exportAction() {} @@ -72,16 +68,12 @@ protected: void filterChanged(const QString &f); - virtual void commandChanged(QTreeWidgetItem *current); - // access to m_page void setImportExportEnabled(bool enabled); QTreeWidget *commandList() const; - QLineEdit *targetEdit() const; QString filterText() const; + void setFilterText(const QString &text); void setPageTitle(const QString &s); - void setTargetLabelText(const QString &s); - void setTargetEditTitle(const QString &s); void setTargetHeader(const QString &s); void setModified(QTreeWidgetItem *item, bool modified); diff --git a/src/plugins/coreplugin/dialogs/shortcutsettings.cpp b/src/plugins/coreplugin/dialogs/shortcutsettings.cpp index 1709e5c0b62..b6812564cc7 100644 --- a/src/plugins/coreplugin/dialogs/shortcutsettings.cpp +++ b/src/plugins/coreplugin/dialogs/shortcutsettings.cpp @@ -41,12 +41,16 @@ #include #include #include +#include #include #include +#include +#include +#include #include #include -#include +#include #include Q_DECLARE_METATYPE(Core::Internal::ShortcutItem*) @@ -71,23 +75,208 @@ static int translateModifiers(Qt::KeyboardModifiers state, return result; } +static QString keySequenceToEditString(const QKeySequence &sequence) +{ + QString text = sequence.toString(QKeySequence::PortableText); + if (Utils::HostOsInfo::isMacHost()) { + // adapt the modifier names + text.replace(QLatin1String("Ctrl"), QLatin1String("Cmd"), Qt::CaseInsensitive); + text.replace(QLatin1String("Alt"), QLatin1String("Opt"), Qt::CaseInsensitive); + text.replace(QLatin1String("Meta"), QLatin1String("Ctrl"), Qt::CaseInsensitive); + } + return text; +} + +static QKeySequence keySequenceFromEditString(const QString &editString) +{ + QString text = editString; + if (Utils::HostOsInfo::isMacHost()) { + // adapt the modifier names + text.replace(QLatin1String("Opt"), QLatin1String("Alt"), Qt::CaseInsensitive); + text.replace(QLatin1String("Ctrl"), QLatin1String("Meta"), Qt::CaseInsensitive); + text.replace(QLatin1String("Cmd"), QLatin1String("Ctrl"), Qt::CaseInsensitive); + } + return QKeySequence::fromString(text, QKeySequence::PortableText); +} + +static bool keySequenceIsValid(const QKeySequence &sequence) +{ + if (sequence.isEmpty()) + return false; + for (int i = 0; i < sequence.count(); ++i) { + if (sequence[i] == Qt::Key_unknown) + return false; + } + return true; +} + namespace Core { namespace Internal { +ShortcutButton::ShortcutButton(QWidget *parent) + : QPushButton(parent) +{ + setToolTip(tr("Click and type the new key sequence.")); + setCheckable(true); + m_checkedText = tr("Stop Recording"); + m_uncheckedText = tr("Record"); + updateText(); + connect(this, &ShortcutButton::toggled, this, &ShortcutButton::handleToggleChange); +} + +QSize ShortcutButton::sizeHint() const +{ + if (m_preferredWidth < 0) { // initialize size hint + const QString originalText = text(); + ShortcutButton *that = const_cast(this); + that->setText(m_checkedText); + m_preferredWidth = QPushButton::sizeHint().width(); + that->setText(m_uncheckedText); + int otherWidth = QPushButton::sizeHint().width(); + if (otherWidth > m_preferredWidth) + m_preferredWidth = otherWidth; + that->setText(originalText); + } + return QSize(m_preferredWidth, QPushButton::sizeHint().height()); +} + +bool ShortcutButton::eventFilter(QObject *obj, QEvent *evt) +{ + if (evt->type() == QEvent::ShortcutOverride) { + evt->accept(); + return true; + } + if (evt->type() == QEvent::KeyRelease + || evt->type() == QEvent::Shortcut + || evt->type() == QEvent::Close/*Escape tries to close dialog*/) { + return true; + } + if (evt->type() == QEvent::MouseButtonPress && isChecked()) { + setChecked(false); + return true; + } + if (evt->type() == QEvent::KeyPress) { + QKeyEvent *k = static_cast(evt); + int nextKey = k->key(); + if (m_keyNum > 3 + || nextKey == Qt::Key_Control + || nextKey == Qt::Key_Shift + || nextKey == Qt::Key_Meta + || nextKey == Qt::Key_Alt) { + return false; + } + + nextKey |= translateModifiers(k->modifiers(), k->text()); + switch (m_keyNum) { + case 0: + m_key[0] = nextKey; + break; + case 1: + m_key[1] = nextKey; + break; + case 2: + m_key[2] = nextKey; + break; + case 3: + m_key[3] = nextKey; + break; + default: + break; + } + m_keyNum++; + k->accept(); + emit keySequenceChanged(QKeySequence(m_key[0], m_key[1], m_key[2], m_key[3])); + if (m_keyNum > 3) + setChecked(false); + return true; + } + return QPushButton::eventFilter(obj, evt); +} + +void ShortcutButton::updateText() +{ + setText(isChecked() ? m_checkedText : m_uncheckedText); +} + +void ShortcutButton::handleToggleChange(bool toogleState) +{ + updateText(); + m_keyNum = m_key[0] = m_key[1] = m_key[2] = m_key[3] = 0; + if (toogleState) { + if (qApp->focusWidget()) + qApp->focusWidget()->clearFocus(); // funny things happen otherwise + qApp->installEventFilter(this); + } else { + qApp->removeEventFilter(this); + } +} + ShortcutSettingsWidget::ShortcutSettingsWidget(QWidget *parent) : CommandMappings(parent) { setPageTitle(tr("Keyboard Shortcuts")); - setTargetLabelText(tr("Key sequence:")); - setTargetEditTitle(tr("Shortcut")); setTargetHeader(tr("Shortcut")); - targetEdit()->setPlaceholderText(tr("Type to set shortcut")); - - m_keyNum = m_key[0] = m_key[1] = m_key[2] = m_key[3] = 0; connect(ActionManager::instance(), &ActionManager::commandListChanged, this, &ShortcutSettingsWidget::initialize); - targetEdit()->installEventFilter(this); + connect(this, &ShortcutSettingsWidget::currentCommandChanged, + this, &ShortcutSettingsWidget::handleCurrentCommandChanged); + + m_shortcutBox = new QGroupBox(tr("Shortcut"), this); + m_shortcutBox->setEnabled(false); + auto vboxLayout = new QVBoxLayout(m_shortcutBox); + m_shortcutBox->setLayout(vboxLayout); + auto hboxLayout = new QHBoxLayout; + vboxLayout->addLayout(hboxLayout); + m_shortcutEdit = new Utils::FancyLineEdit(m_shortcutBox); + m_shortcutEdit->setFiltering(true); + m_shortcutEdit->setPlaceholderText(tr("Enter key sequence as text")); + m_shortcutEdit->setValidationFunction([this](Utils::FancyLineEdit *, QString *) { + return validateShortcutEdit(); + }); + auto shortcutLabel = new QLabel(tr("Key sequence:")); + shortcutLabel->setToolTip(Utils::HostOsInfo::isMacHost() + ? QLatin1String("") + + tr("Use \"Cmd\", \"Opt\", \"Ctrl\", and \"Shift\" for modifier keys. " + "Use \"Escape\", \"Backspace\", \"Delete\", \"Insert\", \"Home\", and so on, for special keys. " + "Combine individual keys with \"+\", " + "and combine multiple shortcuts to a shortcut sequence with \",\". " + "For example, if the user must hold the Ctrl and Shift modifier keys " + "while pressing Escape, and then release and press A, " + "enter \"Ctrl+Shift+Escape,A\".") + + QLatin1String("") + : QLatin1String("") + + tr("Use \"Ctrl\", \"Alt\", \"Meta\", and \"Shift\" for modifier keys. " + "Use \"Escape\", \"Backspace\", \"Delete\", \"Insert\", \"Home\", and so on, for special keys. " + "Combine individual keys with \"+\", " + "and combine multiple shortcuts to a shortcut sequence with \",\". " + "For example, if the user must hold the Ctrl and Shift modifier keys " + "while pressing Escape, and then release and press A, " + "enter \"Ctrl+Shift+Escape,A\".") + + QLatin1String("")); + auto shortcutButton = new ShortcutButton(m_shortcutBox); + connect(shortcutButton, &ShortcutButton::keySequenceChanged, + this, &ShortcutSettingsWidget::setKeySequence); + auto resetButton = new QPushButton(tr("Reset"), m_shortcutBox); + resetButton->setToolTip(tr("Reset to default.")); + connect(resetButton, &QPushButton::clicked, + this, &ShortcutSettingsWidget::resetToDefault); + hboxLayout->addWidget(shortcutLabel); + hboxLayout->addWidget(m_shortcutEdit); + hboxLayout->addWidget(shortcutButton); + hboxLayout->addWidget(resetButton); + + m_warningLabel = new QLabel(m_shortcutBox); + m_warningLabel->setTextFormat(Qt::RichText); + QPalette palette = m_warningLabel->palette(); + palette.setColor(QPalette::Active, QPalette::WindowText, + Utils::creatorTheme()->color(Utils::Theme::TextColorError)); + m_warningLabel->setPalette(palette); + connect(m_warningLabel, &QLabel::linkActivated, this, &ShortcutSettingsWidget::showConflicts); + vboxLayout->addWidget(m_warningLabel); + + layout()->addWidget(m_shortcutBox); + initialize(); } @@ -130,122 +319,86 @@ void ShortcutSettings::finish() delete m_widget; } -bool ShortcutSettingsWidget::eventFilter(QObject *o, QEvent *e) +void ShortcutSettingsWidget::handleCurrentCommandChanged(QTreeWidgetItem *current) { - Q_UNUSED(o) - - if ( e->type() == QEvent::KeyPress ) { - QKeyEvent *k = static_cast(e); - handleKeyEvent(k); - return true; - } - - if ( e->type() == QEvent::Shortcut || - e->type() == QEvent::KeyRelease ) { - return true; - } - - if (e->type() == QEvent::ShortcutOverride) { - // for shortcut overrides, we need to accept as well - e->accept(); - return true; - } - - return false; -} - -void ShortcutSettingsWidget::commandChanged(QTreeWidgetItem *current) -{ - CommandMappings::commandChanged(current); - if (!current || !current->data(0, Qt::UserRole).isValid()) + if (!current || !current->data(0, Qt::UserRole).isValid()) { + m_shortcutEdit->clear(); + m_warningLabel->clear(); + m_shortcutBox->setEnabled(false); return; - ShortcutItem *scitem = qvariant_cast(current->data(0, Qt::UserRole)); - setKeySequence(scitem->m_key); - markCollisions(scitem); -} - -void ShortcutSettingsWidget::targetIdentifierChanged() -{ - QTreeWidgetItem *current = commandList()->currentItem(); - if (current && current->data(0, Qt::UserRole).isValid()) { + } else { ShortcutItem *scitem = qvariant_cast(current->data(0, Qt::UserRole)); - scitem->m_key = QKeySequence(m_key[0], m_key[1], m_key[2], m_key[3]); - if (scitem->m_cmd->defaultKeySequence() != scitem->m_key) - setModified(current, true); - else - setModified(current, false); - current->setText(2, scitem->m_key.toString(QKeySequence::NativeText)); + setKeySequence(scitem->m_key); markCollisions(scitem); + m_shortcutBox->setEnabled(true); } } -bool ShortcutSettingsWidget::hasConflicts() const +bool ShortcutSettingsWidget::validateShortcutEdit() const { + m_warningLabel->clear(); QTreeWidgetItem *current = commandList()->currentItem(); if (!current || !current->data(0, Qt::UserRole).isValid()) - return false; + return true; ShortcutItem *item = qvariant_cast(current->data(0, Qt::UserRole)); - if (!item) - return false; + QTC_ASSERT(item, return true); - const QKeySequence currentKey = QKeySequence::fromString(targetEdit()->text(), QKeySequence::NativeText); - if (currentKey.isEmpty()) - return false; + bool valid = false; - const Id globalId(Constants::C_GLOBAL); - const Context itemContext = item->m_cmd->context(); + const QString text = m_shortcutEdit->text().trimmed(); + const QKeySequence currentKey = keySequenceFromEditString(text); - foreach (ShortcutItem *listItem, m_scitems) { - if (item == listItem) - continue; - if (listItem->m_key.isEmpty()) - continue; - if (listItem->m_key.matches(currentKey) == QKeySequence::NoMatch) - continue; - - const Context listContext = listItem->m_cmd->context(); - if (itemContext.contains(globalId) && !listContext.isEmpty()) - return true; - if (listContext.contains(globalId) && !itemContext.isEmpty()) - return true; - foreach (Id id, listContext) - if (itemContext.contains(id)) - return true; + if (keySequenceIsValid(currentKey) || text.isEmpty()) { + item->m_key = currentKey; + auto that = const_cast(this); + if (item->m_cmd->defaultKeySequence() != item->m_key) + that->setModified(current, true); + else + that->setModified(current, false); + current->setText(2, item->m_key.toString(QKeySequence::NativeText)); + valid = !that->markCollisions(item); + if (!valid) { + m_warningLabel->setText( + tr("Key sequence has potential conflicts. Show.")); + } + } else { + m_warningLabel->setText(tr("Invalid key sequence.")); } - return false; + return valid; } bool ShortcutSettingsWidget::filterColumn(const QString &filterString, QTreeWidgetItem *item, int column) const { - QString text = item->text(column); - if (Utils::HostOsInfo::isMacHost()) { - // accept e.g. Cmd+E in the filter. the text shows special fancy characters for Cmd - if (column == item->columnCount() - 1) { - QKeySequence key = QKeySequence::fromString(text, QKeySequence::NativeText); - if (!key.isEmpty()) { - text = key.toString(QKeySequence::PortableText); - text.replace(QLatin1String("Ctrl"), QLatin1String("Cmd")); - text.replace(QLatin1String("Meta"), QLatin1String("Ctrl")); - text.replace(QLatin1String("Alt"), QLatin1String("Opt")); - } - } + QString text; + if (column == item->columnCount() - 1) { + // filter on the shortcut edit text + if (!item->data(0, Qt::UserRole).isValid()) + return true; + ShortcutItem *scitem = qvariant_cast(item->data(0, Qt::UserRole)); + text = keySequenceToEditString(scitem->m_key); + } else { + text = item->text(column); } return !text.contains(filterString, Qt::CaseInsensitive); } void ShortcutSettingsWidget::setKeySequence(const QKeySequence &key) { - m_key[0] = m_key[1] = m_key[2] = m_key[3] = 0; - m_keyNum = key.count(); - for (int i = 0; i < m_keyNum; ++i) { - m_key[i] = key[i]; - } - targetEdit()->setText(key.toString(QKeySequence::NativeText)); + m_shortcutEdit->setText(keySequenceToEditString(key)); } -void ShortcutSettingsWidget::resetTargetIdentifier() +void ShortcutSettingsWidget::showConflicts() +{ + QTreeWidgetItem *current = commandList()->currentItem(); + if (current && current->data(0, Qt::UserRole).isValid()) { + ShortcutItem *scitem = qvariant_cast(current->data(0, Qt::UserRole)); + setFilterText(keySequenceToEditString(scitem->m_key)); + } +} + +void ShortcutSettingsWidget::resetToDefault() { QTreeWidgetItem *current = commandList()->currentItem(); if (current && current->data(0, Qt::UserRole).isValid()) { @@ -256,15 +409,6 @@ void ShortcutSettingsWidget::resetTargetIdentifier() } } -void ShortcutSettingsWidget::removeTargetIdentifier() -{ - m_keyNum = m_key[0] = m_key[1] = m_key[2] = m_key[3] = 0; - targetEdit()->clear(); - - foreach (ShortcutItem *item, m_scitems) - markCollisions(item); -} - void ShortcutSettingsWidget::importAction() { QString fileName = QFileDialog::getOpenFileName(ICore::dialogParent(), tr("Import Keyboard Mapping Scheme"), @@ -281,7 +425,7 @@ void ShortcutSettingsWidget::importAction() item->m_key = mapping.value(sid); item->m_item->setText(2, item->m_key.toString(QKeySequence::NativeText)); if (item->m_item == commandList()->currentItem()) - commandChanged(item->m_item); + currentCommandChanged(item->m_item); if (item->m_cmd->defaultKeySequence() != item->m_key) setModified(item->m_item, true); @@ -302,7 +446,7 @@ void ShortcutSettingsWidget::defaultAction() item->m_item->setText(2, item->m_key.toString(QKeySequence::NativeText)); setModified(item->m_item, false); if (item->m_item == commandList()->currentItem()) - commandChanged(item->m_item); + currentCommandChanged(item->m_item); } foreach (ShortcutItem *item, m_scitems) @@ -377,66 +521,39 @@ void ShortcutSettingsWidget::initialize() filterChanged(filterText()); } -void ShortcutSettingsWidget::handleKeyEvent(QKeyEvent *e) -{ - int nextKey = e->key(); - if ( m_keyNum > 3 || - nextKey == Qt::Key_Control || - nextKey == Qt::Key_Shift || - nextKey == Qt::Key_Meta || - nextKey == Qt::Key_Alt ) - return; - - nextKey |= translateModifiers(e->modifiers(), e->text()); - switch (m_keyNum) { - case 0: - m_key[0] = nextKey; - break; - case 1: - m_key[1] = nextKey; - break; - case 2: - m_key[2] = nextKey; - break; - case 3: - m_key[3] = nextKey; - break; - default: - break; - } - m_keyNum++; - QKeySequence ks(m_key[0], m_key[1], m_key[2], m_key[3]); - targetEdit()->setText(ks.toString(QKeySequence::NativeText)); - e->accept(); -} - -void ShortcutSettingsWidget::markCollisions(ShortcutItem *item) +bool ShortcutSettingsWidget::markCollisions(ShortcutItem *item) { bool hasCollision = false; if (!item->m_key.isEmpty()) { - Id globalId = Context(Constants::C_GLOBAL).at(0); + Id globalId(Constants::C_GLOBAL); const Context itemContext = item->m_cmd->context(); - + const bool itemHasGlobalContext = itemContext.contains(globalId); foreach (ShortcutItem *currentItem, m_scitems) { - if (currentItem->m_key.isEmpty() || item == currentItem || item->m_key != currentItem->m_key) continue; - - foreach (Id id, currentItem->m_cmd->context()) { - // conflict if context is identical, OR if one - // of the contexts is the global context - const Context thisContext = currentItem->m_cmd->context(); - if (itemContext.contains(id) - || (itemContext.contains(globalId) && !thisContext.isEmpty()) - || (thisContext.contains(globalId) && !itemContext.isEmpty())) { - currentItem->m_item->setForeground(2, Qt::red); - hasCollision = true; + const Context currentContext = currentItem->m_cmd->context(); + bool currentIsConflicting = (itemHasGlobalContext && !currentContext.isEmpty()); + if (!currentIsConflicting) { + foreach (const Id &id, currentContext) { + if ((id == globalId && !itemContext.isEmpty()) + || itemContext.contains(id)) { + currentIsConflicting = true; + break; + } } } + if (currentIsConflicting) { + currentItem->m_item->setForeground( + 2, Utils::creatorTheme()->color(Utils::Theme::TextColorError)); + hasCollision = true; + } } } - item->m_item->setForeground(2, hasCollision ? Qt::red : commandList()->palette().foreground()); + item->m_item->setForeground(2, hasCollision + ? Utils::creatorTheme()->color(Utils::Theme::TextColorError) + : commandList()->palette().foreground()); + return hasCollision; } } // namespace Internal diff --git a/src/plugins/coreplugin/dialogs/shortcutsettings.h b/src/plugins/coreplugin/dialogs/shortcutsettings.h index d3e63dceff5..2a61d017af7 100644 --- a/src/plugins/coreplugin/dialogs/shortcutsettings.h +++ b/src/plugins/coreplugin/dialogs/shortcutsettings.h @@ -36,9 +36,12 @@ #include #include +#include QT_BEGIN_NAMESPACE +class QGroupBox; class QKeyEvent; +class QLabel; QT_END_NAMESPACE namespace Core { @@ -57,6 +60,31 @@ struct ShortcutItem QTreeWidgetItem *m_item; }; +class ShortcutButton : public QPushButton +{ + Q_OBJECT +public: + ShortcutButton(QWidget *parent = 0); + + QSize sizeHint() const; + +signals: + void keySequenceChanged(const QKeySequence &sequence); + +protected: + bool eventFilter(QObject *obj, QEvent *evt); + +private: + void updateText(); + void handleToggleChange(bool toggleState); + + QString m_checkedText; + QString m_uncheckedText; + mutable int m_preferredWidth = -1; + int m_key[4] = { 0, 0, 0, 0 }; + int m_keyNum = 0; +}; + class ShortcutSettingsWidget : public CommandMappings { Q_OBJECT @@ -68,28 +96,25 @@ public: void apply(); protected: - bool eventFilter(QObject *o, QEvent *e) override; - - void commandChanged(QTreeWidgetItem *current) override; - void targetIdentifierChanged() override; - void resetTargetIdentifier() override; - void removeTargetIdentifier() override; void importAction() override; void exportAction() override; void defaultAction() override; - bool hasConflicts() const override; - bool filterColumn(const QString &filterString, QTreeWidgetItem *item, int column) const override; private: void initialize(); - void handleKeyEvent(QKeyEvent *e); - void markCollisions(ShortcutItem *); + void handleCurrentCommandChanged(QTreeWidgetItem *current); + void resetToDefault(); + bool validateShortcutEdit() const; + bool markCollisions(ShortcutItem *); void setKeySequence(const QKeySequence &key); + void showConflicts(); void clear(); QList m_scitems; - int m_key[4], m_keyNum; + QGroupBox *m_shortcutBox; + Utils::FancyLineEdit *m_shortcutEdit; + QLabel *m_warningLabel; }; class ShortcutSettings : public IOptionsPage diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp index 902ffe83f04..c720324923c 100644 --- a/src/plugins/fakevim/fakevimplugin.cpp +++ b/src/plugins/fakevim/fakevimplugin.cpp @@ -544,25 +544,14 @@ class FakeVimExCommandsWidget : public CommandMappings Q_OBJECT public: - FakeVimExCommandsWidget(FakeVimPluginPrivate *q, QWidget *parent = 0) - : CommandMappings(parent), m_q(q) - { - setPageTitle(Tr::tr("Ex Command Mapping")); - setTargetHeader(Tr::tr("Ex Trigger Expression")); - setTargetLabelText(Tr::tr("Regular expression:")); - setTargetEditTitle(Tr::tr("Ex Command")); - targetEdit()->setPlaceholderText(QString()); - setImportExportEnabled(false); - initialize(); - } + FakeVimExCommandsWidget(FakeVimPluginPrivate *q, QWidget *parent = 0); protected: - void targetIdentifierChanged() override; - void resetTargetIdentifier() override; - void removeTargetIdentifier() override; + void commandChanged(); + void resetToDefault(); void defaultAction() override; - void commandChanged(QTreeWidgetItem *current) override; + void handleCurrentCommandChanged(QTreeWidgetItem *current); private: void initialize(); @@ -571,8 +560,41 @@ private: ExCommandMap &defaultExCommandMap(); FakeVimPluginPrivate *m_q; + QGroupBox *m_commandBox; + Utils::FancyLineEdit *m_commandEdit; }; +FakeVimExCommandsWidget::FakeVimExCommandsWidget(FakeVimPluginPrivate *q, QWidget *parent) + : CommandMappings(parent), m_q(q) +{ + setPageTitle(Tr::tr("Ex Command Mapping")); + setTargetHeader(Tr::tr("Ex Trigger Expression")); + setImportExportEnabled(false); + + connect(this, &FakeVimExCommandsWidget::currentCommandChanged, + this, &FakeVimExCommandsWidget::handleCurrentCommandChanged); + + m_commandBox = new QGroupBox(Tr::tr("Ex Command"), this); + m_commandBox->setEnabled(false); + auto boxLayout = new QHBoxLayout(m_commandBox); + m_commandEdit = new Utils::FancyLineEdit(m_commandBox); + m_commandEdit->setFiltering(true); + m_commandEdit->setPlaceholderText(QString()); + connect(m_commandEdit, &Utils::FancyLineEdit::textChanged, + this, &FakeVimExCommandsWidget::commandChanged); + auto resetButton = new QPushButton(Tr::tr("Reset"), m_commandBox); + resetButton->setToolTip(Tr::tr("Reset to default.")); + connect(resetButton, &QPushButton::clicked, + this, &FakeVimExCommandsWidget::resetToDefault); + boxLayout->addWidget(new QLabel(Tr::tr("Regular expression:"))); + boxLayout->addWidget(m_commandEdit); + boxLayout->addWidget(resetButton); + + layout()->addWidget(m_commandBox); + + initialize(); +} + class FakeVimExCommandsPage : public IOptionsPage { Q_OBJECT @@ -647,24 +669,28 @@ void FakeVimExCommandsWidget::initialize() setModified(item, true); } - commandChanged(0); + handleCurrentCommandChanged(0); } -void FakeVimExCommandsWidget::commandChanged(QTreeWidgetItem *current) +void FakeVimExCommandsWidget::handleCurrentCommandChanged(QTreeWidgetItem *current) { - CommandMappings::commandChanged(current); - if (current) - targetEdit()->setText(current->text(2)); + if (current) { + m_commandEdit->setText(current->text(2)); + m_commandBox->setEnabled(true); + } else { + m_commandEdit->clear(); + m_commandBox->setEnabled(false); + } } -void FakeVimExCommandsWidget::targetIdentifierChanged() +void FakeVimExCommandsWidget::commandChanged() { QTreeWidgetItem *current = commandList()->currentItem(); if (!current) return; const QString name = current->data(0, CommandRole).toString(); - const QString regex = targetEdit()->text(); + const QString regex = m_commandEdit->text(); if (current->data(0, Qt::UserRole).isValid()) { current->setText(2, regex); @@ -674,7 +700,7 @@ void FakeVimExCommandsWidget::targetIdentifierChanged() setModified(current, regex != defaultExCommandMap()[name].pattern()); } -void FakeVimExCommandsWidget::resetTargetIdentifier() +void FakeVimExCommandsWidget::resetToDefault() { QTreeWidgetItem *current = commandList()->currentItem(); if (!current) @@ -683,12 +709,7 @@ void FakeVimExCommandsWidget::resetTargetIdentifier() QString regex; if (defaultExCommandMap().contains(name)) regex = defaultExCommandMap()[name].pattern(); - targetEdit()->setText(regex); -} - -void FakeVimExCommandsWidget::removeTargetIdentifier() -{ - targetEdit()->clear(); + m_commandEdit->setText(regex); } void FakeVimExCommandsWidget::defaultAction() @@ -706,7 +727,7 @@ void FakeVimExCommandsWidget::defaultAction() setModified(item, false); item->setText(2, regex); if (item == commandList()->currentItem()) - commandChanged(item); + currentCommandChanged(item); } } }