fixed duplicate actions on shortcuts form

This commit is contained in:
Igor Korsukov 2021-12-13 13:29:45 +02:00
parent 7bf63bb7e5
commit ac527a28d8
14 changed files with 148 additions and 72 deletions

View file

@ -46,6 +46,20 @@ void mu::strings::split(const std::string& str, std::vector<std::string>& out, c
out.push_back(str.substr(previous, current - previous));
}
std::string mu::strings::join(const std::vector<std::string>& strs, const std::string& sep)
{
std::string str;
bool first = true;
for (const std::string& s : strs) {
if (!first) {
str += sep;
}
first = false;
str += s;
}
return str;
}
void mu::strings::ltrim(std::string& s)
{
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {

View file

@ -29,6 +29,7 @@
namespace mu::strings {
bool replace(std::string& source, const std::string& what, const std::string& to);
void split(const std::string& str, std::vector<std::string>& out, const std::string& delim);
std::string join(const std::vector<std::string>& strs, const std::string& sep = ",");
void ltrim(std::string& s);
void rtrim(std::string& s);

View file

@ -60,12 +60,14 @@ void ShortcutsInstanceModel::loadShortcuts()
const ShortcutList& shortcuts = shortcutsRegister()->shortcuts();
for (const Shortcut& sc : shortcuts) {
QString sequence = QString::fromStdString(sc.sequence);
for (const std::string& seq : sc.sequences) {
QString sequence = QString::fromStdString(seq);
//! NOTE There may be several identical shortcuts for different contexts.
//! We only need a list of unique ones.
if (!m_shortcuts.contains(sequence)) {
m_shortcuts << sequence;
//! NOTE There may be several identical shortcuts for different contexts.
//! We only need a list of unique ones.
if (!m_shortcuts.contains(sequence)) {
m_shortcuts << sequence;
}
}
}

View file

@ -23,12 +23,12 @@
#include <QKeySequence>
#include "log.h"
#include "global/xmlreader.h"
#include "global/xmlwriter.h"
#include "multiinstances/resourcelockguard.h"
#include "log.h"
using namespace mu::shortcuts;
using namespace mu::framework;
using namespace mu::async;
@ -54,6 +54,8 @@ static const Shortcut& findShortcut(const ShortcutList& shortcuts, const std::st
void ShortcutsRegister::reload(bool onlyDef)
{
TRACEFUNC;
m_shortcuts.clear();
m_defaultShortcuts.clear();
@ -82,13 +84,15 @@ void ShortcutsRegister::reload(bool onlyDef)
if (ok) {
expandStandardKeys(m_shortcuts);
makeUnique(m_shortcuts);
m_shortcutsChanged.notify();
}
}
void ShortcutsRegister::mergeShortcuts(ShortcutList& shortcuts, const ShortcutList& defaultShortcuts) const
{
TRACEFUNC;
ShortcutList needadd;
for (const Shortcut& defSc : defaultShortcuts) {
auto it = std::find_if(shortcuts.begin(), shortcuts.end(), [defSc](const Shortcut& i) {
@ -110,13 +114,42 @@ void ShortcutsRegister::mergeShortcuts(ShortcutList& shortcuts, const ShortcutLi
}
}
void ShortcutsRegister::makeUnique(ShortcutList& shortcuts)
{
TRACEFUNC;
const ShortcutList all = shortcuts;
shortcuts.clear();
for (const Shortcut& sc : all) {
const std::string& action = sc.action;
auto it = std::find_if(shortcuts.begin(), shortcuts.end(), [action](const Shortcut& s) {
return s.action == action;
});
if (it == shortcuts.end()) {
shortcuts.push_back(sc);
continue;
}
IF_ASSERT_FAILED(it->context == sc.context) {
}
it->sequences.insert(it->sequences.end(), sc.sequences.begin(), sc.sequences.end());
}
}
void ShortcutsRegister::expandStandardKeys(ShortcutList& shortcuts) const
{
TRACEFUNC;
ShortcutList expanded;
ShortcutList notbonded;
for (Shortcut& shortcut : shortcuts) {
if (!shortcut.sequence.empty()) {
if (!shortcut.sequences.empty()) {
continue;
}
@ -128,7 +161,7 @@ void ShortcutsRegister::expandStandardKeys(ShortcutList& shortcuts) const
}
const QKeySequence& first = kslist.first();
shortcut.sequence = first.toString().toStdString();
shortcut.sequences.push_back(first.toString().toStdString());
//LOGD() << "for standard key: " << sc.standardKey << ", sequence: " << sc.sequence;
//! NOTE If the keyBindings contains more than one result,
@ -136,7 +169,7 @@ void ShortcutsRegister::expandStandardKeys(ShortcutList& shortcuts) const
for (int i = 1; i < kslist.count(); ++i) {
const QKeySequence& seq = kslist.at(i);
Shortcut esc = shortcut;
esc.sequence = seq.toString().toStdString();
esc.sequences.push_back(seq.toString().toStdString());
//LOGD() << "for standard key: " << esc.standardKey << ", alternative sequence: " << esc.sequence;
expanded.push_back(esc);
}
@ -175,15 +208,7 @@ bool ShortcutsRegister::readFromFile(ShortcutList& shortcuts, const io::path& pa
Shortcut shortcut = readShortcut(reader);
if (shortcut.isValid()) {
if (shortcut.sequence.empty()) {
shortcuts.push_back(shortcut);
} else {
auto seqList = QString::fromStdString(shortcut.sequence).split("\n", Qt::SkipEmptyParts);
for (QString seq : seqList) {
shortcut.sequence = seq.toStdString();
shortcuts.push_back(shortcut);
}
}
shortcuts.push_back(shortcut);
}
}
@ -206,7 +231,7 @@ Shortcut ShortcutsRegister::readShortcut(framework::XmlReader& reader) const
} else if (tag == STANDARD_KEY_TAG) {
shortcut.standardKey = QKeySequence::StandardKey(reader.readInt());
} else if (tag == SEQUENCE_TAG) {
shortcut.sequence += reader.readString() + "\n";
shortcut.sequences.push_back(reader.readString());
} else if (tag == CONTEXT_TAG) {
shortcut.context = reader.readString();
} else {
@ -228,6 +253,8 @@ const ShortcutList& ShortcutsRegister::shortcuts() const
mu::Ret ShortcutsRegister::setShortcuts(const ShortcutList& shortcuts)
{
TRACEFUNC;
if (shortcuts == m_shortcuts) {
return true;
}
@ -273,7 +300,10 @@ void ShortcutsRegister::writeShortcut(framework::XmlWriter& writer, const Shortc
writer.writeTextElement(STANDARD_KEY_TAG, QString("%1").arg(shortcut.standardKey).toStdString());
}
writer.writeTextElement(SEQUENCE_TAG, shortcut.sequence);
for (const std::string& seq : shortcut.sequences) {
writer.writeTextElement(SEQUENCE_TAG, seq);
}
writer.writeEndElement();
}
@ -295,7 +325,8 @@ const Shortcut& ShortcutsRegister::defaultShortcut(const std::string& actionCode
bool ShortcutsRegister::isRegistered(const std::string& sequence) const
{
for (const Shortcut& sh : m_shortcuts) {
if (sh.sequence == sequence) {
auto it = std::find(sh.sequences.cbegin(), sh.sequences.cend(), sequence);
if (it != sh.sequences.cend()) {
return true;
}
}
@ -306,7 +337,8 @@ ShortcutList ShortcutsRegister::shortcutsForSequence(const std::string& sequence
{
ShortcutList list;
for (const Shortcut& sh : m_shortcuts) {
if (sh.sequence == sequence) {
auto it = std::find(sh.sequences.cbegin(), sh.sequences.cend(), sequence);
if (it != sh.sequences.cend()) {
list.push_back(sh);
}
}

View file

@ -72,6 +72,7 @@ private:
void writeShortcut(framework::XmlWriter& writer, const Shortcut& shortcut) const;
void mergeShortcuts(ShortcutList& shortcuts, const ShortcutList& defaultShortcuts) const;
void makeUnique(ShortcutList& shortcuts);
void expandStandardKeys(ShortcutList& shortcuts) const;
ShortcutList m_shortcuts;

View file

@ -26,13 +26,14 @@
#include <list>
#include <QKeySequence>
#include "stringutils.h"
#include "midi/midievent.h"
namespace mu::shortcuts {
struct Shortcut
{
std::string action;
std::string sequence;
std::vector<std::string> sequences;
std::string context;
QKeySequence::StandardKey standardKey = QKeySequence::UnknownKey;
@ -42,12 +43,26 @@ struct Shortcut
bool isValid() const
{
return !action.empty() && (!sequence.empty() || standardKey != QKeySequence::UnknownKey);
return !action.empty() && (!sequences.empty() || standardKey != QKeySequence::UnknownKey);
}
bool operator ==(const Shortcut& sc) const
{
return action == sc.action && sequence == sc.sequence && standardKey == sc.standardKey;
return action == sc.action && sequences == sc.sequences && standardKey == sc.standardKey;
}
std::string sequencesAsString() const { return sequencesToString(sequences); }
static std::string sequencesToString(const std::vector<std::string>& seqs)
{
return strings::join(seqs, "; ");
}
static std::vector<std::string> sequencesFromString(const std::string& str)
{
std::vector<std::string> seqs;
strings::split(str, seqs, "; ");
return seqs;
}
};

View file

@ -132,5 +132,5 @@ QString EditShortcutModel::unitedSequence() const
inputedSequence()
};
return sequences.join(", ");
return sequences.join("; ");
}

View file

@ -46,15 +46,12 @@ QVariant ShortcutsModel::data(const QModelIndex& index, int role) const
}
Shortcut shortcut = m_shortcuts[index.row()];
QString sequence = QString::fromStdString(shortcut.sequence);
const UiAction& action = this->action(shortcut.action);
QString title = action.title;
switch (role) {
case RoleTitle: return title;
case RoleIcon: return static_cast<int>(action.iconCode);
case RoleSequence: return sequence;
case RoleSearchKey: return title + sequence;
case RoleTitle: return this->action(shortcut.action).title;
case RoleIcon: return static_cast<int>(this->action(shortcut.action).iconCode);
case RoleSequence: return QString::fromStdString(shortcut.sequencesAsString());
case RoleSearchKey: return this->action(shortcut.action).title + QString::fromStdString(shortcut.sequencesAsString());
}
return QVariant();
@ -139,7 +136,7 @@ QString ShortcutsModel::currentSequence() const
QModelIndex index = currentShortcutIndex();
if (index.isValid()) {
return QString::fromStdString(m_shortcuts[index.row()].sequence);
return QString::fromStdString(m_shortcuts[index.row()].sequencesAsString());
}
return QString();
@ -201,7 +198,7 @@ void ShortcutsModel::applySequenceToCurrentShortcut(const QString& newSequence)
}
int row = index.row();
m_shortcuts[row].sequence = newSequence.toStdString();
m_shortcuts[row].sequences = Shortcut::sequencesFromString(newSequence.toStdString());
notifyAboutShortcutChanged(index);
}
@ -210,7 +207,7 @@ void ShortcutsModel::clearSelectedShortcuts()
{
for (const QModelIndex& index : m_selection.indexes()) {
Shortcut& shortcut = m_shortcuts[index.row()];
shortcut.sequence.clear();
shortcut.sequences.clear();
shortcut.standardKey = QKeySequence::StandardKey::UnknownKey;
notifyAboutShortcutChanged(index);
@ -239,7 +236,7 @@ QVariantList ShortcutsModel::shortcuts() const
for (const Shortcut& shortcut: m_shortcuts) {
QVariantMap obj;
obj["title"] = actionTitle(shortcut.action);
obj["sequence"] = QString::fromStdString(shortcut.sequence);
obj["sequence"] = QString::fromStdString(shortcut.sequencesAsString());
result << obj;
}

View file

@ -110,7 +110,7 @@ void UiActionsRegister::updateShortcuts()
auto screg = shortcutsRegister();
for (auto it = m_actions.begin(); it != m_actions.end(); ++it) {
Info& inf = it->second;
inf.action.shortcut = screg->shortcut(inf.action.code).sequence;
inf.action.shortcuts = screg->shortcut(inf.action.code).sequences;
}
}

View file

@ -175,7 +175,7 @@ struct UiAction
QString description;
IconCode::Code iconCode = IconCode::Code::NONE;
Checkable checkable = Checkable::No;
std::string shortcut;
std::vector<std::string> shortcuts;
UiAction() = default;
UiAction(const actions::ActionCode& code, UiContext ctx, Checkable ch = Checkable::No)
@ -280,6 +280,15 @@ struct MenuItem : public UiAction
id = QString::fromStdString(a.code);
}
QString shortcutsAsString() const
{
QStringList list;
for (const std::string& sc : shortcuts) {
list << QString::fromStdString(sc);
}
return list.join("; ");
}
QVariantMap toMap() const
{
QVariantList subitemsVariantList;
@ -290,7 +299,7 @@ struct MenuItem : public UiAction
return {
{ "id", id },
{ "code", QString::fromStdString(code) },
{ "shortcut", QString::fromStdString(shortcut) },
{ "shortcut", shortcutsAsString() },
{ "title", title },
{ "description", description },
{ "section", section },

View file

@ -55,10 +55,11 @@ bool TextInputFieldModel::isShortcutAllowedOverride(int key, Qt::KeyboardModifie
QKeySequence keySequence(newModifiers + newKey);
for (const Shortcut& shortcut : m_notAllowedForOverrideShortcuts) {
QKeySequence shortcutSequence(QString::fromStdString(shortcut.sequence));
if (shortcutSequence == keySequence) {
return false;
for (const std::string& seq : shortcut.sequences) {
QKeySequence shortcutSequence(QString::fromStdString(seq));
if (shortcutSequence == keySequence) {
return false;
}
}
}

View file

@ -1179,7 +1179,7 @@ const UiActionList NotationUiActions::m_actions = {
),
UiAction("enh-current",
mu::context::UiCtxNotationOpened,
QT_TRANSLATE_NOOP("action", "Change enharmonic spelling (both modes)"),
QT_TRANSLATE_NOOP("action", "Change enharmonic spelling (current mode)"),
QT_TRANSLATE_NOOP("action", "Change enharmonic spelling (current mode)"),
IconCode::Code::NONE
),
@ -1390,68 +1390,68 @@ const UiActionList NotationUiActions::m_actions = {
),
UiAction("pad-note-1-TAB",
mu::context::UiCtxNotationOpened,
QT_TRANSLATE_NOOP("action", "Whole note"),
QT_TRANSLATE_NOOP("action", "Note duration: whole note"),
QT_TRANSLATE_NOOP("action", "Whole note (TAB)"),
QT_TRANSLATE_NOOP("action", "Note duration: whole note (TAB)"),
IconCode::Code::NOTE_WHOLE
),
UiAction("pad-note-2-TAB",
mu::context::UiCtxNotationOpened,
QT_TRANSLATE_NOOP("action", "Half note"),
QT_TRANSLATE_NOOP("action", "Note duration: half note"),
QT_TRANSLATE_NOOP("action", "Half note (TAB)"),
QT_TRANSLATE_NOOP("action", "Note duration: half note (TAB)"),
IconCode::Code::NOTE_HALF
),
UiAction("pad-note-4-TAB",
mu::context::UiCtxNotationOpened,
QT_TRANSLATE_NOOP("action", "Quarter note"),
QT_TRANSLATE_NOOP("action", "Note duration: quarter note"),
QT_TRANSLATE_NOOP("action", "Quarter note (TAB)"),
QT_TRANSLATE_NOOP("action", "Note duration: quarter note (TAB)"),
IconCode::Code::NOTE_QUARTER
),
UiAction("pad-note-8-TAB",
mu::context::UiCtxNotationOpened,
QT_TRANSLATE_NOOP("action", "8th note"),
QT_TRANSLATE_NOOP("action", "Note duration: 8th note"),
QT_TRANSLATE_NOOP("action", "8th note (TAB)"),
QT_TRANSLATE_NOOP("action", "Note duration: 8th note (TAB)"),
IconCode::Code::NOTE_8TH
),
UiAction("pad-note-16-TAB",
mu::context::UiCtxNotationOpened,
QT_TRANSLATE_NOOP("action", "16th note"),
QT_TRANSLATE_NOOP("action", "Note duration: 16th note"),
QT_TRANSLATE_NOOP("action", "16th note (TAB)"),
QT_TRANSLATE_NOOP("action", "Note duration: 16th note (TAB)"),
IconCode::Code::NOTE_16TH
),
UiAction("pad-note-32-TAB",
mu::context::UiCtxNotationOpened,
QT_TRANSLATE_NOOP("action", "32nd note"),
QT_TRANSLATE_NOOP("action", "Note duration: 32nd note"),
QT_TRANSLATE_NOOP("action", "32nd note (TAB)"),
QT_TRANSLATE_NOOP("action", "Note duration: 32nd note (TAB)"),
IconCode::Code::NOTE_32ND
),
UiAction("pad-note-64-TAB",
mu::context::UiCtxNotationOpened,
QT_TRANSLATE_NOOP("action", "64th note"),
QT_TRANSLATE_NOOP("action", "Note duration: 64th note"),
QT_TRANSLATE_NOOP("action", "64th note (TAB)"),
QT_TRANSLATE_NOOP("action", "Note duration: 64th note (TAB)"),
IconCode::Code::NOTE_64TH
),
UiAction("pad-note-128-TAB",
mu::context::UiCtxNotationOpened,
QT_TRANSLATE_NOOP("action", "128th note"),
QT_TRANSLATE_NOOP("action", "Note duration: 128th note"),
QT_TRANSLATE_NOOP("action", "128th note (TAB)"),
QT_TRANSLATE_NOOP("action", "Note duration: 128th note (TAB)"),
IconCode::Code::NOTE_128TH
),
UiAction("pad-note-256-TAB",
mu::context::UiCtxNotationOpened,
QT_TRANSLATE_NOOP("action", "256th note"),
QT_TRANSLATE_NOOP("action", "Note duration: 256th note"),
QT_TRANSLATE_NOOP("action", "256th note (TAB)"),
QT_TRANSLATE_NOOP("action", "Note duration: 256th note (TAB)"),
IconCode::Code::NOTE_256TH
),
UiAction("pad-note-512-TAB",
mu::context::UiCtxNotationOpened,
QT_TRANSLATE_NOOP("action", "512th note"),
QT_TRANSLATE_NOOP("action", "Note duration: 512th note"),
QT_TRANSLATE_NOOP("action", "512th note (TAB)"),
QT_TRANSLATE_NOOP("action", "Note duration: 512th note (TAB)"),
IconCode::Code::NOTE_512TH
),
UiAction("pad-note-1024-TAB",
mu::context::UiCtxNotationOpened,
QT_TRANSLATE_NOOP("action", "1024th note"),
QT_TRANSLATE_NOOP("action", "Note duration: 1024th note"),
QT_TRANSLATE_NOOP("action", "1024th note (TAB)"),
QT_TRANSLATE_NOOP("action", "Note duration: 1024th note (TAB)"),
IconCode::Code::NOTE_1024TH
)
};

View file

@ -53,7 +53,7 @@ QVariant NotationToolBarModel::data(const QModelIndex& index, int role) const
case IconRole: return static_cast<int>(item.iconCode);
case EnabledRole: return item.state.enabled;
case DescriptionRole: return item.description;
case ShortcutRole: return QString::fromStdString(item.shortcut);
case ShortcutRole: return item.shortcutsAsString();
}
return QVariant();

View file

@ -21,7 +21,11 @@
*/
#include "templatepaintview.h"
#include "stringutils.h"
#include "notation/imasternotation.h"
#include "log.h"
using namespace mu::project;
@ -51,13 +55,13 @@ void TemplatePaintView::load(const QString& templatePath)
QString TemplatePaintView::zoomInSequence() const
{
shortcuts::Shortcut shortcut = shortcutsRegister()->shortcut("zoomin");
return QString::fromStdString(shortcut.sequence);
return QString::fromStdString(shortcut.sequencesAsString());
}
QString TemplatePaintView::zoomOutSequence() const
{
shortcuts::Shortcut shortcut = shortcutsRegister()->shortcut("zoomout");
return QString::fromStdString(shortcut.sequence);
return QString::fromStdString(shortcut.sequencesAsString());
}
void TemplatePaintView::adjustCanvas()