//============================================================================= // 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 #include "loginmanager.h" #include "uploadscoredialog.h" #include #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 "importmidi/importmidi_panel.h" #include "libmscore/chord.h" #include "mstyle/mstyle.h" #include "mstyle/mconfig.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 "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 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 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 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 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" }; 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 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); mainWindow->setStretchFactor(0, 1); mainWindow->setStretchFactor(1, 0); mainWindow->setSizes(QList({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({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-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")); menuFormat->addAction(getAction("page-settings")); 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); #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()) { 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("delete")->setEnabled(enable); getAction("select-similar-range")->setEnabled(selectionState == SelState::RANGE); if (pianorollEditor) pianorollEditor->changeSelection(selectionState); if (drumrollEditor) drumrollEditor->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 (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 (_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); } 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()) { QListul = 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 from <%s>", qPrintable(localeName), qPrintable(resourceDir)); if (!qtTranslator->load(QLatin1String("qt_") + localeName, resourceDir) && MScore::debugMode) qDebug("load translator 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 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(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(event)->file()); return true; #endif case QEvent::MouseMove: { QMouseEvent* me = static_cast(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(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(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() == "delete")) a->setEnabled(cs && cs->selection().state() != SelState::NONE); 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") 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 ol = menuBar()->children(); foreach(QObject* o, ol) { QMenu* menu = qobject_cast(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->postCmd("note-input"); 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. 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 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(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("%1") .arg(tr( "Visit %1www.musescore.org%2 for new versions and more information.\n" "Support MuseScore with your %3donation%4.\n\n" "Copyright © 1999-2017 Werner Schweer and Others.\n" "Published under the GNU General Public License.") .arg("") .arg("") .arg("") .arg("") .replace("\n","
"))); 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("%1
") .arg(tr( "MusicXML is an open file format for exchanging digital sheet music,\n" "supported by many applications. MusicXML is copyright © MakeMusic, Inc.\n" "All rights reserved. For more information, see: %1MusicXML.com%2.") .arg("") .arg("") .replace("\n","
"))); } //--------------------------------------------------------- // 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)) 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()) score->masterScore()->setName(name); 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 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 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 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 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 == "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 (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(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-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(); } } #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->widget()) : 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(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); } _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 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() { 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; } //--------------------------------------------------------- // saveMp3 //--------------------------------------------------------- bool MuseScore::saveMp3(Score* score, const QString& name) { 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; } } 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 .png'. Set output resolution for image export", "DPI")); parser.addOption(QCommandLineOption({"T", "trim-image"}, "Used with '-o .png' and '-o '. 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 .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 ', ignore warnings reg. score being corrupted or from wrong version")); parser.addOption(QCommandLineOption({"b", "bitrate"}, "Used with '-o .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 qmlRegisterType ("MuseScore", 2, 0, "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 if (preferences.isOxygen()) { MgStyleConfigData::animationsEnabled = preferences.animations; QApplication::setStyle(new MgStyle); } else 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 = "palette_light_fusion.json"; if (preferences.isThemeDark()) jsonPaletteFilename = preferences.isOxygen() ? "palette_dark_oxygen.json" : "palette_dark_fusion.json"; else jsonPaletteFilename = preferences.isOxygen() ? "palette_light_oxygen.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(); for (int i = 0; i < metaEnum.keyCount(); ++i) { QJsonValue v = o.value(metaEnum.valueToKey(i)); if (!v.isUndefined()) p.setColor(static_cast(metaEnum.value(i)), QColor(v.toString())); } } QApplication::setPalette(p); // set UI Style QString css; QString styleFilename("style_light_fusion.css"); if (preferences.isThemeDark()) styleFilename = preferences.isOxygen() ? "style_dark_oxygen.css" : "style_dark_fusion.css"; else styleFilename = preferences.isOxygen() ? "style_light_oxygen.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"); 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(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(); }