    //=============================================================================
    //  MuseScore
    //  Music Composition & Notation
    //
    //  Copyright (C) 2002-2016 Werner Schweer
    //
    //  This program is free software; you can redistribute it and/or modify
    //  it under the terms of the GNU General Public License version 2
    //  as published by the Free Software Foundation and appearing in
    //  the file LICENCE.GPL
    //=============================================================================

    #include <fenv.h>
    #include "loginmanager.h"
    #include "uploadscoredialog.h"
    #include <QStyleFactory>
    #include "palettebox.h"
    #include "config.h"
    #include "musescore.h"
    #include "scoreview.h"
    #include "libmscore/style.h"
    #include "libmscore/score.h"
    #include "instrdialog.h"
    #include "preferences.h"
    #include "prefsdialog.h"
    #include "icons.h"
    #include "libmscore/xml.h"
    #include "seq.h"
    #include "libmscore/tempo.h"
    #include "libmscore/sym.h"
    #include "pagesettings.h"
    #include "debugger/debugger.h"
    #include "editstyle.h"
    #include "playpanel.h"
    #include "libmscore/page.h"
    #include "mixer.h"
    #include "selectionwindow.h"
    #include "palette.h"
    #include "palettebox.h"
    #include "libmscore/part.h"
    #include "libmscore/drumset.h"
    #include "libmscore/instrtemplate.h"
    #include "libmscore/note.h"
    #include "libmscore/staff.h"
    #include "driver.h"
    #include "libmscore/harmony.h"
    #include "magbox.h"
    #include "libmscore/sig.h"
    #include "libmscore/undo.h"
    #include "synthcontrol.h"
    #include "pianoroll.h"
    #include "drumroll.h"
    #include "scoretab.h"
    #include "timedialog.h"
    #include "keyedit.h"
    #include "harmonyedit.h"
    #include "navigator.h"
    #include "timeline.h"
    #include "importmidi/importmidi_panel.h"
    #include "libmscore/chord.h"
    #include "libmscore/segment.h"
    #include "editraster.h"
    #include "pianotools.h"
    #include "mediadialog.h"
    #include "workspace.h"
    #include "selectdialog.h"
    #include "selectnotedialog.h"
    #include "transposedialog.h"
    #include "metaedit.h"
    #include "inspector/inspector.h"
    #ifdef OMR
    #include "omrpanel.h"
    #endif
    #include "shortcut.h"
    #ifdef SCRIPT_INTERFACE
    #include "pluginCreator.h"
    #include "pluginManager.h"
    #endif
    #include "helpBrowser.h"
    #include "drumtools.h"
    #include "editstafftype.h"
    #include "texttools.h"
    #include "textpalette.h"
    #include "resourceManager.h"
    #include "scoreaccessibility.h"
    #include "startupWizard.h"

    #include "libmscore/mscore.h"
    #include "libmscore/system.h"
    #include "libmscore/measure.h"
    #include "libmscore/chordlist.h"
    #include "libmscore/volta.h"
    #include "libmscore/lasso.h"
    #include "libmscore/excerpt.h"
    #include "libmscore/synthesizerstate.h"

    #include "driver.h"

    #include "effects/zita1/zita.h"
    #include "effects/compressor/compressor.h"
    #include "effects/noeffect/noeffect.h"
    #include "synthesizer/synthesizer.h"
    #include "synthesizer/synthesizergui.h"
    #include "synthesizer/msynthesizer.h"
    #include "fluid/fluid.h"
    #include "qmlplugin.h"
    #include "accessibletoolbutton.h"
    #include "toolbuttonmenu.h"
    #include "searchComboBox.h"
    #include "startcenter.h"
    #include "help.h"
    #include "awl/aslider.h"

    #ifdef USE_LAME
    #include "exportmp3.h"
    #endif

    #ifdef AEOLUS
    extern Ms::Synthesizer* createAeolus();
    #endif
    #ifdef ZERBERUS
    extern Ms::Synthesizer* createZerberus();
    #endif

    #ifdef QT_NO_DEBUG
          Q_LOGGING_CATEGORY(undoRedo, "undoRedo", QtCriticalMsg)
    #else
          Q_LOGGING_CATEGORY(undoRedo, "undoRedo", QtCriticalMsg)
    //      Q_LOGGING_CATEGORY(undoRedo, "undoRedo")
    #endif

    namespace Ms {

    MuseScore* mscore;
    MasterSynthesizer* synti;

    bool enableExperimental = false;

    QString dataPath;
    QString iconPath;

    bool converterMode = false;
    bool processJob = false;
    bool externalIcons = false;
    bool pluginMode = false;
    static bool startWithNewScore = false;
    double converterDpi = 0;
    double guiScaling = 0.0;
    static double userDPI = 0.0;
    int trimMargin = -1;
    bool noWebView = false;
    bool exportScoreParts = false;
    bool ignoreWarnings = false;

    QString mscoreGlobalShare;

    static QString outFileName;
    static QString jsonFileName;
    static QString audioDriver;
    static QString pluginName;
    static QString styleFile;
    static bool scoresOnCommandline { false };

    static QList<QTranslator*> translatorList;

    QString localeName;
    bool useFactorySettings = false;
    bool deletePreferences = false;
    QString styleName;
    QString revision;
    QErrorMessage* errorMessage;
    const char* voiceActions[] = { "voice-1", "voice-2", "voice-3", "voice-4" };

    const std::list<const char*> MuseScore::_allNoteInputMenuEntries {
                "note-input",
                "pad-note-128",
                "pad-note-64",
                "pad-note-32",
                "pad-note-16",
                "pad-note-8",
                "pad-note-4",
                "pad-note-2",
                "pad-note-1",
                "note-breve",
                "note-longa",
                "pad-dot",
                "pad-dotdot",
                "pad-dot3",
                "pad-dot4",
                "tie",
                "",
                "pad-rest",
                "",
                "sharp2",
                "sharp",
                "nat",
                "flat",
                "flat2",
                "flip",
                "",
                "voice-1",
                "voice-2",
                "voice-3",
                "voice-4"
                };

    const std::list<const char*> MuseScore::_advancedNoteInputMenuEntries {
                "note-input",
                "pad-note-128",
                "pad-note-64",
                "pad-note-32",
                "pad-note-16",
                "pad-note-8",
                "pad-note-4",
                "pad-note-2",
                "pad-note-1",
                "note-breve",
                "note-longa",
                "pad-dot",
                "pad-dotdot",
                "pad-dot3",
                "pad-dot4",
                "tie",
                "",
                "pad-rest",
                "",
                "sharp2",
                "sharp",
                "nat",
                "flat",
                "flat2",
                "flip",
                "",
                "voice-1",
                "voice-2",
                "voice-3",
                "voice-4"
                };

    const std::list<const char*> MuseScore::_basicNoteInputMenuEntries {
                "note-input",
                "pad-note-32",
                "pad-note-16",
                "pad-note-8",
                "pad-note-4",
                "pad-note-2",
                "pad-note-1",
                "pad-dot",
                "tie",
                "",
                "pad-rest",
                "",
                "sharp",
                "nat",
                "flat",
                "flip",
                "",
                "voice-1",
                "voice-2",
                "voice-3",
                "voice-4"
                };

    const std::list<const char*> MuseScore::_allFileOperationEntries {
                "file-new",
                "file-open",
                "file-save",
                "print",
                "redo",
                "undo"
                };

    const std::list<const char*> MuseScore::_allPlaybackControlEntries {
                "midi-on",
                "rewind",
                "play",
                "loop",
                "repeat",
                "pan",
                "metronome"
                };

    extern bool savePositions(Score*, const QString& name, bool segments );
    extern TextPalette* textPalette;

    static constexpr double SCALE_MAX  = 16.0;
    static constexpr double SCALE_MIN  = 0.05;
    static constexpr double SCALE_STEP = 1.7;

    //---------------------------------------------------------
    // cmdInsertMeasure
    //---------------------------------------------------------

    void MuseScore::cmdInsertMeasures()
          {
          if (cs) {
                if (cs->selection().isNone() && !cs->selection().findMeasure()) {
                      QMessageBox::warning(0, "MuseScore",
                            tr("No measure selected:\n" "Please select a measure and try again"));
                      }
                else {
                      insertMeasuresDialog = new InsertMeasuresDialog;
                      insertMeasuresDialog->show();
                      }
                }
          }

    //---------------------------------------------------------
    // InsertMeasuresDialog
    //---------------------------------------------------------

    InsertMeasuresDialog::InsertMeasuresDialog(QWidget* parent)
       : QDialog(parent)
          {
          setObjectName("InsertMeasuresDialog");
          setupUi(this);
          setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
          insmeasures->selectAll();
          }

    //---------------------------------------------------------
    // Insert Measure -->   accept
    //---------------------------------------------------------

    void InsertMeasuresDialog::accept()
          {
          int n = insmeasures->value();
          if (mscore->currentScore())
                mscore->currentScoreView()->cmdInsertMeasures(n, ElementType::MEASURE);
          done(1);
          }

    //---------------------------------------------------------
    // InsertMeasuresDialog hideEvent
    //---------------------------------------------------------

    void InsertMeasuresDialog::hideEvent(QHideEvent* event)
          {
          MuseScore::saveGeometry(this);
          QDialog::hideEvent(event);
          }

    //---------------------------------------------------------
    //   getSharePath
    //---------------------------------------------------------

    QString getSharePath()
          {
    #ifdef Q_OS_WIN
          QDir dir(QCoreApplication::applicationDirPath() + QString("/../" INSTALL_NAME));
          return dir.absolutePath() + "/";
    #else
    #ifdef Q_OS_MAC
          QDir dir(QCoreApplication::applicationDirPath() + QString("/../Resources"));
          return dir.absolutePath() + "/";
    #else
          // Try relative path (needed for portable AppImage and non-standard installations)
          QDir dir(QCoreApplication::applicationDirPath() + QString("/../share/" INSTALL_NAME));
          if (dir.exists())
                return dir.absolutePath() + "/";
          // Otherwise fall back to default location (e.g. if binary has moved relative to share)
          return QString( INSTPREFIX "/share/" INSTALL_NAME);
    #endif
    #endif
          }

    //---------------------------------------------------------
    //   printVersion
    //---------------------------------------------------------

    static void printVersion(const char* prog)
          {
          if (MuseScore::unstable())
                fprintf(stderr, "%s: Music Score Editor\nUnstable Prerelease for Version %s; Build %s\n",
             prog, VERSION, qPrintable(revision));
          else
                fprintf(stderr, "%s: Music Score Editor; Version %s; Build %s\n", prog, VERSION, qPrintable(revision));
          }

    static const int RECENT_LIST_SIZE = 20;

    //---------------------------------------------------------
    //   closeEvent
    //---------------------------------------------------------

    void MuseScore::closeEvent(QCloseEvent* ev)
          {
          unloadPlugins();
          QList<MasterScore*> removeList;
          for (MasterScore* score : scoreList) {
                if (score->created() && !score->dirty())
                      removeList.append(score);
                else {
                      if (checkDirty(score)) {      // ask user if file is dirty
                            ev->ignore();
                            return;
                            }
                      //
                      // if score is still dirty, then the user has discarded the
                      // score and we can remove it from the list
                      //
                      if (score->created() && score->dirty())
                            removeList.append(score);
                      }
                }

          // remove all new created/not save score so they are
          // note saved as session data
          for (MasterScore* score : removeList)
                scoreList.removeAll(score);

          writeSessionFile(true);
          for (MasterScore* score : scoreList) {
                if (!score->tmpName().isEmpty()) {
                      QFile f(score->tmpName());
                      f.remove();
                      }
                }

          writeSettings();

          _loginManager->save();

          ev->accept();
          if (preferences.dirty)
                preferences.write();
          this->deleteLater();     //this is necessary on windows http://musescore.org/node/16713
          qApp->quit();
          }

    //---------------------------------------------------------
    //   preferencesChanged
    //---------------------------------------------------------

    void MuseScore::preferencesChanged()
          {
          for (int i = 0; i < tab1->count(); ++i) {
                ScoreView* canvas = tab1->view(i);
                if (canvas == 0)
                      continue;
                if (preferences.bgUseColor)
                      canvas->setBackground(MScore::bgColor);
                else {
                      QPixmap* pm = new QPixmap(preferences.bgWallpaper);
                      canvas->setBackground(pm);
                      }
                if (preferences.fgUseColor)
                      canvas->setForeground(preferences.fgColor);
                else {
                      QPixmap* pm = new QPixmap(preferences.fgWallpaper);
                      if (pm == 0 || pm->isNull())
                            qDebug("no valid pixmap %s", preferences.fgWallpaper.toLatin1().data());
                      canvas->setForeground(pm);
                      }
                }
          if (tab2) {
                for (int i = 0; i < tab2->count(); ++i) {
                      ScoreView* canvas = tab2->view(i);
                      if (canvas == 0)
                            continue;
                      if (preferences.bgUseColor)
                            canvas->setBackground(MScore::bgColor);
                      else {
                            QPixmap* pm = new QPixmap(preferences.bgWallpaper);
                            canvas->setBackground(pm);
                            }
                      if (preferences.fgUseColor)
                            canvas->setForeground(preferences.fgColor);
                      else {
                            QPixmap* pm = new QPixmap(preferences.fgWallpaper);
                            if (pm == 0 || pm->isNull())
                                  qDebug("no valid pixmap %s", preferences.fgWallpaper.toLatin1().data());
                            canvas->setForeground(pm);
                            }
                      }
                }

          transportTools->setEnabled(!noSeq && seq && seq->isRunning());
          playId->setEnabled(!noSeq && seq && seq->isRunning());

          getAction("midi-on")->setEnabled(preferences.enableMidiInput);
          _statusBar->setVisible(preferences.showStatusBar);

          delete newWizard;
          newWizard = 0;
          }

    //---------------------------------------------------------
    //   populateNoteInputMenu
    //---------------------------------------------------------

    void MuseScore::populateNoteInputMenu()
          {
          entryTools->clear();

          for (const auto s : _noteInputMenuEntries) {
                if (!*s)
                      entryTools->addSeparator();
                else {
                      QAction* a = getAction(s);
                      QWidget* w;
                      if (strcmp(s, "note-input") == 0) {
                            //-----------------------------------------------------------------
                            // Note Entry Modes menu
                            // ToolButtonMenu to swap between Note Entry Methods
                            //-----------------------------------------------------------------
                            QActionGroup* noteEntryMethods = new QActionGroup(entryTools);

                            noteEntryMethods->addAction(getAction("note-input-steptime"));
                            noteEntryMethods->addAction(getAction("note-input-repitch"));
                            noteEntryMethods->addAction(getAction("note-input-rhythm"));
                            noteEntryMethods->addAction(getAction("note-input-realtime-auto"));
                            noteEntryMethods->addAction(getAction("note-input-realtime-manual"));

                            connect(noteEntryMethods, SIGNAL(triggered(QAction*)), this, SLOT(setNoteEntryState()));

                            w = new ToolButtonMenu(tr("Note Entry Methods"),
                               ToolButtonMenu::TYPES::ICON_CHANGED,
                               getAction("note-input"),
                               noteEntryMethods,
                               this);
                            }
                      else if (strncmp(s, "voice-", 6) == 0) {
                            AccessibleToolButton* tb = new AccessibleToolButton(this, a);
                            tb->setObjectName("voice");
                            tb->setFocusPolicy(Qt::ClickFocus);
                            tb->setToolButtonStyle(Qt::ToolButtonTextOnly);
                            tb->setProperty((QString("voice%1").arg(atoi(s+6))).toUtf8().data(), true);
                            QPalette p(tb->palette());
                            int i = atoi(s+6) - 1;
                            p.setColor(QPalette::Base, MScore::selectColor[i]);
                            tb->setPalette(p);
                            a->setCheckable(true);
                            // tb->setDefaultAction(a);
                            w = tb;
                            }
                      else
                            w = new AccessibleToolButton(entryTools, a);
                      entryTools->addWidget(w);
                      }
                }
          }

    //---------------------------------------------------------
    //   MuseScore
    //---------------------------------------------------------

    MuseScore::MuseScore()
       : QMainWindow()
          {
          QScreen* screen = QGuiApplication::primaryScreen();
          if (userDPI == 0.0) {
    #if defined(Q_OS_WIN)
          if (QSysInfo::WindowsVersion <= QSysInfo::WV_WINDOWS7)
                _physicalDotsPerInch = screen->logicalDotsPerInch() * screen->devicePixelRatio();
          else
                _physicalDotsPerInch = screen->physicalDotsPerInch();  // physical resolution
    #else
          _physicalDotsPerInch = screen->physicalDotsPerInch();        // physical resolution
    #endif
                }
          else {
                _physicalDotsPerInch = userDPI;
                }
          if (guiScaling == 0.0) {
                // set scale for icons, palette elements, window sizes, etc
                // the default values are hard coded in pixel sizes and assume ~96 DPI
                if (qAbs(_physicalDotsPerInch - DPI_DISPLAY) > 6.0)
                      guiScaling = _physicalDotsPerInch / DPI_DISPLAY;
                else
                      guiScaling = 1.0;
                }

          MScore::pixelRatio = DPI / screen->logicalDotsPerInch();

          setObjectName("MuseScore");
          _sstate = STATE_INIT;
          setWindowTitle(QString(MUSESCORE_NAME_VERSION));
          setIconSize(QSize(preferences.iconWidth * guiScaling, preferences.iconHeight * guiScaling));

          ucheck = new UpdateChecker();

          setAcceptDrops(true);
          setFocusPolicy(Qt::NoFocus);

          if (!converterMode && !pluginMode) {
                _loginManager = new LoginManager(this);
    #if 0
                // initialize help engine
                QString lang = mscore->getLocaleISOCode();
                if (lang == "en_US")    // HACK
                      lang = "en";

                QString s = getSharePath() + "manual/doc_" + lang + ".qhc";
                _helpEngine = new QHelpEngine(s, this);
                if (!_helpEngine->setupData()) {
                      qDebug("cannot setup data for help engine: %s", qPrintable(_helpEngine->error()));
                      delete _helpEngine;
                      _helpEngine = 0;
                      }
    #endif
                }

          _positionLabel = new QLabel;
          _positionLabel->setObjectName("decoration widget");  // this prevents animations

          _modeText = new QLabel;
          _modeText->setAutoFillBackground(false);
          _modeText->setObjectName("modeLabel");

          hRasterAction   = getAction("hraster");
          vRasterAction   = getAction("vraster");
          loopAction      = getAction("loop");
          loopInAction    = getAction("loop-in");
          loopOutAction   = getAction("loop-out");
          metronomeAction = getAction("metronome");
          countInAction   = getAction("countin");
          panAction       = getAction("pan");

          _statusBar = new QStatusBar;
          _statusBar->addPermanentWidget(new QWidget(this), 2);
          _statusBar->addPermanentWidget(new QWidget(this), 100);
          _statusBar->addPermanentWidget(_modeText, 0);

          if (enableExperimental) {
                layerSwitch = new QComboBox(this);
                layerSwitch->setToolTip(tr("Switch layer"));
                connect(layerSwitch, SIGNAL(activated(const QString&)), SLOT(switchLayer(const QString&)));
                playMode = new QComboBox(this);
                playMode->addItem(tr("Synthesizer"));
                playMode->addItem(tr("Audio track"));
                playMode->setToolTip(tr("Switch play mode"));
                connect(playMode, SIGNAL(activated(int)), SLOT(switchPlayMode(int)));

                _statusBar->addPermanentWidget(playMode);
                _statusBar->addPermanentWidget(layerSwitch);
                }

          _statusBar->addPermanentWidget(_positionLabel, 0);

          setStatusBar(_statusBar);
          ScoreAccessibility::createInstance(this);

          // otherwise unused actions:
          //   must be added somewere to work
          QActionGroup* ag = Shortcut::getActionGroupForWidget(MsWidget::MAIN_WINDOW);
          ag->setParent(this);
          addActions(ag->actions());
          connect(ag, SIGNAL(triggered(QAction*)), SLOT(cmd(QAction*)));

          mainWindow = new QSplitter;
          mainWindow->setChildrenCollapsible(false);

          QWidget* mainScore = new QWidget;
          mainScore->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
          mainWindow->addWidget(mainScore);

          layout = new QVBoxLayout;
          layout->setMargin(0);
          layout->setSpacing(0);
          mainScore->setLayout(layout);

          _navigator = new NScrollArea;
          _navigator->setFocusPolicy(Qt::NoFocus);
          mainWindow->addWidget(_navigator);
          scorePageLayoutChanged();
          showNavigator(preferences.showNavigator);

          _timeline = new TDockWidget;
          _timeline->setFocusPolicy(Qt::NoFocus);
          addDockWidget(Qt::BottomDockWidgetArea, _timeline);
          scorePageLayoutChanged();
          showTimeline(false);

          mainWindow->setStretchFactor(0, 1);
          mainWindow->setStretchFactor(1, 0);
          mainWindow->setSizes(QList<int>({500, 50}));

          QSplitter* envelope = new QSplitter;
          envelope->setChildrenCollapsible(false);
          envelope->setOrientation(Qt::Vertical);
          envelope->addWidget(mainWindow);

          importmidiPanel = new ImportMidiPanel(this);
          importmidiPanel->setVisible(false);
          envelope->addWidget(importmidiPanel);

          {
          importmidiShowPanel = new QFrame;
          QHBoxLayout *hl = new QHBoxLayout;
          hl->setMargin(0);
          hl->setSpacing(0);
          importmidiShowPanel->setLayout(hl);
          showMidiImportButton = new QPushButton();
          showMidiImportButton->setFocusPolicy(Qt::ClickFocus);
          importmidiShowPanel->setVisible(false);
          connect(showMidiImportButton, SIGNAL(clicked()), SLOT(showMidiImportPanel()));
          connect(importmidiPanel, SIGNAL(closeClicked()), importmidiShowPanel, SLOT(show()));
          hl->addWidget(showMidiImportButton);
          QSpacerItem *item = new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Fixed);
          hl->addSpacerItem(item);
          envelope->addWidget(importmidiShowPanel);
          }

          envelope->setSizes(QList<int>({550, 180}));

          splitter = new QSplitter;
          tab1 = new ScoreTab(&scoreList, this);
          tab1->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
          connect(tab1, SIGNAL(currentScoreViewChanged(ScoreView*)), SLOT(setCurrentScoreView(ScoreView*)));
          connect(tab1, SIGNAL(tabCloseRequested(int)), SLOT(removeTab(int)));
          connect(tab1, SIGNAL(actionTriggered(QAction*)), SLOT(cmd(QAction*)));
          splitter->addWidget(tab1);

          if (splitScreen()) {
                tab2 = new ScoreTab(&scoreList, this);
                tab2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
                connect(tab2, SIGNAL(currentScoreViewChanged(ScoreView*)), SLOT(setCurrentScoreView(ScoreView*)));
                connect(tab2, SIGNAL(tabCloseRequested(int)), SLOT(removeTab(int)));
                connect(tab2, SIGNAL(actionTriggered(QAction*)), SLOT(cmd(QAction*)));
                splitter->addWidget(tab2);
                tab2->setVisible(false);
                }
          else
                tab2 = 0;
          layout->addWidget(splitter);

          //---------------------------------------------------
          //    Transport Action
          //---------------------------------------------------

          QAction* a;
    #ifdef HAS_MIDI
          a  = getAction("midi-on");
          a->setEnabled(preferences.enableMidiInput);
          a->setChecked(_midiinEnabled);
    #endif

          getAction("undo")->setEnabled(false);
          getAction("redo")->setEnabled(false);
          getAction("paste")->setEnabled(false);
          getAction("swap")->setEnabled(false);
          selectionChanged(SelState::NONE);

          //---------------------------------------------------
          //    File Tool Bar
          //---------------------------------------------------

          fileTools = addToolBar("");
          fileTools->setObjectName("file-operations");
          if (qApp->layoutDirection() == Qt::LayoutDirection::LeftToRight) {
                for (auto i : { "file-new", "file-open", "file-save", "print", "undo", "redo"})
                      fileTools->addWidget(new AccessibleToolButton(fileTools, getAction(i)));
                }
          else {
                for (auto i : { "file-new", "file-open", "file-save", "print", "redo", "undo"})
                      fileTools->addWidget(new AccessibleToolButton(fileTools, getAction(i)));
                }

          fileTools->addSeparator();
          mag = new MagBox;
          connect(mag, SIGNAL(magChanged(MagIdx)), SLOT(magChanged(MagIdx)));
          fileTools->addWidget(mag);
          viewModeCombo = new QComboBox(this);
    #if defined(Q_OS_MAC)
          viewModeCombo->setFocusPolicy(Qt::StrongFocus);
    #else
          viewModeCombo->setFocusPolicy(Qt::TabFocus);
    #endif
          viewModeCombo->setFixedHeight(preferences.iconHeight + 8);  // hack
          viewModeCombo->addItem("",       int(LayoutMode::PAGE));
          viewModeCombo->addItem("", int(LayoutMode::LINE));
          viewModeCombo->addItem("", int(LayoutMode::SYSTEM));
          connect(viewModeCombo, SIGNAL(activated(int)), SLOT(switchLayoutMode(int)));
          fileTools->addWidget(viewModeCombo);

          //---------------------
          //    Transport Tool Bar
          //---------------------

          transportTools = addToolBar("");
          transportTools->setObjectName("transport-tools");
    #ifdef HAS_MIDI
          transportTools->addWidget(new AccessibleToolButton(transportTools, getAction("midi-on")));
          transportTools->addSeparator();
    #endif
          transportTools->addWidget(new AccessibleToolButton(transportTools, getAction("rewind")));
          _playButton = new AccessibleToolButton(transportTools, getAction("play"));
          transportTools->addWidget(_playButton);
          transportTools->addWidget(new AccessibleToolButton(transportTools, getAction("loop")));
          transportTools->addSeparator();
          QAction* repeatAction = getAction("repeat");
          repeatAction->setChecked(MScore::playRepeats);
          transportTools->addWidget(new AccessibleToolButton(transportTools, repeatAction));
          transportTools->addWidget(new AccessibleToolButton(transportTools, getAction("pan")));
          transportTools->addWidget(new AccessibleToolButton(transportTools, metronomeAction));

          //-------------------------------
          //    Concert Pitch Tool Bar
          //-------------------------------

          cpitchTools = addToolBar("");
          cpitchTools->setObjectName("pitch-tools");
          a = getAction("concert-pitch");
          a->setCheckable(true);
          cpitchTools->addWidget(new AccessibleToolButton(cpitchTools, a));

          //-------------------------------
          //    Image Capture Tool Bar
          //-------------------------------

          fotoTools = addToolBar("");
          fotoTools->setObjectName("foto-tools");
          fotoTools->addWidget(new AccessibleToolButton(fotoTools, getAction("fotomode")));

          addToolBarBreak();

          //-------------------------------
          //    Note Input Tool Bar
          //-------------------------------

          entryTools = addToolBar("");
          entryTools->setObjectName("entry-tools");

          populateNoteInputMenu();

          //---------------------
          //    Menus
          //---------------------

          QMenuBar* mb = menuBar();

          //---------------------
          //    Menu File
          //---------------------

          menuFile = mb->addMenu("");
          menuFile->setObjectName("File");

          a = getAction("startcenter");
          a->setCheckable(true);
          menuFile->addAction(a);
          menuFile->addAction(getAction("file-new"));
          menuFile->addAction(getAction("file-open"));

          openRecent = menuFile->addMenu("");

          connect(openRecent, SIGNAL(aboutToShow()), SLOT(openRecentMenu()));
          connect(openRecent, SIGNAL(triggered(QAction*)), SLOT(selectScore(QAction*)));

          for (auto i : {
                "",
                "file-save",
                "file-save-as",
                "file-save-a-copy",
                "file-save-selection",
                "file-save-online",
                "file-export",
                "file-part-export",
                "file-import-pdf",
                "",
                "file-close",
                "",
                "parts",
                "album" }) {
                if (!*i)
                      menuFile->addSeparator();
                else if (enableExperimental || strcmp(i,"file-save-online") != 0)
                      menuFile->addAction(getAction(i));
                }
          if (enableExperimental)
                menuFile->addAction(getAction("layer"));
          menuFile->addSeparator();
          menuFile->addAction(getAction("edit-info"));
          if (enableExperimental)
                menuFile->addAction(getAction("media"));
          menuFile->addSeparator();
          menuFile->addAction(getAction("print"));
    #ifndef Q_OS_MAC
          menuFile->addSeparator();
          menuFile->addAction(getAction("quit"));
    #endif

          //---------------------
          //    Menu Edit
          //---------------------

          menuEdit = mb->addMenu("");
          menuEdit->setObjectName("Edit");
          menuEdit->addAction(getAction("undo"));
          menuEdit->addAction(getAction("redo"));

          menuEdit->addSeparator();
          menuEdit->addAction(getAction("cut"));
          menuEdit->addAction(getAction("copy"));
          menuEdit->addAction(getAction("paste"));
          menuEdit->addAction(getAction("swap"));
          menuEdit->addAction(getAction("delete"));

          menuEdit->addSeparator();
          menuEdit->addAction(getAction("select-all"));
          menuEdit->addAction(getAction("select-section"));
          menuEdit->addAction(getAction("find"));

          menuEdit->addSeparator();

          menuEdit->addAction(getAction("instruments"));

    #ifdef NDEBUG
          if (enableExperimental) {
    #endif
                menuEdit->addSeparator();
                menuEdit->addAction(getAction("debugger"));
    #ifdef NDEBUG
                }
    #endif

          menuEdit->addSeparator();
          pref = menuEdit->addAction("", this, SLOT(startPreferenceDialog()));
          pref->setMenuRole(QAction::PreferencesRole);

          //---------------------
          //    Menu View
          //---------------------

          menuView = mb->addMenu("");
          menuView->setObjectName("View");

          a = getAction("toggle-palette");
          a->setCheckable(true);
          menuView->addAction(a);

          a = getAction("masterpalette");
          a->setCheckable(true);
          menuView->addAction(a);

          a = getAction("inspector");
          a->setCheckable(true);
          menuView->addAction(a);
    #ifdef OMR
          a = getAction("omr");
          a->setCheckable(true);
          menuView->addAction(a);
    #endif
          playId = getAction("toggle-playpanel");
          playId->setCheckable(true);
          menuView->addAction(playId);

          a = getAction("toggle-navigator");
          a->setCheckable(true);
          a->setChecked(preferences.showNavigator);
          menuView->addAction(a);

          a = getAction("toggle-timeline");
          a->setCheckable(true);
          menuView->addAction(a);

          a = getAction("toggle-mixer");
          a->setCheckable(true);
          menuView->addAction(a);

          a = getAction("synth-control");
          a->setCheckable(true);
          menuView->addAction(a);

          a = getAction("toggle-selection-window");
          a->setCheckable(true);
          menuView->addAction(a);

          a = getAction("toggle-piano");
          a->setCheckable(true);
          menuView->addAction(a);

          menuView->addSeparator();
          menuView->addAction(getAction("zoomin"));
          menuView->addAction(getAction("zoomout"));
          menuView->addSeparator();

          menuToolbars = new QMenu();

          a = getAction("toggle-fileoperations");
          a->setCheckable(true);
          a->setChecked(fileTools->isVisible());
          connect(fileTools, SIGNAL(visibilityChanged(bool)), a, SLOT(setChecked(bool)));
          menuToolbars->addAction(a);

          a = getAction("toggle-transport");
          a->setCheckable(true);
          a->setChecked(transportTools->isVisible());
          connect(transportTools, SIGNAL(visibilityChanged(bool)), a, SLOT(setChecked(bool)));
          menuToolbars->addAction(a);

          a = getAction("toggle-concertpitch");
          a->setCheckable(true);
          a->setChecked(cpitchTools->isVisible());
          connect(cpitchTools, SIGNAL(visibilityChanged(bool)), a, SLOT(setChecked(bool)));
          menuToolbars->addAction(a);

          a = getAction("toggle-imagecapture");
          a->setCheckable(true);
          a->setChecked(fotoTools->isVisible());
          connect(fotoTools, SIGNAL(visibilityChanged(bool)), a, SLOT(setChecked(bool)));
          menuToolbars->addAction(a);

          a = getAction("toggle-noteinput");
          a->setCheckable(true);
          a->setChecked(entryTools->isVisible());
          connect(entryTools, SIGNAL(visibilityChanged(bool)), a, SLOT(setChecked(bool)));
          menuToolbars->addAction(a);

          menuToolbars->addSeparator();

          menuToolbars->addAction(getAction("edit-toolbars"));

          menuView->addMenu(menuToolbars);

          menuWorkspaces = new QMenu();
          connect(menuWorkspaces, SIGNAL(aboutToShow()), SLOT(showWorkspaceMenu()));
          menuView->addMenu(menuWorkspaces);

          a = getAction("toggle-statusbar");
          a->setCheckable(true);
          a->setChecked(true);
          menuView->addAction(a);

          menuView->addSeparator();
          a = getAction("split-h");
          a->setCheckable(true);
          menuView->addAction(a);
          a = getAction("split-v");
          a->setCheckable(true);
          menuView->addAction(a);

          menuView->addSeparator();
          menuView->addAction(getAction("show-invisible"));
          menuView->addAction(getAction("show-unprintable"));
          menuView->addAction(getAction("show-frames"));
          menuView->addAction(getAction("show-pageborders"));
          menuView->addAction(getAction("mark-irregular"));
          menuView->addSeparator();

          a = getAction("fullscreen");
          a->setCheckable(true);
          a->setChecked(false);
    #ifndef Q_OS_MAC
          menuView->addAction(a);
    #endif

          //---------------------
          //    Menu Add
          //---------------------

          menuAdd = mb->addMenu("");
          menuAdd->setObjectName("Add");

          menuAddPitch = new QMenu();
          menuAddPitch->addAction(getAction("note-input"));
          menuAddPitch->addSeparator();

          for (int i = 0; i < 7; ++i) {
                char buffer[8];
                sprintf(buffer, "note-%c", "cdefgab"[i]);
                a = getAction(buffer);
                menuAddPitch->addAction(a);
                }
          menuAddPitch->addSeparator();
          for (int i = 0; i < 7; ++i) {
                char buffer[8];
                sprintf(buffer, "chord-%c", "cdefgab"[i]);
                a = getAction(buffer);
                menuAddPitch->addAction(a);
                }
          menuAdd->addMenu(menuAddPitch);

          menuAddInterval = new QMenu();
          for (int i = 1; i < 10; ++i) {
                char buffer[16];
                sprintf(buffer, "interval%d", i);
                a = getAction(buffer);
                menuAddInterval->addAction(a);
                }
          menuAddInterval->addSeparator();
          for (int i = 2; i < 10; ++i) {
                char buffer[16];
                sprintf(buffer, "interval-%d", i);
                a = getAction(buffer);
                menuAddInterval->addAction(a);
                }
          menuAdd->addMenu(menuAddInterval);

          menuTuplet = new QMenu();
          for (auto i : { "duplet", "triplet", "quadruplet", "quintuplet", "sextuplet",
                "septuplet", "octuplet", "nonuplet", "tuplet-dialog" })
                menuTuplet->addAction(getAction(i));
          menuAdd->addMenu(menuTuplet);

          menuAdd->addSeparator();

          menuAddMeasures = new QMenu("");
          menuAddMeasures->addAction(getAction("insert-measure"));
          menuAddMeasures->addAction(getAction("insert-measures"));
          menuAddMeasures->addSeparator();
          menuAddMeasures->addAction(getAction("append-measure"));
          menuAddMeasures->addAction(getAction("append-measures"));
          menuAdd->addMenu(menuAddMeasures);

          menuAddFrames = new QMenu();
          menuAddFrames->addAction(getAction("insert-hbox"));
          menuAddFrames->addAction(getAction("insert-vbox"));
          menuAddFrames->addAction(getAction("insert-textframe"));
          if (enableExperimental)
                menuAddFrames->addAction(getAction("insert-fretframe"));
          menuAddFrames->addSeparator();
          menuAddFrames->addAction(getAction("append-hbox"));
          menuAddFrames->addAction(getAction("append-vbox"));
          menuAddFrames->addAction(getAction("append-textframe"));
          menuAdd->addMenu(menuAddFrames);

          menuAddText = new QMenu();
          menuAddText->addAction(getAction("title-text"));
          menuAddText->addAction(getAction("subtitle-text"));
          menuAddText->addAction(getAction("composer-text"));
          menuAddText->addAction(getAction("poet-text"));
          menuAddText->addAction(getAction("part-text"));
          menuAddText->addSeparator();
          menuAddText->addAction(getAction("system-text"));
          menuAddText->addAction(getAction("staff-text"));
          menuAddText->addAction(getAction("expression-text"));
          menuAddText->addAction(getAction("chord-text"));
          menuAddText->addAction(getAction("rehearsalmark-text"));
          menuAddText->addAction(getAction("instrument-change-text"));
          menuAddText->addAction(getAction("fingering-text"));
          menuAddText->addSeparator();
          menuAddText->addAction(getAction("lyrics"));
          menuAddText->addAction(getAction("figured-bass"));
          menuAddText->addAction(getAction("tempo"));
          menuAdd->addMenu(menuAddText);

          menuAddLines = new QMenu();
          menuAddLines->addAction(getAction("add-slur"));
          menuAddLines->addAction(getAction("add-hairpin"));
          menuAddLines->addAction(getAction("add-hairpin-reverse"));
          menuAddLines->addAction(getAction("add-8va"));
          menuAddLines->addAction(getAction("add-8vb"));
          menuAddLines->addAction(getAction("add-noteline"));
          menuAdd->addMenu(menuAddLines);

          //---------------------
          //    Menu Format
          //---------------------

          menuFormat = mb->addMenu("");
          menuFormat->setObjectName("Format");

          menuFormat->addAction(getAction("edit-style"));
          QAction* pageSettingsAction = getAction("page-settings");
          // in some locale (fr), page settings ends up in Application menu on mac
          // this line prevents it.
          pageSettingsAction->setMenuRole(QAction::NoRole);
          menuFormat->addAction(pageSettingsAction);
          menuFormat->addSeparator();

          menuFormat->addAction(getAction("add-remove-breaks"));

          QMenu* menuStretch = new QMenu(tr("&Stretch"));
          for (auto i : { "stretch+", "stretch-", "reset-stretch" })
                menuStretch->addAction(getAction(i));
          menuFormat->addMenu(menuStretch);
          menuFormat->addSeparator();

          menuFormat->addAction(getAction("reset-beammode"));
          menuFormat->addAction(getAction("reset"));
          menuFormat->addSeparator();

          if (enableExperimental)
                menuFormat->addAction(getAction("edit-harmony"));

          menuFormat->addSeparator();
          menuFormat->addAction(getAction("load-style"));
          menuFormat->addAction(getAction("save-style"));

          //---------------------
          //    Menu Tools
          //---------------------

          menuTools = mb->addMenu("");
          menuTools->setObjectName("Tools");

          menuTools->addAction(getAction("transpose"));
          menuTools->addSeparator();
          menuTools->addAction(getAction("explode"));
          menuTools->addAction(getAction("implode"));

          menuVoices = new QMenu("");
          for (auto i : { "voice-x12", "voice-x13", "voice-x14", "voice-x23", "voice-x24", "voice-x34" })
                menuVoices->addAction(getAction(i));
          menuTools->addMenu(menuVoices);
          menuTools->addSeparator();

          menuTools->addAction(getAction("slash-fill"));
          menuTools->addAction(getAction("slash-rhythm"));
          menuTools->addSeparator();

          menuTools->addAction(getAction("pitch-spell"));
          menuTools->addAction(getAction("reset-groupings"));
          menuTools->addAction(getAction("resequence-rehearsal-marks"));
          menuTools->addSeparator();

          menuTools->addAction(getAction("copy-lyrics-to-clipboard"));
          menuTools->addAction(getAction("fotomode"));

          menuTools->addAction(getAction("del-empty-measures"));

          //---------------------
          //    Menu Plugins
          //---------------------

          menuPlugins = mb->addMenu("");
          menuPlugins->setObjectName("Plugins");

          menuPlugins->addAction(getAction("plugin-manager"));

          a = getAction("plugin-creator");
          a->setCheckable(true);
          menuPlugins->addAction(a);

          menuPlugins->addSeparator();

          //---------------------
          //    Menu Debug
          //---------------------

    #ifndef NDEBUG
          QMenu* menuDebug = mb->addMenu("Debug");
          menuDebug->setObjectName("Debug");
          a = getAction("no-horizontal-stretch");
          a->setCheckable(true);
          menuDebug->addAction(a);
          a = getAction("no-vertical-stretch");
          a->setCheckable(true);
          menuDebug->addAction(a);
          menuDebug->addSeparator();
          a = getAction("show-segment-shapes");
          a->setCheckable(true);
          menuDebug->addAction(a);
          a = getAction("show-measure-shapes");
          a->setCheckable(true);
          menuDebug->addAction(a);
          a = getAction("show-bounding-rect");
          a->setCheckable(true);
          menuDebug->addAction(a);
          a = getAction("show-corrupted-measures");
          a->setCheckable(true);
          a->setChecked(true);
          menuDebug->addAction(a);
          a = getAction("relayout");
          menuDebug->addAction(a);
          a = getAction("autoplace-slurs");
          a->setCheckable(true);
          a->setChecked(MScore::autoplaceSlurs);
          menuDebug->addAction(a);
    #endif

          //---------------------
          //    Menu Help
          //---------------------

          mb->addSeparator();
          menuHelp = mb->addMenu("");
          menuHelp->setObjectName("Help");

    #if 0
          if (_helpEngine) {
                HelpQuery* hw = new HelpQuery(menuHelp);
                menuHelp->addAction(hw);
                connect(menuHelp, SIGNAL(aboutToShow()), hw, SLOT(setFocus()));
                }
    #endif
          //menuHelp->addAction(getAction("help"));
          onlineHandbookAction = menuHelp->addAction("", this, SLOT(helpBrowser1()));

          menuHelp->addSeparator();

          aboutAction = new QAction("", 0);

          aboutAction->setMenuRole(QAction::AboutRole);
          connect(aboutAction, SIGNAL(triggered()), this, SLOT(about()));
          menuHelp->addAction(aboutAction);

          aboutQtAction = new QAction("", 0);
          aboutQtAction->setMenuRole(QAction::AboutQtRole);
          connect(aboutQtAction, SIGNAL(triggered()), this, SLOT(aboutQt()));
          menuHelp->addAction(aboutQtAction);

          aboutMusicXMLAction = new QAction("", 0);
          aboutMusicXMLAction->setMenuRole(QAction::ApplicationSpecificRole);
          connect(aboutMusicXMLAction, SIGNAL(triggered()), this, SLOT(aboutMusicXML()));
          menuHelp->addAction(aboutMusicXMLAction);

    #if defined(Q_OS_MAC) || defined(Q_OS_WIN)
    #if not defined(FOR_WINSTORE)
          checkForUpdateAction = menuHelp->addAction("", this, SLOT(checkForUpdate()));
    #endif
    #endif
          menuHelp->addSeparator();
          askForHelpAction = menuHelp->addAction("", this, SLOT(askForHelp()));
          reportBugAction = menuHelp->addAction("", this, SLOT(reportBug()));

          menuHelp->addSeparator();
          menuHelp->addAction(getAction("resource-manager"));
          menuHelp->addSeparator();
          revertToFactoryAction = menuHelp->addAction("", this, SLOT(resetAndRestart()));

          if (!MScore::noGui) {
                retranslate(true);
                //accessibility for menus
                for (QMenu* menu : mb->findChildren<QMenu*>()) {
                      menu->setAccessibleName(menu->objectName());
                      menu->setAccessibleDescription(Shortcut::getMenuShortcutString(menu));
                      }
                }

          setCentralWidget(envelope);

          // load cascading instrument templates
          loadInstrumentTemplates(preferences.instrumentList1);
          if (!preferences.instrumentList2.isEmpty())
                loadInstrumentTemplates(preferences.instrumentList2);

          preferencesChanged();
          if (seq) {
                connect(seq, SIGNAL(started()), SLOT(seqStarted()));
                connect(seq, SIGNAL(stopped()), SLOT(seqStopped()));
                }
          loadScoreList();

          QClipboard* cb = QApplication::clipboard();
          connect(cb, SIGNAL(dataChanged()), SLOT(clipboardChanged()));
          connect(cb, SIGNAL(selectionChanged()), SLOT(clipboardChanged()));

          autoSaveTimer = new QTimer(this);
          autoSaveTimer->setSingleShot(true);
          connect(autoSaveTimer, SIGNAL(timeout()), this, SLOT(autoSaveTimerTimeout()));
          initOsc();
          startAutoSave();

          QInputMethod* im = QGuiApplication::inputMethod();
          connect(im, SIGNAL(localeChanged()), SLOT(inputMethodLocaleChanged()));

          if (enableExperimental) {
                cornerLabel = new QLabel(this);
                cornerLabel->setScaledContents(true);
                cornerLabel->setPixmap(QPixmap(":/data/mscore.png"));
                cornerLabel->setGeometry(width() - 48, 0, 48, 48);
                }
          }

    MuseScore::~MuseScore()
          {
          delete synti;
          }

    //---------------------------------------------------------
    //   showError
    //---------------------------------------------------------

    void MuseScore::showError()
          {
          static QErrorMessage* msg = 0;
          if (msg == 0)
                msg = new QErrorMessage(this);
          msg->showMessage(tr(MScore::errorMessage()), MScore::errorGroup());
          MScore::setError(MS_NO_ERROR);
          }

    //---------------------------------------------------------
    //   retranslate
    //---------------------------------------------------------

    void MuseScore::retranslate(bool firstStart)
          {
          _positionLabel->setToolTip(tr("Measure:Beat:Tick"));

          // retranslate the menu
          menuFile->setTitle(tr("&File"));
          openRecent->setTitle(tr("Open &Recent"));
          menuEdit->setTitle(tr("&Edit"));
          menuView->setTitle(tr("&View"));
          menuToolbars->setTitle(tr("&Toolbars"));
          menuWorkspaces->setTitle(tr("W&orkspaces"));
          pref->setText(tr("&Preferences..."));
          menuAdd->setTitle(tr("&Add"));
          menuAddMeasures->setTitle(tr("&Measures"));
          menuAddFrames->setTitle(tr("&Frames"));
          menuAddText->setTitle(tr("&Text"));
          menuAddLines->setTitle(tr("&Lines"));
          menuAddPitch->setTitle(tr("N&otes"));
          menuAddInterval->setTitle(tr("&Intervals"));
          menuTuplet->setTitle(tr("T&uplets"));
          menuFormat->setTitle(tr("F&ormat"));
          menuTools->setTitle(tr("&Tools"));
          menuVoices->setTitle(tr("&Voices"));
          menuPlugins->setTitle(tr("&Plugins"));
          menuHelp->setTitle(tr("&Help"));

          aboutAction->setText(tr("&About..."));
          aboutQtAction->setText(tr("About &Qt..."));
          aboutMusicXMLAction->setText(tr("About &MusicXML..."));
          onlineHandbookAction->setText(tr("&Online Handbook"));
          if (checkForUpdateAction)
                checkForUpdateAction->setText(tr("Check for &Update"));
          askForHelpAction->setText(tr("Ask for Help"));
          reportBugAction->setText(tr("Report a Bug"));
          revertToFactoryAction->setText(tr("Revert to Factory Settings"));

          fileTools->setWindowTitle(tr("File Operations"));
          transportTools->setWindowTitle(tr("Playback Controls"));
          cpitchTools->setWindowTitle(tr("Concert Pitch"));
          fotoTools->setWindowTitle(tr("Image Capture"));
          entryTools->setWindowTitle(tr("Note Input"));

          viewModeCombo->setAccessibleName(tr("View Mode"));
          viewModeCombo->setItemText(viewModeCombo->findData(int(LayoutMode::PAGE)), tr("Page View"));
          viewModeCombo->setItemText(viewModeCombo->findData(int(LayoutMode::LINE)), tr("Continuous View"));
          viewModeCombo->setItemText(viewModeCombo->findData(int(LayoutMode::SYSTEM)), tr("Single Page"));

          showMidiImportButton->setText(tr("Show MIDI import panel"));

          Shortcut::retranslate();
          if (!firstStart && Workspace::currentWorkspace->readOnly()) {
                changeWorkspace(Workspace::currentWorkspace);
                }
          }

    //---------------------------------------------------------
    //   resizeEvent
    //---------------------------------------------------------

    void MuseScore::resizeEvent(QResizeEvent*)
          {
          if (enableExperimental) {
                cornerLabel->setGeometry(width() - 48, 0, 48, 48);
                }
          }

    //---------------------------------------------------------
    //   startAutoSave
    //---------------------------------------------------------

    void MuseScore::startAutoSave()
          {
          if (preferences.autoSave) {
                int t = preferences.autoSaveTime * 60 * 1000;
                autoSaveTimer->start(t);
                }
          else
                autoSaveTimer->stop();
          }

    //---------------------------------------------------------
    //   getLocaleISOCode
    //---------------------------------------------------------

    QString MuseScore::getLocaleISOCode() const
          {
          QString lang;
          if (localeName.toLower() == "system")
                lang = QLocale::system().name();
          else
                lang = localeName;
          return lang;
          }

    //---------------------------------------------------------
    //   helpBrowser1
    //    show online help
    //---------------------------------------------------------

    void MuseScore::helpBrowser1() const
          {
          QString lang = getLocaleISOCode();

          if (MScore::debugMode)
                qDebug("open online handbook for language <%s>", qPrintable(lang));
          QString help = QString("https://musescore.org/redirect/help?tag=handbook&locale=%1").arg(getLocaleISOCode());
          //try to find an exact match
          bool found = false;
          foreach (LanguageItem item, _languages) {
                if (item.key == lang) {
                      QString handbook = item.handbook;
                      if (!handbook.isNull()) {
                          help = item.handbook;
                          found = true;
                          }
                      break;
                      }
                }
          //try a to find a match on first two letters
          if (!found && lang.size() > 2) {
                lang = lang.left(2);
                foreach (LanguageItem item, _languages) {
                      if (item.key == lang){
                          QString handbook = item.handbook;
                          if (!handbook.isNull())
                              help = item.handbook;
                          break;
                          }
                      }
                }

          //track visits. see: http://www.google.com/support/googleanalytics/bin/answer.py?answer=55578
          help += QString("&utm_source=desktop&utm_medium=menu&utm_content=%1&utm_campaign=MuseScore%2").arg(rev.trimmed()).arg(QString(VERSION));
          QDesktopServices::openUrl(QUrl(help));
          }

    //---------------------------------------------------------
    //   resetAndRestart
    //---------------------------------------------------------

    void MuseScore::resetAndRestart()
          {
          int ret = QMessageBox::question(0, tr("Are you sure?"),
                      tr("This will reset all your preferences.\n"
                       "Custom palettes, custom shortcuts, and the list of recent scores will be deleted. "
                       "MuseScore will restart with its default settings.\n"
                       "Reverting will not remove any scores from your computer.\n"
                       "Are you sure you want to proceed?"),
                       QMessageBox::Yes|QMessageBox::No, QMessageBox::No);
          if (ret == QMessageBox::Yes ) {
                 close();
                 QStringList args("-F");
                 QProcess::startDetached(qApp->arguments()[0], args);
                 }
          }

    //---------------------------------------------------------
    //   aboutQt
    //---------------------------------------------------------

    void MuseScore::aboutQt()
          {
          QMessageBox::aboutQt(this, QString("About Qt"));
          }

    //---------------------------------------------------------
    //   aboutMusicXML
    //---------------------------------------------------------

    void MuseScore::aboutMusicXML()
          {
          AboutMusicXMLBoxDialog ab;
          ab.show();
          ab.exec();
          }

    //---------------------------------------------------------
    //   selectScore
    //    "open recent"
    //---------------------------------------------------------

    void MuseScore::selectScore(QAction* action)
          {
          QString a = action->data().toString();
          if (!a.isEmpty()) {
                if (a == "clear-recent") {
                      _recentScores.clear();
                      if (startcenter)
                            startcenter->updateRecentScores();
                      }
                else {
                      MasterScore* score = readScore(a);
                      if (score) {
                            setCurrentScoreView(appendScore(score));
                            addRecentScore(score);
                            writeSessionFile(false);
                            }
                      }
                }
          }

    //---------------------------------------------------------
    //   selectionChanged
    //---------------------------------------------------------

    void MuseScore::selectionChanged(SelState selectionState)
          {
          bool enable = selectionState != SelState::NONE;
          getAction("cut")->setEnabled(enable);
          getAction("copy")->setEnabled(enable);
          getAction("select-similar-range")->setEnabled(selectionState == SelState::RANGE);
          if (pianorollEditor)
                pianorollEditor->changeSelection(selectionState);
          if (drumrollEditor)
                drumrollEditor->changeSelection(selectionState);
          if (timeline())
                timeline()->changeSelection(selectionState);
          updateInspector();
          }

    //---------------------------------------------------------
    //   updateInspector
    //---------------------------------------------------------

    void MuseScore::updateInspector()
          {
          if (_inspector)
                _inspector->update(cs);
          }

    //---------------------------------------------------------
    //   updateShadowNote
    //   update the shadow note in the current ScoreView
    //---------------------------------------------------------

    void MuseScore::updateShadowNote()
          {
          currentScoreView()->updateShadowNotes();
          }

    //---------------------------------------------------------
    //   appendScore
    //    append score to project list
    //---------------------------------------------------------

    int MuseScore::appendScore(MasterScore* score)
          {
          int index = scoreList.size();
          for (int i = 0; i < scoreList.size(); ++i) {
                if ((!score->importedFilePath().isEmpty()
                     && scoreList[i]->importedFilePath() == score->importedFilePath())
                        || (scoreList[i]->fileInfo()->canonicalFilePath() == score->fileInfo()->canonicalFilePath() && score->fileInfo()->exists())) {
                      removeTab(i);
                      index = i;
                      break;
                      }
                }
          scoreList.insert(index, score);
          tab1->blockSignals(true);
          if (tab2)
                tab2->blockSignals(true);
          tab1->insertTab(score);
          if (tab2)
                tab2->insertTab(score);
          tab1->blockSignals(false);
          if (tab2)
                tab2->blockSignals(false);
          return index;
          }

    //---------------------------------------------------------
    //   addRecentScore
    //---------------------------------------------------------

    void MuseScore::addRecentScore(Score* score)
          {
          QString path = score->importedFilePath(); // defined for scores imported from e.g. MIDI files
          addRecentScore(path);
          path = score->masterScore()->fileInfo()->absoluteFilePath();
          addRecentScore(path);
          if (startcenter)
                startcenter->updateRecentScores();
          }

    void MuseScore::addRecentScore(const QString& scorePath)
          {
          if (scorePath.isEmpty())
                return;
          QFileInfo fi(scorePath);
          QString absoluteFilePath = fi.absoluteFilePath();
          _recentScores.removeAll(absoluteFilePath);
          _recentScores.prepend(absoluteFilePath);
          if (_recentScores.size() > RECENT_LIST_SIZE)
                _recentScores.removeLast();
          }

    #if 0
    //---------------------------------------------------------
    //   updateTabNames
    //---------------------------------------------------------

    void MuseScore::updateTabNames()
          {
          for (int i = 0; i < tab1->count(); ++i) {
                ScoreView* view = tab1->view(i);
                if (view)
                      tab1->setTabText(i, view->score()->masterScore()->fileInfo()->completeBaseName());
                }
          if (tab2) {
                for (int i = 0; i < tab2->count(); ++i) {
                      ScoreView* view = tab2->view(i);
                      if (view)
                            tab2->setTabText(i, view->score()->masterScore()->fileInfo()->completeBaseName());
                      }
                }
          }
    #endif

    //---------------------------------------------------------
    //   loadScoreList
    //    read list of "Recent Scores"
    //---------------------------------------------------------

    void MuseScore::loadScoreList()
          {
          if (useFactorySettings)
                return;
          QSettings s;
          for (int i = RECENT_LIST_SIZE-1; i >= 0; --i) {
                QString path = s.value(QString("recent-%1").arg(i),"").toString();
                if (!path.isEmpty() && QFileInfo(path).exists()) {
                      _recentScores.removeAll(path);
                      _recentScores.prepend(path);
                      }
                }
          }

    //---------------------------------------------------------
    //   openRecentMenu
    //---------------------------------------------------------

    void MuseScore::openRecentMenu()
          {
          openRecent->clear();
          bool one = false;
          for (const QFileInfo& fi : recentScores()) {
                QAction* action = openRecent->addAction(fi.fileName().replace("&", "&&"));  // show filename only
                QString data(fi.canonicalFilePath());
                action->setData(data);
                action->setToolTip(data);
                one = true;
                }
          if (one) {
                openRecent->addSeparator();
                QAction* action = openRecent->addAction(tr("Clear Recent Files"));
                action->setData("clear-recent");
                }
          }

    //---------------------------------------------------------
    //   setCurrentView
    //---------------------------------------------------------

    void MuseScore::setCurrentScoreView(int idx)
          {
          setCurrentView(0, idx);
          if (tab2)
                setCurrentView(1, idx);
          }

    void MuseScore::setCurrentView(int tabIdx, int idx)
          {
          if (idx == -1)
                setCurrentScoreView(nullptr);
          else {
                ScoreTab* tab = tabIdx ? tab2 : tab1;
                if (tab)
                      tab->setCurrentIndex(idx);
                }
          }

    //---------------------------------------------------------
    //   setCurrentScoreView
    //---------------------------------------------------------

    void MuseScore::setCurrentScoreView(ScoreView* view)
          {
          cv = view;
          if (cv) {
                if (timeline())
                      timeline()->setScoreView(cv);
                if (cv->score() && (cs != cv->score())) {
                      // exit note entry mode
                      if (cv->noteEntryMode()) {
                            cv->cmd(getAction("escape"));
                            qApp->processEvents();
                            }
                      updateInputState(cv->score());
                      }
                cs = cv->score();
                cv->setFocusRect();
                }
          else
                cs = 0;

                      // set midi import panel
          QString fileName = cs ? cs->importedFilePath() : "";
          midiPanelOnSwitchToFile(fileName);

          if (enableExperimental) {
                updateLayer();
                updatePlayMode();
                }

          if (seq)
                seq->setScoreView(cv);
          if (playPanel)
                playPanel->setScore(cs);
          if (synthControl)
                synthControl->setScore(cs);
          if (selectionWindow)
                selectionWindow->setScore(cs);
          if (mixer)
                mixer->updateAll(cs ? cs->masterScore() : nullptr);
    #ifdef OMR
          if (omrPanel) {
                if (cv && cv->omrView())
                      omrPanel->setOmrView(cv->omrView());
                else
                      omrPanel->setOmrView(0);
                }
    #endif
          if (!cs) {
                setWindowTitle(MUSESCORE_NAME_VERSION);
                if (_navigator && _navigator->widget()) {
                      navigator()->setScoreView(cv);
                      navigator()->setScore(0);
                      }
                if (timeline()) {
                      timeline()->setScoreView(cv);
                      timeline()->setScore(0);
                      }
                if (_inspector)
                      _inspector->update(0);
                viewModeCombo->setEnabled(false);
                if (_textTools) {
                      _textTools->hide();
                      if (textPalette)
                            textPalette->hide();
                      }
                if (_pianoTools)
                      _pianoTools->hide();
                if (_drumTools)
                      _drumTools->hide();
                changeState(STATE_DISABLED);
                return;
                }

          viewModeCombo->setEnabled(true);
          updateViewModeCombo();

          selectionChanged(cs->selection().state());

          _sstate = STATE_DISABLED; // defeat optimization
          changeState(cv->mscoreState());

          cv->setFocus(Qt::OtherFocusReason);
          setFocusProxy(cv);

          getAction("file-save")->setEnabled(cs->masterScore()->isSavable());
          getAction("file-part-export")->setEnabled(cs->masterScore()->excerpts().size() > 0);
          getAction("show-invisible")->setChecked(cs->showInvisible());
          getAction("show-unprintable")->setChecked(cs->showUnprintable());
          getAction("show-frames")->setChecked(cs->showFrames());
          getAction("show-pageborders")->setChecked(cs->showPageborders());
          getAction("mark-irregular")->setChecked(cs->markIrregularMeasures());
          getAction("fotomode")->setChecked(cv->fotoMode());
          getAction("join-measures")->setEnabled(cs->masterScore()->excerpts().size() == 0);
          getAction("split-measure")->setEnabled(cs->masterScore()->excerpts().size() == 0);
          updateUndoRedo();

          MagIdx midx = cv->magIdx();
          if (midx == MagIdx::MAG_FREE)
                mag->setMag(view->lmag());
          else {
                mag->setMagIdx(midx);
                magChanged(midx);
                }

          setWindowTitle(MUSESCORE_NAME_VERSION ": " + cs->title());

          QAction* a = getAction("concert-pitch");
          a->setChecked(cs->styleB(StyleIdx::concertPitch));

          setPos(cs->inputPos());
          //showMessage(cs->filePath(), 2000);
          if (_navigator && _navigator->widget()) {
                navigator()->setScore(cs);
                navigator()->setScoreView(view);
                }
          if (timeline()) {
                timeline()->setScore(cs);
                timeline()->setScoreView(view);
                }
          ScoreAccessibility::instance()->updateAccessibilityInfo();
          }

    //---------------------------------------------------------
    //   updateViewModeCombo
    //---------------------------------------------------------

    void MuseScore::updateViewModeCombo()
          {
          int idx;
          switch (cs->layoutMode()) {
                case LayoutMode::PAGE:
                case LayoutMode::FLOAT:
                      idx = 0;
                      break;
                case LayoutMode::LINE:
                      idx = 1;
                      break;
                case LayoutMode::SYSTEM:
                      idx = 2;
                      break;
                default:
                      idx = 0;
                      break;
                }
          viewModeCombo->setCurrentIndex(idx);
          }

    //---------------------------------------------------------
    //   showMessage
    //---------------------------------------------------------

    void MuseScore::showMessage(const QString& s, int timeout)
          {
          _statusBar->showMessage(s, timeout);
          }

    //---------------------------------------------------------
    //   midiPanel
    //---------------------------------------------------------

    void MuseScore::midiPanelOnSwitchToFile(const QString &file)
          {
          bool isMidiFile = ImportMidiPanel::isMidiFile(file);
          if (isMidiFile) {
                importmidiPanel->setMidiFile(file);
                if (importmidiPanel->isPreferredVisible())
                      importmidiPanel->setVisible(true);
                }
          else
                importmidiPanel->setVisible(false);
          importmidiShowPanel->setVisible(!importmidiPanel->isPreferredVisible() && isMidiFile);
          }

    //---------------------------------------------------------
    //   midiPanelOnCloseFile
    //---------------------------------------------------------

    void MuseScore::midiPanelOnCloseFile(const QString &file)
          {
          if (ImportMidiPanel::isMidiFile(file))
                importmidiPanel->excludeMidiFile(file);
          }

    //---------------------------------------------------------
    //   allowShowMidiPanel
    //---------------------------------------------------------

    void MuseScore::allowShowMidiPanel(const QString &file)
          {
          if (ImportMidiPanel::isMidiFile(file))
                importmidiPanel->setPreferredVisible(true);
          }

    //---------------------------------------------------------
    //   setMidiReopenInProgress
    //---------------------------------------------------------

    void MuseScore::setMidiReopenInProgress(const QString &file)
          {
          if (ImportMidiPanel::isMidiFile(file))
                importmidiPanel->setReopenInProgress();
          }

    //---------------------------------------------------------
    //   showMidiImportPanel
    //---------------------------------------------------------

    void MuseScore::showMidiImportPanel()
          {
          importmidiPanel->setPreferredVisible(true);
          QString fileName = cs ? cs->importedFilePath() : "";
          if (ImportMidiPanel::isMidiFile(fileName))
                importmidiPanel->setVisible(true);
          importmidiShowPanel->hide();
          }

    //---------------------------------------------------------
    //   dragEnterEvent
    //---------------------------------------------------------

    void MuseScore::dragEnterEvent(QDragEnterEvent* event)
          {
          const QMimeData* data = event->mimeData();
          if (data->hasUrls()) {
                QList<QUrl>ul = event->mimeData()->urls();
                foreach(const QUrl& u, ul) {
                      if (MScore::debugMode)
                            qDebug("drag Url: %s scheme <%s>", qPrintable(u.toString()), qPrintable(u.scheme()));
                      if (u.scheme() == "file") {
                            // QFileInfo fi(u.toLocalFile());
                            event->acceptProposedAction();
                            break;
                            }
                      }
                }
          }

    //---------------------------------------------------------
    //   dropEvent
    //---------------------------------------------------------

    void MuseScore::dropEvent(QDropEvent* event)
          {
          const QMimeData* data = event->mimeData();
          if (data->hasUrls()) {
                int view = -1;
                foreach(const QUrl& u, event->mimeData()->urls()) {
                      if (u.scheme() == "file") {
                            QString file = u.toLocalFile();
                            MasterScore* score = readScore(file);
                            if (score) {
                                  view = appendScore(score);
                                  addRecentScore(score);
                                  }
                            }
                      }
                if (view != -1) {
                      setCurrentScoreView(view);
                      writeSessionFile(false);
                      }
                event->acceptProposedAction();
                }
          }

    //---------------------------------------------------------
    //   changeEvent
    //---------------------------------------------------------

    void MuseScore::changeEvent(QEvent *e)
          {
          QMainWindow::changeEvent(e);
          switch (e->type()) {
                case QEvent::LanguageChange:
                      retranslate();
                      break;
                default:
                      break;
                }
          }

    //---------------------------------------------------------
    //   showPageSettings
    //---------------------------------------------------------

    void MuseScore::showPageSettings()
          {
          if (pageSettings == 0)
                pageSettings = new PageSettings();
          pageSettings->setScore(cs->masterScore());
          pageSettings->show();
          pageSettings->raise();
          }

    //---------------------------------------------------------
    //   startDebugger
    //---------------------------------------------------------

    void MuseScore::startDebugger()
          {
          if (!cs)
                return;
          if (debugger == 0)
                debugger = new Debugger(this);
          debugger->updateList(cs);
          debugger->show();
          }

    //---------------------------------------------------------
    //   showElementContext
    //---------------------------------------------------------

    void MuseScore::showElementContext(Element* el)
          {
          if (el == 0)
                return;
          startDebugger();
          debugger->setElement(el);
          }

    //---------------------------------------------------------
    //   showPlayPanel
    //---------------------------------------------------------

    void MuseScore::showPlayPanel(bool visible)
          {
          if (noSeq || !(seq && seq->isRunning()))
                return;
          if (playPanel == 0) {
                if (!visible)
                      return;
                playPanel = new PlayPanel(this);
                connect(playPanel, SIGNAL(gainChange(float)),     synti, SLOT(setGain(float)));
                connect(playPanel, SIGNAL(metronomeGainChanged(float)), seq, SLOT(setMetronomeGain(float)));
                connect(playPanel, SIGNAL(relTempoChanged(double)),seq, SLOT(setRelTempo(double)));
                connect(playPanel, SIGNAL(posChange(int)),         seq, SLOT(seek(int)));
                connect(playPanel, SIGNAL(closed(bool)),          playId,   SLOT(setChecked(bool)));
                connect(synti,     SIGNAL(gainChanged(float)), playPanel, SLOT(setGain(float)));
                playPanel->setGain(synti->gain());
                playPanel->setScore(cs);
                mscore->stackUnder(playPanel);
                }
          playPanel->setVisible(visible);
          playId->setChecked(visible);
          }

    //---------------------------------------------------------
    //   cmdAppendMeasures
    //---------------------------------------------------------

    void MuseScore::cmdAppendMeasures()
          {
          if (cs) {
                if (measuresDialog == 0)
                      measuresDialog = new MeasuresDialog;
                measuresDialog->show();
                }
          }

    //---------------------------------------------------------
    //   MeasuresDialog
    //---------------------------------------------------------

    MeasuresDialog::MeasuresDialog(QWidget* parent)
       : QDialog(parent)
          {
          setupUi(this);
          setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
          measures->selectAll();
          }

    //---------------------------------------------------------
    //   accept
    //---------------------------------------------------------

    void MeasuresDialog::accept()
          {
          int n = measures->value();
          if (mscore->currentScore())
                mscore->currentScoreView()->cmdAppendMeasures(n, ElementType::MEASURE);
          done(1);
          }

    //---------------------------------------------------------
    //   midiinToggled
    //---------------------------------------------------------

    void MuseScore::midiinToggled(bool val)
          {
          _midiinEnabled = val;
          }

    //---------------------------------------------------------
    //   midiinEnabled
    //---------------------------------------------------------

    bool MuseScore::midiinEnabled() const
          {
          return preferences.enableMidiInput && _midiinEnabled;
          }

    //---------------------------------------------------------
    //   processMidiRemote
    //    return if midi remote command detected
    //---------------------------------------------------------

    bool MuseScore::processMidiRemote(MidiRemoteType type, int data, int value)
          {
          if (!preferences.useMidiRemote)
                return false;
          if (!value) {
                // This was a "NoteOff" or "CtrlOff" event. Most MidiRemote actions should only
                // be triggered by an "On" event, so we need to check if this is one of those.
                if (!preferences.advanceOnRelease
                        || type != preferences.midiRemote[RMIDI_REALTIME_ADVANCE].type
                        || data != preferences.midiRemote[RMIDI_REALTIME_ADVANCE].data)
                      return false;
                }
          for (int i = 0; i < MIDI_REMOTES; ++i) {
                if (preferences.midiRemote[i].type == type && preferences.midiRemote[i].data == data) {
                      if (cv == 0)
                            return false;
                      QAction* a = 0;
                      switch (i) {
                            case RMIDI_REWIND:      a = getAction("rewind"); break;
                            case RMIDI_TOGGLE_PLAY: a = getAction("play");  break;
                            case RMIDI_PLAY:
                                  a = getAction("play");
                                  if (a->isChecked())
                                        return true;
                                  break;
                            case RMIDI_STOP:
                                  a = getAction("play");
                                  if (!a->isChecked())
                                        return true;
                                  break;
                            case RMIDI_NOTE1:   a = getAction("pad-note-1");  break;
                            case RMIDI_NOTE2:   a = getAction("pad-note-2");  break;
                            case RMIDI_NOTE4:   a = getAction("pad-note-4");  break;
                            case RMIDI_NOTE8:   a = getAction("pad-note-8");  break;
                            case RMIDI_NOTE16:  a = getAction("pad-note-16");  break;
                            case RMIDI_NOTE32:  a = getAction("pad-note-32");  break;
                            case RMIDI_NOTE64:  a = getAction("pad-note-64");  break;
                            case RMIDI_REST:    a = getAction("rest");  break;
                            case RMIDI_DOT:     a = getAction("pad-dot");  break;
                            case RMIDI_DOTDOT:  a = getAction("pad-dotdot");  break;
                            case RMIDI_TIE:     a = getAction("tie");  break;
                            case RMIDI_UNDO:    a = getAction("undo"); break;
                            case RMIDI_NOTE_EDIT_MODE: a = getAction("note-input");  break;
                            case RMIDI_REALTIME_ADVANCE: a = getAction("realtime-advance");  break;
                            }
                      if (a)
                            a->trigger();
                      return true;
                      }
                }
          return false;
          }

    //---------------------------------------------------------
    //   midiNoteReceived
    //---------------------------------------------------------

    void MuseScore::midiNoteReceived(int channel, int pitch, int velo)
          {
          static const int THRESHOLD_DRUMS = 5; // iterations required before consecutive drum notes
                                         // are not considered part of a chord
          static int active = 0;
          static int iterDrums = 0;
          static int activeDrums = 0;

          if (!midiinEnabled())
                return;

    // qDebug("midiNoteReceived %d %d %d", channel, pitch, velo);

          if (_midiRecordId != -1) {
                preferences.midiRemote[_midiRecordId].type = MIDI_REMOTE_TYPE_NOTEON;
                preferences.midiRemote[_midiRecordId].data = pitch;
                _midiRecordId = -1;
                if (preferenceDialog)
                      preferenceDialog->updateRemote();
                return;
                }

          if (processMidiRemote(MIDI_REMOTE_TYPE_NOTEON, pitch, velo)) {
                active = 0;
                return;
                }

          QWidget* w = QApplication::activeModalWidget();
          if (!cv || w) {
                active = 1;
                return;
                }
          if (velo) {
                 /*
                 * Since some drum modules do not overlap note on / off messages
                 * we need to take a bit of a different tactic to allow chords
                 * to be entered.
                 *
                 * Rather than decrement active for drums (midi on ch10),
                 * we'll just assume that if read() has been called a couple
                 * times in a row without a drum note, that this note is not
                 * part of a cord.
                 */
                if (channel == 0x09) {
                      if (iterDrums >= THRESHOLD_DRUMS)
                            activeDrums = 0;
                      iterDrums = 0;
                      cv->midiNoteReceived(pitch, activeDrums > 0, velo);
                      }
                else {
                      //qDebug("    midiNoteReceived %d active %d", pitch, active);
                      cv->midiNoteReceived(pitch, active > 0, velo);
                      ++active;
                      }
                }
          else {
                /*
                * Since a note may be assigned to a midi_remote,
                * don't decrease active below zero on noteoff.
                */
                if ((channel != 0x09) && (active > 0))
                      --active;
                if ((channel == 0x09) && (activeDrums > 0))
                      --activeDrums;
                cv->midiNoteReceived(pitch, false, velo);
                }

          if (_pianoTools && _pianoTools->isVisible()) {
                if (velo)
                      _pianoTools->pressPitch(pitch);
                else
                      _pianoTools->releasePitch(pitch);
                }
          }

    //---------------------------------------------------------
    //   midiCtrlReceived
    //---------------------------------------------------------

    void MuseScore::midiCtrlReceived(int controller, int value)
          {
          if (!midiinEnabled())
                return;
          if (_midiRecordId != -1) {
                preferences.midiRemote[_midiRecordId].type = MIDI_REMOTE_TYPE_CTRL;
                preferences.midiRemote[_midiRecordId].data = controller;
                _midiRecordId = -1;
                if (preferenceDialog)
                      preferenceDialog->updateRemote();
                return;
                }
          // when value is 0 (usually when a key is released ) nothing happens
          if (processMidiRemote(MIDI_REMOTE_TYPE_CTRL, controller, value))
                return;
          }

    //---------------------------------------------------------
    //   removeTab
    //---------------------------------------------------------

    void MuseScore::removeTab()
          {
          int n = scoreList.indexOf(cs->masterScore());
          if (n == -1) {
                qDebug("removeTab: %p not found", cs);
                return;
                }
          removeTab(n);
          }

    void MuseScore::removeTab(int i)
          {
          MasterScore* score = scoreList.value(i);

          if (score == 0)
                return;

          QString tmpName = score->tmpName();

          if (checkDirty(score))
                return;
          if (seq && seq->score() == score) {
                seq->stopWait();
                seq->setScoreView(0);
                }

          int idx1      = tab1->currentIndex();
          bool firstTab = tab1->view(idx1) == cv;

          midiPanelOnCloseFile(score->importedFilePath());
          scoreList.removeAt(i);

          tab1->blockSignals(true);
          tab1->removeTab(i);
          tab1->blockSignals(false);

          if (tab2) {
                tab2->blockSignals(true);
                tab2->removeTab(i);
                tab2->blockSignals(false);
                }

          cs = 0;
          cv = 0;
          int n = scoreList.size();
          if (n == 0)
                setCurrentScoreView(nullptr);
          else
                setCurrentScoreView((firstTab ? tab1 : tab2)->view());
          writeSessionFile(false);
          if (!tmpName.isEmpty()) {
                QFile f(tmpName);
                f.remove();
                }
          delete score;
          // Shouldn't be necessary... but fix #21841
          update();
          }

    //---------------------------------------------------------
    //   loadTranslation
    //---------------------------------------------------------

    void loadTranslation(QString filename, QString localeName)
          {
          QString userPrefix    = dataPath + "/locale/"+ filename +"_";
          QString defaultPrefix = mscoreGlobalShare + "locale/"+ filename +"_";
          QString userlp        = userPrefix + localeName;
          QString defaultlp     = defaultPrefix + localeName;
          QString lp            = defaultlp;

          QFileInfo userFi(userlp + ".qm");
          QFileInfo defaultFi(defaultlp + ".qm");

          if (!defaultFi.exists()) {     // try with a shorter locale name
                QString shortLocaleName = localeName.left(localeName.lastIndexOf("_"));
                QString shortDefaultlp = defaultPrefix + shortLocaleName;
                QFileInfo shortDefaultFi(shortDefaultlp + ".qm");
                if (shortDefaultFi.exists()) {
                      userlp    = userPrefix + shortLocaleName;
                      userFi    = QFileInfo(userlp + ".qm");
                      defaultFi = shortDefaultFi;
                      defaultlp = shortDefaultlp;
                      }
                }

          if (userFi.exists()) {
                if (userFi.lastModified() > defaultFi.lastModified())
                      lp = userlp;
    //            else
    //REVIEW                  QFile::remove(userlp + ".qm");
                }

          if (MScore::debugMode)
                qDebug("load translator <%s>", qPrintable(lp));

          QTranslator* translator = new QTranslator;
          bool success = translator->load(lp);
          if (success) {
                qApp->installTranslator(translator);
                translatorList.append(translator);
                }
          else {
                if (MScore::debugMode)
                      qDebug("load translator <%s> failed", qPrintable(lp));
                delete translator;
                }
          }

    //---------------------------------------------------------
    //   setLocale
    //---------------------------------------------------------

    void setMscoreLocale(QString localeName)
          {
          for (QTranslator* t : translatorList) {
                qApp->removeTranslator(t);
                delete t;
                }
          translatorList.clear();

          if (MScore::debugMode)
                qDebug("configured localeName <%s>", qPrintable(localeName));
          if (localeName.toLower() == "system") {
                localeName = QLocale::system().name();
                if (MScore::debugMode)
                      qDebug("real localeName <%s>", qPrintable(localeName));
                if (localeName == "en_AU") {
                      localeName = "en_GB"; // otherwise Australia would fall back to US English
                      if (MScore::debugMode)
                            qDebug("modified localeName <%s>", qPrintable(localeName));
                      }
                }

          // find the most recent translation file
          // try to replicate QTranslator.load algorithm in our particular case
          loadTranslation("mscore", localeName);
          loadTranslation("instruments", localeName);

          QString resourceDir;
    #if defined(Q_OS_MAC) || defined(Q_OS_WIN)
          resourceDir = mscoreGlobalShare + "locale/";
    #else
          resourceDir = QLibraryInfo::location(QLibraryInfo::TranslationsPath);
    #endif
          QTranslator* qtTranslator = new QTranslator;
          if (MScore::debugMode)
                qDebug("load translator <qt_%s> from <%s>",
                   qPrintable(localeName), qPrintable(resourceDir));

          if (!qtTranslator->load(QLatin1String("qt_") + localeName, resourceDir) && MScore::debugMode)
                qDebug("load translator <qt_%s> failed", qPrintable(localeName));
          else {
                qApp->installTranslator(qtTranslator);
                translatorList.append(qtTranslator);
                }
          QLocale locale(localeName);
          QLocale::setDefault(locale);
          qApp->setLayoutDirection(locale.textDirection());
          // initShortcuts();
          }

    //---------------------------------------------------------
    //   loadScores
    //    load scores for a new session
    //---------------------------------------------------------

    static void loadScores(const QStringList& argv)
          {
          int currentScoreView = 0;
          if (argv.isEmpty()) {
                if (startWithNewScore)
                      mscore->newFile();
                else {
                      switch (preferences.sessionStart) {
                            case SessionStart::LAST:
                                  {
                                  QSettings settings;
                                  int n = settings.value("scores", 0).toInt();
                                  int c = settings.value("currentScore", 0).toInt();
                                  for (int i = 0; i < n; ++i) {
                                        QString s = settings.value(QString("score-%1").arg(i),"").toString();
                                        MasterScore* score = mscore->readScore(s);
                                        if (score) {
                                              int view = mscore->appendScore(score);
                                              if (i == c)
                                                    currentScoreView = view;
                                              }
                                        }
                                  }
                                  break;
                            case SessionStart::EMPTY:
                                  break;
                            case SessionStart::NEW:
                                  mscore->newFile();
                                  break;
                            case SessionStart::SCORE:
                                  {
                                  MasterScore* score = mscore->readScore(preferences.startScore);
                                  if (preferences.startScore.startsWith(":/") && score) {
                                        score->setName(mscore->createDefaultName());
                                        // TODO score->setPageFormat(*MScore::defaultStyle().pageFormat());
                                        score->doLayout();
                                        score->setCreated(true);
                                        }
                                  if (score == 0) {
                                        score = mscore->readScore(":/data/My_First_Score.mscz");
                                        if (score) {
                                              score->setName(mscore->createDefaultName());
                                              // TODO score->setPageFormat(*MScore::defaultStyle().pageFormat());
                                              score->doLayout();
                                              score->setCreated(true);
                                              }
                                        }
                                  if (score)
                                        currentScoreView = mscore->appendScore(score);
                                  }
                                  break;
                            }
                      }
                }
          else {
                foreach(const QString& name, argv) {
                      if (name.isEmpty())
                            continue;
                      MasterScore* score = mscore->readScore(name);
                      if (score) {
                            mscore->appendScore(score);
                            scoresOnCommandline = true;
                            if(!MScore::noGui) {
                                  mscore->addRecentScore(score);
                                  mscore->writeSessionFile(false);
                                  }
                            }
                      }
                }

          if (mscore->noScore())
                currentScoreView = -1;
          mscore->setCurrentView(0, currentScoreView);
          mscore->setCurrentView(1, currentScoreView);
          }

    //---------------------------------------------------------
    //   doConvert
    //---------------------------------------------------------

    static bool doConvert(Score* cs, QString fn, QString plugin = "")
          {
          bool rv = true;
          LayoutMode layoutMode = cs->layoutMode();
          cs->setLayoutMode(LayoutMode::PAGE);
          if (cs->layoutMode() != layoutMode) {
                cs->setLayoutMode(LayoutMode::PAGE);
                cs->doLayout();
                }

          if (!styleFile.isEmpty()) {
                QFile f(styleFile);
                if (f.open(QIODevice::ReadOnly))
                      cs->style().load(&f);
                }
          if (!plugin.isEmpty()) {
                mscore->setCurrentScore(cs);
                LayoutMode layoutMode = cs->layoutMode();
                if (layoutMode != LayoutMode::PAGE) {
                      cs->setLayoutMode(LayoutMode::PAGE);
                      cs->doLayout();
                      }
                if (mscore->loadPlugin(plugin))
                      mscore->pluginTriggered(0);
                mscore->unloadPlugins();
                if (layoutMode != cs->layoutMode()) {
                      cs->setLayoutMode(layoutMode);
                      cs->doLayout();
                      }
                }
          if (fn.endsWith(".mscx")) {
                QFileInfo fi(fn);
                if (!cs->saveFile(fi))
                      return false;
                return true;
                }
          else if (fn.endsWith(".mscz")) {
                QFileInfo fi(fn);
                if (!cs->saveCompressedFile(fi, false))
                      return false;
                return true;
                }
          else if (fn.endsWith(".xml")) {
                rv = saveXml(cs, fn);
                }
          else if (fn.endsWith(".mxl")) {
                rv = saveMxl(cs, fn);
                }
          else if (fn.endsWith(".mid"))
                return mscore->saveMidi(cs, fn);
          else if (fn.endsWith(".pdf")) {
                if (!exportScoreParts) {
                      rv = mscore->savePdf(cs, fn);
                      }
                else {
                      if (cs->excerpts().size() == 0) {
                            auto excerpts = Excerpt::createAllExcerpt(cs->masterScore());

                            for (Excerpt* e : excerpts) {
                                  Score* nscore = new Score(e->oscore());
                                  e->setPartScore(nscore);
                                  nscore->style().set(StyleIdx::createMultiMeasureRests, true);
                                  Excerpt::createExcerpt(e);
                                  cs->startCmd();
                                  cs->undo(new AddExcerpt(e));
                                  cs->endCmd();
                                  }
                            }
                      QList<Score*> scores;
                      scores.append(cs);
                      for (Excerpt* e : cs->excerpts())
                            scores.append(e->partScore());
                      return mscore->savePdf(scores, fn);
                      }
                }
          else if (fn.endsWith(".png")) {
                if (!exportScoreParts)
                      return mscore->savePng(cs, fn);
                else {
                      if (cs->excerpts().size() == 0) {
                            auto excerpts = Excerpt::createAllExcerpt(cs->masterScore());

                            for (Excerpt* e: excerpts) {
                                  Score* nscore = new Score(e->oscore());
                                  e->setPartScore(nscore);
                                  nscore->setExcerpt(e);
                                  // nscore->setName(e->title()); // needed before AddExcerpt
                                  nscore->style().set(StyleIdx::createMultiMeasureRests, true);
                                  Excerpt::createExcerpt(e);
                                  cs->startCmd();
                                  cs->undo(new AddExcerpt(e));
                                  cs->endCmd();
                                  }
                            }
                      if (!mscore->savePng(cs, fn))
                            return false;
                      int idx = 0;
                      int padding = QString("%1").arg(cs->excerpts().size()).size();
                      for (Excerpt* e: cs->excerpts()) {
                            QString suffix = QString("__excerpt__%1.png").arg(idx, padding, 10, QLatin1Char('0'));
                            QString excerptFn = fn.left(fn.size() - 4) + suffix;
                            if (!mscore->savePng(e->partScore(), excerptFn))
                                  return false;
                            idx++;
                            }
                      return true;
                      }
                }
          else if (fn.endsWith(".svg")) {
                rv = mscore->saveSvg(cs, fn);
                }
    #ifdef HAS_AUDIOFILE
                else if (fn.endsWith(".wav") || fn.endsWith(".ogg") || fn.endsWith(".flac"))
                      return mscore->saveAudio(cs, fn);
    #endif
    #ifdef USE_LAME
                else if (fn.endsWith(".mp3"))
                      return mscore->saveMp3(cs, fn);
    #endif
          else if (fn.endsWith(".spos")) {
                rv = savePositions(cs, fn, true);
                }
          else if (fn.endsWith(".mpos")) {
                rv = savePositions(cs, fn, false);
                }
          else if (fn.endsWith(".mlog"))
                return cs->sanityCheck(fn);
          else if (plugin.isEmpty()) {
                qDebug("don't know how to convert to %s", qPrintable(outFileName));
                return false;
                }
          if (layoutMode != cs->layoutMode()) {
                cs->setLayoutMode(layoutMode);
                cs->doLayout();
                }
          return rv;
          }

    //---------------------------------------------------------
    //   convert
    //---------------------------------------------------------

    static bool convert(const QString& inFile, const QString& outFile, const QString& plugin = "")
          {
          if (inFile.isEmpty() || (outFile.isEmpty() && plugin.isEmpty())) {
                fprintf(stderr, "cannot convert <%s> to <%s>\n", qPrintable(inFile), qPrintable(outFile));
                return false;
                }
          fprintf(stderr, "convert <%s> to <%s>\n", qPrintable(inFile), qPrintable(outFile));
          MasterScore* score = mscore->readScore(inFile);
          if (!score)
                return false;
          if (!doConvert(score, outFile, plugin)) {
                delete score;
                return false;
                }
          delete score;
          return true;
          }

    //---------------------------------------------------------
    //   doProcessJob
    //---------------------------------------------------------

    static bool doProcessJob(QString jsonFile)
          {
          QFile f(jsonFile);
          if (!f.open(QIODevice::ReadOnly)) {
                fprintf(stderr, "cannon open json file <%s>\n", qPrintable(jsonFile));
                return false;
                }
          QJsonParseError pe;
          QJsonDocument doc = QJsonDocument::fromJson(f.readAll(), &pe);
          if (pe.error != QJsonParseError::NoError) {
                fprintf(stderr, "error reading json file <%s> at %d: %s\n",
                   qPrintable(jsonFile), pe.offset, qPrintable(pe.errorString()));
                return false;
                }
          if (!doc.isArray()) {
                fprintf(stderr, "json file <%s> is not an array\n", qPrintable(jsonFile));
                return false;
                }
          QJsonArray a = doc.array();
          for (const auto i : a) {
                QString inFile;
                QString outFile;
                QString plugin;
                if (!i.isObject()) {
                      fprintf(stderr, "array value is not an object\n");
                      return false;
                      }
                QJsonObject obj = i.toObject();
                for (const auto& key : obj.keys()) {
                      QString val = obj.value(key).toString();
                      if (key == "in")
                            inFile = val;
                      else if (key == "out")
                            outFile = val;
                      else if (key == "plugin")
                            plugin = val;
                      else {
                            fprintf(stderr, "unknown key <%s>\n", qPrintable(key));
                            return false;
                            }
                      }
                if (!convert(inFile, outFile, plugin))
                      return false;
                }
          return true;
          }

    //---------------------------------------------------------
    //   processNonGui
    //---------------------------------------------------------

    static bool processNonGui(const QStringList& argv)
          {
          if (pluginMode) {
                loadScores(argv);
                QString pn(pluginName);
                bool res = false;
                if (mscore->loadPlugin(pn)){
                      Score* cs = mscore->currentScore();
                      if (!styleFile.isEmpty()) {
                            QFile f(styleFile);
                            if (f.open(QIODevice::ReadOnly))
                                  cs->style().load(&f);
                            }
                      LayoutMode layoutMode = cs->layoutMode();
                      if (layoutMode != LayoutMode::PAGE) {
                            cs->setLayoutMode(LayoutMode::PAGE);
                            cs->doLayout();
                            }
                      mscore->pluginTriggered(0);
                      if (layoutMode != cs->layoutMode()) {
                            cs->setLayoutMode(layoutMode);
                            cs->doLayout();
                            }
                      res = true;
                      }
                if (!converterMode)
                      return res;
                }
          bool rv = true;
          if (converterMode) {
                if (processJob)
                      return doProcessJob(jsonFileName);
                else
                      return convert(argv[0], outFileName);
                }
          return rv;
          }

    //---------------------------------------------------------
    //   Message handler
    //---------------------------------------------------------

    #if defined(QT_DEBUG) && defined(Q_OS_WIN)
    static void mscoreMessageHandler(QtMsgType type, const QMessageLogContext &context,const QString &msg)
         {
         QTextStream cerr(stderr);
         QByteArray localMsg = msg.toLocal8Bit();

         switch (type) {
         case QtInfoMsg:
             cerr << "Info: "     << localMsg.constData() << " ("  << context.file << ":" << context.line << ", " << context.function << ")" << endl;
             break;
         case QtDebugMsg:
             cerr << "Debug: "    << localMsg.constData() << " ("  << context.file << ":" << context.line << ", " << context.function << ")" << endl;
             break;
         case QtWarningMsg:
             cerr << "Warning: "  << localMsg.constData() << " ("  << context.file << ":" << context.line << ", " << context.function << ")" << endl;
             break;
         case QtCriticalMsg: // same as QtSystemMsg
             cerr << "Critical: " << localMsg.constData() << " ("  << context.file << ":" << context.line << ", " << context.function << ")" << endl;
             break;
         case QtFatalMsg: // set your breakpoint here, if you want to catch the abort
             cerr << "Fatal: "    << localMsg.constData() << " ("  << context.file << ":" << context.line << ", " << context.function << ")" << endl;
             abort();
             }
         }
    #endif

    //---------------------------------------------------------
    //   synthesizerFactory
    //    create and initialize the master synthesizer
    //---------------------------------------------------------

    MasterSynthesizer* synthesizerFactory()
          {
          MasterSynthesizer* ms = new MasterSynthesizer();

          FluidS::Fluid* fluid = new FluidS::Fluid();
          ms->registerSynthesizer(fluid);

    #ifdef AEOLUS
          ms->registerSynthesizer(::createAeolus());
    #endif
    #ifdef ZERBERUS
          ms->registerSynthesizer(createZerberus());
    #endif
          ms->registerEffect(0, new NoEffect);
          ms->registerEffect(0, new ZitaReverb);
          ms->registerEffect(0, new Compressor);
          // ms->registerEffect(0, new Freeverb);
          ms->registerEffect(1, new NoEffect);
          ms->registerEffect(1, new ZitaReverb);
          ms->registerEffect(1, new Compressor);
          // ms->registerEffect(1, new Freeverb);
          ms->setEffect(0, 1);
          ms->setEffect(1, 0);
          return ms;
          }

    //---------------------------------------------------------
    //   unstable
    //---------------------------------------------------------

    bool MuseScore::unstable()
          {
    #ifdef MSCORE_UNSTABLE
          return true;
    #else
          return false;
    #endif
          }

    //---------------------------------------------------------
    //   MuseScoreApplication::event (mac only)
    //---------------------------------------------------------

    bool MuseScoreApplication::event(QEvent* event)
          {
          switch(event->type()) {
                case QEvent::FileOpen:
                      // store names of files requested to be loaded by OS X to be handled later
                      // this event is generated when a file is dragged onto the MuseScore icon
                      // in the dock and MuseScore is not running yet
                      paths.append(static_cast<QFileOpenEvent *>(event)->file());
                      return true;
                default:
                      return QtSingleApplication::event(event);
                }
          }

    //---------------------------------------------------------
    //   eventFilter
    //---------------------------------------------------------

    bool MuseScore::eventFilter(QObject *obj, QEvent *event)
          {
          switch(event->type()) {
    #ifdef Q_OS_MAC
                case QEvent::FileOpen:
                      // open files requested to be loaded by OS X
                      // this event is generated when a file is dragged onto the MuseScore icon
                      // in the dock when MuseScore is already running
                      scoresOnCommandline = true;
                      handleMessage(static_cast<QFileOpenEvent *>(event)->file());
                      return true;
    #endif
                case QEvent::MouseMove: {
                      QMouseEvent* me = static_cast<QMouseEvent*>(event);
                      globalX = me->globalX();
                      globalY = me->globalY();
                      return QMainWindow::eventFilter(obj, event);
                      }
                case QEvent::StatusTip:
                      return true; // prevent updates to the status bar
                case QEvent::KeyPress:
                      {
                      QKeyEvent* e = static_cast<QKeyEvent*>(event);
                      if(obj->isWidgetType() && e->key() == Qt::Key_Escape && e->modifiers() == Qt::NoModifier) {
                            // Close the search dialog when Escape is pressed:
                            if(_searchDialog != 0)
                                  endSearch();
                            if (isActiveWindow()) {
                                  obj->event(e);
                                  if(currentScoreView())
                                        currentScoreView()->setFocus();
                                  else
                                        mscore->setFocus();
                                  return true;
                                  }

                            QWidget* w = static_cast<QWidget*>(obj);
                            if(getPaletteBox()->isAncestorOf(w) ||
                               inspector()->isAncestorOf(w) ||
                               (selectionWindow && selectionWindow->isAncestorOf(w))) {
                                  activateWindow();
                                  if(currentScoreView())
                                        currentScoreView()->setFocus();
                                  else
                                        mscore->setFocus();
                                  return true;
                                  }
                            }
                      break;
                      }
                default:
                      return QMainWindow::eventFilter(obj, event);
                }
          return QMainWindow::eventFilter(obj, event);
          }

    //---------------------------------------------------------
    //   hasToCheckForUpdate
    //---------------------------------------------------------

    bool MuseScore::hasToCheckForUpdate()
          {
          if (ucheck)
                return ucheck->hasToCheck();
          else
              return false;
          }

    //---------------------------------------------------------
    //   checkForUpdate
    //---------------------------------------------------------

    void MuseScore::checkForUpdate()
          {
          if (ucheck)
                ucheck->check(version(), sender() != 0);
          }

    //---------------------------------------------------------
    //   readLanguages
    //---------------------------------------------------------

    bool MuseScore::readLanguages(const QString& path)
          {
          //: The default language of the operating system. NOT a music system.
          _languages.append(LanguageItem("system", tr("System")));
          QFile qf(path);
          if (qf.exists()){
              QDomDocument doc;
              int line, column;
              QString err;
              if (!doc.setContent(&qf, false, &err, &line, &column)) {
                    QString error;
                    error.sprintf(qPrintable(tr("Error reading language file %s at line %d column %d: %s\n")),
                       qPrintable(qf.fileName()), line, column, qPrintable(err));
                    QMessageBox::warning(0,
                       QWidget::tr("Load Languages Failed:"),
                       error,
                       QString::null, QWidget::tr("Quit"), QString::null, 0, 1);
                    return false;
                    }

              for (QDomElement e = doc.documentElement(); !e.isNull(); e = e.nextSiblingElement()) {
                    if(e.tagName() == "languages") {
                          for (e = e.firstChildElement(); !e.isNull(); e = e.nextSiblingElement()) {
                            if (e.tagName() == "language") {
                                  QString code = e.attribute(QString("code"));
                                  QString name = e.attribute(QString("name"));
                                  QString handbook = e.attribute(QString("handbook"));
                                  _languages.append(LanguageItem(code, name, handbook));
                                  }
                              }
                          }
                    }
                return true;
                }
          return false;
          }

    //---------------------------------------------------------
    //   clipboardChanged
    //---------------------------------------------------------

    void MuseScore::clipboardChanged()
          {
    #if 0
          const QMimeData* ms = QApplication::clipboard()->mimeData();
          QStringList formats = ms->formats();

          bool flag = ms->hasFormat(mimeSymbolFormat)
                ||    ms->hasFormat(mimeStaffListFormat)
                ||    ms->hasFormat(mimeSymbolListFormat)
                ||    ms->hasText();
          // TODO: depends on selection state
    #endif

          bool flag = true;
          getAction("paste")->setEnabled(flag);
          getAction("swap")->setEnabled(flag);
          }

    //---------------------------------------------------------
    //   inputMethodLocaleChanged
    //---------------------------------------------------------

    void MuseScore::inputMethodLocaleChanged()
          {
          qDebug("Input method QLocale::Script enum now #%d.", QGuiApplication::inputMethod()->locale().script());
          }

    //---------------------------------------------------------
    //   showModeText
    //---------------------------------------------------------

    void MuseScore::showModeText(const QString& s)
          {
          _modeText->setText(s);
          _modeText->show();
          }

    //---------------------------------------------------------
    //   changeState
    //---------------------------------------------------------

    void MuseScore::changeState(ScoreState val)
          {
    // printf("MuseScore::changeState: %s\n", stateName(val));
          if (MScore::debugMode)
                qDebug("MuseScore::changeState: %s", stateName(val));

    //      if (_sstate == val)
    //            return;

          // disallow change to edit modes if currently in play mode
          if (_sstate == STATE_PLAY && (val == STATE_EDIT || val & STATE_ALLTEXTUAL_EDIT || val & STATE_NOTE_ENTRY))
                return;

          static const char* stdNames[] = {
                "note-longa", "note-breve", "pad-note-1", "pad-note-2", "pad-note-4",
          "pad-note-8", "pad-note-16", "pad-note-32", "pad-note-64", "pad-note-128", "pad-rest", "rest"};
          static const char* tabNames[] = {
                "note-longa-TAB", "note-breve-TAB", "pad-note-1-TAB", "pad-note-2-TAB", "pad-note-4-TAB",
          "pad-note-8-TAB", "pad-note-16-TAB", "pad-note-32-TAB", "pad-note-64-TAB", "pad-note-128-TAB", "pad-rest-TAB", "rest-TAB"};
          bool intoTAB = (_sstate != STATE_NOTE_ENTRY_STAFF_TAB) && (val == STATE_NOTE_ENTRY_STAFF_TAB);
          bool fromTAB = (_sstate == STATE_NOTE_ENTRY_STAFF_TAB) && (val != STATE_NOTE_ENTRY_STAFF_TAB);
          // if activating TAB note entry, swap "pad-note-...-TAB" shorctuts into "pad-note-..." actions
          if (intoTAB) {
                for (unsigned i = 0; i < sizeof(stdNames)/sizeof(char*); ++i) {
                      QAction* act = getAction(stdNames[i]);
                      const Shortcut* srt = Shortcut::getShortcut(tabNames[i]);
                      act->setShortcuts(srt->keys());
                      }
                }
          // if de-ativating TAB note entry, restore shortcuts for "pad-note-..." actions
          else if (fromTAB) {
                for (unsigned i = 0; i < sizeof(stdNames)/sizeof(char*); ++i) {
                      QAction* act = getAction(stdNames[i]);
                      const Shortcut* srt = Shortcut::getShortcut(stdNames[i]);
                      act->setShortcuts(srt->keys());
                      }
                }

          bool enable = (val != STATE_DISABLED) && (val != STATE_LOCK);

          foreach (const Shortcut* s, Shortcut::shortcuts()) {
                QAction* a = s->action();
                if (!a)
                      continue;
                if (enable && (s->key() == "undo"))
                      a->setEnabled((s->state() & val) && (cs ? cs->undoStack()->canUndo() : false));
                else if (enable && (s->key() == "redo"))
                      a->setEnabled((s->state() & val) && (cs ? cs->undoStack()->canRedo() : false));
                else if (enable && (s->key() == "cut"))
                      a->setEnabled(cs && cs->selection().state() != SelState::NONE);
                else if (enable && (s->key() == "copy"))
                      a->setEnabled(cs && (cs->selection().state() != SelState::NONE || val == STATE_FOTO));
                else if (enable && (s->key() == "select-similar-range"))
                      a->setEnabled(cs && cs->selection().state() == SelState::RANGE);
                else if (enable && (s->key() == "synth-control")) {
                      Driver* driver = seq ? seq->driver() : 0;
                      // a->setEnabled(driver && driver->getSynth());
                      if (MScore::debugMode)
                            qDebug("disable synth control");
                      a->setEnabled(driver);
                      }
                else if (s->key() == "pad-dot" || s->key() == "pad-dot-dot" || s->key() == "delete")
                      a->setEnabled(!(val & (STATE_ALLTEXTUAL_EDIT | STATE_EDIT)));
                else {
                      a->setEnabled(s->state() & val);
                      }
                }

          if (getAction("file-part-export")->isEnabled())
                getAction("file-part-export")->setEnabled(cs && cs->masterScore()->excerpts().size() > 0);
          if (getAction("join-measures")->isEnabled())
                getAction("join-measures")->setEnabled(cs && cs->masterScore()->excerpts().size() == 0);
          if (getAction("split-measure")->isEnabled())
                getAction("split-measure")->setEnabled(cs && cs->masterScore()->excerpts().size() == 0);

          //getAction("split-measure")->setEnabled(cs->masterScore()->excerpts().size() == 0);

          // disabling top level menu entries does not
          // work for MAC

          QList<QObject*> ol = menuBar()->children();
          foreach(QObject* o, ol) {
                QMenu* menu = qobject_cast<QMenu*>(o);
                if (!menu)
                      continue;
                QString s(menu->objectName());
                if (s == "File" || s == "Help" || s == "Edit" || s == "Plugins" || s == "View")
                      continue;
                menu->setEnabled(enable);
                }

          menuWorkspaces->setEnabled(enable);

          transportTools->setEnabled(enable && !noSeq && seq && seq->isRunning());
          cpitchTools->setEnabled(enable);
          mag->setEnabled(enable);
          entryTools->setEnabled(enable);

          if (_sstate == STATE_FOTO)
                updateInspector();
          if (_sstate == STATE_NOTE_ENTRY_STAFF_DRUM)
                showDrumTools(0, 0);

          switch (val) {
                case STATE_DISABLED:
                      showModeText(tr("No score"));
                      if (debugger)
                            debugger->hide();
                      showPianoKeyboard(false);
                      break;
                case STATE_NORMAL:
                      _modeText->hide();
                      break;
                case STATE_NOTE_ENTRY:
                      if (cv && !cv->noteEntryMode())
                            cv->cmd("note-input");
                      // fall through
                case STATE_NOTE_ENTRY_STAFF_PITCHED:
                      if (getAction("note-input-repitch")->isChecked()) {
                            showModeText(tr("Repitch input mode"));
                            cs->setNoteEntryMethod(NoteEntryMethod::REPITCH);
                            val = STATE_NOTE_ENTRY_METHOD_REPITCH;
                            }
                      else if (getAction("note-input-rhythm")->isChecked()) {
                            showModeText(tr("Rhythm input mode"));
                            cs->setNoteEntryMethod(NoteEntryMethod::RHYTHM);
                            val = STATE_NOTE_ENTRY_METHOD_RHYTHM;
                            }
                      else if (getAction("note-input-realtime-auto")->isChecked()) {
                            showModeText(tr("Realtime (automatic) note input mode"));
                            cs->setNoteEntryMethod(NoteEntryMethod::REALTIME_AUTO);
                            val = STATE_NOTE_ENTRY_METHOD_REALTIME_AUTO;
                            }
                      else if (getAction("note-input-realtime-manual")->isChecked()) {
                            showModeText(tr("Realtime (manual) note input mode"));
                            cs->setNoteEntryMethod(NoteEntryMethod::REALTIME_MANUAL);
                            val = STATE_NOTE_ENTRY_METHOD_REALTIME_MANUAL;
                            }
                      else {
                            showModeText(tr("Steptime note input mode"));
                            cs->setNoteEntryMethod(NoteEntryMethod::STEPTIME);
                            val = STATE_NOTE_ENTRY_METHOD_STEPTIME;
                            }
                      break;
                case STATE_NOTE_ENTRY_STAFF_DRUM:
                      {
                      showModeText(tr("Drum input mode"));
                      InputState& is = cs->inputState();
                      showDrumTools(is.drumset(), cs->staff(is.track() / VOICES));
                      if (_drumTools)
                            is.setDrumNote(_drumTools->selectedDrumNote());
                      }
                      break;
                case STATE_NOTE_ENTRY_STAFF_TAB:
                      showModeText(tr("TAB input mode"));
                      break;
                case STATE_EDIT:
                      showModeText(tr("Edit mode"));
                      break;
                case STATE_TEXT_EDIT:
                      showModeText(tr("Text edit mode"));
                      break;
                case STATE_LYRICS_EDIT:
                      showModeText(tr("Lyrics edit mode"));
                      break;
                case STATE_HARMONY_FIGBASS_EDIT:
                      showModeText(tr("Chord symbol/figured bass edit mode"));
                      break;
                case STATE_PLAY:
                      showModeText(tr("Play"));
                      break;
                case STATE_FOTO:
                      showModeText(tr("Image capture mode"));
                      updateInspector();
                      break;
                case STATE_LOCK:
                      showModeText(tr("Score locked"));
                      break;
                default:
                      qFatal("MuseScore::changeState: illegal state %d", val);
                      break;
                }
          if (paletteBox)
                paletteBox->setDisabled(val == STATE_PLAY || val == STATE_DISABLED);
          if (selectionWindow)
                selectionWindow->setDisabled(val == STATE_PLAY || val == STATE_DISABLED);
          QAction* a = getAction("note-input");
          bool noteEntry = val & STATE_NOTE_ENTRY;
          a->setChecked(noteEntry);
          _sstate = val;

          Element* e = cv && (_sstate & STATE_ALLTEXTUAL_EDIT || _sstate == STATE_EDIT) ? cv->getEditElement() : 0;
          if (!e) {
                textTools()->hide();
                if (textTools()->kbAction()->isChecked())
                      textTools()->kbAction()->setChecked(false);
                }
          else {
                if (e->isText()) {
                      textTools()->updateTools(cv->getEditData());
                      if (!(e->isFiguredBass() || e->isHarmony())) {  // do not show text tools for f.b.
                            if (timelineScrollArea() && timelineScrollArea()->isVisible()) {
                                  if (dockWidgetArea(timelineScrollArea()) != dockWidgetArea(textTools()) || timelineScrollArea()->isFloating()) {
                                        QSizePolicy policy(QSizePolicy::Maximum, QSizePolicy::Maximum);
                                        textTools()->widget()->setSizePolicy(policy);
                                        }
                                  else {
                                        QSizePolicy policy(QSizePolicy::Expanding, QSizePolicy::Expanding);
                                        textTools()->widget()->setSizePolicy(policy);
                                        }
                                  }
                            else {
                                  QSizePolicy policy(QSizePolicy::Maximum, QSizePolicy::Maximum);
                                  textTools()->widget()->setSizePolicy(policy);
                                  }
                            if (timelineScrollArea())
                                  splitDockWidget(textTools(), timelineScrollArea(), Qt::Vertical);
                            textTools()->show();
                            }
                      }
                if (_inspector)
                      _inspector->update(e->score());
                }
          }

    //---------------------------------------------------------
    //   saveDialogState
    //---------------------------------------------------------

    void MuseScore::saveDialogState(const char* name, QFileDialog* d)
          {
          if (d) {
                settings.beginGroup(name);
                settings.setValue("geometry", d->saveGeometry());
                settings.setValue("state", d->saveState());
                settings.endGroup();
                }
          }

    //---------------------------------------------------------
    //   restoreDialogState
    //---------------------------------------------------------

    void MuseScore::restoreDialogState(const char* name, QFileDialog* d)
          {
          settings.beginGroup(name);
          d->restoreGeometry(settings.value("geometry").toByteArray());
          d->restoreState(settings.value("state").toByteArray());
          settings.endGroup();
          }

    //---------------------------------------------------------
    //   writeSettings
    //---------------------------------------------------------

    void MuseScore::writeSettings()
          {
          // save score list
          for (int i = 0; i < RECENT_LIST_SIZE; ++i)
                settings.setValue(QString("recent-%1").arg(i), _recentScores.value(i));

          settings.setValue("scores", scoreList.size());
          if (cs) {
                int curScore = scoreList.indexOf(cs->masterScore());
                if (curScore == -1)  // cs removed if new created and not modified
                      curScore = 0;
                settings.setValue("currentScore", curScore);

                for (int idx = 0; idx < scoreList.size(); ++idx)
                      settings.setValue(QString("score-%1").arg(idx), scoreList[idx]->masterScore()->fileInfo()->absoluteFilePath());
                }

          settings.setValue("lastSaveCopyDirectory", lastSaveCopyDirectory);
          settings.setValue("lastSaveCopyFormat", lastSaveCopyFormat);
          settings.setValue("lastSaveDirectory", lastSaveDirectory);

          MuseScore::saveGeometry(this);

          settings.beginGroup("MainWindow");
          settings.setValue("showPanel", paletteBox && paletteBox->isVisible());
          settings.setValue("showInspector", _inspector && _inspector->isVisible());
          settings.setValue("showPianoKeyboard", _pianoTools && _pianoTools->isVisible());
          settings.setValue("showSelectionWindow", selectionWindow && selectionWindow->isVisible());
          settings.setValue("state", saveState());
          settings.setValue("splitScreen", _splitScreen);
          settings.setValue("debuggerSplitter", mainWindow->saveState());
          settings.setValue("split", _horizontalSplit);
          settings.setValue("splitter", splitter->saveState());
          settings.endGroup();

          Workspace::currentWorkspace->save();
          if (keyEditor && keyEditor->dirty())
                keyEditor->save();
          if (chordStyleEditor)
                chordStyleEditor->save();

          saveDialogState("loadScoreDialog",      loadScoreDialog);
          saveDialogState("saveScoreDialog",      saveScoreDialog);
          saveDialogState("loadStyleDialog",      loadStyleDialog);
          saveDialogState("saveStyleDialog",      saveStyleDialog);
          saveDialogState("saveImageDialog",      saveImageDialog);
          saveDialogState("loadChordStyleDialog", loadChordStyleDialog);
          saveDialogState("saveChordStyleDialog", saveChordStyleDialog);
          saveDialogState("loadScanDialog",       loadScanDialog);
          saveDialogState("loadAudioDialog",      loadAudioDialog);
          saveDialogState("loadDrumsetDialog",    loadDrumsetDialog);
          saveDialogState("saveDrumsetDialog",    saveDrumsetDialog);
          saveDialogState("loadPaletteDialog",    loadPaletteDialog);
          saveDialogState("savePaletteDialog",    savePaletteDialog);

          if (debugger)
                debugger->writeSettings();

    #ifdef SCRIPT_INTERFACE
          if (_pluginCreator)
                _pluginCreator->writeSettings();
    #endif
          if (synthControl)
                synthControl->writeSettings();
          settings.setValue("synthControlVisible", synthControl && synthControl->isVisible());
          if (mixer)
                mixer->writeSettings();
          settings.setValue("mixerVisible", mixer && mixer->isVisible());
          if (seq) {
                seq->stopWait();
                seq->exit();
                }
          if (instrList)
                instrList->writeSettings();
          if (pianorollEditor)
                pianorollEditor->writeSettings();
          if (drumrollEditor)
                drumrollEditor->writeSettings();
          if (startcenter)
                startcenter->writeSettings();
          }

    //---------------------------------------------------------
    //   readSettings
    //---------------------------------------------------------

    void MuseScore::readSettings()
          {
          int margin = 100;
          int offset = margin / 2;
          int w = 1024;
          int h = 768;
          QScreen* screen      = QGuiApplication::primaryScreen();
          const QSize screenSize = screen->availableVirtualSize();
          if (screenSize.width() - margin > w)
                w = screenSize.width() - margin;
          else
                offset = 0;
          if (screenSize.height() - margin > h)
                h = screenSize.height() - margin;

          resize(QSize(w, h)); //ensure default size if no geometry in settings
          move(offset, 0);
          if (useFactorySettings) {
                QList<int> sizes;
                sizes << 500 << 100;
                mainWindow->setSizes(sizes);
                mscore->showPalette(true);
                mscore->showInspector(true);
                return;
                }

          MuseScore::restoreGeometry(this);

          settings.beginGroup("MainWindow");
          mainWindow->restoreState(settings.value("debuggerSplitter").toByteArray());
          mainWindow->setOpaqueResize(false);
          scorePageLayoutChanged();

          //for some reason when MuseScore starts maximized the screen-reader
          //doesn't respond to QAccessibleEvents --> so force normal mode
          if (isMaximized() && QAccessible::isActive()) {
                showNormal();
                }
          mscore->showPalette(settings.value("showPanel", "1").toBool());
          mscore->showInspector(settings.value("showInspector", "1").toBool());
          mscore->showPianoKeyboard(settings.value("showPianoKeyboard", "0").toBool());
          mscore->showSelectionWindow(settings.value("showSelectionWindow", "0").toBool());

          restoreState(settings.value("state").toByteArray());
          //if we were in full screen mode, go to maximized mode
          if (isFullScreen()) {
                showMaximized();
                }

          _horizontalSplit = settings.value("split", true).toBool();
          bool splitScreen = settings.value("splitScreen", false).toBool();
          if (splitScreen) {
                splitWindow(_horizontalSplit);
                QAction* a = getAction(_horizontalSplit ? "split-h" : "split-v");
                a->setChecked(true);
                }
          splitter->restoreState(settings.value("splitter").toByteArray());
          settings.endGroup();

          QAction* a = getAction("toggle-fileoperations");
          a->setChecked(!fileTools->isHidden());

          a = getAction("toggle-transport");
          a->setChecked(!transportTools->isHidden());

          a = getAction("toggle-concertpitch");
          a->setChecked(!cpitchTools->isHidden());

          a = getAction("toggle-imagecapture");
          a->setChecked(!fotoTools->isHidden());

          a = getAction("toggle-noteinput");
          a->setChecked(!entryTools->isHidden());
          }

    //---------------------------------------------------------
    //   play
    //    play note for preferences.defaultPlayDuration
    //---------------------------------------------------------

    void MuseScore::play(Element* e) const
          {
          if (noSeq || !(seq && seq->isRunning()) || !preferences.playNotes)
                return;

          if (e->isNote()) {
                Note* note = toNote(e);
                play(e, note->ppitch());
                }
          else if (e->isChord()) {
                seq->stopNotes();
                Chord* c   = toChord(e);
                Part* part = c->staff()->part();
                int tick   = c->segment() ? c->segment()->tick() : 0;
                seq->seek(tick);
                Instrument* instr = part->instrument(tick);
                for (Note* n : c->notes()) {
                      const Channel* channel = instr->channel(n->subchannel());
                      seq->startNote(channel->channel, n->ppitch(), 80, n->tuning());
                      }
                seq->startNoteTimer(MScore::defaultPlayDuration);
                }
          }

    void MuseScore::play(Element* e, int pitch) const
          {
          if (noSeq || !(seq && seq->isRunning()))
                return;
          if (preferences.playNotes && e->isNote()) {
                Note* note = static_cast<Note*>(e);
                int tick = note->chord()->tick();
                if (tick < 0)
                      tick = 0;
                Instrument* instr = note->part()->instrument(tick);
                const Channel* channel = instr->channel(note->subchannel());
                seq->startNote(channel->channel, pitch, 80, MScore::defaultPlayDuration, note->tuning());
                }
          }

    //---------------------------------------------------------
    //   reportBug
    //---------------------------------------------------------

    void MuseScore::reportBug()
          {
          QString url = QString("https://musescore.org/redirect/post/bug-report?sha=%1&locale=%2").arg(revision()).arg(getLocaleISOCode());
          QDesktopServices::openUrl(QUrl(url.trimmed()));
          }

    //---------------------------------------------------------
    //   askForHelp
    //---------------------------------------------------------

    void MuseScore::askForHelp()
          {
          QString url = QString("https://musescore.org/redirect/post/question?locale=%1").arg(getLocaleISOCode());
          QDesktopServices::openUrl(QUrl(url.trimmed()));
          }

    //---------------------------------------------------------
    //   about
    //---------------------------------------------------------

    void MuseScore::about()
          {
          AboutBoxDialog ab;
          ab.show();
          ab.exec();
          }

    //---------------------------------------------------------
    //   AboutBoxDialog
    //---------------------------------------------------------

    AboutBoxDialog::AboutBoxDialog()
          {
          setupUi(this);
          museLogo->setPixmap(QPixmap(preferences.isThemeDark() ?
                ":/data/musescore-logo-transbg-m.png" : ":/data/musescore_logo_full.png"));

          if (MuseScore::unstable())
                versionLabel->setText(tr("Unstable Prerelease for Version: %1").arg(VERSION));
          else
                versionLabel->setText(tr("Version: %1").arg(VERSION));
          revisionLabel->setText(tr("Revision: %1").arg(revision));
          setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);

          copyrightLabel->setText(QString("<span style=\"font-size:10pt;\">%1</span>")
                                  .arg(tr(   "Visit %1www.musescore.org%2 for new versions and more information.\n"
                                             "Support MuseScore with your %3donation%4.\n\n"
                                             "Copyright &copy; 1999-2017 Werner Schweer and Others.\n"
                                             "Published under the GNU General Public License.")
                                       .arg("<a href=\"http://www.musescore.org/\">")
                                       .arg("</a>")
                                       .arg("<a href=\"http://www.musescore.org/donate\">")
                                       .arg("</a>")
                                       .replace("\n","<br/>")));
          connect(copyRevisionButton, SIGNAL(clicked()), this, SLOT(copyRevisionToClipboard()));
          }

    //---------------------------------------------------------
    //   copyRevisionToClipboard
    //---------------------------------------------------------

    void AboutBoxDialog::copyRevisionToClipboard()
          {
          QClipboard* cb = QApplication::clipboard();
          cb->setText(QString("github-musescore-musescore-") + revision);
          }

    //---------------------------------------------------------
    //   AboutBoxDialog
    //---------------------------------------------------------

    AboutMusicXMLBoxDialog::AboutMusicXMLBoxDialog()
          {
          setupUi(this);
          setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
          label->setText(QString("<span style=\"font-size:10pt;\">%1<br/></span>")
                         .arg(tr(   "MusicXML is an open file format for exchanging digital sheet music,\n"
                                    "supported by many applications. MusicXML is copyright &copy; MakeMusic, Inc.\n"
                                    "All rights reserved. For more information, see: %1MusicXML.com%2.")
                              .arg("<a href=\"http://www.musicxml.com\">")
                              .arg("</a>")
                              .replace("\n","<br/>")));
          }

    //---------------------------------------------------------
    //   dirtyChanged
    //---------------------------------------------------------

    void MuseScore::dirtyChanged(Score* s)
          {
          MasterScore* score = s->masterScore();

          int idx = scoreList.indexOf(score);
          if (idx == -1) {
                qDebug("score not in list");
                return;
                }
          QString label(score->fileInfo()->completeBaseName());
          if (score->dirty())
                label += "*";
          tab1->setTabText(idx, label);
          if (tab2)
                tab2->setTabText(idx, label);
          }

    //---------------------------------------------------------
    //   magChanged
    //---------------------------------------------------------

    void MuseScore::magChanged(MagIdx idx)
          {
          if (cv)
                cv->setMag(idx, mag->getLMag(cv));
          }

    //---------------------------------------------------------
    //   incMag
    //---------------------------------------------------------

    void MuseScore::incMag()
          {
          if (cv) {
                qreal _mag = cv->lmag() * SCALE_STEP;
                if (_mag > SCALE_MAX)
                      _mag = SCALE_MAX;
                cv->setMag(MagIdx::MAG_FREE, _mag);
                setMag(_mag);
                }
          }

    //---------------------------------------------------------
    //   decMag
    //---------------------------------------------------------

    void MuseScore::decMag()
          {
          if (cv) {
                qreal _mag = cv->lmag() / SCALE_STEP;
                if (_mag < SCALE_MIN)
                      _mag = SCALE_MIN;
                cv->setMag(MagIdx::MAG_FREE, _mag);
                setMag(_mag);
                }
          }

    //---------------------------------------------------------
    //   getMag
    //    return physical scale
    //---------------------------------------------------------

    double MuseScore::getMag(ScoreView* canvas) const
          {
          return mag->getMag(canvas);
          }

    //---------------------------------------------------------
    //   setMag
    //    set logical scale
    //---------------------------------------------------------

    void MuseScore::setMag(double d)
          {
          mag->setMag(d);
          mag->setMagIdx(MagIdx::MAG_FREE);
          }

    //---------------------------------------------------------
    //   setPos
    //    set position label
    //---------------------------------------------------------

    void MuseScore::setPos(int t)
          {
          if (cs == 0 || t < 0)
                return;

          TimeSigMap* s = cs->sigmap();
          int bar, beat, tick;
          s->tickValues(t, &bar, &beat, &tick);
          _positionLabel->setText(QString("%1:%2:%3")
             .arg(bar + 1,  3, 10, QLatin1Char(' '))
             .arg(beat + 1, 2, 10, QLatin1Char('0'))
             .arg(tick,     3, 10, QLatin1Char('0'))
             );
          }

    //---------------------------------------------------------
    //   undoRedo
    //---------------------------------------------------------

    void MuseScore::undoRedo(bool undo)
          {
          Q_ASSERT(cv);
          Q_ASSERT(cs);
    //      if (_sstate & (STATE_EDIT | STATE_TEXT_EDIT | STATE_HARMONY_FIGBASS_EDIT | STATE_LYRICS_EDIT))
          if (_sstate & (STATE_EDIT | STATE_HARMONY_FIGBASS_EDIT | STATE_LYRICS_EDIT))
                cv->changeState(ViewState::NORMAL);
          cv->startUndoRedo(undo);
          updateInputState(cs);
          endCmd();
          if (_inspector)
                _inspector->update();
          }

    //---------------------------------------------------------
    //   showProgressBar
    //---------------------------------------------------------

    QProgressBar* MuseScore::showProgressBar()
          {
          if (_progressBar == 0)
                _progressBar = new QProgressBar(this);
          _statusBar->addWidget(_progressBar);
          _progressBar->show();
          return _progressBar;
          }

    //---------------------------------------------------------
    //   hideProgressBar
    //---------------------------------------------------------

    void MuseScore::hideProgressBar()
          {
          if (_progressBar)
                _statusBar->removeWidget(_progressBar);
          }

    //---------------------------------------------------------
    //   handleMessage
    //---------------------------------------------------------

    void MuseScore::handleMessage(const QString& message)
          {
          if (message.isEmpty())
                return;
          if (startcenter)
                showStartcenter(false);
          ((QtSingleApplication*)(qApp))->activateWindow();
          MasterScore* score = readScore(message);
          if (score) {
                setCurrentScoreView(appendScore(score));
                addRecentScore(score);
                writeSessionFile(false);
                }
          }

    //---------------------------------------------------------
    //   editInPianoroll
    //---------------------------------------------------------

    void MuseScore::editInPianoroll(Staff* staff)
          {
          if (pianorollEditor == 0)
                pianorollEditor = new PianorollEditor;
          pianorollEditor->setScore(staff->score());
          pianorollEditor->setStaff(staff);
          pianorollEditor->show();
          }

    //---------------------------------------------------------
    //   editInDrumroll
    //---------------------------------------------------------

    void MuseScore::editInDrumroll(Staff* staff)
          {
          if (drumrollEditor == 0)
                drumrollEditor = new DrumrollEditor;
          drumrollEditor->setStaff(staff);
          drumrollEditor->show();
          }

    //---------------------------------------------------------
    //   writeSessionFile
    //---------------------------------------------------------

    void MuseScore::writeSessionFile(bool cleanExit)
          {
    // qDebug("write session file");

          QDir dir;
          dir.mkpath(dataPath);
          QFile f(dataPath + "/session");
          if (!f.open(QIODevice::WriteOnly)) {
                qDebug("cannot create session file <%s>", qPrintable(f.fileName()));
                return;
                }
          XmlWriter xml(0, &f);
          xml.header();
          xml.stag("museScore version=\"" MSC_VERSION "\"");
          xml.tagE(cleanExit ? "clean" : "dirty");

          foreach(MasterScore* score, scoreList) {
                xml.stag("Score");
                xml.tag("created", score->created());
                xml.tag("dirty", score->dirty());

                QString path;
                if (score->importedFilePath().isEmpty()) {
                                  // score was not imported from another format, e.g. MIDI file
                      path = score->masterScore()->fileInfo()->absoluteFilePath();
                      }
                else if (score->masterScore()->fileInfo()->exists()) {   // score was saved
                      path = score->masterScore()->fileInfo()->absoluteFilePath();
                      }
                else {      // score was imported but not saved - store original file (e.g. MIDI) path
                      path = score->importedFilePath();
                      }

                if (cleanExit || score->tmpName().isEmpty()) {
                      xml.tag("path", path);
                      }
                else {
                      xml.tag("name", path);
                      xml.tag("path", score->tmpName());
                      }
                xml.etag();
                }
          int tab = 0;
          int idx = 0;
          for (int i = 0; i < tab1->count(); ++i) {
                ScoreView* v = tab1->view(i);
                if (v) {
                      if (v == cv) {
                            tab = 0;
                            idx = i;
                            }
                      xml.stag("ScoreView");
                      xml.tag("tab", tab);    // 0 instead of "tab" does not work
                      xml.tag("idx", i);
                      if (v->magIdx() == MagIdx::MAG_FREE)
                            xml.tag("mag", v->lmag());
                      else
                            xml.tag("magIdx", int(v->magIdx()));
                      xml.tag("x",   v->xoffset() / DPMM);
                      xml.tag("y",   v->yoffset() / DPMM);
                      xml.etag();
                      }
                }
          if (splitScreen()) {
                for (int i = 0; i < tab2->count(); ++i) {
                      ScoreView* v = tab2->view(i);
                      if (v) {
                            if (v == cv) {
                                  tab = 1;
                                  idx = i;
                                  }
                            xml.stag("ScoreView");
                            xml.tag("tab", 1);
                            xml.tag("idx", i);
                            if (v->magIdx() == MagIdx::MAG_FREE)
                                  xml.tag("mag", v->lmag());
                            else
                                  xml.tag("magIdx", int(v->magIdx()));
                            xml.tag("x",   v->xoffset() / DPMM);
                            xml.tag("y",   v->yoffset() / DPMM);
                            xml.etag();
                            }
                      }
                }
          xml.tag("tab", tab);
          xml.tag("idx", idx);
          xml.etag();
          f.close();
          if (cleanExit) {
                // TODO: remove all temporary session backup files
                }
          }

    //---------------------------------------------------------
    //   removeSessionFile
    //    remove temp files and session file
    //---------------------------------------------------------

    void MuseScore::removeSessionFile()
          {
          QFile f(dataPath + "/session");
          if (!f.exists())
                return;
          if (!f.remove()) {
                qDebug("cannot remove session file <%s>", qPrintable(f.fileName()));
                }
          }

    //---------------------------------------------------------
    //   autoSaveTimerTimeout
    //---------------------------------------------------------

    void MuseScore::autoSaveTimerTimeout()
          {
          bool sessionChanged = false;
          for (MasterScore* s : scoreList) {
                if (s->autosaveDirty()) {
                      QString tmp = s->tmpName();
                      if (!tmp.isEmpty()) {
                            QFileInfo fi(tmp);
                            // TODO: cannot catch exeption here:
                            s->saveCompressedFile(fi, false);
                            }
                      else {
                            QDir dir;
                            dir.mkpath(dataPath);
                            QTemporaryFile tf(dataPath + "/scXXXXXX.mscz");
                            tf.setAutoRemove(false);
                            if (!tf.open()) {
                                  qDebug("autoSaveTimerTimeout(): create temporary file failed");
                                  return;
                                  }
                            s->setTmpName(tf.fileName());
                            QFileInfo info(tf.fileName());
                            s->saveCompressedFile(&tf, info, false, false);  // no thumbnail
                            tf.close();
                            sessionChanged = true;
                            }
                      s->setAutosaveDirty(false);
                      }
                }
          if (sessionChanged)
                writeSessionFile(false);
          if (preferences.autoSave) {
                int t = preferences.autoSaveTime * 60 * 1000;
                autoSaveTimer->start(t);
                }
          }

    //---------------------------------------------------------
    //   restoreSession
    //    Restore last session. If "always" is true, then restore
    //    last session even on a clean exit else only if last
    //    session ended abnormal.
    //    Return true if a session was found and restored.
    //---------------------------------------------------------

    bool MuseScore::restoreSession(bool always)
          {
          QFile f(dataPath + "/session");
          if (!f.exists())
                return false;
          if (!f.open(QIODevice::ReadOnly)) {
                qDebug("Cannot open session file <%s>", qPrintable(f.fileName()));
                return false;
                }
          XmlReader e(0, &f);
          int tab = 0;
          int idx = -1;
          bool cleanExit = false;
          while (e.readNextStartElement()) {
                if (e.name() == "museScore") {
                      /* QString version = e.attribute(QString("version"));
                      QStringList sl  = version.split('.');
                      int v           = sl[0].toInt() * 100 + sl[1].toInt();
                      */
                      while (e.readNextStartElement()) {
                            const QStringRef& tag(e.name());
                            if (tag == "clean") {
                                  if (!always)
                                        return false;
                                  cleanExit = true;
                                  e.readNext();
                                  }
                            else if (tag == "dirty") {
                                  QMessageBox::StandardButton b = QMessageBox::question(0,
                                     tr("MuseScore"),
                                     tr("The previous session quit unexpectedly.\n\nRestore session?"),
                                     QMessageBox::Yes | QMessageBox::No,
                                     QMessageBox::Yes
                                     );
                                  if (b != QMessageBox::Yes)
                                        return false;
                                  e.readNext();
                                  }
                            else if (tag == "Score") {
                                  QString name;
                                  bool created = false;
                                  while (e.readNextStartElement()) {
                                        const QStringRef& tag(e.name());
                                        if (tag == "name")
                                              name = e.readElementText();
                                        else if (tag == "created")
                                              created = e.readInt();
                                        else if (tag == "dirty")
                                              /*int dirty =*/ e.readInt();
                                        else if (tag == "path") {
                                              MasterScore* score = readScore(e.readElementText());
                                              if (score) {
                                                    if (!name.isEmpty()) {
                                                          QFileInfo* fi = score->masterScore()->fileInfo();
                                                          fi->setFile(name);
                                                          // TODO: what if that path is no longer valid?
                                                          }
                                                    if (cleanExit) {
                                                          // override if last session did a clean exit
                                                          created = false;
                                                          }
                                                    appendScore(score);
                                                    score->setCreated(created);
                                                    }
                                              }
                                        else {
                                              e.unknown();
                                              return false;
                                              }
                                        }
                                  }
                            else if (tag == "ScoreView") {
                                  qreal x       = .0;
                                  qreal y       = .0;
                                  qreal vmag    = 1.0;
                                  MagIdx magIdx = MagIdx::MAG_FREE;
                                  int tab       = 0;
                                  int idx       = 0;
                                  while (e.readNextStartElement()) {
                                        const QStringRef& tag(e.name());
                                        if (tag == "tab")
                                              tab = e.readInt();
                                        else if (tag == "idx")
                                              idx = e.readInt();
                                        else if (tag == "mag")
                                              vmag = e.readDouble();
                                        else if (tag == "magIdx")
                                              magIdx = MagIdx(e.readInt());
                                        else if (tag == "x")
                                              x = e.readDouble() * DPMM;
                                        else if (tag == "y")
                                              y = e.readDouble() * DPMM;
                                        else {
                                              e.unknown();
                                              return false;
                                              }
                                        }
                                  (tab == 0 ? tab1 : tab2)->initScoreView(idx, vmag, magIdx, x, y);
                                  }
                            else if (tag == "tab")
                                  tab = e.readInt();
                            else if (tag == "idx")
                                  idx = e.readInt();
                            else {
                                  e.unknown();
                                  return false;
                                  }
                            }
                      }
                else {
                      e.unknown();
                      return false;
                      }
                }
          setCurrentView(tab, idx);
          return true;
          }

    //---------------------------------------------------------
    //   splitWindow
    //---------------------------------------------------------

    void MuseScore::splitWindow(bool horizontal)
          {
          if (!_splitScreen) {
                if (tab2 == 0) {
                      tab2 = new ScoreTab(&scoreList, this);
                      tab2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
                      connect(tab2, SIGNAL(currentScoreViewChanged(ScoreView*)), SLOT(setCurrentScoreView(ScoreView*)));
                      connect(tab2, SIGNAL(tabCloseRequested(int)), SLOT(removeTab(int)));
                      connect(tab2, SIGNAL(actionTriggered(QAction*)), SLOT(cmd(QAction*)));
                      splitter->addWidget(tab2);
                      }
                tab2->setVisible(true);
                _splitScreen = true;
                _horizontalSplit = horizontal;
                splitter->setOrientation(_horizontalSplit ? Qt::Horizontal : Qt::Vertical);
                if (!scoreList.isEmpty()) {
                      tab2->setCurrentIndex(0);
                      MasterScore* s = scoreList[0];
                      s->setLayoutAll();
                      s->update();
                      setCurrentView(1, 0);
                      }
                }
          else {
                if (_horizontalSplit == horizontal) {
                      _splitScreen = false;
                      tab2->setVisible(false);
                      }
                else {
                      _horizontalSplit = horizontal;
                      QAction* a;
                      if (_horizontalSplit)
                            a = getAction("split-v");
                      else
                            a = getAction("split-h");
                      a->setChecked(false);
                      splitter->setOrientation(_horizontalSplit ? Qt::Horizontal : Qt::Vertical);
                      }
                }
          }

    //---------------------------------------------------------
    //   stateName
    //---------------------------------------------------------

    const char* stateName(ScoreState s)
          {
          switch(s) {
                case STATE_DISABLED:           return "STATE_DISABLED";
                case STATE_NORMAL:             return "STATE_NORMAL";
                case STATE_NOTE_ENTRY_STAFF_PITCHED: return "STATE_NOTE_ENTRY_STAFF_PITCHED";
                case STATE_NOTE_ENTRY_STAFF_DRUM:    return "STATE_NOTE_ENTRY_STAFF_DRUM";
                case STATE_NOTE_ENTRY_STAFF_TAB:     return "STATE_NOTE_ENTRY_STAFF_TAB";
                case STATE_NOTE_ENTRY:         return "STATE_NOTE_ENTRY";
                case STATE_NOTE_ENTRY_METHOD_STEPTIME:          return "STATE_NOTE_ENTRY_METHOD_STEPTIME";
                case STATE_NOTE_ENTRY_METHOD_REPITCH:           return "STATE_NOTE_ENTRY_METHOD_REPITCH";
                case STATE_NOTE_ENTRY_METHOD_RHYTHM:            return "STATE_NOTE_ENTRY_METHOD_RHYTHM";
                case STATE_NOTE_ENTRY_METHOD_REALTIME_AUTO:     return "STATE_NOTE_ENTRY_METHOD_REALTIME_AUTO";
                case STATE_NOTE_ENTRY_METHOD_REALTIME_MANUAL:   return "STATE_NOTE_ENTRY_METHOD_REALTIME_MANUAL";
                case STATE_EDIT:               return "STATE_EDIT";
                case STATE_TEXT_EDIT:          return "STATE_TEXT_EDIT";
                case STATE_LYRICS_EDIT:        return "STATE_LYRICS_EDIT";
                case STATE_HARMONY_FIGBASS_EDIT: return "STATE_HARMONY_FIGBASS_EDIT";
                case STATE_PLAY:               return "STATE_PLAY";
                case STATE_FOTO:               return "STATE_FOTO";
                default:                       return "??";
                }
          }

    //---------------------------------------------------------
    //   scorePageLayoutChanged
    //---------------------------------------------------------

    void MuseScore::scorePageLayoutChanged()
          {
          if (mainWindow) {
                mainWindow->setOrientation(MScore::verticalOrientation() ? Qt::Horizontal : Qt::Vertical);
                if (navigatorScrollArea())
                      navigatorScrollArea()->orientationChanged();
                }
          }

    //---------------------------------------------------------
    //   editRaster
    //---------------------------------------------------------

    void MuseScore::editRaster()
          {
          if (editRasterDialog == 0) {
                editRasterDialog = new EditRaster(this);
                }
          if (editRasterDialog->exec()) {
                qDebug("=====accept config raster");
                }
          }

    //---------------------------------------------------------
    //   showPianoKeyboard
    //---------------------------------------------------------

    void MuseScore::showPianoKeyboard(bool on)
          {
          if (_pianoTools == 0) {
                QAction* a = getAction("toggle-piano");
                _pianoTools = new PianoTools(this);
                addDockWidget(Qt::BottomDockWidgetArea, _pianoTools);
                connect(_pianoTools, SIGNAL(keyPressed(int, bool, int)), SLOT(midiNoteReceived(int, bool, int)));
                connect(_pianoTools, SIGNAL(keyReleased(int, bool, int)), SLOT(midiNoteReceived(int, bool, int)));
                connect(_pianoTools, SIGNAL(visibilityChanged(bool)), a, SLOT(setChecked(bool)));
                }
          if (on) {
                _pianoTools->show();
                }
          else {
                if (_pianoTools)
                      _pianoTools->hide();
                }
          }

    //---------------------------------------------------------
    //   showPluginCreator
    //---------------------------------------------------------

    void MuseScore::showPluginCreator(QAction* a)
          {
    #ifdef SCRIPT_INTERFACE
          bool on = a->isChecked();
          if (on) {
                if (_pluginCreator == 0) {
                      _pluginCreator = new PluginCreator(0);
                      connect(_pluginCreator, SIGNAL(closed(bool)), a, SLOT(setChecked(bool)));
                      }
                _pluginCreator->show();
                }
          else {
                if (_pluginCreator)
                      _pluginCreator->hide();
                }
    #endif
          }

    //---------------------------------------------------------
    //   showPluginManager
    //---------------------------------------------------------

    void MuseScore::showPluginManager()
          {
    #ifdef SCRIPT_INTERFACE
          if (!pluginManager)
                pluginManager = new PluginManager(0);
          pluginManager->init();
          pluginManager->show();
    #endif
          }

    //---------------------------------------------------------
    //   showMediaDialog
    //---------------------------------------------------------

    void MuseScore::showMediaDialog()
          {
          if (_mediaDialog == 0)
                _mediaDialog = new MediaDialog(this);
          _mediaDialog->setScore(cs);
          _mediaDialog->exec();
          }

    //---------------------------------------------------------
    //   getPaletteBox
    //---------------------------------------------------------

    PaletteBox* MuseScore::getPaletteBox()
          {
          if (paletteBox == 0) {
                paletteBox = new PaletteBox(this);
                QAction* a = getAction("toggle-palette");
                connect(paletteBox, SIGNAL(visibilityChanged(bool)), a, SLOT(setChecked(bool)));
                addDockWidget(Qt::LeftDockWidgetArea, paletteBox);
                }
          return paletteBox;
          }

    //---------------------------------------------------------
    //   midiNoteReceived
    //---------------------------------------------------------

    void MuseScore::midiNoteReceived(int pitch, bool ctrl, int vel)
          {
          if (cv)
                cv->midiNoteReceived(pitch, ctrl, vel);
          }

    //---------------------------------------------------------
    //   switchLayer
    //---------------------------------------------------------

    void MuseScore::switchLayer(const QString& s)
          {
          if (cs->switchLayer(s)) {
                cs->setLayoutAll();
                cs->update();
                }
          }

    //---------------------------------------------------------
    //   switchPlayMode
    //---------------------------------------------------------

    void MuseScore::switchPlayMode(int mode)
          {
          if (cs)
                cs->setPlayMode(PlayMode(mode));
          }

    //---------------------------------------------------------
    //   networkFinished
    //---------------------------------------------------------

    void MuseScore::networkFinished(QNetworkReply* reply)
          {
          if (reply->error() != QNetworkReply::NoError) {
                qDebug("Error while checking update [%s]", qPrintable(reply->errorString()));
                return;
                }
          QByteArray ha = reply->rawHeader("Content-Disposition");
          QString s(ha);
          QString name;
          QRegExp re(".*filename=\"(.*)\"");

          if (!s.isEmpty() && re.indexIn(s) != -1) {
                name = re.cap(1);
                 }
          else {
                QUrl url = reply->url();
                QString path = url.path();
                qDebug("Path <%s>", qPrintable(path));
                QFileInfo fi(path);
                name = fi.fileName();
                }

          qDebug("header <%s>", qPrintable(s));
          qDebug("name <%s>", qPrintable(name));

          QByteArray data = reply->readAll();
          QString tmpName = QDir::tempPath () + "/"+ name;
          QFile f(tmpName);
          f.open(QIODevice::WriteOnly);
          f.write(data);
          f.close();

          reply->deleteLater();

          MasterScore* score = readScore(tmpName);
          if (!score) {
                qDebug("readScore failed");
                return;
                }
          score->setCreated(true);
          setCurrentScoreView(appendScore(score));
          }

    //---------------------------------------------------------
    //   loadFile
    //    load file from url
    //---------------------------------------------------------

    void MuseScore::loadFile(const QString& s)
          {
          loadFile(QUrl(s));
          }

    void MuseScore::loadFile(const QUrl& url)
          {
          QNetworkReply* nr = networkManager()->get(QNetworkRequest(url));
          connect(nr, SIGNAL(finished(QNetworkReply*)),
                   SLOT(networkFinished(QNetworkReply*)));
          }

    //---------------------------------------------------------
    //   networkManager
    //---------------------------------------------------------

    QNetworkAccessManager* MuseScore::networkManager()
          {
          if (!_networkManager)
                _networkManager = new QNetworkAccessManager(this);
          return _networkManager;
          }

    //---------------------------------------------------------
    //   selectSimilar
    //---------------------------------------------------------

    void MuseScore::selectSimilar(Element* e, bool sameStaff)
          {
          Score* score = e->score();
          score->selectSimilar(e, sameStaff);

          if (score->selectionChanged()) {
                score->setSelectionChanged(false);
                SelState ss = score->selection().state();
                selectionChanged(ss);
                }
          }

    void MuseScore::selectSimilarInRange(Element* e)
          {
          Score* score = e->score();
          score->selectSimilarInRange(e);

          if (score->selectionChanged()) {
                score->setSelectionChanged(false);
                SelState ss = score->selection().state();
                selectionChanged(ss);
                }
          }

    //---------------------------------------------------------
    //   selectElementDialog
    //---------------------------------------------------------

    void MuseScore::selectElementDialog(Element* e)
          {
          Score* score = e->score();
          if (e->isNote()) {
                SelectNoteDialog sd(toNote(e), 0);
                if (sd.exec()) {
                      NotePattern pattern;
                      sd.setPattern(&pattern);

                      if (sd.isInSelection())
                            score->scanElementsInRange(&pattern, Score::collectNoteMatch);
                      else
                            score->scanElements(&pattern, Score::collectNoteMatch);

                      if (sd.doReplace()) {
                            score->select(0, SelectType::SINGLE, 0);
                            for (Note* ee : pattern.el)
                                  score->select(ee, SelectType::ADD, 0);
                            }
                      else if (sd.doSubtract()) {
                            QList<Element*> sl(score->selection().elements());
                            for (Note* ee : pattern.el)
                                  sl.removeOne(ee);
                            score->select(0, SelectType::SINGLE, 0);
                            for (Element* ee : sl)
                                  score->select(ee, SelectType::ADD, 0);
                            }
                      else if (sd.doAdd()) {
                            QList<Element*> sl(score->selection().elements());
                            for (Note* ee : pattern.el) {
                                  if(!sl.contains(ee))
                                        score->select(ee, SelectType::ADD, 0);
                                  }
                            }
                      }
                }
          else {
                SelectDialog sd(e, 0);
                if (sd.exec()) {
                      ElementPattern pattern;
                      sd.setPattern(&pattern);

                      if (sd.isInSelection())
                            score->scanElementsInRange(&pattern, Score::collectMatch);
                      else
                            score->scanElements(&pattern, Score::collectMatch);

                      if (sd.doReplace()) {
                            score->select(0, SelectType::SINGLE, 0);
                            for (Element* ee : pattern.el)
                                  score->select(ee, SelectType::ADD, 0);
                            }
                      else if (sd.doSubtract()) {
                            QList<Element*> sl(score->selection().elements());
                            for (Element* ee : pattern.el)
                                  sl.removeOne(ee);
                            score->select(0, SelectType::SINGLE, 0);
                            for (Element* ee : sl)
                                  score->select(ee, SelectType::ADD, 0);
                            }
                      else if (sd.doAdd()) {
                            QList<Element*> sl(score->selection().elements());
                            for (Element* ee : pattern.el) {
                                  if(!sl.contains(ee))
                                        score->select(ee, SelectType::ADD, 0);
                                  }
                            }
                      }
                }
          if (score->selectionChanged()) {
                score->setSelectionChanged(false);
                SelState ss = score->selection().state();
                selectionChanged(ss);
                }
          }

    //---------------------------------------------------------
    //   RecordButton
    //---------------------------------------------------------

    RecordButton::RecordButton(QWidget* parent)
       : SimpleButton(":/data/recordOn.svg", ":/data/recordOff.svg", parent)
          {
          setCheckable(true);
          defaultAction()->setCheckable(true);
          setToolTip(qApp->translate("RecordButton", "Record"));
          }

    //---------------------------------------------------------
    //   GreendotButton
    //---------------------------------------------------------

    GreendotButton::GreendotButton(QWidget* parent)
       : SimpleButton(":/data/greendot.svg", ":/data/darkgreendot.svg", parent)
          {
          setCheckable(true);
          setToolTip(qApp->translate("GreendotButton", "Record"));
          }

    //---------------------------------------------------------
    //   drawHandle
    //---------------------------------------------------------

    QRectF drawHandle(QPainter& p, const QPointF& pos, bool active)
          {
          p.save();
          p.setPen(QPen(QColor(MScore::selectColor[0]), 2.0/p.matrix().m11()));
          if (active)
                p.setBrush(MScore::selectColor[0]);
          else
                p.setBrush(Qt::NoBrush);
          qreal w = 8.0 / p.matrix().m11();
          qreal h = 8.0 / p.matrix().m22();

          QRectF r(-w/2, -h/2, w, h);
          r.translate(pos);
          p.drawRect(r);
          p.restore();
          return r;
          }

    //---------------------------------------------------------
    //   transpose
    //---------------------------------------------------------

    void MuseScore::transpose()
          {
          if (cs->last() == 0)     // empty score?
                return;

          bool noSelection = cs->selection().isNone();
          if (noSelection)
                cs->cmdSelectAll();
          bool rangeSelection = cs->selection().isRange();
          TransposeDialog td;

          // TRANSPOSE_BY_KEY and "transpose keys" is only possible if selection state is SelState::RANGE
          td.enableTransposeKeys(rangeSelection);
          td.enableTransposeByKey(rangeSelection);
          td.enableTransposeChordNames(rangeSelection);

          int startStaffIdx = 0;
          int endStaffIdx   = 0;
          int startTick     = 0;
          if (rangeSelection) {
                startStaffIdx = cs->selection().staffStart();
                endStaffIdx   = cs->selection().staffEnd();
                startTick     = cs->selection().tickStart();
                }

          // find the key of the first pitched staff
          Key key = Key::C;
          for (int i = startStaffIdx; i < endStaffIdx; ++i) {
                Staff* staff = cs->staff(i);
                if (staff->isPitchedStaff(startTick)) {
                      key = staff->key(startTick);
                      if (!cs->styleB(StyleIdx::concertPitch)) {
                            int diff = staff->part()->instrument(startTick)->transpose().chromatic;
                            if (diff)
                                  key = transposeKey(key, diff);
                            }
                      break;
                      }
                }

          td.setKey(key);
          if (!td.exec())
                return;

          cs->transpose(td.mode(), td.direction(), td.transposeKey(), td.transposeInterval(),
             td.getTransposeKeys(), td.getTransposeChordNames(), td.useDoubleSharpsFlats());

          if (noSelection)
                cs->deselectAll();
          }

    //---------------------------------------------------------
    //   cmd
    //---------------------------------------------------------

    void MuseScore::cmd(QAction* a)
          {
          if (inChordEditor)      // HACK
                return;

          MScore::setError(MS_NO_ERROR);

          QString cmdn(a->data().toString());

          if (MScore::debugMode)
                qDebug("MuseScore::cmd <%s>", qPrintable(cmdn));

          const Shortcut* sc = Shortcut::getShortcut(cmdn.toLatin1().data());
          if (sc == 0) {
                qDebug("MuseScore::cmd(): unknown action <%s>", qPrintable(cmdn));
                return;
                }
          if (cs && (sc->state() & _sstate) == 0) {
                qDebug("invalid state %04x %04x", sc->state(), _sstate);
                QMessageBox::warning(0,
                   QWidget::tr("Invalid Command"),
                   QString("Command %1 not valid in current state").arg(cmdn));
                return;
                }
          if (cmdn == "palette-search") {
                PaletteBox* pb = getPaletteBox();
                QLineEdit* sb = pb->searchBox();
                sb->setFocus();
                if (pb->noSelection())
                      pb->setKeyboardNavigation(false);
                else
                      pb->setKeyboardNavigation(true);
                return;
                }
          if (cmdn == "apply-current-palette-element") {
                PaletteBox* pb = getPaletteBox();
                for (Palette* p : pb->palettes()) {
                      if (p->getCurrentIdx() != -1) {
                            p->applyPaletteElement();
                            break;
                            }
                      }
                return;
                }
          if (cmdn == "repeat-cmd") {
                a  = lastCmd;
                sc = lastShortcut;
                if (a == 0)
                      return;
                cmdn = a->data().toString();
                }
          else {
                lastCmd = a;
                lastShortcut = sc;
                }

          if (sc->needsScore() && ! cs) {
                qDebug("no score");
                return;
                }
          if (sc->isCmd()) {
                if (!cv->editMode())
                      cs->startCmd();
                }
          cmd(a, cmdn);
          if (lastShortcut->isCmd())
                cs->endCmd();
          endCmd();
          }

    //---------------------------------------------------------
    //   endCmd
    //    Called after every command action (including every
    //    mouse action).
    //    Updates the UI after a possible score change.
    //---------------------------------------------------------

    void MuseScore::endCmd()
          {
          if (timeline())
                timeline()->updateGrid();
          if (MScore::_error != MS_NO_ERROR)
                showError();
          if (cs) {
                setPos(cs->inputState().tick());
                updateInputState(cs);
                updateUndoRedo();
                dirtyChanged(cs);
                Element* e = cs->selection().element();

                // For multiple notes selected check if they all have same pitch and tuning
                bool samePitch = true;
                int pitch    = -1;
                float tuning = 0;
                for (Element* e : cs->selection().elements()) {
                      if (!e->isNote()) {
                            samePitch = false;
                            break;
                            }
                      Note* note = toNote(e);
                      if (pitch == -1) {
                            pitch = note->ppitch();
                            tuning = note->tuning();
                            }
                      else if (note->ppitch() != pitch || fabs(tuning - note->tuning()) > 0.01) {
                            samePitch = false;
                            break;
                            }
                      }
                if (samePitch && pitch >= 0)
                      e = cs->selection().elements()[0];

                NoteEntryMethod entryMethod = cs->noteEntryMethod();
                if (e && (cs->playNote() || cs->playChord())
                            && entryMethod != NoteEntryMethod::REALTIME_AUTO
                            && entryMethod != NoteEntryMethod::REALTIME_MANUAL) {
                      if (cs->playChord() && preferences.playChordOnAddNote &&  e->type() == ElementType::NOTE)
                            play(static_cast<Note*>(e)->chord());
                      else
                            play(e);
                      cs->setPlayNote(false);
                      cs->setPlayChord(false);
                      }
                MasterScore* ms = cs->masterScore();
                if (ms->excerptsChanged()) {
                      if (tab2) {
    //                      ScoreView* v = tab2->view();
    //                      if (v && v->score() == ms) {
                                  tab2->updateExcerpts();
    //                            }
                            }
                      if (tab1) {
                            ScoreView* v = tab1->view();
                            if (v && v->score()->masterScore() == ms) {
                                  tab1->updateExcerpts();
                                  }
                            else if (v == 0) {
                                  tab1->setExcerpt(0);
                                  tab1->updateExcerpts();
                                  }
                            }
                      ms->setExcerptsChanged(false);
                      }
                if (ms->instrumentsChanged()) {
                      if (!noSeq && (seq && seq->isRunning()))
                            seq->initInstruments();
                      instrumentChanged();                // update mixer
                      ms->setInstrumentsChanged(false);
                      }
                if (cs->selectionChanged()) {
                      cs->setSelectionChanged(false);
                      SelState ss = cs->selection().state();
                      selectionChanged(ss);
                      }
                getAction("concert-pitch")->setChecked(cs->styleB(StyleIdx::concertPitch));

                if (e == 0 && cs->noteEntryMode())
                      e = cs->inputState().cr();
                updateViewModeCombo();
                ScoreAccessibility::instance()->updateAccessibilityInfo();
                }
          else {
                selectionChanged(SelState::NONE);
                }
          updateInspector();
          }

    //---------------------------------------------------------
    //   updateUndoRedo
    //---------------------------------------------------------

    void MuseScore::updateUndoRedo()
          {
          QAction* a = getAction("undo");
          a->setEnabled(cs ? cs->undoStack()->canUndo() : false);
          a = getAction("redo");
          a->setEnabled(cs ? cs->undoStack()->canRedo() : false);
          }

    //---------------------------------------------------------
    //   cmd
    //---------------------------------------------------------

    void MuseScore::cmd(QAction* a, const QString& cmd)
          {
          if (cmd == "instruments") {
                editInstrList();
                if (mixer)
                      mixer->updateAll(cs->masterScore());
                }
          else if (cmd == "rewind") {
                seq->rewindStart();
                if (playPanel)
                      playPanel->heartBeat(0, 0, 0);
                }
          else if (cmd == "play-next-measure")
                seq->nextMeasure();
          else if (cmd == "play-next-chord")
                seq->nextChord();
          else if (cmd == "play-prev-measure")
                seq->prevMeasure();
          else if (cmd == "play-prev-chord")
                seq->prevChord();
          else if (cmd == "seek-begin")
                seq->rewindStart();
          else if (cmd == "seek-end")
                seq->seekEnd();
          else if (cmd == "keys")
                showKeyEditor();
          else if (cmd == "file-open")
                loadFiles();
          else if (cmd == "file-save")
                saveFile();
          else if (cmd == "file-save-online")
                showUploadScoreDialog();
          else if (cmd == "file-export")
                exportFile();
          else if (cmd == "file-part-export")
                exportParts();
          else if (cmd == "file-import-pdf")
                openExternalLink("https://musescore.com/import");
          else if (cmd == "file-close")
                closeScore(cs);
          else if (cmd == "file-save-as")
                saveAs(cs, false);
          else if (cmd == "file-save-selection")
                saveSelection(cs);
          else if (cmd == "file-save-a-copy")
                saveAs(cs, true);
          else if (cmd == "file-new")
                newFile();
          else if (cmd == "quit")
                close();
          else if (cmd == "masterpalette")
                showMasterPalette();
          else if (cmd == "key-signatures")
                showMasterPalette(qApp->translate("Palette", "Key Signatures"));
          else if (cmd == "time-signatures")
                showMasterPalette(qApp->translate("Palette", "Time Signatures"));
          else if (cmd == "symbols")
                showMasterPalette(qApp->translate("MasterPalette", "Symbols"));
          else if (cmd == "toggle-statusbar") {
                preferences.showStatusBar = a->isChecked();
                _statusBar->setVisible(preferences.showStatusBar);
                preferences.write();
                }
          else if (cmd == "append-measures")
                cmdAppendMeasures();
          else if (cmd == "insert-measures")
                cmdInsertMeasures();
          else if (cmd == "debugger")
                startDebugger();
          else if (cmd == "album")
                showAlbumManager();
          else if (cmd == "layer")
                showLayerManager();
          else if (cmd == "backspace") {
                if (_sstate != STATE_NORMAL )
                      undoRedo(true);
    #ifdef Q_OS_MAC
                else if (cs) {
                      cs->startCmd();
                      cs->cmdDeleteSelection();
                      cs->endCmd();
                      }
    #endif
                }
          else if (cmd == "zoomin")
                incMag();
          else if (cmd == "zoomout")
                decMag();
          else if (cmd == "zoom100") {
                if (cv)
                      cv->setMag(MagIdx::MAG_100, 1.0);
                setMag(1.0);
                }
          else if (cmd == "midi-on")
                midiinToggled(a->isChecked());
          else if (cmd == "undo")
                undoRedo(true);
          else if (cmd == "redo")
                undoRedo(false);
          else if (cmd == "toggle-palette")
                showPalette(a->isChecked());
          else if (cmd == "startcenter")
                showStartcenter(a->isChecked());
          else if (cmd == "inspector")
                showInspector(a->isChecked());
    #ifdef OMR
          else if (cmd == "omr")
                showOmrPanel(a->isChecked());
    #endif
          else if (cmd == "toggle-playpanel")
                showPlayPanel(a->isChecked());
          else if (cmd == "toggle-navigator")
                showNavigator(a->isChecked());
          else if (cmd == "toggle-timeline")
                showTimeline(a->isChecked());
          else if (cmd == "toggle-midiimportpanel")
                importmidiPanel->setVisible(a->isChecked());
          else if (cmd == "toggle-mixer")
                showMixer(a->isChecked());
          else if (cmd == "synth-control")
                showSynthControl(a->isChecked());
          else if (cmd == "toggle-selection-window")
                showSelectionWindow(a->isChecked());
          else if (cmd == "show-keys")
                ;
          else if (cmd == "toggle-fileoperations")
                fileTools->setVisible(!fileTools->isVisible());
          else if (cmd == "toggle-transport")
                transportTools->setVisible(!transportTools->isVisible());
          else if (cmd == "toggle-concertpitch")
                cpitchTools->setVisible(!cpitchTools->isVisible());
          else if (cmd == "toggle-imagecapture")
                fotoTools->setVisible(!fotoTools->isVisible());
          else if (cmd == "toggle-noteinput")
                entryTools->setVisible(!entryTools->isVisible());
          else if (cmd == "help")
                showContextHelp();
          else if (cmd == "follow")
                preferences.followSong = a->isChecked();
          else if (cmd == "split-h")
                splitWindow(true);
          else if (cmd == "split-v")
                splitWindow(false);
          else if (cmd == "edit-harmony")
                editChordStyle();
          else if (cmd == "parts")
                startExcerptsDialog();
          else if (cmd == "fullscreen") {
                _fullscreen = a->isChecked();
                if (_fullscreen)
                      showFullScreen();
                else
                      showNormal();

    #ifdef Q_OS_MAC
                // Qt Bug: Toolbar goes into unified mode
                // after switching back from fullscreen
                setUnifiedTitleAndToolBarOnMac(false);
    #endif
                }
          else if (cmd == "config-raster")
                editRaster();
          else if (cmd == "hraster" || cmd == "vraster")  // value in [hv]RasterAction already set
                ;
          else if (cmd == "toggle-piano")
                showPianoKeyboard(a->isChecked());
          else if (cmd == "plugin-creator")
                showPluginCreator(a);
          else if (cmd == "plugin-manager")
                showPluginManager();
          else if(cmd == "resource-manager"){
                ResourceManager r(0);
                r.exec();
                }
          else if (cmd == "media")
                showMediaDialog();
          else if (cmd == "page-settings")
                showPageSettings();
          else if (cmd == "next-score")
                changeScore(1);
          else if (cmd == "previous-score")
                changeScore(1);
          else if (cmd == "transpose")
                transpose();
          else if (cmd == "save-style") {
                QString name = getStyleFilename(false);
                if (!name.isEmpty()) {
                      if (!cs->saveStyle(name)) {
                            QMessageBox::critical(this,
                               tr("Save Style"), MScore::lastError);
                            }
                      }
                }
          else if (cmd == "load-style") {
                QString name = mscore->getStyleFilename(true);
                if (!name.isEmpty()) {
                      cs->startCmd();
                      if (!cs->loadStyle(name)) {
                            QMessageBox::critical(this,
                               tr("Load Style"), MScore::lastError);
                            }
                      cs->endCmd();
                      }
                }
          else if (cmd == "edit-style") {
                EditStyle es(cs, this);
                es.exec();
                }
          else if (cmd == "edit-info") {
                MetaEditDialog med(cs, 0);
                med.exec();
                }
          else if (cmd == "print")
                printFile();
          else if (cmd == "repeat") {
                MScore::playRepeats = a->isChecked();
                if (cs) {
                      cs->updateRepeatList(MScore::playRepeats);
                      emit cs->playlistChanged();
                      }
                }
          else if (cmd == "pan")
                MScore::panPlayback = !MScore::panPlayback;
          else if (cmd == "show-invisible")
                cs->setShowInvisible(a->isChecked());
          else if (cmd == "show-unprintable")
                cs->setShowUnprintable(a->isChecked());
          else if (cmd == "show-frames")
                cs->setShowFrames(a->isChecked());
          else if (cmd == "show-pageborders")
                cs->setShowPageborders(a->isChecked());
          else if (cmd == "mark-irregular")
                cs->setMarkIrregularMeasures(a->isChecked());
          else if (cmd == "tempo")
                addTempo();
          else if (cmd == "loop") {
                if (loop()) {
                      if (cs->selection().isRange())
                            seq->setLoopSelection();
                      }
                }
          else if (cmd == "loop-in") {
                seq->setLoopIn();
                loopAction->setChecked(true);
                }
          else if (cmd == "loop-out") {
                seq->setLoopOut();
                loopAction->setChecked(true);
                }
          else if (cmd == "metronome")  // no action
                ;
          else if (cmd == "countin")    // no action
                ;
          else if (cmd == "lock") {
                if (_sstate == STATE_LOCK)
                      changeState(STATE_NORMAL);
                else
                      changeState(STATE_LOCK);
                }
          else if (cmd == "find")
                showSearchDialog();
          else if (cmd == "text-b") {
                if (_textTools)
                      _textTools->toggleBold();
                }
          else if (cmd == "text-i") {
                if (_textTools)
                      _textTools->toggleItalic();
                }
          else if (cmd == "text-u") {
                if (_textTools)
                      _textTools->toggleUnderline();
                }
          else if (cmd == "edit-toolbars")
                showToolbarEditor();
          else if (cmd == "viewmode") {
                if (cs) {
                      if (cs->layoutMode() == LayoutMode::PAGE)
                            switchLayoutMode(LayoutMode::LINE);
                      else
                            switchLayoutMode(LayoutMode::PAGE);
                      }
                }
    #ifndef NDEBUG
          else if (cmd == "no-horizontal-stretch") {
                MScore::noHorizontalStretch = a->isChecked();
                if (cs) {
                      cs->setLayoutAll();
                      cs->update();
                      }
                }
          else if (cmd == "no-vertical-stretch") {
                MScore::noVerticalStretch = a->isChecked();
                if (cs) {
                      cs->setLayoutAll();
                      cs->update();
                      }
                }
          else if (cmd == "show-segment-shapes") {
                MScore::showSegmentShapes = a->isChecked();
                if (cs) {
                      cs->setLayoutAll();
                      cs->update();
                      }
                }
          else if (cmd == "show-measure-shapes") {
                MScore::showMeasureShapes = a->isChecked();
                if (cs) {
                      cs->setLayoutAll();
                      cs->update();
                      }
                }
          else if (cmd == "show-bounding-rect") {
                MScore::showBoundingRect = a->isChecked();
                if (cs) {
                      cs->setLayoutAll();
                      cs->update();
                      }
                }
          else if (cmd == "show-corrupted-measures") {
                MScore::showCorruptedMeasures = a->isChecked();
                if (cs) {
                      cs->setLayoutAll();
                      cs->update();
                      }
                }
          else if (cmd == "autoplace-slurs") {
                MScore::autoplaceSlurs = a->isChecked();
                if (cs) {
                      cs->setLayoutAll();
                      cs->update();
                      }
                }
    #endif
          else {
                if (cv) {
                      //isAncestorOf is called to see if a widget from inspector has focus
                      //if so, the focus doesn't get shifted to the score, unless escape is
                      //pressed, or the user clicks in the score
                      if (!inspector()->isAncestorOf(qApp->focusWidget()) || cmd == "escape")
                            cv->setFocus();
                      cv->cmd(a);
                      }
                else
                      qDebug("2:unknown cmd <%s>", qPrintable(cmd));
                }
          if (debugger)
                debugger->reloadClicked();
          }

    //---------------------------------------------------------
    //   openExternalLink
    //---------------------------------------------------------

    void MuseScore::openExternalLink(const QString& url)
          {
          QDesktopServices::openUrl(url);
          }

    //---------------------------------------------------------
    //   navigator
    //---------------------------------------------------------

    Navigator* MuseScore::navigator() const
          {
          return _navigator ? static_cast<Navigator*>(_navigator->widget()) : 0;
          }

    //---------------------------------------------------------
    //   timeline
    //---------------------------------------------------------

    Timeline* MuseScore::timeline() const
          {
          if (_timeline) {
                QSplitter* s = static_cast<QSplitter *>(_timeline->widget());
                if (s && s->count() > 0)
                      return _timeline ? static_cast<Timeline*>(s->widget(1)) : 0;
                return 0;
                }
          return 0;
          }

    //---------------------------------------------------------
    //   getSearchDialog
    //---------------------------------------------------------

    QWidget* MuseScore::searchDialog() const
          {
          return _searchDialog;
          }

    //---------------------------------------------------------
    //   updateLayer
    //---------------------------------------------------------

    void MuseScore::updateLayer()
          {
          layerSwitch->clear();
          bool enable;
          if (cs) {
                enable = cs->layer().size() > 1;
                if (enable) {
                      foreach(const Layer& l, cs->layer())
                            layerSwitch->addItem(l.name);
                      layerSwitch->setCurrentIndex(cs->currentLayer());
                      }
                }
          else
               enable = false;
          layerSwitch->setVisible(enable);
          }

    //---------------------------------------------------------
    //   updatePlayMode
    //---------------------------------------------------------

    void MuseScore::updatePlayMode()
          {
          bool enable = false;
          if (cs) {
                enable = cs->audio() != 0;
                playMode->setCurrentIndex(int(cs->playMode()));
                }
          playMode->setVisible(enable);
          }

    //---------------------------------------------------------
    //   closeScore
    //---------------------------------------------------------

    void MuseScore::closeScore(Score* score)
          {
          // Let's compute maximum count of ports in remaining scores
          if (seq)
                seq->recomputeMaxMidiOutPort();
          removeTab(scoreList.indexOf(score->masterScore()));
          }

    //---------------------------------------------------------
    //   noteTooShortForTupletDialog
    //---------------------------------------------------------

    void MuseScore::noteTooShortForTupletDialog()
          {
          QMessageBox::warning(this, tr("Warning"),
            tr("Cannot create tuplet: Note value is too short")
            );
          }

    //---------------------------------------------------------
    //   instrumentChanged
    //---------------------------------------------------------

    void MuseScore::instrumentChanged()
          {
          if (mixer)
                mixer->updateAll(cs->masterScore());
          }

    //---------------------------------------------------------
    //   mixerPreferencesChanged
    //---------------------------------------------------------

    void MuseScore::mixerPreferencesChanged(bool showMidiControls)
          {
          if (mixer)
                mixer->midiPrefsChanged(showMidiControls);
          }

    //---------------------------------------------------------
    //   changeScore
    //    switch current score
    //    step = 1    switch to next score
    //    step = -1   switch to previous score
    //---------------------------------------------------------

    void MuseScore::changeScore(int step)
          {
          int index = tab1->currentIndex();
          int n     = tab1->count();
          if (n == 1)
                return;
          index += step;
          if (index >= n)
                index = 0;
          if (index < 0)
                index = n - 1;
          setCurrentScoreView(index);
          }

    //---------------------------------------------------------
    //   switchLayoutMode
    //    val is index in QComboBox viewModeCombo
    //---------------------------------------------------------

    void MuseScore::switchLayoutMode(int val)
          {
          if (!cs)
                return;
          switchLayoutMode(static_cast<LayoutMode>(viewModeCombo->itemData(val).toInt()));
          }

    void MuseScore::switchLayoutMode(LayoutMode mode)
          {
          // find a measure to use as reference, if possible
          QRectF view = cv->toLogical(QRect(0.0, 0.0, width(), height()));
          Measure* m = cs->firstMeasure();
          while (m && !view.intersects(m->canvasBoundingRect()))
                m = m->nextMeasureMM();

          cv->loopUpdate(getAction("loop")->isChecked());

          if (mode != cs->layoutMode()) {
                cs->setLayoutMode(mode);
                cs->doLayout();
                }

          // adjustCanvasPosition often tries to preserve Y position
          // but this doesn't make sense when switching modes
          // also, better positioning is usually achieved if you start from the top
          // and there is really no better place to position canvas if we were all the way off page previously
          cv->pageTop();
          if (m && m != cs->firstMeasure())
                cv->adjustCanvasPosition(m, false);
          }

    //---------------------------------------------------------
    //   showDrumTools
    //---------------------------------------------------------

    void MuseScore::showDrumTools(const Drumset* drumset, Staff* staff)
          {
          if (drumset) {
                if (!_drumTools) {
                      _drumTools = new DrumTools(this);
                      addDockWidget(Qt::BottomDockWidgetArea, _drumTools);
                      }
                if (timelineScrollArea())
                      splitDockWidget(_drumTools, timelineScrollArea(), Qt::Vertical);
                _drumTools->setDrumset(cs, staff, drumset);
                _drumTools->show();
                }
          else {
                if (_drumTools)
                      _drumTools->hide();
                }
          }

    //---------------------------------------------------------
    //   updateDrumTools
    //---------------------------------------------------------

    void MuseScore::updateDrumTools(const Drumset* ds)
          {
          if (_drumTools)
                _drumTools->updateDrumset(ds);
          }

    //---------------------------------------------------------
    //   endSearch
    //---------------------------------------------------------

    void MuseScore::endSearch()
          {
          _searchDialog->hide();
          if (cv)
                cv->setFocus();
          }

    //---------------------------------------------------------
    //   showSearchDialog
    //---------------------------------------------------------

    void MuseScore::showSearchDialog()
          {
          if (_searchDialog == 0) {
                _searchDialog = new QWidget;
                _searchDialog->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
                QHBoxLayout* searchDialogLayout = new QHBoxLayout;
                _searchDialog->setLayout(searchDialogLayout);
                layout->insertWidget(2, _searchDialog);

                QToolButton* searchExit = new QToolButton;
                searchExit->setAutoRaise(true);
                searchExit->setIcon(*icons[int(Icons::close_ICON)]);
                connect(searchExit, SIGNAL(clicked()), SLOT(endSearch()));
                searchDialogLayout->addWidget(searchExit);
                searchDialogLayout->addSpacing(10);

                searchDialogLayout->addWidget(new QLabel(tr("Go To: ")));

                searchCombo = new SearchComboBox;
                searchDialogLayout->addWidget(searchCombo);

                searchDialogLayout->addStretch(10);
                _searchDialog->hide();

                qDebug("Line edit %p", searchCombo->lineEdit());

                connect(searchCombo->lineEdit(), SIGNAL(returnPressed()), SLOT(endSearch()));
                }

          searchCombo->clearEditText();
          searchCombo->setFocus();
          _searchDialog->show();
          }

    #ifndef SCRIPT_INTERFACE
    void MuseScore::pluginTriggered(int) {}
    void MuseScore::loadPlugins() {}
    bool MuseScore::loadPlugin(const QString&) { return false;}
    void MuseScore::unloadPlugins() {}
    #endif

    void MuseScore::saveGeometry(QWidget const*const qw)
          {
          QSettings settings;
          QString objectName = qw->objectName();
          Q_ASSERT(!objectName.isEmpty());
          settings.beginGroup("Geometries");
          settings.setValue(objectName, qw->saveGeometry());
          settings.endGroup();
          }

    void MuseScore::restoreGeometry(QWidget *const qw)
          {
          if (!useFactorySettings) {
                QSettings settings;
                QString objectName = qw->objectName();
                Q_ASSERT(!objectName.isEmpty());
                settings.beginGroup("Geometries");
                qw->restoreGeometry(settings.value(objectName).toByteArray());
                settings.endGroup();
                }
          }

    //---------------------------------------------------------
    //   recentScores
    //    return a list of recent scores
    //    omit loaded scores
    //---------------------------------------------------------

    QFileInfoList MuseScore::recentScores() const
          {
          QFileInfoList fil;
          for (const QString& s : _recentScores) {
                if (s.isEmpty())
                      continue;
                QString data(s);
                QFileInfo fi(s);
                bool alreadyLoaded = false;
                QString fp = fi.canonicalFilePath();
                for (Score* s : mscore->scores()) {
                      if ((s->masterScore()->fileInfo()->canonicalFilePath() == fp) || (s->importedFilePath() == fp)) {
                            alreadyLoaded = true;
                            break;
                            }
                      }
                if (!alreadyLoaded && fi.exists())
                      fil.append(fi);
                }
          return fil;
          }

    //---------------------------------------------------------
    //   createPopupMenu
    //---------------------------------------------------------

    QMenu* MuseScore::createPopupMenu()
          {
          QMenu* m = QMainWindow::createPopupMenu();
          QList<QAction*> al = m->actions();
          for (QAction* a : al) {
                // textTool visibility is handled differentlyr
                if (_textTools && a->text() == _textTools->windowTitle())
                      m->removeAction(a);
                }
          return m;
          }

    //---------------------------------------------------------
    //   synthesizerState
    //---------------------------------------------------------

    SynthesizerState MuseScore::synthesizerState()
          {
          SynthesizerState state;
          return synti ? synti->state() : state;
          }

    //---------------------------------------------------------
    //   canSaveMp3
    //---------------------------------------------------------

    bool MuseScore::canSaveMp3()
          {
    #ifndef USE_LAME
          return false;
    #else
          MP3Exporter exporter;
          if (!exporter.loadLibrary(MP3Exporter::AskUser::NO)) {
                qDebug("Could not open MP3 encoding library!");
                return false;
                }

          if (!exporter.validLibraryLoaded()) {
                qDebug("Not a valid or supported MP3 encoding library!");
                return false;
                }
          return true;
    #endif
          }

    //---------------------------------------------------------
    //   saveMp3
    //---------------------------------------------------------

    bool MuseScore::saveMp3(Score* score, const QString& name)
          {
    #ifndef USE_LAME
          return false;
    #else
          EventMap events;
          score->renderMidi(&events);
          if(events.size() == 0)
                return false;

          MP3Exporter exporter;
          if (!exporter.loadLibrary(MP3Exporter::AskUser::MAYBE)) {
                QSettings settings;
                settings.setValue("/Export/lameMP3LibPath", "");
                if(!MScore::noGui)
                      QMessageBox::warning(0,
                                   tr("Error Opening LAME library"),
                                   tr("Could not open MP3 encoding library!"),
                                   QString::null, QString::null);
                qDebug("Could not open MP3 encoding library!");
                return false;
                }

          if (!exporter.validLibraryLoaded()) {
                QSettings settings;
                settings.setValue("/Export/lameMP3LibPath", "");
                if(!MScore::noGui)
                      QMessageBox::warning(0,
                                   tr("Error Opening LAME library"),
                                   tr("Not a valid or supported MP3 encoding library!"),
                                   QString::null, QString::null);
                qDebug("Not a valid or supported MP3 encoding library!");
                return false;
                }

          // Retrieve preferences
    //      int highrate = 48000;
    //      int lowrate = 8000;
    //      int bitrate = 64;
    //      int brate = 128;
    //      int rmode = MODE_CBR;
    //      int vmode = ROUTINE_FAST;
    //      int cmode = CHANNEL_STEREO;

          int channels = 2;

          int oldSampleRate = MScore::sampleRate;
          int sampleRate = preferences.exportAudioSampleRate;
          exporter.setBitrate(preferences.exportMp3BitRate);

          int inSamples = exporter.initializeStream(channels, sampleRate);
          if (inSamples < 0) {
                if (!MScore::noGui) {
                      QMessageBox::warning(0, tr("Encoding Error"),
                         tr("Unable to initialize MP3 stream"),
                         QString::null, QString::null);
                      }
                qDebug("Unable to initialize MP3 stream");
                MScore::sampleRate = oldSampleRate;
                return false;
                }

          QFile file(name);
          if (!file.open(QIODevice::WriteOnly)) {
                if (!MScore::noGui) {
                      QMessageBox::warning(0,
                         tr("Encoding Error"),
                         tr("Unable to open target file for writing"),
                         QString::null, QString::null);
                      }
                MScore::sampleRate = oldSampleRate;
                return false;
                }

          int bufferSize   = exporter.getOutBufferSize();
          uchar* bufferOut = new uchar[bufferSize];
          MasterSynthesizer* synti = synthesizerFactory();
          synti->init();
          synti->setSampleRate(sampleRate);
          if (MScore::noGui) { // use score settings if possible
                bool r = synti->setState(score->synthesizerState());
                if (!r)
                      synti->init();
                }
          else { // use current synth settings
                bool r = synti->setState(mscore->synthesizerState());
                if (!r)
                      synti->init();
                }

          MScore::sampleRate = sampleRate;

          QProgressDialog progress(this);
          progress.setWindowFlags(Qt::WindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowTitleHint));
          progress.setWindowModality(Qt::ApplicationModal);
          //progress.setCancelButton(0);
          progress.setCancelButtonText(tr("Cancel"));
          progress.setLabelText(tr("Exporting..."));
          if (!MScore::noGui)
                progress.show();

          static const int FRAMES = 512;
          float bufferL[FRAMES];
          float bufferR[FRAMES];

          float  peak = 0.0;
          double gain = 1.0;
          EventMap::const_iterator endPos = events.cend();
          --endPos;
          const int et = (score->utick2utime(endPos->first) + 1) * MScore::sampleRate;
          const int maxEndTime = (score->utick2utime(endPos->first) + 3) * MScore::sampleRate;
          progress.setRange(0, et);

          for (int pass = 0; pass < 2; ++pass) {
                EventMap::const_iterator playPos;
                playPos = events.cbegin();
                synti->allSoundsOff(-1);

                //
                // init instruments
                //
                foreach(Part* part, score->parts()) {
                      const InstrumentList* il = part->instruments();
                      for(auto i = il->begin(); i!= il->end(); i++) {
                            foreach(const Channel* a, i->second->channel()) {
                                  a->updateInitList();
                                  foreach(MidiCoreEvent e, a->init) {
                                        if (e.type() == ME_INVALID)
                                              continue;
                                        e.setChannel(a->channel);
                                        int syntiIdx= synti->index(score->masterScore()->midiMapping(a->channel)->articulation->synti);
                                        synti->play(e, syntiIdx);
                                        }
                                  }
                            }
                      }

                int playTime = 0.0;

                for (;;) {
                      unsigned frames = FRAMES;
                      float max = 0;
                      //
                      // collect events for one segment
                      //
                      memset(bufferL, 0, sizeof(float) * FRAMES);
                      memset(bufferR, 0, sizeof(float) * FRAMES);
                      double endTime = playTime + frames;

                      float* l = bufferL;
                      float* r = bufferR;

                      for (; playPos != events.cend(); ++playPos) {
                            double f = score->utick2utime(playPos->first) * MScore::sampleRate;
                            if (f >= endTime)
                                  break;
                            int n = f - playTime;
                            if (n) {
                                  float bu[n * 2];
                                  memset(bu, 0, sizeof(float) * 2 * n);

                                  synti->process(n, bu);
                                  float* sp = bu;
                                  for (int i = 0; i < n; ++i) {
                                        *l++ = *sp++;
                                        *r++ = *sp++;
                                        }
                                  playTime  += n;
                                  frames    -= n;
                                  }
                            const NPlayEvent& e = playPos->second;
                            if (e.isChannelEvent()) {
                                  int channelIdx = e.channel();
                                  Channel* c = score->masterScore()->midiMapping(channelIdx)->articulation;
                                  if (!c->mute) {
                                        synti->play(e, synti->index(c->synti));
                                        }
                                  }
                            }
                      if (frames) {
                            float bu[frames * 2];
                            memset(bu, 0, sizeof(float) * 2 * frames);
                            synti->process(frames, bu);
                            float* sp = bu;
                            for (unsigned i = 0; i < frames; ++i) {
                                  *l++ = *sp++;
                                  *r++ = *sp++;
                                  }
                            playTime += frames;
                            }

                      if (pass == 1) {
                            for (int i = 0; i < FRAMES; ++i) {
                                  max = qMax(max, qAbs(bufferL[i]));
                                  max = qMax(max, qAbs(bufferR[i]));
                                  bufferL[i] *= gain;
                                  bufferR[i] *= gain;
                                  }
                            long bytes;
                            if (FRAMES < inSamples)
                                  bytes = exporter.encodeRemainder(bufferL, bufferR,  FRAMES , bufferOut);
                            else
                                  bytes = exporter.encodeBuffer(bufferL, bufferR, bufferOut);
                            if (bytes < 0) {
                                  if (MScore::noGui)
                                        qDebug("exportmp3: error from encoder: %ld", bytes);
                                  else
                                        QMessageBox::warning(0,
                                           tr("Encoding Error"),
                                           tr("Error %1 returned from MP3 encoder").arg(bytes),
                                           QString::null, QString::null);
                                  break;
                                  }
                            else
                                  file.write((char*)bufferOut, bytes);
                            }
                      else {
                            for (int i = 0; i < FRAMES; ++i) {
                                  max = qMax(max, qAbs(bufferL[i]));
                                  max = qMax(max, qAbs(bufferR[i]));
                                  peak = qMax(peak, qAbs(bufferL[i]));
                                  peak = qMax(peak, qAbs(bufferR[i]));
                                  }
                            }
                      playTime = endTime;
                      if (!MScore::noGui) {
                            if (progress.wasCanceled())
                                  break;
                            progress.setValue((pass * et + playTime) / 2);
                            qApp->processEvents();
                            }
                      if (playTime >= et)
                            synti->allNotesOff(-1);
                      // create sound until the sound decays
                      if (playTime >= et && max * peak < 0.000001)
                            break;
                      // hard limit
                      if (playTime > maxEndTime)
                            break;
                      }
                if (progress.wasCanceled())
                      break;
                if (pass == 0 && peak == 0.0) {
                      qDebug("song is empty");
                      break;
                      }
                gain = 0.99 / peak;
                }

          long bytes = exporter.finishStream(bufferOut);
          if (bytes > 0L)
                file.write((char*)bufferOut, bytes);

          bool wasCanceled = progress.wasCanceled();
          progress.close();
          delete synti;
          delete[] bufferOut;
          file.close();
          if (wasCanceled)
                file.remove();
          MScore::sampleRate = oldSampleRate;
          return true;
    #endif
          }
    }

    using namespace Ms;

    //---------------------------------------------------------
    //   main
    //---------------------------------------------------------

    int main(int argc, char* av[])
          {
    #ifndef NDEBUG
          qSetMessagePattern("%{file}:%{function}: %{message}");
          Ms::checkStyles();
    #endif

          QApplication::setDesktopSettingsAware(true);
    #if defined(QT_DEBUG) && defined(Q_OS_WIN)
          qInstallMessageHandler(mscoreMessageHandler);
    #endif

          QFile f(":/revision.h");
          f.open(QIODevice::ReadOnly);
          revision = QString(f.readAll()).trimmed();
          f.close();

          const char* appName;
          const char* appName2;
          if (MuseScore::unstable()) {
                appName2 = "mscore-dev3";
                appName  = "MuseScoreDevelopment";
                }
          else {
                appName2 = "mscore3";
                appName  = "MuseScore3";
                }
          MuseScoreApplication* app = new MuseScoreApplication(appName2, argc, av);
          QCoreApplication::setApplicationName(appName);

          QCoreApplication::setOrganizationName("MuseScore");
          QCoreApplication::setOrganizationDomain("musescore.org");
          QCoreApplication::setApplicationVersion(VERSION);

          QAccessible::installFactory(AccessibleScoreView::ScoreViewFactory);
          QAccessible::installFactory(AccessibleSearchBox::SearchBoxFactory);
          QAccessible::installFactory(Awl::AccessibleAbstractSlider::AbstractSliderFactory);

          Q_INIT_RESOURCE(zita);

    #ifndef Q_OS_MAC
          QSettings::setDefaultFormat(QSettings::IniFormat);
    #endif

          QCommandLineParser parser;

          parser.addHelpOption(); // -?, -h, --help
          parser.addVersionOption(); // -v, --version

        //parser.addOption(QCommandLineOption({"v", "version"}, "Print version")); // see above
          parser.addOption(QCommandLineOption(      "long-version", "Print detailed version information"));
          parser.addOption(QCommandLineOption({"d", "debug"}, "Debug mode"));
          parser.addOption(QCommandLineOption({"L", "layout-debug"}, "Layout debug mode"));
          parser.addOption(QCommandLineOption({"s", "no-synthesizer"}, "No internal synthesizer"));
          parser.addOption(QCommandLineOption({"m", "no-midi"}, "No MIDI"));
          parser.addOption(QCommandLineOption({"a", "use-audio"}, "Use audio driver: jack, alsa, pulse, or portaudio", "driver"));
          parser.addOption(QCommandLineOption({"n", "new-score"}, "Start with new score"));
          parser.addOption(QCommandLineOption({"I", "dump-midi-in"}, "Dump midi input"));
          parser.addOption(QCommandLineOption({"O", "dump-midi-out"}, "Dump midi output"));
          parser.addOption(QCommandLineOption({"o", "export-to"}, "Export to 'file'. Format depends on file's extension", "file"));
          parser.addOption(QCommandLineOption({"r", "image-resolution"}, "Used with '-o <file>.png'. Set output resolution for image export", "DPI"));
          parser.addOption(QCommandLineOption({"T", "trim-image"}, "Used with '-o <file>.png' and '-o <file.svg>'. Trim exported image with specified margin (in pixels)", "margin"));
          parser.addOption(QCommandLineOption({"x", "gui-scaling"}, "Set scaling factor for GUI elements", "factor"));
          parser.addOption(QCommandLineOption({"D", "monitor-resolution"}, "Specify monitor resolution", "DPI"));
          parser.addOption(QCommandLineOption({"S", "style"}, "Load style file", "style"));
          parser.addOption(QCommandLineOption({"p", "plugin"}, "Execute named plugin", "name"));
          parser.addOption(QCommandLineOption(      "template-mode", "Save template mode, no page size"));
          parser.addOption(QCommandLineOption({"F", "factory-settings"}, "Use factory settings"));
          parser.addOption(QCommandLineOption({"R", "revert-settings"}, "Revert to default preferences"));
          parser.addOption(QCommandLineOption({"i", "load-icons"}, "Load icons from INSTALLPATH/icons"));
          parser.addOption(QCommandLineOption({"j", "job"}, "Process a conversion job", "file"));
          parser.addOption(QCommandLineOption({"e", "experimental"}, "Enable experimental features"));
          parser.addOption(QCommandLineOption({"c", "config-folder"}, "Override configuration and settings folder", "dir"));
          parser.addOption(QCommandLineOption({"t", "test-mode"}, "Set test mode flag for all files"));
          parser.addOption(QCommandLineOption({"M", "midi-operations"}, "Specify MIDI import operations file", "file"));
          parser.addOption(QCommandLineOption({"w", "no-webview"}, "No web view in start center"));
          parser.addOption(QCommandLineOption({"P", "export-score-parts"}, "Used with '-o <file>.pdf', export score and parts"));
          parser.addOption(QCommandLineOption(      "no-fallback-font", "Don't use Bravura as fallback musical font"));
          parser.addOption(QCommandLineOption({"f", "force"}, "Used with '-o <file>', ignore warnings reg. score being corrupted or from wrong version"));
          parser.addOption(QCommandLineOption({"b", "bitrate"}, "Used with '-o <file>.mp3', sets bitrate", "bitrate"));

          parser.addPositionalArgument("scorefiles", "The files to open", "[scorefile...]");

          parser.process(QCoreApplication::arguments());

        //if (parser.isSet("v")) parser.showVersion(); // a) needs Qt >= 5.4 , b) instead we use addVersionOption()
          if (parser.isSet("long-version")) {
                printVersion("MuseScore");
                return EXIT_SUCCESS;
                }
          MScore::debugMode = parser.isSet("d");
          MScore::noHorizontalStretch = MScore::noVerticalStretch = parser.isSet("L");
          noSeq = parser.isSet("s");
          noMidi = parser.isSet("m");
          if (parser.isSet("a")) {
                audioDriver = parser.value("a");
                if (audioDriver.isEmpty())
                      parser.showHelp(EXIT_FAILURE);
                }
          startWithNewScore = parser.isSet("n");
          externalIcons = parser.isSet("i");
          midiInputTrace = parser.isSet("I");
          midiOutputTrace = parser.isSet("O");
          MScore::useFallbackFont = !parser.isSet("no-fallback-font");

          if ((converterMode = parser.isSet("o"))) {
                MScore::noGui = true;
                outFileName = parser.value("o");
                if (outFileName.isEmpty())
                      parser.showHelp(EXIT_FAILURE);
                }
          if ((processJob = parser.isSet("j"))) {
                MScore::noGui = true;
                converterMode = true;
                jsonFileName = parser.value("j");
                if (jsonFileName.isEmpty()) {
                      fprintf(stderr, "json file name missing\n");
                      parser.showHelp(EXIT_FAILURE);
                      }
                }
          if ((pluginMode = parser.isSet("p"))) {
                MScore::noGui = true;
                pluginName = parser.value("p");
                if (pluginName.isEmpty())
                      parser.showHelp(EXIT_FAILURE);
                }
          MScore::saveTemplateMode = parser.isSet("template-mode");
          if (parser.isSet("r")) {
                QString temp = parser.value("r");
                if (temp.isEmpty())
                       parser.showHelp(EXIT_FAILURE);
                converterDpi = temp.toDouble();
                }
          if (parser.isSet("T")) {
                QString temp = parser.value("T");
                if (temp.isEmpty())
                       parser.showHelp(EXIT_FAILURE);
                bool ok = false;
                trimMargin = temp.toInt(&ok);
                if (!ok)
                      trimMargin = -1;
               }
          if (parser.isSet("x")) {
                QString temp = parser.value("x");
                if (temp.isEmpty())
                       parser.showHelp(EXIT_FAILURE);
                bool ok = false;
                guiScaling = temp.toDouble(&ok);
                if (!ok)
                      guiScaling = 0.0;
                }
          if (parser.isSet("D")) {
                QString temp = parser.value("D");
                if (temp.isEmpty())
                       parser.showHelp(EXIT_FAILURE);
                bool ok = 0.0;
                userDPI = temp.toDouble(&ok);
                if (!ok)
                      userDPI = 0.0;
                }
          if (parser.isSet("S")) {
                styleFile = parser.value("S");
                if (styleFile.isEmpty())
                      parser.showHelp(EXIT_FAILURE);
                }
          useFactorySettings = parser.isSet("F");
          deletePreferences = (useFactorySettings || parser.isSet("R"));
          enableExperimental = parser.isSet("e");
          if (parser.isSet("c")) {
                QString path = parser.value("c");
                if (path.isEmpty())
                      parser.showHelp(EXIT_FAILURE);
                QDir dir;
                if (dir.exists(path)) {
                      QSettings::setPath(QSettings::IniFormat, QSettings::UserScope, path);
                      QSettings::setPath(QSettings::IniFormat, QSettings::SystemScope, path);
                      dataPath = path;
                      }
                }
          MScore::testMode = parser.isSet("t");
          if (parser.isSet("M")) {
                QString temp = parser.value("M");
                if (temp.isEmpty())
                      parser.showHelp(EXIT_FAILURE);
                preferences.midiImportOperations.setOperationsFile(temp);
                }
          noWebView = parser.isSet("w");
          exportScoreParts = parser.isSet("export-score-parts");
          if (exportScoreParts && !converterMode)
                parser.showHelp(EXIT_FAILURE);
          ignoreWarnings = parser.isSet("f");
          if (parser.isSet("b")) {
                QString temp = parser.value("b");
                if (temp.isEmpty())
                       parser.showHelp(EXIT_FAILURE);
                bool ok = false;
                preferences.exportMp3BitRate = temp.toInt(&ok);
                if (!ok)
                      preferences.exportMp3BitRate = 128;
               }

          QStringList argv = parser.positionalArguments();

          mscoreGlobalShare = getSharePath();
          iconPath = externalIcons ? mscoreGlobalShare + QString("icons/") :  QString(":/data/icons/");

          if (!converterMode && !pluginMode) {
                if (!argv.isEmpty()) {
                      int ok = true;
                      for (const QString& message : argv) {
                            QFileInfo fi(message);
                            if (!app->sendMessage(fi.absoluteFilePath())) {
                                  ok = false;
                                  break;
                                  }
                            }
                      if (ok)
                            return 0;
                      }
                else
                      if (app->sendMessage(QString("")))
                          return 0;
                }
          if (dataPath.isEmpty())
                dataPath = QStandardPaths::writableLocation(QStandardPaths::DataLocation);

          if (deletePreferences) {
                QDir(dataPath).removeRecursively();
                QSettings settings;
                QFile::remove(settings.fileName() + ".lock"); //forcibly remove lock
                QFile::remove(settings.fileName());
                settings.clear();
                }

          // create local plugin directory
          // if not already there:
          QDir().mkpath(dataPath + "/plugins");

          if (MScore::debugMode)
                qDebug("global share: <%s>", qPrintable(mscoreGlobalShare));

          // set translator before preferences are read to get
          //    translations for all shortcuts
          //
          if (useFactorySettings)
                localeName = "system";
          else {
                QSettings s;
                localeName = s.value("language", "system").toString();
                }

          setMscoreLocale(localeName);

          Shortcut::init();
          preferences.init();

          QNetworkProxyFactory::setUseSystemConfiguration(true);

          MScore::init();         // initialize libmscore

          // initialize current page size from default printer
    #ifndef QT_NO_PRINTER
          if (!MScore::testMode) {
                QPrinter p;
                if (p.isValid()) {
                      qDebug("set paper size from default printer");
                      QRectF psf = p.paperRect(QPrinter::Inch);
                      MScore::defaultStyle().set(StyleIdx::pageWidth,  psf.width());
                      MScore::defaultStyle().set(StyleIdx::pageHeight, psf.height());
                      MScore::defaultStyle().set(StyleIdx::pagePrintableWidth, psf.width()-20.0/INCH);
                      }
                }
    #endif

    #ifdef SCRIPT_INTERFACE
          if (-1 == qmlRegisterType<QmlPlugin>  ("MuseScore", 3, 0, "MuseScore"))
                qDebug("qmlRegisterType failed: MuseScore");
    #endif
          if (MScore::debugMode) {
                qDebug("DPI %f", DPI);

                QScreen* screen      = QGuiApplication::primaryScreen();
                qDebug() << "Information for screen:" << screen->name();
                qDebug() << "  Available geometry:" << screen->availableGeometry().x() << screen->availableGeometry().y() << screen->availableGeometry().width() << "x" << screen->availableGeometry().height();
                qDebug() << "  Available size:" << screen->availableSize().width() << "x" << screen->availableSize().height();
                qDebug() << "  Available virtual geometry:" << screen->availableVirtualGeometry().x() << screen->availableVirtualGeometry().y() << screen->availableVirtualGeometry().width() << "x" << screen->availableVirtualGeometry().height();
                qDebug() << "  Available virtual size:" << screen->availableVirtualSize().width() << "x" << screen->availableVirtualSize().height();
                qDebug() << "  Depth:" << screen->depth() << "bits";
                qDebug() << "  Geometry:" << screen->geometry().x() << screen->geometry().y() << screen->geometry().width() << "x" << screen->geometry().height();
                qDebug() << "  Logical DPI:" << screen->logicalDotsPerInch();
                qDebug() << "  Logical DPI X:" << screen->logicalDotsPerInchX();
                qDebug() << "  Logical DPI Y:" << screen->logicalDotsPerInchY();
                qDebug() << "  Physical DPI:" << screen->physicalDotsPerInch();
                qDebug() << "  Physical DPI X:" << screen->physicalDotsPerInchX();
                qDebug() << "  Physical DPI Y:" << screen->physicalDotsPerInchY();
                qDebug() << "  Physical size:" << screen->physicalSize().width() << "x" << screen->physicalSize().height() << "mm";
                qDebug() << "  Refresh rate:" << screen->refreshRate() << "Hz";
                qDebug() << "  Size:" << screen->size().width() << "x" << screen->size().height();
                qDebug() << "  Virtual geometry:" << screen->virtualGeometry().x() << screen->virtualGeometry().y() << screen->virtualGeometry().width() << "x" << screen->virtualGeometry().height();
                qDebug() << "  Virtual size:" << screen->virtualSize().width() << "x" << screen->virtualSize().height();
                }

          if (!(useFactorySettings || MScore::testMode))
                preferences.read();

          if (!MScore::testMode)
                preferences.readDefaultStyle();

          if (converterDpi == 0)
                converterDpi = preferences.pngResolution;

          QSplashScreen* sc = 0;
          QTimer* stimer = 0;
          if (!MScore::noGui && preferences.showSplashScreen) {
                QPixmap pm(":/data/splash.png");
                sc = new QSplashScreen(pm);
                sc->setWindowTitle(QString("MuseScore Startup"));
    #ifdef Q_OS_MAC // to have session dialog on top of splashscreen on mac
                sc->setWindowFlags(Qt::FramelessWindowHint);
    #endif
                // show splash screen for 5 sec
                stimer = new QTimer(0);
                qApp->connect(stimer, SIGNAL(timeout()), sc, SLOT(close()));
                stimer->start(5000);
                sc->show();
                qApp->processEvents();
                }

          if (!converterMode && !pluginMode) {

                // set UI Theme
                QApplication::setStyle(QStyleFactory::create("Fusion"));

                QString wd      = QString("%1/%2").arg(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)).arg(QCoreApplication::applicationName());
                // set UI Color Palette
                QPalette p(QApplication::palette());
                QString jsonPaletteFilename = preferences.isThemeDark() ? "palette_dark_fusion.json" : "palette_light_fusion.json";;
                QFile jsonPalette(QString(":/themes/%1").arg(jsonPaletteFilename));
                // read from Documents TODO: remove this
                if (QFile::exists(QString("%1/%2").arg(wd, "ms_palette.json")))
                      jsonPalette.setFileName(QString("%1/%2").arg(wd, "ms_palette.json"));
                if (jsonPalette.open(QFile::ReadOnly | QFile::Text)) {
                      QJsonDocument d = QJsonDocument::fromJson(jsonPalette.readAll());
                      QJsonObject o = d.object();
                      QMetaEnum metaEnum = QMetaEnum::fromType<QPalette::ColorRole>();
                      for (int i = 0; i < metaEnum.keyCount(); ++i) {
                            QJsonValue v = o.value(metaEnum.valueToKey(i));
                            if (!v.isUndefined())
                                  p.setColor(static_cast<QPalette::ColorRole>(metaEnum.value(i)), QColor(v.toString()));
                            }
                      }
                QApplication::setPalette(p);

                // set UI Style
                QString css;
                QString styleFilename = preferences.isThemeDark() ? "style_dark_fusion.css" : "style_light_fusion.css";
                QFile fstyle(QString(":/themes/%1").arg(styleFilename));
                // read from Documents TODO: remove this
                if (QFile::exists(QString("%1/%2").arg(wd, "ms_style.css")))
                      fstyle.setFileName(QString("%1/%2").arg(wd, "ms_style.css"));
                if (fstyle.open(QFile::ReadOnly | QFile::Text)) {
                      QTextStream in(&fstyle);
                      css = in.readAll();
                      }
                css.replace("$voice1-bgcolor", MScore::selectColor[0].name(QColor::HexRgb));
                css.replace("$voice2-bgcolor", MScore::selectColor[1].name(QColor::HexRgb));
                css.replace("$voice3-bgcolor", MScore::selectColor[2].name(QColor::HexRgb));
                css.replace("$voice4-bgcolor", MScore::selectColor[3].name(QColor::HexRgb));
                qApp->setStyleSheet(css);

                qApp->setAttribute(Qt::AA_UseHighDpiPixmaps);
                }
          else
                noSeq = true;

          genIcons();

          // Do not create sequencer and audio drivers if run with '-s'
          if (!noSeq) {
                seq            = new Seq();
                MScore::seq    = seq;
                Driver* driver = driverFactory(seq, audioDriver);
                synti          = synthesizerFactory();
                if (driver) {
                      MScore::sampleRate = driver->sampleRate();
                      synti->setSampleRate(MScore::sampleRate);
                      synti->init();

                      seq->setDriver(driver);
                      }
                else {
                      // Do not delete the sequencer If we can't load driver.
                      // Allow user to select the working driver later.
                      MScore::sampleRate = 44100;  // Would be changed when user changes driver
                      synti->setSampleRate(MScore::sampleRate);
                      synti->init();
                      }
                seq->setMasterSynthesizer(synti);
                }
          else {
                seq         = 0;
                MScore::seq = 0;
                }
    //---
          //
          // avoid font problems by overriding the environment
          //    fall back to "C" locale
          //

          //#ifndef Q_OS_WIN
          //setenv("LANG", "C", 1);
          //#endif
          //QLocale::setDefault(QLocale(QLocale::C));

          if (MScore::debugMode) {
                QStringList sl(QCoreApplication::libraryPaths());
                foreach(const QString& s, sl)
                      qDebug("LibraryPath: <%s>", qPrintable(s));
                }

          // rastral size of font is 20pt = 20/72 inch = 20*DPI/72 dots
          //   staff has 5 lines = 4 * _spatium
          //   _spatium    = SPATIUM20;     // 20.0 / 72.0 * DPI / 4.0;

          if (!MScore::noGui) {
    #ifndef Q_OS_MAC
                qApp->setWindowIcon(*icons[int(Icons::window_ICON)]);
    #endif
                Workspace::initWorkspace();
                }

          mscore = new MuseScore();
          // create a score for internal use
          gscore = new MasterScore();
          gscore->setMovements(new Movements());
          gscore->setStyle(MScore::baseStyle());

          gscore->style().set(StyleIdx::MusicalTextFont, QString("Bravura Text"));
          ScoreFont* scoreFont = ScoreFont::fontFactory("Bravura");
          gscore->setScoreFont(scoreFont);
          gscore->setNoteHeadWidth(scoreFont->width(SymId::noteheadBlack, gscore->spatium()) / SPATIUM20);

          if (!noSeq) {
                if (!seq->init())
                      qDebug("sequencer init failed");
                }

          //read languages list
          mscore->readLanguages(mscoreGlobalShare + "locale/languages.xml");

          if (!MScore::noGui) {
                QSettings s;
                if (!s.contains("firstStart")) {
                      StartupWizard* sw = new StartupWizard;
                      sw->exec();
                      s.setValue("firstStart", false);
                      s.setValue("keyboardLayout", sw->keyboardLayout());
                      s.setValue("language", sw->language());
                      setMscoreLocale(sw->language());
                      for (auto ws : Workspace::workspaces()) {
                            if (ws->name().compare(sw->workspace()) == 0) {
                                  mscore->changeWorkspace(ws);
                                  preferences.workspace = ws->name();
                                  mscore->getPaletteBox()->updateWorkspaces();
                                  }
                            }
                      delete sw;
                      }
                QString keyboardLayout = s.value("keyboardLayout").toString();
                StartupWizard::autoSelectShortcuts(keyboardLayout);
                }

          QApplication::instance()->installEventFilter(mscore);

          mscore->setRevision(revision);
          int files = 0;
          bool restoredSession = false;
          if (MScore::noGui) {
    #ifdef Q_OS_MAC
                // see issue #28706: Hangup in converter mode with MusicXML source
                qApp->processEvents();
    #endif
                exit(processNonGui(argv) ? 0 : EXIT_FAILURE);
                }
          else {
                mscore->readSettings();
                QObject::connect(qApp, SIGNAL(messageReceived(const QString&)),
                   mscore, SLOT(handleMessage(const QString&)));

                static_cast<QtSingleApplication*>(qApp)->setActivationWindow(mscore, false);
                // count filenames specified on the command line
                // these are the non-empty strings remaining in argv
                foreach(const QString& name, argv) {
                      if (!name.isEmpty())
                            ++files;
                      }
    #ifdef Q_WS_MAC
                // app->paths contains files requested to be loaded by OS X
                // append these to argv and update file count
                foreach(const QString& name, app->paths) {
                      if (!name.isEmpty()) {
                            argv << name;
                            ++files;
                            }
                      }
    #endif
                //
                // TODO: delete old session backups
                //
                restoredSession = mscore->restoreSession((preferences.sessionStart == SessionStart::LAST && (files == 0)));
                if (!restoredSession || files)
                      loadScores(argv);
                }

          errorMessage = new QErrorMessage(mscore);
          mscore->loadPlugins();
          mscore->writeSessionFile(false);

    #ifdef Q_OS_MAC
          // there's a bug in Qt showing the toolbar unified after switching showFullScreen(), showMaximized(),
          // showNormal()...
          mscore->setUnifiedTitleAndToolBarOnMac(false);
    #endif

          mscore->changeState(mscore->noScore() ? STATE_DISABLED : STATE_NORMAL);
          mscore->show();

          if (mscore->hasToCheckForUpdate())
                mscore->checkForUpdate();

          if (!scoresOnCommandline && preferences.showStartcenter && (!restoredSession || mscore->scores().size() == 0)) {
    #ifdef Q_OS_MAC
    // ugly, but on mac we get an event when a file is open.
    // We can't get the event when the startcenter is shown.
    // So we let the event loop run a bit before showing the start center.
                QTimer *timer = new QTimer();
                timer->setSingleShot(true);
                QObject::connect(timer, &QTimer::timeout, [=]() {
                      if (!scoresOnCommandline) {
                            getAction("startcenter")->setChecked(true);
                            mscore->showStartcenter(true);
                            }
                      timer->deleteLater();
                      } );
                timer->start(500);
    #else

                getAction("startcenter")->setChecked(true);
                mscore->showStartcenter(true);
    #endif
                }

          mscore->showPlayPanel(preferences.showPlayPanel);
          QSettings settings;
          if (settings.value("synthControlVisible", false).toBool())
                mscore->showSynthControl(true);
          if (settings.value("mixerVisible", false).toBool())
                mscore->showMixer(true);

          return qApp->exec();
          }

↑ V668 There is no sense in testing the 'pm' pointer against null, as the memory was allocated using the 'new' operator. The exception will be generated in the case of memory allocation error.

↑ V668 There is no sense in testing the 'pm' pointer against null, as the memory was allocated using the 'new' operator. The exception will be generated in the case of memory allocation error.

↑ V547 Expression '_timeline' is always true.

↑ V688 The 'settings' local variable possesses the same name as one of the class members, which can result in a confusion.

↑ V688 The 'settings' local variable possesses the same name as one of the class members, which can result in a confusion.