1 //=============================================================================
2 //  MuseScore
3 //  Music Composition & Notation
4 //
5 //  Copyright (C) 2002-2017 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 #include "musescore.h"
21 #include "timeline.h"
22 #include "preferences.h"
23 #include "prefsdialog.h"
24 #include "seq.h"
25 #include "shortcutcapturedialog.h"
26 #include "scoreview.h"
27 #include "shortcut.h"
28 #include "workspace.h"
29 
30 #include "audio/drivers/pa.h"
31 #ifdef USE_PORTMIDI
32 #include "audio/drivers/pm.h"
33 #endif
34 
35 #include "pathlistdialog.h"
36 #include "resourceManager.h"
37 #include "audio/midi/msynthesizer.h"
38 
39 #ifdef AVSOMR
40 #include "avsomr/avsomrlocal.h"
41 #endif
42 
43 #ifdef Q_OS_MAC
44 #include "macos/cocoabridge.h"
45 #endif
46 
47 namespace Ms {
48 
49 //---------------------------------------------------------
50 //   startPreferenceDialog
51 //---------------------------------------------------------
52 
startPreferenceDialog()53 void MuseScore::startPreferenceDialog()
54       {
55       if (!preferenceDialog) {
56             preferenceDialog = new PreferenceDialog(this);
57             connect(preferenceDialog, &PreferenceDialog::preferencesChanged, this,
58                &MuseScore::preferencesChanged);
59             connect(preferenceDialog, &PreferenceDialog::mixerPreferencesChanged, this,
60                &MuseScore::mixerPreferencesChanged);
61             }
62       preferenceDialog->start();
63       }
64 
65 //---------------------------------------------------------
66 //   PreferenceDialog
67 //---------------------------------------------------------
68 
PreferenceDialog(QWidget * parent)69 PreferenceDialog::PreferenceDialog(QWidget* parent)
70    : AbstractDialog(parent)
71       {
72       setObjectName("PreferenceDialog");
73       setupUi(this);
74       setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
75       setModal(true);
76       shortcutsChanged = false;
77 
78       styleName->clear();
79       styleName->addItem(tr("Light"));
80       styleName->addItem(tr("Dark"));
81 #ifdef Q_OS_MAC // On Mac, we have a theme option to follow the system's Dark Mode
82       if (CocoaBridge::isSystemDarkModeSupported())
83             styleName->addItem(tr("System"));
84 #endif
85 
86 #ifndef USE_JACK
87       jackDriver->setVisible(false);
88 #endif
89 #ifndef USE_ALSA
90       alsaDriver->setVisible(false);
91       alsaDriver->setChecked(false);
92 #else
93       alsaSampleRate->clear();
94       alsaSampleRate->addItem(tr("192000"), 192000);
95       alsaSampleRate->addItem( tr("96000"),  96000);
96       alsaSampleRate->addItem( tr("88200"),  88200);
97       alsaSampleRate->addItem( tr("48000"),  48000); // default
98       alsaSampleRate->addItem( tr("44100"),  44100);
99       alsaSampleRate->addItem( tr("32000"),  32000);
100       alsaSampleRate->addItem( tr("22050"),  22050);
101 
102       alsaPeriodSize->clear();
103       alsaPeriodSize->addItem(tr("4096"), 4096);
104       alsaPeriodSize->addItem(tr("2048"), 2048);
105       alsaPeriodSize->addItem(tr("1024"), 1024); // default
106       alsaPeriodSize->addItem( tr("512"),  512);
107       alsaPeriodSize->addItem( tr("256"),  256);
108       alsaPeriodSize->addItem( tr("128"),  128);
109       alsaPeriodSize->addItem(  tr("64"),   64);
110 #endif
111 
112       exportAudioSampleRate->clear();
113       exportAudioSampleRate->addItem(tr("32000"), 32000);
114       exportAudioSampleRate->addItem(tr("44100"), 44100); // default
115       exportAudioSampleRate->addItem(tr("48000"), 48000);
116 
117 #ifndef USE_LAME
118       exportMp3BitRateLabel->setVisible(false);
119       exportMp3BitRate->setVisible(false);
120       exportMp3BitRateUnit->setVisible(false);
121 #else
122       exportMp3BitRate->clear();
123       exportMp3BitRate->addItem( tr("32"),  32);
124       exportMp3BitRate->addItem( tr("40"),  40);
125       exportMp3BitRate->addItem( tr("48"),  48);
126       exportMp3BitRate->addItem( tr("56"),  56);
127       exportMp3BitRate->addItem( tr("64"),  64);
128       exportMp3BitRate->addItem( tr("80"),  80);
129       exportMp3BitRate->addItem( tr("96"),  96);
130       exportMp3BitRate->addItem(tr("112"), 112);
131       exportMp3BitRate->addItem(tr("128"), 128); // default
132       exportMp3BitRate->addItem(tr("160"), 160);
133       exportMp3BitRate->addItem(tr("192"), 192);
134       exportMp3BitRate->addItem(tr("224"), 224);
135       exportMp3BitRate->addItem(tr("256"), 256);
136       exportMp3BitRate->addItem(tr("320"), 320);
137 #endif
138 
139 #ifndef USE_PORTAUDIO
140       portaudioDriver->setVisible(false);
141 #endif
142 #ifndef USE_PORTMIDI
143       portMidiInput->setVisible(false);
144       portMidiInputLabel->setVisible(false);
145 #endif
146 #ifndef USE_PULSEAUDIO
147       pulseaudioDriver->setVisible(false);
148 #endif
149 
150       tabIO->setEnabled(!noSeq);
151 
152       QButtonGroup* fgButtons = new QButtonGroup(this);
153       fgButtons->setExclusive(true);
154       fgButtons->addButton(fgColorButton);
155       fgButtons->addButton(fgWallpaperButton);
156       connect(fgColorButton, &QRadioButton::toggled, this, &PreferenceDialog::updateFgView);
157 
158       QButtonGroup* bgButtons = new QButtonGroup(this);
159       bgButtons->setExclusive(true);
160       bgButtons->addButton(bgColorButton);
161       bgButtons->addButton(bgWallpaperButton);
162       connect(bgColorButton, &QRadioButton::toggled, this, &PreferenceDialog::updateBgView);
163 
164       zoomDefaultType->clear();
165       zoomDefaultType->addItem(tr("Percentage"), 0);
166       zoomDefaultType->addItem(tr("Page Width"), 1);
167       zoomDefaultType->addItem(tr("Whole Page"), 2);
168       zoomDefaultType->addItem(tr("Two Pages"), 3);
169 
170       zoomPrecisionKeyboard->setRange(ZOOM_PRECISION_MIN, ZOOM_PRECISION_MAX);
171       zoomPrecisionMouse->setRange(ZOOM_PRECISION_MIN, ZOOM_PRECISION_MAX);
172 
173       connect(buttonBox,            &QDialogButtonBox::clicked, this, &PreferenceDialog::buttonBoxClicked);
174       connect(fgWallpaperSelect,    &QToolButton::clicked, this, &PreferenceDialog::selectFgWallpaper);
175       connect(bgWallpaperSelect,    &QToolButton::clicked, this, &PreferenceDialog::selectBgWallpaper);
176 
177       bgWallpaperSelect->setIcon(*icons[int(Icons::fileOpen_ICON)]);
178       fgWallpaperSelect->setIcon(*icons[int(Icons::fileOpen_ICON)]);
179 
180       connect(myScoresButton, &QToolButton::clicked, this, &PreferenceDialog::selectScoresDirectory);
181       connect(myStylesButton, &QToolButton::clicked, this, &PreferenceDialog::selectStylesDirectory);
182       connect(myTemplatesButton, &QToolButton::clicked, this, &PreferenceDialog::selectTemplatesDirectory);
183       connect(myPluginsButton, &QToolButton::clicked, this, &PreferenceDialog::selectPluginsDirectory);
184       connect(mySoundfontsButton, &QToolButton::clicked, this, &PreferenceDialog::changeSoundfontPaths);
185       connect(myImagesButton, &QToolButton::clicked, this, &PreferenceDialog::selectImagesDirectory);
186       connect(myExtensionsButton, &QToolButton::clicked, this, &PreferenceDialog::selectExtensionsDirectory);
187 
188       myScoresButton->setIcon(*icons[int(Icons::fileOpen_ICON)]);
189       myStylesButton->setIcon(*icons[int(Icons::fileOpen_ICON)]);
190       myTemplatesButton->setIcon(*icons[int(Icons::fileOpen_ICON)]);
191       myPluginsButton->setIcon(*icons[int(Icons::fileOpen_ICON)]);
192       mySoundfontsButton->setIcon(*icons[int(Icons::edit_ICON)]);
193       myImagesButton->setIcon(*icons[int(Icons::fileOpen_ICON)]);
194       myExtensionsButton->setIcon(*icons[int(Icons::fileOpen_ICON)]);
195 
196       connect(updateTranslation, &QToolButton::clicked, this, &PreferenceDialog::updateTranslationClicked);
197 
198       connect(defaultStyleButton,     &QToolButton::clicked, this, &PreferenceDialog::selectDefaultStyle);
199       connect(partStyleButton,        &QToolButton::clicked, this, &PreferenceDialog::selectPartStyle);
200       connect(styleFileButton,        &QToolButton::clicked, this, &PreferenceDialog::styleFileButtonClicked);
201       connect(instrumentList1Button,  &QToolButton::clicked, this, &PreferenceDialog::selectInstrumentList1);
202       connect(instrumentList2Button,  &QToolButton::clicked, this, &PreferenceDialog::selectInstrumentList2);
203       connect(scoreOrderList1Button,  &QToolButton::clicked, this, &PreferenceDialog::selectScoreOrderList1);
204       connect(scoreOrderList2Button,  &QToolButton::clicked, this, &PreferenceDialog::selectScoreOrderList2);
205       connect(startWithButton,        &QToolButton::clicked, this, &PreferenceDialog::selectStartWith);
206 
207       defaultStyleButton->setIcon(*icons[int(Icons::fileOpen_ICON)]);
208       partStyleButton->setIcon(*icons[int(Icons::fileOpen_ICON)]);
209       styleFileButton->setIcon(*icons[int(Icons::fileOpen_ICON)]);
210       instrumentList1Button->setIcon(*icons[int(Icons::fileOpen_ICON)]);
211       instrumentList2Button->setIcon(*icons[int(Icons::fileOpen_ICON)]);
212       scoreOrderList1Button->setIcon(*icons[int(Icons::fileOpen_ICON)]);
213       scoreOrderList2Button->setIcon(*icons[int(Icons::fileOpen_ICON)]);
214       startWithButton->setIcon(*icons[int(Icons::fileOpen_ICON)]);
215 
216       connect(shortcutList,   &QTreeWidget::itemActivated, this, &PreferenceDialog::defineShortcutClicked);
217       connect(resetShortcut,  &QToolButton::clicked, this, &PreferenceDialog::resetShortcutClicked);
218       connect(saveShortcutList,  &QToolButton::clicked, this, &PreferenceDialog::saveShortcutListClicked);
219       connect(loadShortcutList,  &QToolButton::clicked, this, &PreferenceDialog::loadShortcutListClicked);
220       connect(clearShortcut, &QToolButton::clicked, this, &PreferenceDialog::clearShortcutClicked);
221       connect(defineShortcut, &QToolButton::clicked, this, &PreferenceDialog::defineShortcutClicked);
222       connect(resetToDefault, &QToolButton::clicked, this, &PreferenceDialog::resetAllValues);
223       connect(filterShortcuts, &QLineEdit::textChanged, this, &PreferenceDialog::filterShortcutsTextChanged);
224       connect(printShortcuts, &QToolButton::clicked, this, &PreferenceDialog::printShortcutsClicked);
225       connect(zoomDefaultType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &PreferenceDialog::zoomDefaultTypeChanged);
226 
227       recordButtons = new QButtonGroup(this);
228       recordButtons->setExclusive(false);
229       recordButtons->addButton(recordRewind, RMIDI_REWIND);
230       recordButtons->addButton(recordTogglePlay,   RMIDI_TOGGLE_PLAY);
231       recordButtons->addButton(recordPlay,   RMIDI_PLAY);
232       recordButtons->addButton(recordStop,   RMIDI_STOP);
233       recordButtons->addButton(rcr2,         RMIDI_NOTE1);
234       recordButtons->addButton(rcr3,         RMIDI_NOTE2);
235       recordButtons->addButton(rcr4,         RMIDI_NOTE4);
236       recordButtons->addButton(rcr5,         RMIDI_NOTE8);
237       recordButtons->addButton(rcr6,         RMIDI_NOTE16);
238       recordButtons->addButton(rcr7,         RMIDI_NOTE32);
239       recordButtons->addButton(rcr8,         RMIDI_NOTE64);
240       recordButtons->addButton(rcr9,         RMIDI_REST);
241       recordButtons->addButton(rcr10,        RMIDI_DOT);
242       recordButtons->addButton(rcr11,        RMIDI_DOTDOT);
243       recordButtons->addButton(rcr12,        RMIDI_TIE);
244       recordButtons->addButton(recordUndo,   RMIDI_UNDO);
245       recordButtons->addButton(recordEditMode, RMIDI_NOTE_EDIT_MODE);
246       recordButtons->addButton(recordRealtimeAdvance, RMIDI_REALTIME_ADVANCE);
247 
248       connect(recordButtons,              QOverload<int>::of(&QButtonGroup::buttonClicked), this, &PreferenceDialog::recordButtonClicked);
249       connect(midiRemoteControlClear,     &QToolButton::clicked, this, &PreferenceDialog::midiRemoteControlClearClicked);
250       connect(portaudioDriver,            &QGroupBox::toggled, this, &PreferenceDialog::exclusiveAudioDriver);
251       connect(pulseaudioDriver,           &QGroupBox::toggled, this, &PreferenceDialog::exclusiveAudioDriver);
252       connect(alsaDriver,                 &QGroupBox::toggled, this, &PreferenceDialog::exclusiveAudioDriver);
253       connect(jackDriver,                 &QGroupBox::toggled, this, &PreferenceDialog::exclusiveAudioDriver);
254       connect(useJackAudio,               &QRadioButton::toggled, this, &PreferenceDialog::nonExclusiveJackDriver);
255       connect(useJackMidi,                &QRadioButton::toggled, this, &PreferenceDialog::nonExclusiveJackDriver);
256       connect(rescanDrivers,              &QToolButton::clicked, this, &PreferenceDialog::restartAudioEngine);
257       updateRemote();
258 
259       advancedWidget = new PreferencesListWidget();
260       QVBoxLayout* l = static_cast<QVBoxLayout*> (tabAdvanced->layout());
261       l->insertWidget(0, advancedWidget);
262       advancedWidget->loadPreferences();
263       connect(advancedSearch, &QLineEdit::textChanged, this, &PreferenceDialog::filterAdvancedPreferences);
264       connect(resetPreference, &QPushButton::clicked, this, &PreferenceDialog::resetAdvancedPreferenceToDefault);
265       connect(this, &PreferenceDialog::preferencesChanged, mscore->timeline(),  &Timeline::updateTimelineTheme); // this should probably be moved to updateUiStyleAndTheme
266       MuseScore::restoreGeometry(this);
267 #if !defined(Q_OS_MAC) && (!defined(Q_OS_WIN) || defined(FOR_WINSTORE))
268       General->removeTab(General->indexOf(tabUpdate)); // updateTab not needed on Linux and not wanted in Windows Store
269 #endif
270       }
271 
272 //---------------------------------------------------------
273 //   start
274 //---------------------------------------------------------
275 
start()276 void PreferenceDialog::start()
277       {
278 
279       // Each entry to one of the vectors controls one widget (and usually one preference).
280       // Each entry is a *PreferenceItem(preference_key, widget, optional applyFunction, optional updateFunction).
281       // A *PreferenceItem with only the first 2 parameters saves its value on apply and loads it when the dialog starts or when reset is pressed.
282       //
283       // The default apply/update(load) behavior can be overriden by providing an applyFunction and/or updateFunction (the default value is nullptr).
284       // The apply function (either the default or the provided one) is called in PreferenceDialog::Apply.
285       // The update function (either the default or the provided one) is called in PreferenceDialog::Update.
286       //
287       // If the logic is too complicated to be implemented like this (for example for multiple interconnected preferences),
288       // doNothing can be used in place of a function to disable the call to that function.
289       // Then the related functionality must be called directly from PrefsDialog::Apply (or PrefsDialog::Update).
290 
291       const auto doNothing = []() { }; // used to disable the default apply/update functions (in contrast to nullptr which instructs the use of the defaults)
292 
293       // Most widgets go here.
294       normalWidgets = std::vector<PreferenceItem*>{
295                   new IntPreferenceItem(PREF_APP_AUTOSAVE_AUTOSAVETIME, autoSaveTime),
296                   new BoolPreferenceItem(PREF_APP_AUTOSAVE_USEAUTOSAVE, autoSave),
297                   new StringPreferenceItem(PREF_APP_PATHS_INSTRUMENTLIST1, instrumentList1),
298                   new StringPreferenceItem(PREF_APP_PATHS_INSTRUMENTLIST2, instrumentList2),
299                   new StringPreferenceItem(PREF_APP_PATHS_SCOREORDERLIST1, scoreOrderList1),
300                   new StringPreferenceItem(PREF_APP_PATHS_SCOREORDERLIST2, scoreOrderList2),
301                   new StringPreferenceItem(PREF_APP_PATHS_MYIMAGES, myImages),
302                   new StringPreferenceItem(PREF_APP_PATHS_MYPLUGINS, myPlugins),
303                   new StringPreferenceItem(PREF_APP_PATHS_MYSCORES, myScores),
304                   new StringPreferenceItem(PREF_APP_PATHS_MYSOUNDFONTS, mySoundfonts),
305                   new StringPreferenceItem(PREF_APP_PATHS_MYSTYLES, myStyles),
306                   new StringPreferenceItem(PREF_APP_PATHS_MYTEMPLATES, myTemplates),
307                   new StringPreferenceItem(PREF_APP_PATHS_MYEXTENSIONS, myExtensions),
308                   new StringPreferenceItem(PREF_APP_STARTUP_STARTSCORE, sessionScore),
309                   new IntPreferenceItem(PREF_EXPORT_PDF_DPI, exportPdfDpi),
310                   new DoublePreferenceItem(PREF_EXPORT_PNG_RESOLUTION, pngResolution),
311                   new BoolPreferenceItem(PREF_EXPORT_PNG_USETRANSPARENCY, pngTransparent),
312                   new BoolPreferenceItem(PREF_IMPORT_MUSICXML_IMPORTBREAKS, importBreaks),
313                   new BoolPreferenceItem(PREF_IMPORT_MUSICXML_IMPORTLAYOUT, importLayout),
314                   new BoolPreferenceItem(PREF_MIGRATION_APPLY_EDWIN_FOR_XML_FILES, applyDefaultTypeFaceToImportedScores,
315                                       [this]() { preferences.setPreference(PREF_MIGRATION_APPLY_EDWIN_FOR_XML_FILES, applyDefaultTypeFaceToImportedScores->isChecked()); }, // apply function
316                                       [this]() {
317                                             bool value = preferences.getBool(PREF_MIGRATION_DO_NOT_ASK_ME_AGAIN_XML) && preferences.getBool(PREF_MIGRATION_APPLY_EDWIN_FOR_XML_FILES);
318                                             applyDefaultTypeFaceToImportedScores->setChecked(value);
319                                             }), // update function
320             #ifdef AVSOMR
321                   new BoolPreferenceItem(PREF_IMPORT_AVSOMR_USELOCAL, useLocalAvsOmr, [&](){ updateUseLocalAvsOmr(); }),
322             #endif
323                   new BoolPreferenceItem(PREF_IO_MIDI_ADVANCEONRELEASE, advanceOnRelease),
324                   new BoolPreferenceItem(PREF_IO_MIDI_ENABLEINPUT, enableMidiInput),
325                   new BoolPreferenceItem(PREF_IO_MIDI_EXPANDREPEATS, expandRepeats),
326                   new BoolPreferenceItem(PREF_EXPORT_AUDIO_NORMALIZE, normalize),
327                   new BoolPreferenceItem(PREF_IO_MIDI_EXPORTRPNS, exportRPNs),
328                   new IntPreferenceItem(PREF_IO_MIDI_REALTIMEDELAY, realtimeDelay),
329                   new BoolPreferenceItem(PREF_IO_MIDI_USEREMOTECONTROL, rcGroup),
330                   new IntPreferenceItem(PREF_IO_OSC_PORTNUMBER, oscPort),
331                   new BoolPreferenceItem(PREF_IO_OSC_USEREMOTECONTROL, oscServer),
332                   new BoolPreferenceItem(PREF_SCORE_CHORD_PLAYONADDNOTE, playChordOnAddNote),
333                   new BoolPreferenceItem(PREF_SCORE_HARMONY_PLAY_ONEDIT, playHarmonyOnEdit),
334                   new IntPreferenceItem(PREF_SCORE_NOTE_DEFAULTPLAYDURATION, defaultPlayDuration),
335                   new BoolPreferenceItem(PREF_SCORE_NOTE_PLAYONCLICK, playNotes),
336                   new BoolPreferenceItem(PREF_UI_APP_STARTUP_CHECKUPDATE, checkUpdateStartup),
337                   new BoolPreferenceItem(PREF_UI_APP_STARTUP_SHOWNAVIGATOR, navigatorShow),
338                   new BoolPreferenceItem(PREF_UI_APP_STARTUP_SHOWPLAYPANEL, playPanelShow),
339                   new BoolPreferenceItem(PREF_UI_APP_STARTUP_SHOWSPLASHSCREEN, showSplashScreen),
340                   new BoolPreferenceItem(PREF_UI_APP_STARTUP_SHOWSTARTCENTER, showStartcenter),
341                   new BoolPreferenceItem(PREF_UI_APP_STARTUP_SHOWTOURS, showTours),
342                   new BoolPreferenceItem(PREF_APP_TELEMETRY_ALLOWED, collectTelemetry),
343                   new BoolPreferenceItem(PREF_IO_JACK_TIMEBASEMASTER, becomeTimebaseMaster),
344                   new BoolPreferenceItem(PREF_IO_JACK_REMEMBERLASTCONNECTIONS, rememberLastMidiConnections),
345                   new BoolPreferenceItem(PREF_SCORE_NOTE_WARNPITCHRANGE, warnPitchRange),
346                   new StringPreferenceItem(PREF_IMPORT_OVERTURE_CHARSET, importCharsetListOve, nullptr, [&](){ updateCharsetListOve(); }),      // keep the default apply
347                   new StringPreferenceItem(PREF_IMPORT_GUITARPRO_CHARSET, importCharsetListGP, nullptr, [&](){ updateCharsetListGP(); }),       // keep the default apply
348                   new IntPreferenceItem(PREF_EXPORT_AUDIO_SAMPLERATE, exportAudioSampleRate),
349                   new IntPreferenceItem(PREF_EXPORT_MP3_BITRATE, exportMp3BitRate),
350                   new StringPreferenceItem(PREF_SCORE_STYLE_DEFAULTSTYLEFILE, defaultStyle,
351                                           [this]() { // apply function
352                                                 preferences.setPreference(PREF_SCORE_STYLE_DEFAULTSTYLEFILE, defaultStyle->text());
353                                                 MScore::readDefaultStyle(preferences.getString(PREF_SCORE_STYLE_DEFAULTSTYLEFILE));
354                                                 }),
355                   new StringPreferenceItem(PREF_SCORE_STYLE_PARTSTYLEFILE, partStyle,
356                                           [this]() { // apply function
357                                                 preferences.setPreference(PREF_SCORE_STYLE_PARTSTYLEFILE, partStyle->text());
358                                                 MScore::defaultStyleForPartsHasChanged();
359                                                 }),
360                   new StringPreferenceItem(PREF_IMPORT_STYLE_STYLEFILE, importStyleFile,
361                                           [this]() { // apply function
362                                                 preferences.setPreference(PREF_IMPORT_STYLE_STYLEFILE, useImportStyleFile->isChecked() ? importStyleFile->text() : "");
363                                                 },
364                                           [this]() { // update function
365                                                 QString styleFile = preferences.getString(PREF_IMPORT_STYLE_STYLEFILE);
366                                                 importStyleFile->setText(styleFile);
367                                                 useImportBuiltinStyle->setChecked(styleFile.isEmpty());
368                                                 useImportStyleFile->setChecked(!styleFile.isEmpty());
369                                                 }),
370                   new BoolPreferenceItem(PREF_IO_MIDI_SHOWCONTROLSINMIXER, showMidiControls,
371                                           [this]() { // apply function
372                                                 preferences.setPreference(PREF_IO_MIDI_SHOWCONTROLSINMIXER, showMidiControls->isChecked());
373                                                 emit mixerPreferencesChanged(preferences.getBool(PREF_IO_MIDI_SHOWCONTROLSINMIXER));
374                                                 }),
375                   new BoolPreferenceItem(PREF_UI_CANVAS_SCROLL_VERTICALORIENTATION, pageVertical,
376                                           [this]() { applyPageVertical(); },  // apply function
377                                           [this]() { pageVertical->setChecked(MScore::verticalOrientation()); }), // update function
378                   new IntPreferenceItem(PREF_IO_MIDI_SHORTESTNOTE, shortestNote,
379                                           [this]() { applyShortestNote();  },  // apply function
380                                           [this]() { updateShortestNote(); }), // update function
381                   new BoolPreferenceItem(PREF_MIGRATION_DO_NOT_ASK_ME_AGAIN, scoreMigrationEnabled,
382                                           [this]() { preferences.setPreference(PREF_MIGRATION_DO_NOT_ASK_ME_AGAIN, !scoreMigrationEnabled->isChecked()); }, // apply function
383                                           [this]() { scoreMigrationEnabled->setChecked(!preferences.getBool(PREF_MIGRATION_DO_NOT_ASK_ME_AGAIN)); }), // update function
384                   new BoolPreferenceItem(PREF_MIGRATION_DO_NOT_ASK_ME_AGAIN_XML),
385                   new StringPreferenceItem(PREF_UI_APP_LANGUAGE, language, [&](){ languageApply(); }, [&](){ languageUpdate(); }),
386                   new CustomPreferenceItem(PREF_APP_STARTUP_SESSIONSTART, lastSession,
387                                           [this]() { // apply function
388                                                 if (lastSession->isChecked())
389                                                       preferences.setCustomPreference<SessionStart>(PREF_APP_STARTUP_SESSIONSTART, SessionStart::LAST);
390                                                 },
391                                           [this]() { // update function
392                                                 lastSession->setChecked(preferences.sessionStart() == SessionStart::LAST);
393                                                 }),
394                   new CustomPreferenceItem(PREF_APP_STARTUP_SESSIONSTART, newSession,
395                                           [this]() { // apply function
396                                                 if (newSession->isChecked())
397                                                       preferences.setCustomPreference<SessionStart>(PREF_APP_STARTUP_SESSIONSTART, SessionStart::NEW);
398                                                 },
399                                           [this]() { // update function
400                                                 newSession->setChecked(preferences.sessionStart() == SessionStart::NEW);
401                                                 }),
402                   new CustomPreferenceItem(PREF_APP_STARTUP_SESSIONSTART, scoreSession,
403                                           [this]() { // apply function
404                                                 if (scoreSession->isChecked())
405                                                       preferences.setCustomPreference<SessionStart>(PREF_APP_STARTUP_SESSIONSTART, SessionStart::SCORE);
406                                                 },
407                                           [this]() { // update function
408                                                 scoreSession->setChecked(preferences.sessionStart() == SessionStart::SCORE);
409                                                 }),
410                   new CustomPreferenceItem(PREF_APP_STARTUP_SESSIONSTART, emptySession,
411                                           [this]() { // apply function
412                                                if (emptySession->isChecked())
413                                                      preferences.setCustomPreference<SessionStart>(PREF_APP_STARTUP_SESSIONSTART, SessionStart::EMPTY);
414                                                 },
415                                           [this]() { // update function
416                                                 emptySession->setChecked(preferences.sessionStart() == SessionStart::EMPTY);
417                                                 }),
418                   new BoolPreferenceItem(PREF_EXPORT_MUSICXML_EXPORTLAYOUT, exportAllLayouts),
419                   new CustomPreferenceItem(PREF_EXPORT_MUSICXML_EXPORTBREAKS, exportAllLayouts,
420                                           [this]() { // apply function
421                                                 if (exportAllLayouts->isChecked())
422                                                       preferences.setCustomPreference<MusicxmlExportBreaks>(PREF_EXPORT_MUSICXML_EXPORTBREAKS, MusicxmlExportBreaks::ALL);
423                                                 },
424                                           []()  { // update function
425                                                 ;
426                                                 }),
427                   new CustomPreferenceItem(PREF_EXPORT_MUSICXML_EXPORTBREAKS, exportAllBreaks,
428                                           [this]() { // apply function
429                                                 if (exportAllBreaks->isChecked())
430                                                       preferences.setCustomPreference<MusicxmlExportBreaks>(PREF_EXPORT_MUSICXML_EXPORTBREAKS, MusicxmlExportBreaks::ALL);
431                                                 },
432                                           [this]() { // update function
433                                                 if (!preferences.getBool(PREF_EXPORT_MUSICXML_EXPORTLAYOUT))
434                                                       exportAllBreaks->setChecked(preferences.musicxmlExportBreaks() == MusicxmlExportBreaks::ALL);
435                                                 }),
436                   new CustomPreferenceItem(PREF_EXPORT_MUSICXML_EXPORTBREAKS, exportManualBreaks,
437                                           [this]() { // apply function
438                                                 if (exportManualBreaks->isChecked())
439                                                       preferences.setCustomPreference<MusicxmlExportBreaks>(PREF_EXPORT_MUSICXML_EXPORTBREAKS, MusicxmlExportBreaks::MANUAL);
440                                                 },
441                                           [this]() { // update function
442                                                 if (!preferences.getBool(PREF_EXPORT_MUSICXML_EXPORTLAYOUT))
443                                                       exportManualBreaks->setChecked(preferences.musicxmlExportBreaks() == MusicxmlExportBreaks::MANUAL);
444                                                 }),
445                   new CustomPreferenceItem(PREF_EXPORT_MUSICXML_EXPORTBREAKS, exportNoBreaks,
446                                           [this]() { // apply function
447                                                 if (exportNoBreaks->isChecked())
448                                                       preferences.setCustomPreference<MusicxmlExportBreaks>(PREF_EXPORT_MUSICXML_EXPORTBREAKS, MusicxmlExportBreaks::NO);
449                                                 },
450                                           [this]() { // update function
451                                                 if (!preferences.getBool(PREF_EXPORT_MUSICXML_EXPORTLAYOUT))
452                                                       exportNoBreaks->setChecked(preferences.musicxmlExportBreaks() == MusicxmlExportBreaks::NO);
453                                                 }),
454 
455       };
456 
457       // Contains widgets that change the appearance of MuseScore (style/theme) and/or are saved in Workspaces.
458       uiRelatedWidgets = std::vector<PreferenceItem*>{
459                   new BoolPreferenceItem(PREF_UI_CANVAS_BG_USECOLOR, bgColorButton, nullptr, [&](){ updateBgView(preferences.getBool(PREF_UI_CANVAS_BG_USECOLOR)); }),
460                   new ColorPreferenceItem(PREF_UI_CANVAS_BG_COLOR, bgColorLabel, nullptr, doNothing),
461                   new BoolPreferenceItem(PREF_UI_CANVAS_FG_USECOLOR, fgColorButton, nullptr, [&](){ updateFgView(preferences.getBool(PREF_UI_CANVAS_FG_USECOLOR)); }),
462                   new BoolPreferenceItem(PREF_UI_CANVAS_FG_USECOLOR_IN_PALETTES, fgUseColorInPalettes, nullptr, doNothing),
463                   new ColorPreferenceItem(PREF_UI_CANVAS_FG_COLOR, fgColorLabel, nullptr, doNothing),
464                   new StringPreferenceItem(PREF_UI_CANVAS_BG_WALLPAPER, bgWallpaper, nullptr, doNothing),
465                   new StringPreferenceItem(PREF_UI_CANVAS_FG_WALLPAPER, fgWallpaper, nullptr, doNothing),
466                   new IntPreferenceItem(PREF_UI_CANVAS_ZOOM_DEFAULT_TYPE, zoomDefaultType, nullptr,
467                                           [this]() { // update function
468                                                 zoomDefaultType->setCurrentIndex(preferences.getInt(PREF_UI_CANVAS_ZOOM_DEFAULT_TYPE));
469                                                 zoomDefaultTypeChanged(preferences.getInt(PREF_UI_CANVAS_ZOOM_DEFAULT_TYPE));
470                                                 }),
471                   new IntPreferenceItem(PREF_UI_CANVAS_ZOOM_DEFAULT_LEVEL, zoomDefaultLevel,
472                                           [this]() { preferences.setPreference(PREF_UI_CANVAS_ZOOM_DEFAULT_LEVEL, zoomDefaultLevel->value()); }, // apply function
473                                           [this]() { zoomDefaultLevel->setValue(preferences.getInt(PREF_UI_CANVAS_ZOOM_DEFAULT_LEVEL)); }        // update function
474                                                 ),
475                   new IntPreferenceItem(PREF_UI_CANVAS_ZOOM_PRECISION_KEYBOARD, zoomPrecisionKeyboard),
476                   new IntPreferenceItem(PREF_UI_CANVAS_ZOOM_PRECISION_MOUSE, zoomPrecisionMouse),
477                   new BoolPreferenceItem(PREF_UI_CANVAS_MISC_ANTIALIASEDDRAWING, drawAntialiased),
478                   new BoolPreferenceItem(PREF_UI_CANVAS_SCROLL_LIMITSCROLLAREA, limitScrollArea),
479                   new IntPreferenceItem(PREF_UI_CANVAS_MISC_SELECTIONPROXIMITY, proximity),
480                   new IntPreferenceItem(PREF_UI_THEME_ICONWIDTH, iconWidth),
481                   new IntPreferenceItem(PREF_UI_THEME_ICONHEIGHT, iconHeight),
482                   new StringPreferenceItem(PREF_UI_THEME_FONTFAMILY, fontFamily, nullptr,
483                                           [&]() { // update function
484                                                 auto currFontFamily = preferences.getString(PREF_UI_THEME_FONTFAMILY);
485                                                 if (-1 == fontFamily->findText(currFontFamily))
486                                                       fontFamily->addItem(currFontFamily);
487                                                 fontFamily->setCurrentIndex(fontFamily->findText(currFontFamily));
488                                                 }),
489                   new DoublePreferenceItem(PREF_UI_THEME_FONTSIZE, fontSize),
490                   new CustomPreferenceItem(PREF_UI_APP_GLOBALSTYLE, styleName,
491                                           [&]() { // apply function
492                                                 preferences.setCustomPreference<MuseScorePreferredStyleType>(PREF_UI_APP_GLOBALSTYLE, MuseScorePreferredStyleType(styleName->currentIndex()));
493                                                 },
494                                           [&]() { // update function
495                                                 styleName->setCurrentIndex(int(preferences.preferredGlobalStyle()));
496                                                 }),
497       };
498 
499       // All these widgets are interconnected and are used together to set their preferences. Don't add unrelated, or not immediately related widgets.
500       audioRelatedWidgets = std::vector<PreferenceItem*>{
501                   new BoolPreferenceItem(PREF_IO_ALSA_USEALSAAUDIO, alsaDriver, doNothing),
502                   new BoolPreferenceItem(PREF_IO_JACK_USEJACKAUDIO, useJackAudio, doNothing),
503                   new BoolPreferenceItem(PREF_IO_PORTAUDIO_USEPORTAUDIO, portaudioDriver, doNothing),
504                   new BoolPreferenceItem(PREF_IO_PULSEAUDIO_USEPULSEAUDIO, pulseaudioDriver, doNothing),
505                   new BoolPreferenceItem(PREF_IO_JACK_USEJACKMIDI, useJackMidi, doNothing),
506                   new BoolPreferenceItem(PREF_IO_JACK_USEJACKTRANSPORT, useJackTransport, doNothing),
507                   new StringPreferenceItem(PREF_IO_ALSA_DEVICE, alsaDevice, doNothing),
508                   new IntPreferenceItem(PREF_IO_ALSA_SAMPLERATE, alsaSampleRate, doNothing),
509                   new IntPreferenceItem(PREF_IO_ALSA_PERIODSIZE, alsaPeriodSize, doNothing),
510                   new IntPreferenceItem(PREF_IO_ALSA_FRAGMENTS, alsaFragments, doNothing),
511                   new IntPreferenceItem(PREF_IO_PORTAUDIO_DEVICE, portaudioApi, doNothing, doNothing),
512                   new IntPreferenceItem(PREF_IO_PORTAUDIO_DEVICE, portaudioDevice, doNothing, doNothing),
513             #ifdef USE_PORTMIDI
514                   new StringPreferenceItem(PREF_IO_PORTMIDI_INPUTDEVICE, portMidiInput, doNothing, doNothing),
515                   new StringPreferenceItem(PREF_IO_PORTMIDI_OUTPUTDEVICE, portMidiOutput, doNothing, doNothing),
516                   new IntPreferenceItem(PREF_IO_PORTMIDI_OUTPUTLATENCYMILLISECONDS, portMidiOutputLatencyMilliseconds),
517             #endif
518       };
519 
520       // These connections are used to enable the Apply button and to save only the changed preferences.
521 
522       for (auto& x : normalWidgets)
523             connect(x, &PreferenceItem::editorValueModified, this, &PreferenceDialog::widgetModified);
524 
525       for (auto& x : uiRelatedWidgets)
526             connect(x, &PreferenceItem::editorValueModified, this, &PreferenceDialog::uiWidgetModified);
527 
528       for (auto& x : audioRelatedWidgets)
529             connect(x, &PreferenceItem::editorValueModified, this, &PreferenceDialog::audioWidgetModified);
530 
531       for (auto& x : advancedWidget->preferenceItems())
532             connect(x, &PreferenceItem::editorValueModified, this, &PreferenceDialog::applyActivate);
533 
534       updateValues(false, true);
535       modifiedWidgets.clear();
536       modifiedUiWidgets.clear();
537       modifiedAudioWidgets.clear();
538       applySetActive(false);
539       show();
540       }
541 
542 //---------------------------------------------------------
543 //   ~PreferenceDialog
544 //---------------------------------------------------------
545 
~PreferenceDialog()546 PreferenceDialog::~PreferenceDialog()
547       {
548       for (size_t i = 0; i < normalWidgets.size(); i++)
549             delete normalWidgets.at(i);
550       normalWidgets.clear();
551 
552       for (size_t i = 0; i < uiRelatedWidgets.size(); i++)
553             delete uiRelatedWidgets.at(i);
554       uiRelatedWidgets.clear();
555 
556       for (size_t i = 0; i < audioRelatedWidgets.size(); i++)
557             delete audioRelatedWidgets.at(i);
558       audioRelatedWidgets.clear();
559 
560       qDeleteAll(localShortcuts);
561       }
562 
563 //---------------------------------------------------------
564 //   retranslate
565 //---------------------------------------------------------
566 
retranslate()567 void PreferenceDialog::retranslate()
568       {
569       retranslateUi(this);
570       updateValues();
571       }
572 
573 //---------------------------------------------------------
574 //   hideEvent
575 //---------------------------------------------------------
576 
hideEvent(QHideEvent * ev)577 void PreferenceDialog::hideEvent(QHideEvent* ev)
578       {
579       MuseScore::saveGeometry(this);
580       QWidget::hideEvent(ev);
581       }
582 
583 //---------------------------------------------------------
584 //   recordButtonClicked
585 //---------------------------------------------------------
586 
recordButtonClicked(int val)587 void PreferenceDialog::recordButtonClicked(int val)
588       {
589       for (QAbstractButton* b : recordButtons->buttons()) {
590             b->setChecked(recordButtons->id(b) == val);
591             }
592       mscore->setMidiRecordId(val);
593       }
594 
595 //---------------------------------------------------------
596 //   updateRemote
597 //---------------------------------------------------------
598 
updateRemote()599 void PreferenceDialog::updateRemote()
600       {
601       rewindActive->setChecked(preferences.midiRemote(RMIDI_REWIND).type != -1);
602       togglePlayActive->setChecked(preferences.midiRemote(RMIDI_TOGGLE_PLAY).type   != -1);
603       playActive->setChecked(preferences.midiRemote(RMIDI_PLAY).type         != -1);
604       stopActive->setChecked(preferences.midiRemote(RMIDI_STOP).type         != -1);
605       rca2->setChecked(preferences.midiRemote(RMIDI_NOTE1).type        != -1);
606       rca3->setChecked(preferences.midiRemote(RMIDI_NOTE2).type        != -1);
607       rca4->setChecked(preferences.midiRemote(RMIDI_NOTE4).type        != -1);
608       rca5->setChecked(preferences.midiRemote(RMIDI_NOTE8).type        != -1);
609       rca6->setChecked(preferences.midiRemote(RMIDI_NOTE16).type       != -1);
610       rca7->setChecked(preferences.midiRemote(RMIDI_NOTE32).type       != -1);
611       rca8->setChecked(preferences.midiRemote(RMIDI_NOTE64).type      != -1);
612       rca9->setChecked(preferences.midiRemote(RMIDI_REST).type        != -1);
613       rca10->setChecked(preferences.midiRemote(RMIDI_DOT).type         != -1);
614       rca11->setChecked(preferences.midiRemote(RMIDI_DOTDOT).type      != -1);
615       rca12->setChecked(preferences.midiRemote(RMIDI_TIE).type        != -1);
616       recordUndoActive->setChecked(preferences.midiRemote(RMIDI_UNDO).type != -1);
617       editModeActive->setChecked(preferences.midiRemote(RMIDI_NOTE_EDIT_MODE).type != -1);
618       realtimeAdvanceActive->setChecked(preferences.midiRemote(RMIDI_REALTIME_ADVANCE).type != -1);
619 
620       int id = mscore->midiRecordId();
621       recordRewind->setChecked(id == RMIDI_REWIND);
622       recordTogglePlay->setChecked(id == RMIDI_TOGGLE_PLAY);
623       recordPlay->setChecked(id == RMIDI_PLAY);
624       recordStop->setChecked(id == RMIDI_STOP);
625       rcr2->setChecked(id       == RMIDI_NOTE1);
626       rcr3->setChecked(id       == RMIDI_NOTE2);
627       rcr4->setChecked(id       == RMIDI_NOTE4);
628       rcr5->setChecked(id       == RMIDI_NOTE8);
629       rcr6->setChecked(id       == RMIDI_NOTE16);
630       rcr7->setChecked(id       == RMIDI_NOTE32);
631       rcr8->setChecked(id       == RMIDI_NOTE64);
632       rcr9->setChecked(id       == RMIDI_REST);
633       rcr10->setChecked(id      == RMIDI_DOT);
634       rcr11->setChecked(id      == RMIDI_DOTDOT);
635       rcr12->setChecked(id      == RMIDI_TIE);
636       recordUndo->setChecked(id == RMIDI_UNDO);
637       recordEditMode->setChecked(id == RMIDI_NOTE_EDIT_MODE);
638       recordRealtimeAdvance->setChecked(id == RMIDI_REALTIME_ADVANCE);
639       }
640 
641 //---------------------------------------------------------
642 //   updateValues
643 //---------------------------------------------------------
644 
updateValues(bool useDefaultValues,bool setup)645 void PreferenceDialog::updateValues(bool useDefaultValues, bool setup)
646       {
647       if (useDefaultValues)
648             preferences.setReturnDefaultValuesMode(true);
649 
650       styleName->clear();
651       styleName->addItem(tr("Light"));
652       styleName->addItem(tr("Dark"));
653 #ifdef Q_OS_MAC // On Mac, we have a theme option to follow the system's Dark Mode
654       if (CocoaBridge::isSystemDarkModeSupported())
655             styleName->addItem(tr("System"));
656 #endif
657 
658       advancedWidget->updatePreferences();
659 
660       //macOS default fonts are not in QFontCombobox because they are "private":
661       //https://code.woboq.org/qt5/qtbase/src/widgets/widgets/qfontcombobox.cpp.html#329
662 
663       jackDriver->setChecked(preferences.getBool(PREF_IO_JACK_USEJACKAUDIO) || preferences.getBool(PREF_IO_JACK_USEJACKMIDI));
664 
665 #ifndef AVSOMR
666     groupBox_omr->setVisible(false);
667 #endif
668 
669       //
670       // initialize local shortcut table
671       //    we need a deep copy to be able to rewind all
672       //    changes on "Abort"
673       //
674       qDeleteAll(localShortcuts);
675       localShortcuts.clear();
676       for(const Shortcut* s : Shortcut::shortcuts())
677             localShortcuts[s->key()] = new Shortcut(*s);
678       updateSCListView();
679 
680       //Generate the filtered Shortcut List
681       filterShortcutsTextChanged(filterShortcuts->text());
682 
683       //
684       // initialize portaudio
685       //
686 #ifdef USE_PORTAUDIO
687       if (portAudioIsUsed) {
688             Portaudio* audio = static_cast<Portaudio*>(seq->driver());
689             if (audio) {
690                   QStringList apis = audio->apiList();
691                   portaudioApi->clear();
692                   portaudioApi->addItems(apis);
693                   portaudioApi->setCurrentIndex(audio->currentApi());
694 
695                   QStringList devices = audio->deviceList(audio->currentApi());
696                   portaudioDevice->clear();
697                   portaudioDevice->addItems(devices);
698                   portaudioDevice->setCurrentIndex(audio->currentDevice());
699 
700                   connect(portaudioApi, QOverload<int>::of(&QComboBox::activated), this, &PreferenceDialog::portaudioApiActivated);
701 #ifdef USE_PORTMIDI
702                   PortMidiDriver* midiDriver = static_cast<PortMidiDriver*>(audio->mididriver());
703                   if (midiDriver) {
704                         QStringList midiInputs = midiDriver->deviceInList();
705                         int curMidiInIdx = 0;
706                         portMidiInput->clear();
707                         for(int i = 0; i < midiInputs.size(); ++i) {
708                               portMidiInput->addItem(midiInputs.at(i), i);
709                               if (midiInputs.at(i) == preferences.getString(PREF_IO_PORTMIDI_INPUTDEVICE))
710                                     curMidiInIdx = i;
711                               }
712                         portMidiInput->setCurrentIndex(curMidiInIdx);
713 
714                         QStringList midiOutputs = midiDriver->deviceOutList();
715                         int curMidiOutIdx = -1; // do not set a midi out device if user never selected one
716                         portMidiOutput->clear();
717                         portMidiOutput->addItem("", -1);
718                         for(int i = 0; i < midiOutputs.size(); ++i) {
719                               portMidiOutput->addItem(midiOutputs.at(i), i);
720                               if (midiOutputs.at(i) == preferences.getString(PREF_IO_PORTMIDI_OUTPUTDEVICE))
721                                     curMidiOutIdx = i + 1;
722                               }
723                         portMidiOutput->setCurrentIndex(curMidiOutIdx);
724                         }
725 #endif
726                   }
727             }
728 #endif
729 
730 #ifndef HAS_MIDI
731       enableMidiInput->setEnabled(false);
732       rcGroup->setEnabled(false);
733 #endif
734 
735       for (auto& x : normalWidgets)
736             x->update(setup);
737 
738       for (auto& x : uiRelatedWidgets)
739             x->update(setup);
740 
741       for (auto& x : audioRelatedWidgets)
742             x->update(setup);
743 
744       if (useDefaultValues)
745             preferences.setReturnDefaultValuesMode(false);
746       }
747 
748 //---------------------------------------------------------
749 //   portaudioApiActivated
750 //---------------------------------------------------------
751 
752 #ifdef USE_PORTAUDIO
portaudioApiActivated(int idx)753 void PreferenceDialog::portaudioApiActivated(int idx)
754       {
755       Portaudio* audio = static_cast<Portaudio*>(seq->driver());
756       QStringList devices = audio->deviceList(idx);
757       portaudioDevice->clear();
758       portaudioDevice->addItems(devices);
759       }
760 #else
portaudioApiActivated(int)761 void PreferenceDialog::portaudioApiActivated(int)  {}
762 #endif
763 
764 //---------------------------------------------------------
765 //   ShortcutItem
766 //---------------------------------------------------------
767 
operator <(const QTreeWidgetItem & item) const768 bool ShortcutItem::operator<(const QTreeWidgetItem& item) const
769       {
770 
771       const QTreeWidget * pTree =treeWidget ();
772       int column   = pTree ? pTree->sortColumn() : 0;
773       return QString::localeAwareCompare(text(column).toLower(), item.text(column).toLower()) > 0;
774       }
775 
776 //---------------------------------------------------------
777 //   updateSCListView
778 //---------------------------------------------------------
779 
updateSCListView()780 void PreferenceDialog::updateSCListView()
781       {
782       shortcutList->clear();
783       for (Shortcut* s : localShortcuts) {
784             if (!s)
785                   continue;
786             ShortcutItem* newItem = new ShortcutItem;
787             newItem->setText(0, s->descr());
788             if (s->icon() != Icons::Invalid_ICON)
789                   newItem->setIcon(0, *icons[int(s->icon())]);
790             newItem->setText(1, s->keysToString());
791             newItem->setData(0, Qt::UserRole, s->key());
792             QString accessibleInfo = tr("Action: %1; Shortcut: %2")
793                .arg(newItem->text(0)).arg(newItem->text(1).isEmpty()
794                   ? tr("No shortcut defined") : newItem->text(1));
795             newItem->setData(0, Qt::AccessibleTextRole, accessibleInfo);
796             newItem->setData(1, Qt::AccessibleTextRole, accessibleInfo);
797             if (enableExperimental
798                         || (!s->key().startsWith("media")
799                             && !s->key().startsWith("layer")
800 #ifdef NDEBUG
801                             && !s->key().startsWith("debugger")
802 #endif
803                             && !s->key().startsWith("edit_harmony")
804                             && !s->key().startsWith("insert-fretframe"))) {
805                   shortcutList->addTopLevelItem(newItem);
806                   }
807             }
808       shortcutList->resizeColumnToContents(0);
809       }
810 
811 //---------------------------------------------------------
812 //   resetShortcutClicked
813 //    reset selected shortcut to buildin default
814 //---------------------------------------------------------
815 
resetShortcutClicked()816 void PreferenceDialog::resetShortcutClicked()
817       {
818       QTreeWidgetItem* active = shortcutList->currentItem();
819       if (!active)
820             return;
821       QString str = active->data(0, Qt::UserRole).toString();
822       if (str.isEmpty())
823             return;
824       Shortcut* shortcut = localShortcuts[str.toLatin1().data()];
825 
826       shortcut->reset();
827 
828       active->setText(1, shortcut->keysToString());
829       shortcutsChanged = true;
830       applySetActive(true);
831       }
832 
833 //---------------------------------------------------------
834 //   saveShortcutListClicked
835 //---------------------------------------------------------
836 
saveShortcutListClicked()837 void PreferenceDialog::saveShortcutListClicked()
838       {
839       QString saveFileName = QFileDialog::getSaveFileName(this, tr("Save Shortcuts"), preferences.getString(PREF_APP_PATHS_MYSHORTCUTS) + "/shortcuts.xml", tr("MuseScore Shortcuts File") + " (*.xml)", 0, preferences.getBool(PREF_UI_APP_USENATIVEDIALOGS) ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog);
840       preferences.setPreference(PREF_APP_PATHS_MYSHORTCUTS, saveFileName);
841       Shortcut::saveToNewFile(saveFileName);
842       }
843 
844 //---------------------------------------------------------
845 //   loadShortcutListClicked
846 //---------------------------------------------------------
847 
loadShortcutListClicked()848 void PreferenceDialog::loadShortcutListClicked()
849       {
850       QString loadFileName = QFileDialog::getOpenFileName(this, tr("Load Shortcuts"), preferences.getString(PREF_APP_PATHS_MYSHORTCUTS), tr("MuseScore Shortcuts File") +  " (*.xml)", 0, preferences.getBool(PREF_UI_APP_USENATIVEDIALOGS) ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog);
851       if (!loadFileName.isNull()) {
852             preferences.setPreference(PREF_APP_PATHS_MYSHORTCUTS, loadFileName);
853             Shortcut::loadFromNewFile(loadFileName);
854             }
855       }
856 
857 //---------------------------------------------------------
858 //   clearShortcutClicked
859 //---------------------------------------------------------
860 
clearShortcutClicked()861 void PreferenceDialog::clearShortcutClicked()
862       {
863       QTreeWidgetItem* active = shortcutList->currentItem();
864       if (!active)
865             return;
866       QString str = active->data(0, Qt::UserRole).toString();
867       if (str.isEmpty())
868             return;
869       Shortcut* s = localShortcuts[str.toLatin1().data()];
870       s->clear();
871       active->setText(1, "");
872       shortcutsChanged = true;
873       applySetActive(true);
874       }
875 
876 //--------------------------------------------------------
877 //   filterShortcutsTextChanged
878 //--------------------------------------------------------
879 
filterShortcutsTextChanged(const QString & query)880 void  PreferenceDialog::filterShortcutsTextChanged(const QString &query )
881       {
882       QTreeWidgetItem *item;
883       for(int i = 0; i < shortcutList->topLevelItemCount(); i++) {
884           item = shortcutList->topLevelItem(i);
885           item->setHidden(!(item->text(0).contains(query, Qt::CaseInsensitive) || item->text(1).contains(query, Qt::CaseInsensitive)));
886           }
887       }
888 
889 //--------------------------------------------------------
890 //   filterAdvancedPreferences
891 //--------------------------------------------------------
892 
filterAdvancedPreferences(const QString & query)893 void PreferenceDialog::filterAdvancedPreferences(const QString& query)
894       {
895       QTreeWidgetItem *item;
896       for(int i = 0; i < advancedWidget->topLevelItemCount(); i++) {
897             item = advancedWidget->topLevelItem(i);
898 
899             if(item->text(0).toLower().contains(query.toLower()))
900                   item->setHidden(false);
901             else
902                   item->setHidden(true);
903             }
904       }
905 
906 //--------------------------------------------------------
907 //   resetAdvancedPreferenceToDefault
908 //--------------------------------------------------------
909 
resetAdvancedPreferenceToDefault()910 void PreferenceDialog::resetAdvancedPreferenceToDefault()
911       {
912       preferences.setReturnDefaultValuesMode(true);
913       for (QTreeWidgetItem* item : advancedWidget->selectedItems()) {
914             PreferenceItem* pref = static_cast<PreferenceItem*>(item);
915             pref->setDefaultValue();
916             }
917       preferences.setReturnDefaultValuesMode(false);
918       }
919 
920 //---------------------------------------------------------
921 //   selectFgWallpaper
922 //---------------------------------------------------------
923 
selectFgWallpaper()924 void PreferenceDialog::selectFgWallpaper()
925       {
926       QString s = mscore->getWallpaper(tr("Choose Notepaper"));
927       if (!s.isNull()) {
928             fgWallpaper->setText(s);
929             updateFgView(false);
930             }
931       }
932 
933 //---------------------------------------------------------
934 //   selectBgWallpaper
935 //---------------------------------------------------------
936 
selectBgWallpaper()937 void PreferenceDialog::selectBgWallpaper()
938       {
939       QString s = mscore->getWallpaper(tr("Choose Background Wallpaper"));
940       if (!s.isNull()) {
941             bgWallpaper->setText(s);
942             updateBgView(false);
943             }
944       }
945 
946 //---------------------------------------------------------
947 //   selectDefaultStyle
948 //---------------------------------------------------------
949 
selectDefaultStyle()950 void PreferenceDialog::selectDefaultStyle()
951       {
952       QString s = mscore->getStyleFilename(true, tr("Choose Default Style"));
953       if (!s.isNull())
954             defaultStyle->setText(s);
955       }
956 
957 //---------------------------------------------------------
958 //   selectPartStyle
959 //---------------------------------------------------------
960 
selectPartStyle()961 void PreferenceDialog::selectPartStyle()
962       {
963       QString s = mscore->getStyleFilename(true, tr("Choose Default Style for Parts"));
964       if (!s.isNull())
965             partStyle->setText(s);
966       }
967 
968 //---------------------------------------------------------
969 //   selectInstrumentList1
970 //---------------------------------------------------------
971 
selectInstrumentList1()972 void PreferenceDialog::selectInstrumentList1()
973       {
974       QString s = QFileDialog::getOpenFileName(
975          this,
976          tr("Choose Instrument List"),
977          instrumentList1->text(),
978          tr("Instrument List") + " (*.xml)",
979          0,
980          preferences.getBool(PREF_UI_APP_USENATIVEDIALOGS) ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog
981          );
982       if (!s.isNull())
983             instrumentList1->setText(s);
984       }
985 
986 //---------------------------------------------------------
987 //   selectInstrumentList2
988 //---------------------------------------------------------
989 
selectInstrumentList2()990 void PreferenceDialog::selectInstrumentList2()
991       {
992       QString s = QFileDialog::getOpenFileName(
993          this,
994          tr("Choose Instrument List"),
995          instrumentList2->text(),
996          tr("Instrument List") + " (*.xml)",
997          0,
998          preferences.getBool(PREF_UI_APP_USENATIVEDIALOGS) ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog
999          );
1000       if (!s.isNull())
1001             instrumentList2->setText(s);
1002       }
1003 
1004 //---------------------------------------------------------
1005 //   selectScoreOrderList1
1006 //---------------------------------------------------------
1007 
selectScoreOrderList1()1008 void PreferenceDialog::selectScoreOrderList1()
1009       {
1010       QString s = QFileDialog::getOpenFileName(
1011          this,
1012          tr("Choose Score Order List"),
1013          scoreOrderList1->text(),
1014          tr("Score Order List") + " (*.xml)",
1015          0,
1016          preferences.getBool(PREF_UI_APP_USENATIVEDIALOGS) ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog
1017          );
1018       if (!s.isNull())
1019             scoreOrderList1->setText(s);
1020       }
1021 
1022 //---------------------------------------------------------
1023 //   selectScoreOrderList2
1024 //---------------------------------------------------------
1025 
selectScoreOrderList2()1026 void PreferenceDialog::selectScoreOrderList2()
1027       {
1028       QString s = QFileDialog::getOpenFileName(
1029          this,
1030          tr("Choose Score Order List"),
1031          scoreOrderList2->text(),
1032          tr("Score Order List") + " (*.xml)",
1033          0,
1034          preferences.getBool(PREF_UI_APP_USENATIVEDIALOGS) ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog
1035          );
1036       if (!s.isNull())
1037             scoreOrderList2->setText(s);
1038       }
1039 
1040 //---------------------------------------------------------
1041 //   zoomDefaultTypeChanged
1042 //---------------------------------------------------------
1043 
zoomDefaultTypeChanged(const int index)1044 void PreferenceDialog::zoomDefaultTypeChanged(const int index)
1045       {
1046       // Only enable editing of [zoom-percentage spinner widget] if [Percentage] is selected
1047       zoomDefaultLevel->setEnabled(static_cast<ZoomType>(index) == ZoomType::PERCENTAGE);
1048       }
1049 
1050 //---------------------------------------------------------
1051 //   selectStartWith
1052 //---------------------------------------------------------
1053 
selectStartWith()1054 void PreferenceDialog::selectStartWith()
1055       {
1056       QString s = QFileDialog::getOpenFileName(
1057          this,
1058          tr("Choose Starting Score"),
1059          sessionScore->text(),
1060          tr("MuseScore Files") + " (*.mscz *.mscx);;" + tr("All") + " (*)",
1061          0,
1062          preferences.getBool(PREF_UI_APP_USENATIVEDIALOGS) ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog
1063          );
1064       if (!s.isNull())
1065             sessionScore->setText(s);
1066       }
1067 
1068 //---------------------------------------------------------
1069 //   fgClicked
1070 //---------------------------------------------------------
1071 
updateFgView(bool useColor)1072 void PreferenceDialog::updateFgView(bool useColor)
1073       {
1074       fgColorButton->setChecked(useColor);
1075       fgWallpaperButton->setChecked(!useColor);
1076       fgUseColorInPalettes->setChecked(preferences.getBool(PREF_UI_CANVAS_FG_USECOLOR_IN_PALETTES));
1077       fgWallpaper->setEnabled(!useColor);
1078       fgWallpaperSelect->setEnabled(!useColor);
1079       fgUseColorInPalettes->setEnabled(useColor);
1080 
1081       if (useColor) {
1082             fgColorLabel->setColor(preferences.getColor(PREF_UI_CANVAS_FG_COLOR));
1083             fgColorLabel->setPixmap(0);
1084             }
1085       else {
1086             fgColorLabel->setPixmap(new QPixmap(fgWallpaper->text()));
1087             }
1088       }
1089 
1090 //---------------------------------------------------------
1091 //   bgClicked
1092 //---------------------------------------------------------
1093 
updateBgView(bool useColor)1094 void PreferenceDialog::updateBgView(bool useColor)
1095       {
1096       bgColorButton->setChecked(useColor);
1097       bgWallpaperButton->setChecked(!useColor);
1098       bgWallpaper->setEnabled(!useColor);
1099       bgWallpaperSelect->setEnabled(!useColor);
1100 
1101       if (useColor) {
1102             bgColorLabel->setColor(preferences.getColor(PREF_UI_CANVAS_BG_COLOR));
1103             bgColorLabel->setPixmap(0);
1104             }
1105       else {
1106             bgColorLabel->setPixmap(new QPixmap(bgWallpaper->text()));
1107             }
1108       }
1109 
1110 
1111 //---------------------------------------------------------
1112 //   languageUpdate
1113 //---------------------------------------------------------
1114 
languageUpdate()1115 void PreferenceDialog::languageUpdate()
1116       {
1117       language->blockSignals(true);
1118       language->clear();
1119       QString lang = preferences.getString(PREF_UI_APP_LANGUAGE);
1120       int curIdx = 0;
1121       for(int i = 0; i < mscore->languages().size(); ++i) {
1122             language->addItem(mscore->languages().at(i).name, i);
1123             if (mscore->languages().at(i).key == lang)
1124                   curIdx = i;
1125             }
1126       language->blockSignals(false);
1127       language->setCurrentIndex(curIdx);
1128       }
1129 
1130 //---------------------------------------------------------
1131 //   languageApply
1132 //---------------------------------------------------------
1133 
languageApply()1134 void PreferenceDialog::languageApply()
1135       {
1136       int lang = language->itemData(language->currentIndex()).toInt();
1137       QString l = lang == 0 ? "system" : mscore->languages().at(lang).key;
1138       bool languageChanged = l != preferences.getString(PREF_UI_APP_LANGUAGE);
1139 
1140       if (languageChanged) {
1141             preferences.setPreference(PREF_UI_APP_LANGUAGE, l);
1142             setMscoreLocale(preferences.getString(PREF_UI_APP_LANGUAGE));
1143             mscore->update();
1144             }
1145       }
1146 
1147 
1148 //---------------------------------------------------------
1149 //   updateCharsetListGP
1150 //---------------------------------------------------------
1151 
updateCharsetListGP()1152 void PreferenceDialog::updateCharsetListGP()
1153       {
1154       QList<QByteArray> charsets = QTextCodec::availableCodecs();
1155       std::sort(charsets.begin(), charsets.end());
1156       int idx = 0;
1157       importCharsetListGP->clear();
1158       for (QByteArray charset : charsets) {
1159             importCharsetListGP->addItem(charset);
1160             if (charset == preferences.getString(PREF_IMPORT_GUITARPRO_CHARSET))
1161                   importCharsetListGP->setCurrentIndex(idx);
1162             idx++;
1163             }
1164       }
1165 
1166 //---------------------------------------------------------
1167 //   updateCharsetListOve
1168 //---------------------------------------------------------
1169 
updateCharsetListOve()1170 void PreferenceDialog::updateCharsetListOve()
1171       {
1172       QList<QByteArray> charsets = QTextCodec::availableCodecs();
1173       std::sort(charsets.begin(), charsets.end());
1174       int idx = 0;
1175       importCharsetListOve->clear();
1176       for (QByteArray charset : charsets) {
1177             importCharsetListOve->addItem(charset);
1178             if (charset == preferences.getString(PREF_IMPORT_OVERTURE_CHARSET))
1179                   importCharsetListOve->setCurrentIndex(idx);
1180             idx++;
1181             }
1182       }
1183 
1184 #ifdef AVSOMR
1185 //---------------------------------------------------------
1186 //   updateUseLocalAvsOmr
1187 //---------------------------------------------------------
1188 
updateUseLocalAvsOmr()1189 void PreferenceDialog::updateUseLocalAvsOmr()
1190       {
1191       useLocalAvsOmr->setChecked(preferences.getBool(PREF_IMPORT_AVSOMR_USELOCAL));
1192       Avs::AvsOmrLocal::instance()->isInstalledAsync([this](bool isInstalled) {
1193             QString text = QObject::tr("Use local OMR engine");
1194             if (isInstalled)
1195                   text += " (" + QObject::tr("Installed") + ")";
1196             else
1197                   text += " (" + QObject::tr("Not installed, needs internet connection for installing") + ")";
1198 
1199             useLocalAvsOmr->setText(text);
1200             });
1201       }
1202 #else
updateUseLocalAvsOmr()1203 void PreferenceDialog::updateUseLocalAvsOmr()
1204       {
1205       ;
1206       }
1207 #endif
1208 
1209 //---------------------------------------------------------
1210 //   applyPageVertical
1211 //---------------------------------------------------------
1212 
applyPageVertical()1213 void PreferenceDialog::applyPageVertical()
1214       {
1215       const auto cv = mscore->currentScoreView();
1216       preferences.setPreference(PREF_UI_CANVAS_SCROLL_VERTICALORIENTATION, pageVertical->isChecked());
1217       MScore::setVerticalOrientation(pageVertical->isChecked());
1218       for (Score* s : mscore->scores()) {
1219             s->doLayout();
1220             for (Score* ss : s->scoreList())
1221                   ss->doLayout();
1222             }
1223       if (cv)
1224             cv->pageTop();
1225       mscore->scorePageLayoutChanged();
1226       mscore->update();
1227       }
1228 
1229 //---------------------------------------------------------
1230 //   buttonBoxClicked
1231 //---------------------------------------------------------
1232 
buttonBoxClicked(QAbstractButton * button)1233 void PreferenceDialog::buttonBoxClicked(QAbstractButton* button)
1234       {
1235       switch(buttonBox->standardButton(button)) {
1236             case QDialogButtonBox::Apply:
1237                   apply();
1238                   break;
1239             case QDialogButtonBox::Ok:
1240                   apply();
1241                   // intentional ??
1242                   // fall through
1243             case QDialogButtonBox::Cancel:
1244             default:
1245                   hide();
1246                   break;
1247             }
1248       }
1249 
1250 //---------------------------------------------------------
1251 //   applySetActive
1252 //---------------------------------------------------------
1253 
applySetActive(bool active)1254 void PreferenceDialog::applySetActive(bool active)
1255       {
1256       buttonBox->button(QDialogButtonBox::Apply)->setEnabled(active);
1257       }
1258 
1259 
1260 //---------------------------------------------------------
1261 //   applyActivate
1262 //---------------------------------------------------------
1263 
applyActivate()1264 void PreferenceDialog::applyActivate()
1265       {
1266       applySetActive(true);
1267       }
1268 
1269 //---------------------------------------------------------
1270 //   applyActivate
1271 //---------------------------------------------------------
1272 
checkApplyActivation()1273 void PreferenceDialog::checkApplyActivation()
1274       {
1275       qDebug() << modifiedWidgets.size() << " " << modifiedUiWidgets.size() << " " << modifiedAudioWidgets.size();
1276       if (modifiedWidgets.size() == 0 && modifiedUiWidgets.size() == 0 && modifiedAudioWidgets.size() == 0)
1277             applySetActive(false);
1278       }
1279 
1280 //---------------------------------------------------------
1281 //   widgetModified
1282 //---------------------------------------------------------
1283 
widgetModified()1284 void PreferenceDialog::widgetModified()
1285       {
1286       PreferenceItem* item = static_cast<PreferenceItem*>(sender());
1287       const auto itemIter = std::find(modifiedWidgets.begin(), modifiedWidgets.end(), item);
1288       if (itemIter == modifiedWidgets.end()) {
1289             modifiedWidgets.push_back(item);
1290             applySetActive(true);
1291             }
1292       else {
1293             if (!item->isModified()) {
1294                   modifiedWidgets.erase(itemIter);
1295                   checkApplyActivation();
1296                   }
1297             }
1298       }
1299 
1300 //---------------------------------------------------------
1301 //   uiWidgetModified
1302 //---------------------------------------------------------
1303 
uiWidgetModified()1304 void PreferenceDialog::uiWidgetModified()
1305       {
1306       PreferenceItem* item = static_cast<PreferenceItem*>(sender());
1307       const auto itemIter = std::find(modifiedUiWidgets.begin(), modifiedUiWidgets.end(), item);
1308       if (itemIter == modifiedUiWidgets.end()) {
1309             modifiedUiWidgets.push_back(item);
1310             applySetActive(true);
1311             }
1312       else {
1313             if (!item->isModified()) {
1314                   modifiedUiWidgets.erase(itemIter);
1315                   checkApplyActivation();
1316                   }
1317             }
1318       }
1319 
1320 
1321 //---------------------------------------------------------
1322 //   audioWidgetModified
1323 //---------------------------------------------------------
1324 
audioWidgetModified()1325 void PreferenceDialog::audioWidgetModified()
1326       {
1327       PreferenceItem* item = static_cast<PreferenceItem*>(sender());
1328       const auto itemIter = std::find(modifiedAudioWidgets.begin(), modifiedAudioWidgets.end(), item);
1329       if (itemIter == modifiedAudioWidgets.end()) {
1330             modifiedAudioWidgets.push_back(item);
1331             applySetActive(true);
1332             }
1333       else {
1334             if (!item->isModified()) {
1335                   modifiedAudioWidgets.erase(itemIter);
1336                   checkApplyActivation();
1337                   }
1338             }
1339       }
1340 
1341 //---------------------------------------------------------
1342 //   apply
1343 //---------------------------------------------------------
1344 
apply()1345 void PreferenceDialog::apply()
1346       {
1347       const auto cv = mscore->currentScoreView();
1348 
1349       QElapsedTimer timer;
1350       timer.start();
1351 
1352       if(buttonBox->button(QDialogButtonBox::Apply)->isEnabled() == false)
1353             return;
1354 
1355       bool uiStyleThemeChanged = false;
1356       bool audioModified = false;
1357 
1358       applySetActive(false);
1359       buttonBox->button(QDialogButtonBox::Apply)->setText(tr("Applying…"));
1360       buttonBox->repaint();
1361 
1362       std::vector<QString> changedAdvancedProperties = advancedWidget->save();
1363       for (auto x : changedAdvancedProperties)
1364             if (x.startsWith("ui"))
1365                   uiStyleThemeChanged = true;
1366 
1367       for (auto& x : modifiedWidgets)
1368             x->apply();
1369 
1370       for (auto& x : modifiedUiWidgets) {
1371             x->apply();
1372             uiStyleThemeChanged = true;
1373             }
1374 
1375       if (modifiedAudioWidgets.size() > 0)
1376             audioModified = true;
1377 
1378 #ifdef AVSOMR
1379       preferences.setPreference(PREF_IMPORT_AVSOMR_USELOCAL, useLocalAvsOmr->isChecked());
1380 #endif
1381 
1382       if (audioModified) {
1383             bool wasJack = (preferences.getBool(PREF_IO_JACK_USEJACKMIDI) || preferences.getBool(PREF_IO_JACK_USEJACKAUDIO));
1384             bool wasJackAudio = preferences.getBool(PREF_IO_JACK_USEJACKAUDIO);
1385             bool wasJackMidi = preferences.getBool(PREF_IO_JACK_USEJACKMIDI);
1386             preferences.setPreference(PREF_IO_JACK_USEJACKAUDIO, jackDriver->isChecked() && useJackAudio->isChecked());
1387             preferences.setPreference(PREF_IO_JACK_USEJACKMIDI, jackDriver->isChecked() && useJackMidi->isChecked());
1388             bool nowJack = (preferences.getBool(PREF_IO_JACK_USEJACKMIDI) || preferences.getBool(PREF_IO_JACK_USEJACKAUDIO));
1389             bool jackParametersChanged = (preferences.getBool(PREF_IO_JACK_USEJACKAUDIO) != wasJackAudio
1390                         || preferences.getBool(PREF_IO_JACK_USEJACKMIDI) != wasJackMidi
1391                         || preferences.getBool(PREF_IO_JACK_REMEMBERLASTCONNECTIONS) != rememberLastMidiConnections->isChecked()
1392                         || preferences.getBool(PREF_IO_JACK_TIMEBASEMASTER) != becomeTimebaseMaster->isChecked())
1393                         && (wasJack && nowJack);
1394             //till this
1395 
1396             preferences.setPreference(PREF_IO_JACK_USEJACKTRANSPORT, jackDriver->isChecked() && useJackTransport->isChecked()); //this
1397 
1398             if (jackParametersChanged) {
1399                   // Change parameters of JACK driver without unload
1400                   if (seq) {
1401                         if (seq->driver() == nullptr) {
1402                               qDebug("sequencer driver is null");
1403                               restartAudioEngine();
1404                               }
1405                         seq->driver()->init(true);
1406                         if (!seq->init(true))
1407                               qDebug("sequencer init failed");
1408                         }
1409                   }
1410             else if (
1411                (wasJack != nowJack)
1412                || (preferences.getBool(PREF_IO_PORTAUDIO_USEPORTAUDIO) != portaudioDriver->isChecked())
1413                || (preferences.getBool(PREF_IO_PULSEAUDIO_USEPULSEAUDIO) != pulseaudioDriver->isChecked())
1414       #ifdef USE_ALSA
1415                || (preferences.getString(PREF_IO_ALSA_DEVICE) != alsaDevice->text())
1416                || (preferences.getInt(PREF_IO_ALSA_SAMPLERATE) != alsaSampleRate->currentData().toInt())
1417                || (preferences.getInt(PREF_IO_ALSA_PERIODSIZE) != alsaPeriodSize->currentData().toInt())
1418                || (preferences.getInt(PREF_IO_ALSA_FRAGMENTS) != alsaFragments->value())
1419       #endif
1420                   ) {
1421                   preferences.setPreference(PREF_IO_ALSA_USEALSAAUDIO, alsaDriver->isChecked());
1422                   preferences.setPreference(PREF_IO_PORTAUDIO_USEPORTAUDIO, portaudioDriver->isChecked());
1423                   preferences.setPreference(PREF_IO_PULSEAUDIO_USEPULSEAUDIO, pulseaudioDriver->isChecked());
1424                   preferences.setPreference(PREF_IO_ALSA_DEVICE, alsaDevice->text());
1425                   preferences.setPreference(PREF_IO_ALSA_SAMPLERATE, alsaSampleRate->currentData().toInt());
1426                   preferences.setPreference(PREF_IO_ALSA_PERIODSIZE, alsaPeriodSize->currentData().toInt());
1427                   preferences.setPreference(PREF_IO_ALSA_FRAGMENTS, alsaFragments->value());
1428 
1429                   restartAudioEngine();
1430                   }
1431       #ifdef USE_PORTAUDIO
1432             if (portAudioIsUsed && !noSeq) {
1433                   Portaudio* audio = static_cast<Portaudio*>(seq->driver());
1434                   preferences.setPreference(PREF_IO_PORTAUDIO_DEVICE, audio->deviceIndex(portaudioApi->currentIndex(), portaudioDevice->currentIndex()));
1435                   }
1436       #endif
1437 
1438       #ifdef USE_PORTMIDI
1439             preferences.setPreference(PREF_IO_PORTMIDI_INPUTDEVICE, portMidiInput->currentText());
1440             preferences.setPreference(PREF_IO_PORTMIDI_OUTPUTDEVICE, portMidiOutput->currentText());
1441             if (seq->driver() && static_cast<PortMidiDriver*>(static_cast<Portaudio*>(seq->driver())->mididriver())->isSameCoreMidiIacBus(preferences.getString(PREF_IO_PORTMIDI_INPUTDEVICE), preferences.getString(PREF_IO_PORTMIDI_OUTPUTDEVICE))) {
1442                   QMessageBox msgBox;
1443                   msgBox.setWindowTitle(tr("Possible MIDI Loopback"));
1444                   msgBox.setIcon(QMessageBox::Warning);
1445                   msgBox.setText(tr("Warning: You used the same CoreMIDI IAC bus for input and output. This will cause problematic loopback, whereby MuseScore's output MIDI messages will be sent back to MuseScore as input, causing confusion. To avoid this problem, access Audio MIDI Setup via Spotlight to create a dedicated virtual port for MuseScore's MIDI output, restart MuseScore, return to Preferences, and select your new virtual port for MuseScore's MIDI output. Other programs may then use that dedicated virtual port to receive MuseScore's MIDI output."));
1446                   msgBox.exec();
1447                   }
1448       #endif
1449             }
1450 
1451       if (shortcutsChanged) {
1452             shortcutsChanged = false;
1453             for(const Shortcut* s : localShortcuts) {
1454                   Shortcut* os = Shortcut::getShortcut(s->key());
1455                   if (os) {
1456                         if (!os->compareKeys(*s))
1457                               os->setKeys(*s);
1458                         }
1459                   }
1460             Shortcut::dirty = true;
1461             }
1462 
1463       if(uiStyleThemeChanged) {
1464             WorkspacesManager::retranslateAll();
1465             preferences.setPreference(PREF_APP_WORKSPACE, WorkspacesManager::currentWorkspace()->id());
1466             WorkspacesManager::currentWorkspace()->save();
1467             emit mscore->workspacesChanged();
1468             }
1469 
1470       emit preferencesChanged(false, uiStyleThemeChanged);
1471       uiStyleThemeChanged = false;
1472       preferences.save();
1473       mscore->startAutoSave();
1474 
1475       // Smooth panning
1476       if (cv) {
1477             cv->panSettings().loadFromPreferences();
1478             cv->setControlCursorVisible(preferences.getBool(PREF_PAN_CURSOR_VISIBLE));
1479             }
1480 
1481       modifiedWidgets.clear();
1482       modifiedUiWidgets.clear();
1483       modifiedAudioWidgets.clear();
1484 
1485       buttonBox->button(QDialogButtonBox::Apply)->setText(tr("Apply"));
1486       qDebug() << "Final: " << timer.elapsed();
1487       }
1488 
1489 //---------------------------------------------------------
1490 //   resetAllValues
1491 //---------------------------------------------------------
1492 
resetAllValues()1493 void PreferenceDialog::resetAllValues()
1494       {
1495       updateValues(true);
1496 
1497       shortcutsChanged = true;
1498       applySetActive(true);
1499       qDeleteAll(localShortcuts);
1500       localShortcuts.clear();
1501       Shortcut::resetToDefault();
1502       for (const Shortcut* s : Shortcut::shortcuts())
1503             localShortcuts[s->key()] = new Shortcut(*s);
1504       updateSCListView();
1505       }
1506 
1507 //---------------------------------------------------------
1508 //   styleFileButtonClicked
1509 //---------------------------------------------------------
1510 
styleFileButtonClicked()1511 void PreferenceDialog::styleFileButtonClicked()
1512       {
1513       QString fn = mscore->getStyleFilename(true, tr("Choose Default Style for Imports"));
1514       if (fn.isEmpty())
1515             return;
1516       importStyleFile->setText(fn);
1517       }
1518 
1519 //---------------------------------------------------------
1520 //   midiRemoteControlClearClicked
1521 //---------------------------------------------------------
1522 
midiRemoteControlClearClicked()1523 void PreferenceDialog::midiRemoteControlClearClicked()
1524       {
1525       for (int i = 0; i < MIDI_REMOTES; ++i)
1526             preferences.clearMidiRemote(i);
1527       updateRemote();
1528       }
1529 
1530 //---------------------------------------------------------
1531 //   exclusiveAudioDriver
1532 //   Allow user to select only one audio driver, restrict
1533 //   to uncheck all drivers.
1534 //---------------------------------------------------------
1535 
exclusiveAudioDriver(bool on)1536 void PreferenceDialog::exclusiveAudioDriver(bool on)
1537       {
1538       if (on) {
1539             if (portaudioDriver != QObject::sender())
1540                   portaudioDriver->setChecked(false);
1541             if (pulseaudioDriver != QObject::sender())
1542                   pulseaudioDriver->setChecked(false);
1543             if (alsaDriver != QObject::sender())
1544                   alsaDriver->setChecked(false);
1545             if (jackDriver != QObject::sender())
1546                   jackDriver->setChecked(false);
1547             if (jackDriver == QObject::sender() && !useJackMidi->isChecked() && !useJackAudio->isChecked()) {
1548                   useJackMidi->setChecked(true);
1549                   useJackAudio->setChecked(true);
1550                   }
1551             }
1552       else {
1553             // True if QGroupBox is checked now or was checked before clicking on it
1554             bool portAudioChecked =  portaudioDriver->isVisible()  && ((QObject::sender() != portaudioDriver  && portaudioDriver->isChecked())  || QObject::sender() == portaudioDriver);
1555             bool pulseaudioChecked = pulseaudioDriver->isVisible() && ((QObject::sender() != pulseaudioDriver && pulseaudioDriver->isChecked()) || QObject::sender() == pulseaudioDriver);
1556             bool alsaChecked =       alsaDriver->isVisible()       && ((QObject::sender() != alsaDriver       && alsaDriver->isChecked())       || QObject::sender() == alsaDriver);
1557             bool jackChecked =       jackDriver->isVisible()       && ((QObject::sender() != jackDriver       && jackDriver->isChecked())       || QObject::sender() == jackDriver);
1558             // If nothing is checked, prevent looping (run with -s, sequencer disabled)
1559             if (!(portAudioChecked || pulseaudioChecked || alsaChecked || jackChecked))
1560                   return;
1561             // Don't allow to uncheck all drivers
1562             if (portaudioDriver == QObject::sender())
1563                   portaudioDriver->setChecked(!(pulseaudioChecked || alsaChecked || jackChecked));
1564             if (pulseaudioDriver == QObject::sender())
1565                   pulseaudioDriver->setChecked(!(portAudioChecked || alsaChecked || jackChecked));
1566             if (alsaDriver == QObject::sender())
1567                   alsaDriver->setChecked(!(portAudioChecked || pulseaudioChecked || jackChecked));
1568             if (jackDriver == QObject::sender())
1569                   jackDriver->setChecked(!(portAudioChecked || pulseaudioChecked || alsaChecked));
1570             }
1571       }
1572 
1573 //---------------------------------------------------------
1574 //   exclusiveJackDriver
1575 //   Allow user to select "use Jack Audio", "use Jack MIDI"
1576 //   or both, but forbid unchecking both.
1577 //   There is no need to select "JACK audio server" without
1578 //   checking any of them.
1579 //---------------------------------------------------------
1580 
nonExclusiveJackDriver(bool on)1581 void PreferenceDialog::nonExclusiveJackDriver(bool on)
1582       {
1583       if (!on) {
1584             if (QObject::sender() == useJackAudio)
1585                   useJackAudio->setChecked(!useJackMidi->isChecked());
1586             else if (QObject::sender() == useJackMidi)
1587                   useJackMidi->setChecked(!useJackAudio->isChecked());
1588             }
1589       }
1590 
1591 //---------------------------------------------------------
1592 //   selectScoresDirectory
1593 //---------------------------------------------------------
1594 
selectScoresDirectory()1595 void PreferenceDialog::selectScoresDirectory()
1596       {
1597       QString s = QFileDialog::getExistingDirectory(
1598          this,
1599          tr("Choose Score Folder"),
1600          myScores->text(),
1601          QFileDialog::ShowDirsOnly | (preferences.getBool(PREF_UI_APP_USENATIVEDIALOGS) ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog)
1602          );
1603       if (!s.isNull())
1604             myScores->setText(s);
1605       }
1606 
1607 //---------------------------------------------------------
1608 //   selectStylesDirectory
1609 //---------------------------------------------------------
1610 
selectStylesDirectory()1611 void PreferenceDialog::selectStylesDirectory()
1612       {
1613       QString s = QFileDialog::getExistingDirectory(
1614          this,
1615          tr("Choose Style Folder"),
1616          myStyles->text(),
1617          QFileDialog::ShowDirsOnly | (preferences.getBool(PREF_UI_APP_USENATIVEDIALOGS) ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog)
1618          );
1619       if (!s.isNull())
1620             myStyles->setText(s);
1621       }
1622 
1623 //---------------------------------------------------------
1624 //   selectTemplatesDirectory
1625 //---------------------------------------------------------
1626 
selectTemplatesDirectory()1627 void PreferenceDialog::selectTemplatesDirectory()
1628       {
1629       QString s = QFileDialog::getExistingDirectory(
1630          this,
1631          tr("Choose Template Folder"),
1632          myTemplates->text(),
1633          QFileDialog::ShowDirsOnly | (preferences.getBool(PREF_UI_APP_USENATIVEDIALOGS) ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog)
1634          );
1635       if (!s.isNull())
1636             myTemplates->setText(s);
1637       }
1638 
1639 //---------------------------------------------------------
1640 //   selectPluginsDirectory
1641 //---------------------------------------------------------
1642 
selectPluginsDirectory()1643 void PreferenceDialog::selectPluginsDirectory()
1644       {
1645       QString s = QFileDialog::getExistingDirectory(
1646          this,
1647          tr("Choose Plugin Folder"),
1648          myPlugins->text(),
1649          QFileDialog::ShowDirsOnly | (preferences.getBool(PREF_UI_APP_USENATIVEDIALOGS) ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog)
1650          );
1651       if (!s.isNull())
1652             myPlugins->setText(s);
1653       }
1654 
1655 //---------------------------------------------------------
1656 //   selectImagesDirectory
1657 //---------------------------------------------------------
1658 
selectImagesDirectory()1659 void PreferenceDialog::selectImagesDirectory()
1660       {
1661       QString s = QFileDialog::getExistingDirectory(
1662          this,
1663          tr("Choose Image Folder"),
1664          myImages->text(),
1665          QFileDialog::ShowDirsOnly | (preferences.getBool(PREF_UI_APP_USENATIVEDIALOGS) ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog)
1666          );
1667       if (!s.isNull())
1668             myImages->setText(s);
1669       }
1670 
1671 //---------------------------------------------------------
1672 //   changeSoundfontPaths
1673 //---------------------------------------------------------
1674 
changeSoundfontPaths()1675 void PreferenceDialog::changeSoundfontPaths()
1676       {
1677       PathListDialog pld(this);
1678       pld.setWindowTitle(tr("SoundFont Folders"));
1679       pld.setPath(mySoundfonts->text());
1680       if(pld.exec())
1681             mySoundfonts->setText(pld.path());
1682       }
1683 
1684 //---------------------------------------------------------
1685 //   selectExtensionsDirectory
1686 //---------------------------------------------------------
1687 
selectExtensionsDirectory()1688 void PreferenceDialog::selectExtensionsDirectory()
1689       {
1690       QString s = QFileDialog::getExistingDirectory(
1691          this,
1692          tr("Choose Extensions Folder"),
1693          myExtensions->text(),
1694          QFileDialog::ShowDirsOnly | (preferences.getBool(PREF_UI_APP_USENATIVEDIALOGS) ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog)
1695          );
1696       if (!s.isNull())
1697             myExtensions->setText(s);
1698       }
1699 
1700 //---------------------------------------------------------
1701 //   updateLanguagesClicked
1702 //---------------------------------------------------------
1703 
updateTranslationClicked()1704 void PreferenceDialog::updateTranslationClicked()
1705       {
1706       ResourceManager r(this);
1707       r.selectLanguagesTab();
1708       r.exec();
1709       }
1710 
1711 //---------------------------------------------------------
1712 //   defineShortcutClicked
1713 //---------------------------------------------------------
1714 
defineShortcutClicked()1715 void PreferenceDialog::defineShortcutClicked()
1716       {
1717       QTreeWidgetItem* active = shortcutList->currentItem();
1718       if (!active)
1719             return;
1720       QString str = active->data(0, Qt::UserRole).toString();
1721       if (str.isEmpty())
1722             return;
1723       Shortcut* s = localShortcuts[str.toLatin1().data()];
1724       ShortcutCaptureDialog sc(s, localShortcuts, this);
1725       int rv = sc.exec();
1726       if (rv == 0)
1727             return;
1728       if (rv == 2)
1729             s->clear();
1730       s->addShortcut(sc.getKey());
1731       active->setText(1, s->keysToString());
1732       shortcutsChanged = true;
1733       applySetActive(true);
1734       }
1735 
1736 
1737 //---------------------------------------------------------
1738 //   printShortcutsClicked
1739 //---------------------------------------------------------
1740 
printShortcutsClicked()1741 void PreferenceDialog::printShortcutsClicked()
1742       {
1743 #ifndef QT_NO_PRINTER
1744       QPrinter printer(QPrinter::HighResolution);
1745       const MStyle& s = MScore::defaultStyle();
1746       qreal pageW = s.value(Sid::pageWidth).toReal();
1747       qreal pageH = s.value(Sid::pageHeight).toReal();
1748       printer.setPaperSize(QSizeF(pageW, pageH), QPrinter::Inch);
1749 
1750       printer.setCreator("MuseScore Version: " VERSION);
1751       printer.setFullPage(true);
1752       printer.setColorMode(QPrinter::Color);
1753       printer.setDocName(tr("MuseScore Shortcuts"));
1754       printer.setOutputFormat(QPrinter::NativeFormat);
1755 
1756       QPrintDialog pd(&printer, 0);
1757       pd.setWindowTitle(tr("Print Shortcuts"));
1758       if (!pd.exec())
1759             return;
1760       qreal dpmm = printer.logicalDpiY() / 25.4;
1761       qreal ph   = printer.height();
1762       qreal tm   = dpmm * 15;
1763       qreal bm   = dpmm * 15;
1764       qreal lm   = dpmm * 20;
1765 
1766       QPainter p;
1767       p.begin(&printer);
1768       qreal y = 0.0;
1769       qreal lh = QFontMetricsF(p.font()).lineSpacing();
1770 
1771       // get max width for description
1772       QMapIterator<QString, Shortcut*> isc(localShortcuts);
1773       qreal col1Width = 0.0;
1774       while (isc.hasNext()) {
1775             isc.next();
1776             Shortcut* sc = isc.value();
1777             col1Width = qMax(col1Width, QFontMetricsF(p.font()).width(sc->descr()));
1778             }
1779 
1780       int idx = 0;
1781       QTreeWidgetItem* item = shortcutList->topLevelItem(0);
1782       while (item) {
1783             if (idx == 0 || y >= (ph - bm)) {
1784                   y = tm;
1785                   if (idx)
1786                         printer.newPage();
1787                   else {
1788                         p.save();
1789                         QFont font(p.font());
1790                         font.setPointSizeF(14.0);
1791                         font.setBold(true);
1792                         p.setFont(font);
1793                         p.drawText(lm, y, tr("MuseScore Shortcuts"));
1794                         p.restore();
1795                         y += QFontMetricsF(font).lineSpacing();
1796                         y += 5 * dpmm;
1797                         }
1798                   }
1799             p.drawText(lm, y, item->text(0));
1800             p.drawText(col1Width + lm + 5 * dpmm, y, item->text(1));
1801             y += lh;
1802             ++idx;
1803             item = shortcutList->itemBelow(item);
1804             }
1805       p.end();
1806 #endif
1807 }
1808 
1809 //---------------------------------------------------------
1810 //   rebuildAudioDrivers
1811 //---------------------------------------------------------
1812 
restartAudioEngine()1813 void PreferenceDialog::restartAudioEngine()
1814       {
1815       mscore->restartAudioEngine();
1816       }
1817 
1818 //---------------------------------------------------------
1819 //   updateShortestNote
1820 //---------------------------------------------------------
1821 
updateShortestNote()1822 void PreferenceDialog::updateShortestNote()
1823       {
1824       int shortestNoteIndex;
1825       int nn = preferences.getInt(PREF_IO_MIDI_SHORTESTNOTE);
1826       if (nn == MScore::division)
1827             shortestNoteIndex = 0;           // Quarter
1828       else if (nn == MScore::division / 2)
1829             shortestNoteIndex = 1;  // Eighth
1830       else if (nn == MScore::division / 4)
1831             shortestNoteIndex = 2;  // etc.
1832       else if (nn == MScore::division / 8)
1833             shortestNoteIndex = 3;
1834       else if (nn == MScore::division / 16)
1835             shortestNoteIndex = 4;
1836       else if (nn == MScore::division / 32)
1837             shortestNoteIndex = 5;
1838       else if (nn == MScore::division / 64)
1839             shortestNoteIndex = 6;
1840       else if (nn == MScore::division / 128)
1841             shortestNoteIndex = 7;
1842       else if (nn == MScore::division / 256)
1843             shortestNoteIndex = 8;
1844       else {
1845             qDebug("Unknown shortestNote value of %d, defaulting to 16th", nn);
1846             shortestNoteIndex = 2;
1847             }
1848       shortestNote->setCurrentIndex(shortestNoteIndex);
1849       }
1850 
1851 //---------------------------------------------------------
1852 //   applyShortestNote
1853 //---------------------------------------------------------
1854 
applyShortestNote()1855 void PreferenceDialog::applyShortestNote()
1856       {
1857       int ticks = MScore::division / 4;
1858       switch (shortestNote->currentIndex()) {
1859             case 0: ticks = MScore::division;       break;
1860             case 1: ticks = MScore::division / 2;   break;
1861             case 2: ticks = MScore::division / 4;   break;
1862             case 3: ticks = MScore::division / 8;   break;
1863             case 4: ticks = MScore::division / 16;  break;
1864             case 5: ticks = MScore::division / 32;  break;
1865             case 6: ticks = MScore::division / 64;  break;
1866             case 7: ticks = MScore::division / 128; break;
1867             case 8: ticks = MScore::division / 256; break;
1868             default: {
1869                   qDebug("Unknown index for shortestNote: %d, defaulting to 16th",
1870                          shortestNote->currentIndex());
1871                   ticks = MScore::division / 4;
1872                   }
1873             }
1874       preferences.setPreference(PREF_IO_MIDI_SHORTESTNOTE, ticks);
1875       }
1876 
1877 } // namespace Ms
1878