1 //=============================================================================
2 //  MusE Score
3 //  Linux Music Score Editor
4 //
5 //  Copyright (C) 2002-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 //
10 //  This program is distributed in the hope that it will be useful,
11 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //  GNU General Public License for more details.
14 //
15 //  You should have received a copy of the GNU General Public License
16 //  along with this program; if not, write to the Free Software
17 //  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 //=============================================================================
19 
20 #ifndef __PREFERENCES_H__
21 #define __PREFERENCES_H__
22 
23 /*
24  * HOW TO ADD A NEW PREFERENCE
25  * - Add a new define to the list of defines below
26  * - Add the preference to the _allPreferences map in the init() function in preferences.cpp
27  *   and specify the default value for this preference
28  * - That's it. The preference is stored and retrieved automatically and can be read
29  *   using getString(), getInt(), etc., and changed using setPreference()
30  */
31 
32 #include <functional>
33 #include "globals.h"
34 #include "global/settings/types/preferencekeys.h"
35 
36 namespace Ms {
37 
38 extern QString mscoreGlobalShare;
39 
40 enum class SessionStart : char {
41       EMPTY, LAST, NEW, SCORE
42       };
43 
44 // midi remote control values:
45 enum {
46       RMIDI_REWIND,
47       RMIDI_TOGGLE_PLAY,
48       RMIDI_PLAY,
49       RMIDI_STOP,
50       RMIDI_NOTE1,
51       RMIDI_NOTE2,
52       RMIDI_NOTE4,
53       RMIDI_NOTE8,
54       RMIDI_NOTE16,
55       RMIDI_NOTE32,
56       RMIDI_NOTE64,
57       RMIDI_REST,
58       RMIDI_DOT,
59       RMIDI_DOTDOT,
60       RMIDI_TIE,
61       RMIDI_UNDO,
62       RMIDI_NOTE_EDIT_MODE,
63       RMIDI_REALTIME_ADVANCE,
64       MIDI_REMOTES
65       };
66 
67 // The "theme" the user chooses in Preferences
68 enum class MuseScorePreferredStyleType : char {
69       LIGHT_FUSION = 0,
70       DARK_FUSION,
71 #ifdef Q_OS_MAC
72       FOLLOW_SYSTEM,
73 #endif
74       };
75 
76 // The actual "theme", resulting from the user's choice
77 enum class MuseScoreEffectiveStyleType : char {
78       LIGHT_FUSION = 0,
79       DARK_FUSION
80       };
81 
82 // MusicXML export break values
83 enum class MusicxmlExportBreaks : char {
84       ALL, MANUAL, NO
85       };
86 
87 // Default-zoom-type options
88 enum class ZoomType : int {
89       PERCENTAGE = 0, PAGE_WIDTH, WHOLE_PAGE, TWO_PAGES,
90       };
91 
92 class PreferenceVisitor;
93 
94 //---------------------------------------------------------
95 //   Preference
96 //---------------------------------------------------------
97 class Preference {
98    private:
99       QVariant _defaultValue = 0;
100       bool _showInAdvancedList = true;
101 
102    protected:
103       QMetaType::Type _type = QMetaType::UnknownType;
Preference(QVariant defaultValue)104       Preference(QVariant defaultValue) : _defaultValue(defaultValue) {}
105 
106    public:
107       Preference(QVariant defaultValue, QMetaType::Type type, bool showInAdvancedList = true);
~Preference()108       virtual ~Preference() {}
109 
defaultValue()110       QVariant defaultValue() const {return _defaultValue;}
showInAdvancedList()111       bool showInAdvancedList() const {return _showInAdvancedList;}
type()112       QMetaType::Type type() {return _type;}
113       virtual void accept(QString key, PreferenceVisitor&) = 0;
114       };
115 
116 class IntPreference : public Preference {
117    public:
118       IntPreference(int defaultValue, bool showInAdvancedList = true);
119       virtual void accept(QString key, PreferenceVisitor&);
120       };
121 
122 class DoublePreference : public Preference {
123    public:
124       DoublePreference(double defaultValue, bool showInAdvancedList = true);
125       virtual void accept(QString key, PreferenceVisitor&);
126       };
127 
128 class BoolPreference : public Preference {
129    public:
130       BoolPreference(bool defaultValue, bool showInAdvancedList = true);
131       virtual void accept(QString key, PreferenceVisitor&);
132       };
133 
134 class StringPreference: public Preference {
135    public:
136       StringPreference(QString defaultValue, bool showInAdvancedList = true);
137       virtual void accept(QString key, PreferenceVisitor&);
138       };
139 
140 class ColorPreference: public Preference {
141    public:
142       ColorPreference(QColor defaultValue, bool showInAdvancedList = true);
143       virtual void accept(QString key, PreferenceVisitor&);
144       };
145 
146 // Support for EnumPreference is currently not fully implemented
147 class EnumPreference: public Preference {
148    public:
149       EnumPreference(QVariant defaultValue, bool showInAdvancedList = true);
150       virtual void accept(QString, PreferenceVisitor&);
151       };
152 
153 //---------------------------------------------------------
154 //   Preferences
155 //---------------------------------------------------------
156 
157 class Preferences {
158    public:
159       typedef QHash<QString, Preference*> prefs_map_t;
160       using OnSetListener = std::function<void(const QString& key, const QVariant& value)>;
161       using ListenerID = uint32_t;
162 
163    private:
164 
165       // Map of all preferences and their default values
166       // A preference can not be read or set if it is not present in this map
167       // This map is not used for storing a preference it is only for default values
168       prefs_map_t _allPreferences;
169       // used for storing preferences in memory when _storeInMemoryOnly is true
170       // and for storing temporary preferences
171       QHash<QString, QVariant> _inMemorySettings;
172       bool _storeInMemoryOnly = false;
173       bool _returnDefaultValues = false;
174       bool _initialized = false;
175       QSettings* _settings; // should not be used directly but through settings() accessor
176 
177       QSettings* settings() const;
178       // the following functions must be used to access and change a preference
179       // instead of using QSettings directly
180       QVariant get(const QString key) const;
181       bool has(const QString key) const;
182       void set(const QString key, QVariant value, bool temporary = false);
183       void remove(const QString key);
184 
185       QVariant preference(const QString key) const;
186       QMetaType::Type type(const QString key) const;
187       bool checkIfKeyExists(const QString key) const;
188       bool checkType(const QString key, QMetaType::Type t) const;
189 
190       // Used with workspace
191       QMap<QString, QVariant> localPreferences;
192       QMap<QString, QVariant> getDefaultLocalPreferences();
193       bool useLocalPrefs = false;
194 
195       QMap<ListenerID, OnSetListener> _onSetListeners;
196 
197    public:
198       Preferences();
199       ~Preferences();
200       void init(bool storeInMemoryOnly = false);
201       void save();
202       // set to true to let getters return default values instead of values from QSettings
setReturnDefaultValuesMode(bool returnDefaultValues)203       void setReturnDefaultValuesMode(bool returnDefaultValues) {_returnDefaultValues = returnDefaultValues;}
204 
allPreferences()205       const prefs_map_t& allPreferences() const {return _allPreferences;}
206 
207       // general getters
208       QVariant defaultValue(const QString key) const;
209       bool getBool(const QString key) const;
210       QColor getColor(const QString key) const;
211       QString getString(const QString key) const;
212       int getInt(const QString key) const;
213       double getDouble(const QString key) const;
214 
215       // general setters
216       void setToDefaultValue(const QString key);
217       void setPreference(const QString key, QVariant value);
218 
219       // set listeners
220       ListenerID addOnSetListener(const OnSetListener& l);
221       void removeOnSetListener(const ListenerID& id);
222 
223       // A temporary preference is stored "in memory" only and not written to file.
224       // If there is both a "normal" preference and a temporary preference with the same
225       // key the temporary preference is used
226       void setTemporaryPreference(const QString key, QVariant value);
227 
228       /*
229        * Some preferences like enums and structs/classes are not easily read using the general set/get methods
230        * and therefore require specific getters and/or setters
231        */
232       SessionStart sessionStart() const;
233       MusicxmlExportBreaks musicxmlExportBreaks() const;
234       MuseScorePreferredStyleType preferredGlobalStyle() const;
235       MuseScoreEffectiveStyleType effectiveGlobalStyle() const;
236       bool isThemeDark() const;
237 
238       template<typename T>
setCustomPreference(const QString key,T t)239       void setCustomPreference(const QString key, T t)
240             {
241             set(key, QVariant::fromValue<T>(t));
242             }
243 
244       // The midiRemote preference requires special handling due to its complexity
245       MidiRemote midiRemote(int recordId) const;
246       void updateMidiRemote(int recordId, MidiRemoteType type, int data);
247       void clearMidiRemote(int recordId);
248 
getLocalPreferences()249       QMap<QString, QVariant> getLocalPreferences()  { return localPreferences; }
250       void setLocalPreference(QString key, QVariant value);
setUseLocalPreferences(bool value)251       void setUseLocalPreferences(bool value)         { useLocalPrefs = value;   }
getUseLocalPreferences()252       bool getUseLocalPreferences()                   { return useLocalPrefs;    }
updateLocalPreferences()253       void updateLocalPreferences() { localPreferences = getDefaultLocalPreferences(); }
254       };
255 
256 // singleton
257 extern Preferences preferences;
258 
259 // Stream operators for enum classes
260 // enum classes don't play well with QSettings without custom serialization
261 inline QDataStream&
262 operator<<(QDataStream &out, const Ms::MuseScorePreferredStyleType &val)
263 {
264     return out << static_cast<int>(val);
265 }
266 
267 inline QDataStream&
268 operator>>(QDataStream &in, Ms::MuseScorePreferredStyleType &val)
269 {
270     int tmp;
271     in >> tmp;
272     val = static_cast<Ms::MuseScorePreferredStyleType>(tmp);
273     return in;
274 }
275 
276 inline QDataStream&
277 operator<<(QDataStream &out, const Ms::MuseScoreEffectiveStyleType &val)
278 {
279     return out << static_cast<int>(val);
280 }
281 
282 inline QDataStream&
283 operator>>(QDataStream &in, Ms::MuseScoreEffectiveStyleType &val)
284 {
285     int tmp;
286     in >> tmp;
287     val = static_cast<Ms::MuseScoreEffectiveStyleType>(tmp);
288     return in;
289 }
290 
291 inline QDataStream&
292 operator<<(QDataStream &out, const Ms::SessionStart &val)
293 {
294     return out << static_cast<int>(val);
295 }
296 
297 inline QDataStream&
298 operator>>(QDataStream &in, Ms::SessionStart &val)
299 {
300     int tmp;
301     in >> tmp;
302     val = static_cast<Ms::SessionStart>(tmp);
303     return in;
304 }
305 
306 inline QDataStream&
307 operator<<(QDataStream &out, const Ms::MusicxmlExportBreaks &val)
308 {
309     return out << static_cast<int>(val);
310 }
311 
312 inline QDataStream&
313 operator>>(QDataStream &in, Ms::MusicxmlExportBreaks &val)
314 {
315     int tmp;
316     in >> tmp;
317     val = static_cast<Ms::MusicxmlExportBreaks>(tmp);
318     return in;
319 }
320 
321 
322 class PreferenceVisitor {
323    public:
324       virtual void visit(QString key, IntPreference*) = 0;
325       virtual void visit(QString key, DoublePreference*) = 0;
326       virtual void visit(QString key, BoolPreference*) = 0;
327       virtual void visit(QString key, StringPreference*) = 0;
328       virtual void visit(QString key, ColorPreference*) = 0;
329       };
330 
331 
332 } // namespace Ms
333 
334 Q_DECLARE_METATYPE(Ms::SessionStart);
335 Q_DECLARE_METATYPE(Ms::MusicxmlExportBreaks);
336 Q_DECLARE_METATYPE(Ms::MuseScorePreferredStyleType);
337 Q_DECLARE_METATYPE(Ms::MuseScoreEffectiveStyleType);
338 
339 #endif
340