1 //============================================================================= 2 // MuseScore 3 // Music Composition & Notation 4 // 5 // Copyright (C) 2011-2016 Werner Schweer and others 6 // 7 // This program is free software; you can redistribute it and/or modify 8 // it under the terms of the GNU General Public License version 2 9 // as published by the Free Software Foundation and appearing in 10 // the file LICENSE.GPL 11 //============================================================================= 12 13 #ifndef __SHORTCUT_H__ 14 #define __SHORTCUT_H__ 15 16 /*--------------------------------------------------------- 17 NOTE ON ARCHITECTURE 18 19 The Shortcut class describes the basic configurable shortcut element. 20 'Real' data are contained in 2 static member variables: 21 22 1) sc[], an array of Shortcut: contains the default, built-in data for each shortcut 23 except the key sequences; it is initialized at startup (code at the beginning of 24 mscore/actions.cpp) 25 2) _shortcuts, a QMap using the shortcut xml tag name as hash value: is initialized from 26 data in sc via a call to Shortcut::init() in program main() (mscore/musescore.cpp). 27 This also load actual key sequences either from an external, hard-coded, file with 28 user customizations or from a resource (<= mscore/data/shortcuts.xml), if there are 29 no customizations. 30 Later during startup, QAction's are derived from each of its elements and pooled 31 in a single QActionGroup during MuseScore::MuseScore() constructor (mscore/musescore.cpp) 32 33 ShortcutFlags: 34 To be documented 35 36 State flags: 37 38 Defined in mscore/global.h (ScoreState enum): each shortcut is ignored if its _flags mask 39 does not include the current score state. This is different from (and additional to) 40 QAction processing performed by the Qt framework and happens only after the action has 41 been forwarded to the application (the action must be enabled). 42 43 The STATE_NEVER requires an explanation. It has been introduced to mark shortcuts 44 which need to be recorded (and possibly customized) but are never used directly. 45 Currently, this applies to a number of shortcuts which: 46 - have been split between a common and a TAB-specific variant AND 47 - are linked to tool bar buttons or menu items 48 If QAction's are created for both, Qt blocks either as duplicate; in addition, the button 49 or menu item may become disabled on state change. The currently implemented solution is 50 to create a QAction only for one of them (the common one) and swap the key sequences when 51 entering or leaving the relevant state. 52 Swapping is implemented in MuseScore::changeState() (mscore/musescore.cpp). 53 QAction creation for the 'other' shortcut is blocked in Shortcut::action() (mscore/shortcut.cpp). 54 55 This means that Shortcut::action() may return 0. When scanning the whole 56 shortcuts[] array, this has to be taken into account; currently it happens in two 57 cases: 58 - in MuseScore::MuseScore() constructor (mscore/musescore.cpp) 59 - in MuseScore::changeState() method (mscore/musescore.cpp) 60 61 Shortcuts marked with the STATE_NEVER state should NEVER used directly as shortcuts! 62 ---------------------------------------------------------*/ 63 64 #include "icons.h" 65 #include "globals.h" 66 namespace Ms { 67 68 class XmlWriter; 69 class XmlReader; 70 71 //--------------------------------------------------------- 72 // ShortcutFlags 73 //--------------------------------------------------------- 74 75 enum class ShortcutFlags : char { 76 NONE = 0, 77 A_SCORE = 1, 78 A_CMD = 1 << 1, 79 A_CHECKABLE = 1 << 2, 80 A_CHECKED = 1 << 3, 81 A_UNDO_REDO = 1 << 4, 82 }; 83 84 constexpr ShortcutFlags operator| (ShortcutFlags t1, ShortcutFlags t2) { 85 return static_cast<ShortcutFlags>(static_cast<int>(t1) | static_cast<int>(t2)); 86 } 87 88 constexpr bool operator& (ShortcutFlags t1, ShortcutFlags t2) { 89 return static_cast<int>(t1) & static_cast<int>(t2); 90 } 91 92 static const int KEYSEQ_SIZE = 4; 93 94 //--------------------------------------------------------- 95 // Shortcut 96 // hold the basic values for configurable shortcuts 97 //--------------------------------------------------------- 98 99 class Shortcut { 100 MsWidget _assignedWidget; //! the widget where the action will be assigned 101 int _state { 0 }; //! shortcut is valid in this Mscore state 102 QByteArray _key; //! xml tag name for configuration file 103 QByteArray _descr; //! descriptor, shown in editor 104 QByteArray _text; //! text as shown on buttons or menus 105 QByteArray _help; //! ballon help 106 //! (or'd list of states) 107 108 Icons _icon { Icons::Invalid_ICON }; 109 Qt::ShortcutContext _context { Qt::WindowShortcut }; 110 ShortcutFlags _flags { ShortcutFlags::NONE }; 111 112 QList<QKeySequence> _keys; //! shortcut list 113 114 QKeySequence::StandardKey _standardKey { QKeySequence::UnknownKey }; 115 mutable QAction* _action { 0 }; //! cached action 116 117 static QString source; 118 119 static Shortcut _sc[]; 120 static QHash<QByteArray, Shortcut*> _shortcuts; 121 void translateAction(QAction* action) const; 122 123 public: 124 125 static constexpr const char* defaultFileName = ":/data/shortcuts.xml"; 126 Shortcut()127 Shortcut() {} 128 Shortcut( 129 Ms::MsWidget assignedWidget, 130 int state, 131 const char* key, 132 const char* d = 0, 133 const char* txt = 0, 134 const char* h = 0, 135 Icons i = Icons::Invalid_ICON, 136 Qt::ShortcutContext cont = Qt::WindowShortcut, 137 ShortcutFlags f = ShortcutFlags::NONE 138 ); 139 140 QAction* action() const; key()141 const QByteArray& key() const { return _key; } setKey(const QByteArray & key)142 void setKey(const QByteArray& key) { _key = key; } 143 QString descr() const; 144 QString text() const; 145 QString help() const; assignedWidget()146 MsWidget assignedWidget() const { return _assignedWidget; } 147 void clear(); //! remove shortcuts 148 void reset(); //! reset to buildin 149 void addShortcut(const QKeySequence&); state()150 int state() const { return _state; } setState(int v)151 void setState(int v) { _state = v; } needsScore()152 bool needsScore() const { return _flags & ShortcutFlags::A_SCORE; } isCmd()153 bool isCmd() const { return _flags & ShortcutFlags::A_CMD; } isUndoRedo()154 bool isUndoRedo() const { return _flags & ShortcutFlags::A_UNDO_REDO; } isCheckable()155 bool isCheckable() const { return _flags & ShortcutFlags::A_CHECKABLE; } isChecked()156 bool isChecked() const { return _flags & ShortcutFlags::A_CHECKED; } icon()157 Icons icon() const { return _icon; } keys()158 const QList<QKeySequence>& keys() const { return _keys; } standardKey()159 QKeySequence::StandardKey standardKey() const { return _standardKey; } 160 void setStandardKey(QKeySequence::StandardKey k); 161 void setKeys(const QList<QKeySequence>& ks); 162 void setKeys(const Shortcut&); 163 164 bool compareKeys(const Shortcut&) const; 165 QString keysToString() const; 166 static QString getMenuShortcutString(const QMenu* menu); 167 168 void write(Ms::XmlWriter&) const; 169 void read(Ms::XmlReader&); 170 171 static void init(); 172 static void retranslate(); 173 static void refreshIcons(); 174 static void load(); 175 static void loadFromNewFile(QString fileLocation); 176 static void save(); 177 static void saveToNewFile(QString fileLocation); 178 static void resetToDefault(); 179 static bool dirty; customSource()180 static bool customSource() { return source != defaultFileName; } 181 static Shortcut* getShortcutByKeySequence(const QKeySequence &keySequence, const ScoreState state); 182 static Shortcut* getShortcut(const char* key); shortcuts()183 static const QHash<QByteArray, Shortcut*>& shortcuts() { return _shortcuts; } 184 static QActionGroup* getActionGroupForWidget(MsWidget w); 185 static QActionGroup* getActionGroupForWidget(MsWidget w, Qt::ShortcutContext newShortcutContext); 186 187 static QString keySeqToString(const QKeySequence& keySeq, QKeySequence::SequenceFormat fmt, bool escapeKeyStr = false); 188 static QKeySequence keySeqFromString(const QString& str, QKeySequence::SequenceFormat fmt); 189 }; 190 191 } // namespace Ms 192 #endif 193 194