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