forked from qt-creator/qt-creator
Make it possible to set more than one shortcut per action
Multiple shortcuts per action make it possible to configure friendlier behavior. E.g. on macOS decreasing/increasing font sizes, and deleting elements usually have two shortcuts each. But also custom configurations that assign a different key to a common function without removing the default can be useful. In this patch the functionality is still pretty much hidden from the user, even though there is a "secret" way to enter such multiple shortcuts in the settings dialog, by separating shortcuts with " | ". Task-number: QTCREATORBUG-72 Change-Id: I16bec0a71aaf4abf50335b0fd7da620c73b31777 Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
@@ -30,6 +30,7 @@
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/id.h>
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/fadingindicator.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
@@ -46,6 +47,7 @@ namespace {
|
||||
}
|
||||
|
||||
static const char kKeyboardSettingsKey[] = "KeyboardShortcuts";
|
||||
static const char kKeyboardSettingsKeyV2[] = "KeyboardShortcutsV2";
|
||||
|
||||
using namespace Core;
|
||||
using namespace Core::Internal;
|
||||
@@ -495,23 +497,51 @@ Action *ActionManagerPrivate::overridableAction(Id id)
|
||||
|
||||
void ActionManagerPrivate::readUserSettings(Id id, Action *cmd)
|
||||
{
|
||||
// TODO Settings V2 were introduced in Qt Creator 4.13, remove old settings at some point
|
||||
QSettings *settings = ICore::settings();
|
||||
settings->beginGroup(QLatin1String(kKeyboardSettingsKey));
|
||||
if (settings->contains(id.toString()))
|
||||
cmd->setKeySequence(QKeySequence(settings->value(id.toString()).toString()));
|
||||
// transfer from old settings if not done before
|
||||
const QString group = settings->childGroups().contains(kKeyboardSettingsKeyV2)
|
||||
? QString(kKeyboardSettingsKeyV2)
|
||||
: QString(kKeyboardSettingsKey);
|
||||
settings->beginGroup(group);
|
||||
if (settings->contains(id.toString())) {
|
||||
const QVariant v = settings->value(id.toString());
|
||||
if (QMetaType::Type(v.type()) == QMetaType::QStringList) {
|
||||
cmd->setKeySequences(Utils::transform<QList>(v.toStringList(), [](const QString &s) {
|
||||
return QKeySequence::fromString(s);
|
||||
}));
|
||||
} else {
|
||||
cmd->setKeySequences({QKeySequence::fromString(v.toString())});
|
||||
}
|
||||
}
|
||||
settings->endGroup();
|
||||
}
|
||||
|
||||
void ActionManagerPrivate::saveSettings(Action *cmd)
|
||||
{
|
||||
const QString settingsKey = QLatin1String(kKeyboardSettingsKey) + QLatin1Char('/')
|
||||
+ cmd->id().toString();
|
||||
QKeySequence key = cmd->keySequence();
|
||||
if (key != cmd->defaultKeySequence())
|
||||
ICore::settings()->setValue(settingsKey, key.toString());
|
||||
else
|
||||
const QString id = cmd->id().toString();
|
||||
const QString settingsKey = QLatin1String(kKeyboardSettingsKeyV2) + '/' + id;
|
||||
const QString compatSettingsKey = QLatin1String(kKeyboardSettingsKey) + '/' + id;
|
||||
const QList<QKeySequence> keys = cmd->keySequences();
|
||||
const QList<QKeySequence> defaultKeys = cmd->defaultKeySequences();
|
||||
if (keys != defaultKeys) {
|
||||
if (keys.isEmpty()) {
|
||||
ICore::settings()->setValue(settingsKey, QString());
|
||||
ICore::settings()->setValue(compatSettingsKey, QString());
|
||||
} else if (keys.size() == 1) {
|
||||
ICore::settings()->setValue(settingsKey, keys.first().toString());
|
||||
ICore::settings()->setValue(compatSettingsKey, keys.first().toString());
|
||||
} else {
|
||||
ICore::settings()->setValue(settingsKey,
|
||||
Utils::transform<QStringList>(keys,
|
||||
[](const QKeySequence &k) {
|
||||
return k.toString();
|
||||
}));
|
||||
}
|
||||
} else {
|
||||
ICore::settings()->remove(settingsKey);
|
||||
}
|
||||
}
|
||||
|
||||
void ActionManagerPrivate::saveSettings()
|
||||
{
|
||||
|
@@ -253,13 +253,20 @@ Id Action::id() const
|
||||
void Action::setDefaultKeySequence(const QKeySequence &key)
|
||||
{
|
||||
if (!m_isKeyInitialized)
|
||||
setKeySequence(key);
|
||||
m_defaultKey = key;
|
||||
setKeySequences({key});
|
||||
m_defaultKeys = {key};
|
||||
}
|
||||
|
||||
QKeySequence Action::defaultKeySequence() const
|
||||
void Action::setDefaultKeySequences(const QList<QKeySequence> &keys)
|
||||
{
|
||||
return m_defaultKey;
|
||||
if (!m_isKeyInitialized)
|
||||
setKeySequences(keys);
|
||||
m_defaultKeys = keys;
|
||||
}
|
||||
|
||||
QList<QKeySequence> Action::defaultKeySequences() const
|
||||
{
|
||||
return m_defaultKeys;
|
||||
}
|
||||
|
||||
QAction *Action::action() const
|
||||
@@ -277,13 +284,18 @@ Context Action::context() const
|
||||
return m_context;
|
||||
}
|
||||
|
||||
void Action::setKeySequence(const QKeySequence &key)
|
||||
void Action::setKeySequences(const QList<QKeySequence> &keys)
|
||||
{
|
||||
m_isKeyInitialized = true;
|
||||
m_action->setShortcut(key);
|
||||
m_action->setShortcuts(keys);
|
||||
emit keySequenceChanged();
|
||||
}
|
||||
|
||||
QList<QKeySequence> Action::keySequences() const
|
||||
{
|
||||
return m_action->shortcuts();
|
||||
}
|
||||
|
||||
QKeySequence Action::keySequence() const
|
||||
{
|
||||
return m_action->shortcut();
|
||||
|
@@ -58,7 +58,9 @@ public:
|
||||
Q_DECLARE_FLAGS(CommandAttributes, CommandAttribute)
|
||||
|
||||
virtual void setDefaultKeySequence(const QKeySequence &key) = 0;
|
||||
virtual QKeySequence defaultKeySequence() const = 0;
|
||||
virtual void setDefaultKeySequences(const QList<QKeySequence> &keys) = 0;
|
||||
virtual QList<QKeySequence> defaultKeySequences() const = 0;
|
||||
virtual QList<QKeySequence> keySequences() const = 0;
|
||||
virtual QKeySequence keySequence() const = 0;
|
||||
// explicitly set the description (used e.g. in shortcut settings)
|
||||
// default is to use the action text for actions, or the whatsThis for shortcuts,
|
||||
@@ -78,7 +80,7 @@ public:
|
||||
|
||||
virtual bool isActive() const = 0;
|
||||
|
||||
virtual void setKeySequence(const QKeySequence &key) = 0;
|
||||
virtual void setKeySequences(const QList<QKeySequence> &keys) = 0;
|
||||
virtual QString stringWithAppendedShortcut(const QString &str) const = 0;
|
||||
void augmentActionWithShortcutToolTip(QAction *action) const;
|
||||
static QToolButton *toolButtonWithAppendedShortcut(QAction *action, Command *cmd);
|
||||
|
@@ -52,9 +52,11 @@ public:
|
||||
Id id() const override;
|
||||
|
||||
void setDefaultKeySequence(const QKeySequence &key) override;
|
||||
QKeySequence defaultKeySequence() const override;
|
||||
void setDefaultKeySequences(const QList<QKeySequence> &key) override;
|
||||
QList<QKeySequence> defaultKeySequences() const override;
|
||||
|
||||
void setKeySequence(const QKeySequence &key) override;
|
||||
void setKeySequences(const QList<QKeySequence> &keys) override;
|
||||
QList<QKeySequence> keySequences() const override;
|
||||
QKeySequence keySequence() const override;
|
||||
|
||||
void setDescription(const QString &text) override;
|
||||
@@ -92,7 +94,7 @@ private:
|
||||
Context m_context;
|
||||
CommandAttributes m_attributes;
|
||||
Id m_id;
|
||||
QKeySequence m_defaultKey;
|
||||
QList<QKeySequence> m_defaultKeys;
|
||||
QString m_defaultText;
|
||||
QString m_touchBarText;
|
||||
QIcon m_touchBarIcon;
|
||||
|
@@ -83,9 +83,9 @@ CommandsFile::CommandsFile(const QString &filename)
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
QMap<QString, QKeySequence> CommandsFile::importCommands() const
|
||||
QMap<QString, QList<QKeySequence>> CommandsFile::importCommands() const
|
||||
{
|
||||
QMap<QString, QKeySequence> result;
|
||||
QMap<QString, QList<QKeySequence>> result;
|
||||
|
||||
QFile file(m_filename);
|
||||
if (!file.open(QIODevice::ReadOnly|QIODevice::Text))
|
||||
@@ -101,19 +101,17 @@ QMap<QString, QKeySequence> CommandsFile::importCommands() const
|
||||
case QXmlStreamReader::StartElement: {
|
||||
const QStringRef name = r.name();
|
||||
if (name == ctx.shortCutElement) {
|
||||
if (!currentId.isEmpty()) // shortcut element without key element == empty shortcut
|
||||
result.insert(currentId, QKeySequence());
|
||||
currentId = r.attributes().value(ctx.idAttribute).toString();
|
||||
if (!result.contains(currentId))
|
||||
result.insert(currentId, {});
|
||||
} else if (name == ctx.keyElement) {
|
||||
QTC_ASSERT(!currentId.isEmpty(), return result);
|
||||
QTC_ASSERT(!currentId.isEmpty(), continue);
|
||||
const QXmlStreamAttributes attributes = r.attributes();
|
||||
if (attributes.hasAttribute(ctx.valueAttribute)) {
|
||||
const QString keyString = attributes.value(ctx.valueAttribute).toString();
|
||||
result.insert(currentId, QKeySequence(keyString));
|
||||
} else {
|
||||
result.insert(currentId, QKeySequence());
|
||||
QList<QKeySequence> keys = result.value(currentId);
|
||||
result.insert(currentId, keys << QKeySequence(keyString));
|
||||
}
|
||||
currentId.clear();
|
||||
} // if key element
|
||||
} // case QXmlStreamReader::StartElement
|
||||
default:
|
||||
@@ -144,14 +142,16 @@ bool CommandsFile::exportCommands(const QList<ShortcutItem *> &items)
|
||||
w.writeStartElement(ctx.mappingElement);
|
||||
foreach (const ShortcutItem *item, items) {
|
||||
const Id id = item->m_cmd->id();
|
||||
if (item->m_key.isEmpty()) {
|
||||
if (item->m_keys.isEmpty() || item->m_keys.first().isEmpty()) {
|
||||
w.writeEmptyElement(ctx.shortCutElement);
|
||||
w.writeAttribute(ctx.idAttribute, id.toString());
|
||||
} else {
|
||||
w.writeStartElement(ctx.shortCutElement);
|
||||
w.writeAttribute(ctx.idAttribute, id.toString());
|
||||
for (const QKeySequence &k : item->m_keys) {
|
||||
w.writeEmptyElement(ctx.keyElement);
|
||||
w.writeAttribute(ctx.valueAttribute, item->m_key.toString());
|
||||
w.writeAttribute(ctx.valueAttribute, k.toString());
|
||||
}
|
||||
w.writeEndElement(); // Shortcut
|
||||
}
|
||||
}
|
||||
|
@@ -43,7 +43,7 @@ class CommandsFile : public QObject
|
||||
public:
|
||||
CommandsFile(const QString &filename);
|
||||
|
||||
QMap<QString, QKeySequence> importCommands() const;
|
||||
QMap<QString, QList<QKeySequence> > importCommands() const;
|
||||
bool exportCommands(const QList<ShortcutItem *> &items);
|
||||
|
||||
private:
|
||||
|
@@ -33,6 +33,7 @@
|
||||
#include <coreplugin/actionmanager/command_p.h>
|
||||
#include <coreplugin/actionmanager/commandsfile.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/fancylineedit.h>
|
||||
#include <utils/hostosinfo.h>
|
||||
#include <utils/qtcassert.h>
|
||||
@@ -50,6 +51,8 @@
|
||||
|
||||
Q_DECLARE_METATYPE(Core::Internal::ShortcutItem*)
|
||||
|
||||
const char kSeparator[] = " | ";
|
||||
|
||||
static int translateModifiers(Qt::KeyboardModifiers state,
|
||||
const QString &text)
|
||||
{
|
||||
@@ -82,9 +85,23 @@ static QString keySequenceToEditString(const QKeySequence &sequence)
|
||||
return text;
|
||||
}
|
||||
|
||||
static QString keySequencesToEditString(const QList<QKeySequence> &sequence)
|
||||
{
|
||||
return Utils::transform(sequence, keySequenceToEditString).join(kSeparator);
|
||||
}
|
||||
|
||||
static QString keySequencesToNativeString(const QList<QKeySequence> &sequence)
|
||||
{
|
||||
return Utils::transform(sequence,
|
||||
[](const QKeySequence &k) {
|
||||
return k.toString(QKeySequence::NativeText);
|
||||
})
|
||||
.join(kSeparator);
|
||||
}
|
||||
|
||||
static QKeySequence keySequenceFromEditString(const QString &editString)
|
||||
{
|
||||
QString text = editString;
|
||||
QString text = editString.trimmed();
|
||||
if (Utils::HostOsInfo::isMacHost()) {
|
||||
// adapt the modifier names
|
||||
text.replace(QLatin1String("Opt"), QLatin1String("Alt"), Qt::CaseInsensitive);
|
||||
@@ -94,6 +111,21 @@ static QKeySequence keySequenceFromEditString(const QString &editString)
|
||||
return QKeySequence::fromString(text, QKeySequence::PortableText);
|
||||
}
|
||||
|
||||
struct ParsedKey
|
||||
{
|
||||
QString text;
|
||||
QKeySequence key;
|
||||
};
|
||||
|
||||
static QList<ParsedKey> keySequencesFromEditString(const QString &editString)
|
||||
{
|
||||
if (editString.trimmed().isEmpty())
|
||||
return {};
|
||||
return Utils::transform(editString.split(kSeparator), [](const QString &str) {
|
||||
return ParsedKey{str, keySequenceFromEditString(str)};
|
||||
});
|
||||
}
|
||||
|
||||
static bool keySequenceIsValid(const QKeySequence &sequence)
|
||||
{
|
||||
if (sequence.isEmpty())
|
||||
@@ -242,7 +274,7 @@ private:
|
||||
void resetToDefault();
|
||||
bool validateShortcutEdit() const;
|
||||
bool markCollisions(ShortcutItem *);
|
||||
void setKeySequence(const QKeySequence &key);
|
||||
void setKeySequences(const QList<QKeySequence> &keys);
|
||||
void showConflicts();
|
||||
void clear();
|
||||
|
||||
@@ -292,8 +324,10 @@ ShortcutSettingsWidget::ShortcutSettingsWidget()
|
||||
"enter \"Ctrl+Shift+Escape,A\".")
|
||||
+ QLatin1String("</body></html>"));
|
||||
auto shortcutButton = new ShortcutButton(m_shortcutBox);
|
||||
connect(shortcutButton, &ShortcutButton::keySequenceChanged,
|
||||
this, &ShortcutSettingsWidget::setKeySequence);
|
||||
connect(shortcutButton,
|
||||
&ShortcutButton::keySequenceChanged,
|
||||
this,
|
||||
[this](const QKeySequence &k) { setKeySequences({k}); });
|
||||
auto resetButton = new QPushButton(tr("Reset"), m_shortcutBox);
|
||||
resetButton->setToolTip(tr("Reset to default."));
|
||||
connect(resetButton, &QPushButton::clicked,
|
||||
@@ -343,7 +377,7 @@ QWidget *ShortcutSettings::widget()
|
||||
void ShortcutSettingsWidget::apply()
|
||||
{
|
||||
foreach (ShortcutItem *item, m_scitems)
|
||||
item->m_cmd->setKeySequence(item->m_key);
|
||||
item->m_cmd->setKeySequences(item->m_keys);
|
||||
}
|
||||
|
||||
void ShortcutSettings::apply()
|
||||
@@ -372,12 +406,32 @@ void ShortcutSettingsWidget::handleCurrentCommandChanged(QTreeWidgetItem *curren
|
||||
m_warningLabel->clear();
|
||||
m_shortcutBox->setEnabled(false);
|
||||
} else {
|
||||
setKeySequence(scitem->m_key);
|
||||
setKeySequences(scitem->m_keys);
|
||||
markCollisions(scitem);
|
||||
m_shortcutBox->setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
static bool checkValidity(const QList<ParsedKey> &keys, QString *warningMessage)
|
||||
{
|
||||
QTC_ASSERT(warningMessage, return true);
|
||||
for (const ParsedKey &k : keys) {
|
||||
if (!keySequenceIsValid(k.key)) {
|
||||
*warningMessage = ShortcutSettingsWidget::tr("Invalid key sequence \"%1\".").arg(k.text);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (const ParsedKey &k : keys) {
|
||||
if (textKeySequence(k.key)) {
|
||||
*warningMessage = ShortcutSettingsWidget::tr(
|
||||
"Key sequence \"%1\" will not work in editor.")
|
||||
.arg(k.text);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ShortcutSettingsWidget::validateShortcutEdit() const
|
||||
{
|
||||
m_warningLabel->clear();
|
||||
@@ -385,43 +439,57 @@ bool ShortcutSettingsWidget::validateShortcutEdit() const
|
||||
ShortcutItem *item = shortcutItem(current);
|
||||
if (!item)
|
||||
return true;
|
||||
bool valid = false;
|
||||
|
||||
const QString text = m_shortcutEdit->text().trimmed();
|
||||
const QKeySequence currentKey = keySequenceFromEditString(text);
|
||||
const QList<ParsedKey> currentKeys = keySequencesFromEditString(text);
|
||||
QString warningMessage;
|
||||
bool isValid = checkValidity(currentKeys, &warningMessage);
|
||||
|
||||
if (keySequenceIsValid(currentKey) || text.isEmpty()) {
|
||||
item->m_key = currentKey;
|
||||
if (isValid) {
|
||||
item->m_keys = Utils::transform(currentKeys, &ParsedKey::key);
|
||||
auto that = const_cast<ShortcutSettingsWidget *>(this);
|
||||
if (item->m_cmd->defaultKeySequence() != item->m_key)
|
||||
if (item->m_keys != item->m_cmd->defaultKeySequences())
|
||||
that->setModified(current, true);
|
||||
else
|
||||
that->setModified(current, false);
|
||||
current->setText(2, item->m_key.toString(QKeySequence::NativeText));
|
||||
valid = !that->markCollisions(item);
|
||||
if (!valid) {
|
||||
current->setText(2, keySequencesToNativeString(item->m_keys));
|
||||
isValid = !that->markCollisions(item);
|
||||
if (!isValid) {
|
||||
m_warningLabel->setText(
|
||||
tr("Key sequence has potential conflicts. <a href=\"#conflicts\">Show.</a>"));
|
||||
} else if (textKeySequence(currentKey)) {
|
||||
m_warningLabel->setText(tr("Key sequence will not work in editor."));
|
||||
}
|
||||
} else {
|
||||
m_warningLabel->setText(m_warningLabel->text() + tr("Invalid key sequence."));
|
||||
}
|
||||
return valid;
|
||||
if (!warningMessage.isEmpty()) {
|
||||
if (m_warningLabel->text().isEmpty())
|
||||
m_warningLabel->setText(warningMessage);
|
||||
else
|
||||
m_warningLabel->setText(m_warningLabel->text() + " " + warningMessage);
|
||||
}
|
||||
return isValid;
|
||||
}
|
||||
|
||||
bool ShortcutSettingsWidget::filterColumn(const QString &filterString, QTreeWidgetItem *item,
|
||||
int column) const
|
||||
{
|
||||
QString text;
|
||||
ShortcutItem *scitem = shortcutItem(item);
|
||||
const ShortcutItem *scitem = shortcutItem(item);
|
||||
if (column == item->columnCount() - 1) { // shortcut
|
||||
// filter on the shortcut edit text
|
||||
if (!scitem)
|
||||
return true;
|
||||
text = keySequenceToEditString(scitem->m_key);
|
||||
} else if (column == 0 && scitem) { // command id
|
||||
const QStringList filters = Utils::transform(filterString.split(kSeparator),
|
||||
[](const QString &s) { return s.trimmed(); });
|
||||
for (const QKeySequence &k : scitem->m_keys) {
|
||||
const QString &keyString = keySequenceToEditString(k);
|
||||
const bool found = Utils::anyOf(filters, [keyString](const QString &f) {
|
||||
return keyString.contains(f, Qt::CaseInsensitive);
|
||||
});
|
||||
if (found)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
QString text;
|
||||
if (column == 0 && scitem) { // command id
|
||||
text = scitem->m_cmd->id().toString();
|
||||
} else {
|
||||
text = item->text(column);
|
||||
@@ -429,9 +497,9 @@ bool ShortcutSettingsWidget::filterColumn(const QString &filterString, QTreeWidg
|
||||
return !text.contains(filterString, Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
void ShortcutSettingsWidget::setKeySequence(const QKeySequence &key)
|
||||
void ShortcutSettingsWidget::setKeySequences(const QList<QKeySequence> &keys)
|
||||
{
|
||||
m_shortcutEdit->setText(keySequenceToEditString(key));
|
||||
m_shortcutEdit->setText(keySequencesToEditString(keys));
|
||||
}
|
||||
|
||||
void ShortcutSettingsWidget::showConflicts()
|
||||
@@ -439,7 +507,7 @@ void ShortcutSettingsWidget::showConflicts()
|
||||
QTreeWidgetItem *current = commandList()->currentItem();
|
||||
ShortcutItem *scitem = shortcutItem(current);
|
||||
if (scitem)
|
||||
setFilterText(keySequenceToEditString(scitem->m_key));
|
||||
setFilterText(keySequencesToEditString(scitem->m_keys));
|
||||
}
|
||||
|
||||
void ShortcutSettingsWidget::resetToDefault()
|
||||
@@ -447,7 +515,7 @@ void ShortcutSettingsWidget::resetToDefault()
|
||||
QTreeWidgetItem *current = commandList()->currentItem();
|
||||
ShortcutItem *scitem = shortcutItem(current);
|
||||
if (scitem) {
|
||||
setKeySequence(scitem->m_cmd->defaultKeySequence());
|
||||
setKeySequences(scitem->m_cmd->defaultKeySequences());
|
||||
foreach (ShortcutItem *item, m_scitems)
|
||||
markCollisions(item);
|
||||
}
|
||||
@@ -461,17 +529,16 @@ void ShortcutSettingsWidget::importAction()
|
||||
if (!fileName.isEmpty()) {
|
||||
|
||||
CommandsFile cf(fileName);
|
||||
QMap<QString, QKeySequence> mapping = cf.importCommands();
|
||||
|
||||
foreach (ShortcutItem *item, m_scitems) {
|
||||
QMap<QString, QList<QKeySequence>> mapping = cf.importCommands();
|
||||
for (ShortcutItem *item : qAsConst(m_scitems)) {
|
||||
QString sid = item->m_cmd->id().toString();
|
||||
if (mapping.contains(sid)) {
|
||||
item->m_key = mapping.value(sid);
|
||||
item->m_item->setText(2, item->m_key.toString(QKeySequence::NativeText));
|
||||
item->m_keys = mapping.value(sid);
|
||||
item->m_item->setText(2, keySequencesToNativeString(item->m_keys));
|
||||
if (item->m_item == commandList()->currentItem())
|
||||
emit currentCommandChanged(item->m_item);
|
||||
|
||||
if (item->m_cmd->defaultKeySequence() != item->m_key)
|
||||
if (item->m_keys != item->m_cmd->defaultKeySequences())
|
||||
setModified(item->m_item, true);
|
||||
else
|
||||
setModified(item->m_item, false);
|
||||
@@ -486,8 +553,8 @@ void ShortcutSettingsWidget::importAction()
|
||||
void ShortcutSettingsWidget::defaultAction()
|
||||
{
|
||||
foreach (ShortcutItem *item, m_scitems) {
|
||||
item->m_key = item->m_cmd->defaultKeySequence();
|
||||
item->m_item->setText(2, item->m_key.toString(QKeySequence::NativeText));
|
||||
item->m_keys = item->m_cmd->defaultKeySequences();
|
||||
item->m_item->setText(2, keySequencesToNativeString(item->m_keys));
|
||||
setModified(item->m_item, false);
|
||||
if (item->m_item == commandList()->currentItem())
|
||||
emit currentCommandChanged(item->m_item);
|
||||
@@ -551,11 +618,11 @@ void ShortcutSettingsWidget::initialize()
|
||||
}
|
||||
sections[section]->addChild(item);
|
||||
|
||||
s->m_key = c->keySequence();
|
||||
s->m_keys = c->keySequences();
|
||||
item->setText(0, subId);
|
||||
item->setText(1, c->description());
|
||||
item->setText(2, s->m_key.toString(QKeySequence::NativeText));
|
||||
if (s->m_cmd->defaultKeySequence() != s->m_key)
|
||||
item->setText(2, keySequencesToNativeString(s->m_keys));
|
||||
if (s->m_keys != s->m_cmd->defaultKeySequences())
|
||||
setModified(item, true);
|
||||
|
||||
item->setData(0, Qt::UserRole, QVariant::fromValue(s));
|
||||
@@ -568,33 +635,40 @@ void ShortcutSettingsWidget::initialize()
|
||||
bool ShortcutSettingsWidget::markCollisions(ShortcutItem *item)
|
||||
{
|
||||
bool hasCollision = false;
|
||||
if (!item->m_key.isEmpty()) {
|
||||
if (!item->m_keys.isEmpty()) {
|
||||
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)
|
||||
for (ShortcutItem *currentItem : qAsConst(m_scitems)) {
|
||||
if (item == currentItem)
|
||||
continue;
|
||||
const bool containsSameShortcut = Utils::anyOf(currentItem->m_keys,
|
||||
[item](const QKeySequence &k) {
|
||||
return item->m_keys.contains(k);
|
||||
});
|
||||
if (!containsSameShortcut)
|
||||
continue;
|
||||
// check if contexts might conflict
|
||||
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)) {
|
||||
for (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));
|
||||
currentItem->m_item->setForeground(2,
|
||||
Utils::creatorTheme()->color(
|
||||
Utils::Theme::TextColorError));
|
||||
hasCollision = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
item->m_item->setForeground(2, hasCollision
|
||||
item->m_item->setForeground(2,
|
||||
hasCollision
|
||||
? Utils::creatorTheme()->color(Utils::Theme::TextColorError)
|
||||
: commandList()->palette().windowText());
|
||||
return hasCollision;
|
||||
|
@@ -51,7 +51,7 @@ class ShortcutSettingsWidget;
|
||||
struct ShortcutItem
|
||||
{
|
||||
Command *m_cmd;
|
||||
QKeySequence m_key;
|
||||
QList<QKeySequence> m_keys;
|
||||
QTreeWidgetItem *m_item;
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user