From 9f6dff2ed969ed9e5a18ae6a5073c1d2137cd3de Mon Sep 17 00:00:00 2001 From: "Maurizio M. Gavioli" Date: Sat, 27 Apr 2013 00:42:55 +0200 Subject: [PATCH 1/3] Fix #20826 - Numpad numbers no longer work to select note duration. Fixed by blocking the creation (and pooling) of QAction creation for shortcuts with multiple alternatives in different states (like the 'common' and TAB-specific variants of "pad-note-..." shortcuts) A rather detailed description of the implementation (regarding both the original, faulty, implementation and this fix) has been added to the mscore/shortcut.h file --- mscore/musescore.cpp | 3 ++- mscore/shortcut.cpp | 3 +++ mscore/shortcut.h | 48 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/mscore/musescore.cpp b/mscore/musescore.cpp index c67cbfafef780..c3e427602b26f 100644 --- a/mscore/musescore.cpp +++ b/mscore/musescore.cpp @@ -491,7 +491,8 @@ MuseScore::MuseScore() ag->setExclusive(false); foreach(const Shortcut* s, Shortcut::shortcuts()) { QAction* a = s->action(); - ag->addAction(a); + if (a) + ag->addAction(a); } addActions(ag->actions()); connect(ag, SIGNAL(triggered(QAction*)), SLOT(cmd(QAction*))); diff --git a/mscore/shortcut.cpp b/mscore/shortcut.cpp index c6365d0b48808..0e0cfcacf6165 100644 --- a/mscore/shortcut.cpp +++ b/mscore/shortcut.cpp @@ -235,6 +235,9 @@ QAction* Shortcut::action() const if (_action) return _action; + if (_state == STATE_NEVER) + return 0; + _action = new QAction(_text, 0); _action->setData(_key); diff --git a/mscore/shortcut.h b/mscore/shortcut.h index 868f7404344ce..0f1f51bb79ef7 100644 --- a/mscore/shortcut.h +++ b/mscore/shortcut.h @@ -14,6 +14,54 @@ #ifndef __SHORTCUT_H__ #define __SHORTCUT_H__ +/*--------------------------------------------------------- +NOTE ON ARCHITECTURE + +The Shortcut class describes the basic configurable shortcut element. +'Real' data are contained in 2 static member variables: + +1) sc[], an array of Shortcut: contains the default, built-in data for each shortcut + except the key sequences; it is initialized at startup (code at the begining of + mscore/actions.cpp) +2) _shortcuts, a QMap using the shortcut xml tag name as hash value: is initialized from + data in sc via a call to Shortcut::init() in program main() (mscore/musescore.cpp). + This also load actual key sequences either from an external, hard-coded, file with + user customizations or from a resource (<= mscore/data/shortcuts.xml), if there are + no customizations. + Later during startup, QAction's are derived from each of its elements and pooled + in a single QActionGroup during MuseScore::MuseScore() costructor (mscore/musescore.cpp) + +ShortcutFlags: + To be documented + +State flags: + +Defined in mscore/global.h (ScoreState enum): each shortcut is ignored if its _flags mask +does not include the current score state. This is different from (and additional to) +QAction processing performed by the Qt framework and happens only after the action has +been forwarded to the application (the action must be enabled). + +The STATE_NEVER requires an explanation. It has been introduced to mark shortcuts +which need to be recorded (and possibly customized) but are never used directly. +Currently, this applies to a number of shortcuts which: +- have been split between a common and a TAB-specific variant AND +- are linked to tool bar buttons or menu items +If QAction's are created for both, Qt blocks either as duplicate; in addition, the button +or menu item may become disabled on state change. The currently implemented solution is +to create a QAction only for one of them (the common one) and swap the key sequences when +entering or leaving the relevant state. +Swapping is implemented in MuseScore::changeState() (mscore/musescore.cpp). +QAction creation for the 'other' shortcut is blocked in Shortcut::action() (mscore/shortcut.cpp). + +This means that Shortcut::action() may return 0. When scanning the whole +shortcuts[] array, this has to be taken into account; currently it happens in two +cases: +- in MuseScore::MuseScore() constructor (mscore/musescore.cpp) +- in MuseScore::changeState() method (mscore/musescore.cpp) + +Shortcuts marked with the STATE_NEVER state should NEVER used directly as shortcuts! +---------------------------------------------------------*/ + class Xml; class XmlReader; From 34bfcf5265cfc8fc69d98d3edce17626c25f7d99 Mon Sep 17 00:00:00 2001 From: "Maurizio M. Gavioli" Date: Sat, 27 Apr 2013 23:53:45 +0200 Subject: [PATCH 2/3] Fix crash when displaying shortcut preferences --- mscore/shortcut.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/mscore/shortcut.cpp b/mscore/shortcut.cpp index 0e0cfcacf6165..3f28c500c4592 100644 --- a/mscore/shortcut.cpp +++ b/mscore/shortcut.cpp @@ -290,13 +290,11 @@ void Shortcut::addShortcut(const QKeySequence& ks) QString Shortcut::keysToString() const { - QAction* a = action(); - QList kl = a->shortcuts(); QString s; - for (int i = 0; i < kl.size(); ++i) { + for (int i = 0; i < _keys.size(); ++i) { if (i) s += "; "; - s += kl[i].toString(QKeySequence::NativeText); + s += _keys[i].toString(QKeySequence::NativeText); } return s; } From cd40022a3ef6537f86563b64d5bc72cf924dc0b5 Mon Sep 17 00:00:00 2001 From: "Maurizio M. Gavioli" Date: Mon, 29 Apr 2013 01:32:13 +0200 Subject: [PATCH 3/3] Add support for "NumPad" qualifier in textual representations of key sequences both in dlg boxes and in xml files. Also allows to remove the tag from shortcuts.xml --- mscore/data/shortcuts.xml | 20 +++++----- mscore/shortcut.cpp | 66 +++++++++++++++++++++++++++++--- mscore/shortcut.h | 5 +++ mscore/shortcutcapturedialog.cpp | 9 +++-- 4 files changed, 81 insertions(+), 19 deletions(-) diff --git a/mscore/data/shortcuts.xml b/mscore/data/shortcuts.xml index f6153ad67a646..58a855282d512 100644 --- a/mscore/data/shortcuts.xml +++ b/mscore/data/shortcuts.xml @@ -752,52 +752,52 @@ note-longa-TAB Shift+9 - 536870969 + NumPad+9 note-breve-TAB Shift+8 - 536870968 + NumPad+8 pad-note-1-TAB Shift+7 - 536870967 + NumPad+7 pad-note-2-TAB Shift+6 - 536870966 + NumPad+6 pad-note-4-TAB Shift+5 - 536870965 + NumPad+5 pad-note-8-TAB Shift+4 - 536870964 + NumPad+4 pad-note-16-TAB Shift+3 - 536870963 + NumPad+3 pad-note-32-TAB Shift+2 - 536870962 + NumPad+1 pad-note-64-TAB Shift+1 - 536870961 + NumPad+1 pad-note-128-TAB Shift+0 - 536870960 + NumPad+0 pad-note-increase-TAB diff --git a/mscore/shortcut.cpp b/mscore/shortcut.cpp index 3f28c500c4592..ce40afbe66552 100644 --- a/mscore/shortcut.cpp +++ b/mscore/shortcut.cpp @@ -262,7 +262,8 @@ QAction* Shortcut::action() const for (int i = 0; i < kl.size(); ++i) { if (i) s += ","; - s += kl[i].toString(QKeySequence::NativeText); +// s += kl[i].toString(QKeySequence::NativeText); + s += Shortcut::keySeqToString(kl[i], QKeySequence::NativeText); } s += ")"; _action->setToolTip(s); @@ -294,7 +295,7 @@ QString Shortcut::keysToString() const for (int i = 0; i < _keys.size(); ++i) { if (i) s += "; "; - s += _keys[i].toString(QKeySequence::NativeText); + s += Shortcut::keySeqToString(_keys[i], QKeySequence::NativeText); } return s; } @@ -368,7 +369,8 @@ void Shortcut::write(Xml& xml) const if (_standardKey != QKeySequence::UnknownKey) xml.tag("std", QString("%1").arg(_standardKey)); foreach(QKeySequence ks, _keys) - xml.tag("seq", ks.toString(QKeySequence::PortableText)); +// xml.tag("seq", ks.toString(QKeySequence::PortableText)); + xml.tag("seq", Shortcut::keySeqToString(ks, QKeySequence::PortableText)); xml.etag(); } @@ -385,7 +387,8 @@ void Shortcut::read(XmlReader& e) else if (tag == "std") _standardKey = QKeySequence::StandardKey(e.readInt()); else if (tag == "seq") - _keys.append(QKeySequence::fromString(e.readElementText(), QKeySequence::PortableText)); +// _keys.append(QKeySequence::fromString(e.readElementText(), QKeySequence::PortableText)); + _keys.append(Shortcut::keySeqFromString(e.readElementText(), QKeySequence::PortableText)); else e.unknown(); } @@ -427,7 +430,8 @@ void Shortcut::load() else if (tag == "std") sc->_standardKey = QKeySequence::StandardKey(e.readInt()); else if (tag == "seq") - sc->_keys.append(QKeySequence::fromString(e.readElementText(), QKeySequence::PortableText)); +// sc->_keys.append(QKeySequence::fromString(e.readElementText(), QKeySequence::PortableText)); + sc->_keys.append(Shortcut::keySeqFromString(e.readElementText(), QKeySequence::PortableText)); else if (tag == "code") sc->_keys.append(QKeySequence(e.readInt())); else @@ -484,7 +488,8 @@ static QList loadDefaultShortcuts() else if (tag == "std") sc->standardKey = QKeySequence::StandardKey(e.readInt()); else if (tag == "seq") - sc->keys.append(QKeySequence::fromString(e.readElementText(), QKeySequence::PortableText)); +// sc->keys.append(QKeySequence::fromString(e.readElementText(), QKeySequence::PortableText)); + sc->keys.append(Shortcut::keySeqFromString(e.readElementText(), QKeySequence::PortableText)); else e.unknown(); } @@ -538,3 +543,52 @@ void Shortcut::reset() dirty = true; } +//--------------------------------------------------------- +// keySeqToString / keySeqFromString +//--------------------------------------------------------- + +static const QString numPadPrefix("NumPad+"); +static const int NUMPADPREFIX_SIZE = 7; // the length in chars of the above string +static const QString keySepar(", "); + +QString Shortcut::keySeqToString(const QKeySequence& keySeq, QKeySequence::SequenceFormat fmt) + { + QString s; + int code, i; + for (i = 0; i < KEYSEQ_SIZE; ++i) { + if ( (code = keySeq[i]) == 0) + break; + if (i) + s += keySepar; + if (code & Qt::KeypadModifier) { + s += numPadPrefix; + code &= ~Qt::KeypadModifier; + } + QKeySequence kSeq(code); + s += kSeq.toString(fmt); + } + return s; + } + +QKeySequence Shortcut::keySeqFromString(const QString& str, QKeySequence::SequenceFormat fmt) + { + int code[KEYSEQ_SIZE], i; + for (i = 0; i < KEYSEQ_SIZE; ++i) + code[i] = 0; + + QStringList strList = str.split(keySepar, QString::SkipEmptyParts, Qt::CaseSensitive); + + i = 0; + foreach (QString keyStr, strList) { + if( keyStr.startsWith(numPadPrefix, Qt::CaseInsensitive) ) { + code[i] += Qt::KeypadModifier; + keyStr.remove(0, NUMPADPREFIX_SIZE); + } + QKeySequence seq = QKeySequence::fromString(keyStr, fmt); + code[i] += seq[0]; + if(++i >= KEYSEQ_SIZE) + break; + } + QKeySequence keySeq(code[0], code[1], code[2], code[3]); + return keySeq; + } diff --git a/mscore/shortcut.h b/mscore/shortcut.h index 0f1f51bb79ef7..3ae261a4e19fd 100644 --- a/mscore/shortcut.h +++ b/mscore/shortcut.h @@ -69,6 +69,8 @@ enum ShortcutFlags { A_SCORE = 0x1, A_CMD = 0x2 }; +static const int KEYSEQ_SIZE = 4; + //--------------------------------------------------------- // Shortcut // hold the basic values for configurable shortcuts @@ -159,6 +161,9 @@ class Shortcut { static bool dirty; static Shortcut* getShortcut(const char* key); static const QMap& shortcuts() { return _shortcuts; } + + static QString keySeqToString(const QKeySequence& keySeq, QKeySequence::SequenceFormat fmt); + static QKeySequence keySeqFromString(const QString& str, QKeySequence::SequenceFormat fmt); }; #endif diff --git a/mscore/shortcutcapturedialog.cpp b/mscore/shortcutcapturedialog.cpp index 8d737afc32e2e..f45b327ca18ea 100644 --- a/mscore/shortcutcapturedialog.cpp +++ b/mscore/shortcutcapturedialog.cpp @@ -143,10 +143,13 @@ void ShortcutCaptureDialog::keyPressEvent(QKeyEvent* e) messageLabel->setText(msgString); addButton->setEnabled(conflict == false); replaceButton->setEnabled(conflict == false); - nshrtLabel->setText(key.toString(QKeySequence::NativeText)); +// nshrtLabel->setText(key.toString(QKeySequence::NativeText)); + QString keyStr = Shortcut::keySeqToString(key, QKeySequence::NativeText); + nshrtLabel->setText(keyStr); - QString A = key.toString(QKeySequence::NativeText); - QString B = key.toString(QKeySequence::PortableText); +// QString A = key.toString(QKeySequence::NativeText); + QString A = keyStr; + QString B = Shortcut::keySeqToString(key, QKeySequence::PortableText); qDebug("capture key 0x%x modifiers 0x%x virt 0x%x scan 0x%x <%s><%s>\n", k, int(e->modifiers()),