    //=============================================================================
    //  MuseScore
    //  Music Composition & Notation
    //
    //  Copyright (C) 2002-2011 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 "pluginCreator.h"
    #include "musescore.h"
    #include "qmlplugin.h"
    #include "icons.h"
    #include "helpBrowser.h"
    #include "preferences.h"
    #include "libmscore/score.h"

    namespace Ms {

    extern bool useFactorySettings;

    //static const char* states[] = {
    //      "S_INIT", "S_EMPTY", "S_CLEAN", "S_DIRTY"
    //      };

    //---------------------------------------------------------
    //   PluginCreator
    //---------------------------------------------------------

    PluginCreator::PluginCreator(QWidget* parent)
       : QMainWindow(parent)
          {
          state       = PCState::INIT;
          item        = 0;
          view        = 0;
          dock        = 0;
          manualDock  = 0;
          helpBrowser = 0;

          setObjectName("PluginCreator");
          setIconSize(QSize(preferences.iconWidth * guiScaling, preferences.iconHeight * guiScaling));

          setupUi(this);

          QToolBar* fileTools = addToolBar(tr("File Operations"));
          fileTools->setObjectName("FileOperations");

          actionNew->setIcon(*icons[int(Icons::fileNew_ICON)]);
          actionNew->setShortcut(QKeySequence(QKeySequence::New));
          fileTools->addAction(actionNew);

          actionOpen->setIcon(*icons[int(Icons::fileOpen_ICON)]);
          actionOpen->setShortcut(QKeySequence(QKeySequence::Open));
          fileTools->addAction(actionOpen);

          actionReload->setIcon(*icons[int(Icons::viewRefresh_ICON)]);
          fileTools->addAction(actionReload);

          actionSave->setIcon(*icons[int(Icons::fileSave_ICON)]);
          actionSave->setShortcut(QKeySequence(QKeySequence::Save));
          fileTools->addAction(actionSave);

          actionQuit->setShortcut(QKeySequence(QKeySequence::Close));

          actionManual->setIcon(QIcon(*icons[int(Icons::helpContents_ICON)]));
          actionManual->setShortcut(QKeySequence(QKeySequence::HelpContents));
          fileTools->addAction(actionManual);

          QToolBar* editTools = addToolBar(tr("Edit Operations"));
          editTools->setObjectName("EditOperations");
          actionUndo->setIcon(*icons[int(Icons::undo_ICON)]);
          actionUndo->setShortcut(QKeySequence(QKeySequence::Undo));
          actionRedo->setIcon(*icons[int(Icons::redo_ICON)]);
          actionRedo->setShortcut(QKeySequence(QKeySequence::Redo));
          if (qApp->layoutDirection() == Qt::LayoutDirection::LeftToRight) {
                editTools->addAction(actionUndo);
                editTools->addAction(actionRedo);
                }
          else {
                editTools->addAction(actionUndo);
                editTools->addAction(actionRedo);
                }
          actionUndo->setEnabled(false);
          actionRedo->setEnabled(false);

          log->setReadOnly(true);
          log->setMaximumBlockCount(1000);

          readSettings();
          setState(PCState::EMPTY);

          connect(run,        SIGNAL(clicked()),     SLOT(runClicked()));
          connect(stop,       SIGNAL(clicked()),     SLOT(stopClicked()));
          connect(actionOpen, SIGNAL(triggered()),   SLOT(loadPlugin()));
          connect(actionReload, SIGNAL(triggered()), SLOT(load()));
          connect(actionSave, SIGNAL(triggered()),   SLOT(savePlugin()));
          connect(actionNew,  SIGNAL(triggered()),   SLOT(newPlugin()));
          connect(actionQuit, SIGNAL(triggered()),   SLOT(close()));
          connect(actionManual, SIGNAL(triggered()), SLOT(showManual()));
          connect(actionUndo, SIGNAL(triggered()),         textEdit,   SLOT(undo()));
          connect(actionRedo, SIGNAL(triggered()),         textEdit,   SLOT(redo()));
          connect(textEdit,   SIGNAL(undoAvailable(bool)), actionUndo, SLOT(setEnabled(bool)));
          connect(textEdit,   SIGNAL(redoAvailable(bool)), actionRedo, SLOT(setEnabled(bool)));
          connect(textEdit,   SIGNAL(textChanged()), SLOT(textChanged()));
          }

    //---------------------------------------------------------
    //   manualPath
    //---------------------------------------------------------

    QString PluginCreator::manualPath()
          {
          QString path = mscoreGlobalShare;
          path += "/manual/plugins/plugins.html";
          return path;
          }

    //---------------------------------------------------------
    //   setState
    //---------------------------------------------------------

    void PluginCreator::setState(PCState newState)
          {
          if (state == newState)
                return;
          switch(state) {
                case PCState::INIT:
                      switch(newState) {
                            case PCState::INIT:
                                  break;
                            case PCState::EMPTY:
                                  setTitle("");
                                  actionSave->setEnabled(false);
                                  run->setEnabled(false);
                                  stop->setEnabled(false);
                                  textEdit->setEnabled(false);
                                  break;
                            case PCState::CLEAN:
                            case PCState::DIRTY:
                                  break;
                            }
                      break;
                case PCState::EMPTY:
                      switch(newState) {
                            case PCState::INIT:
                            case PCState::EMPTY:
                                  break;
                            case PCState::CLEAN:
                                  setTitle(path);
                                  run->setEnabled(true);
                                  textEdit->setEnabled(true);
                                  break;
                            case PCState::DIRTY:
                                  return;
                            }
                      break;
                case PCState::CLEAN:
                      switch(newState) {
                            case PCState::INIT:
                            case PCState::EMPTY:
                            case PCState::CLEAN:
                                  break;
                            case PCState::DIRTY:
                                  actionSave->setEnabled(true);
                                  break;
                            }
                      break;
                case PCState::DIRTY:
                      switch(newState) {
                            case PCState::INIT:
                            case PCState::EMPTY:
                            case PCState::CLEAN:
                                  actionSave->setEnabled(false);
                            case PCState::DIRTY:
                                  break;
                            }
                      break;
                }
          state = newState;
          }

    //---------------------------------------------------------
    //   setTitle
    //---------------------------------------------------------

    void PluginCreator::setTitle(const QString& s)
          {
          QString t(tr("MuseScore Plugin Creator"));
          if (s.isEmpty())
                setWindowTitle(t);
          else
                setWindowTitle(t + " - " + s);
          }

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

    void PluginCreator::writeSettings()
          {
          QSettings settings;
          settings.beginGroup(objectName());
          settings.setValue("windowState", saveState());
          settings.setValue("splitter", splitter->saveState());
          settings.endGroup();

          MuseScore::saveGeometry(this);
          }

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

    void PluginCreator::readSettings()
          {
          if (!useFactorySettings) {
                QSettings settings;
                settings.beginGroup(objectName());
                splitter->restoreState(settings.value("splitter").toByteArray());
                restoreState(settings.value("windowState").toByteArray());
                settings.endGroup();
                }

          MuseScore::restoreGeometry(this);
          }

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

    void PluginCreator::closeEvent(QCloseEvent* ev)
          {
          if (state == PCState::DIRTY) {
                QMessageBox::StandardButton n = QMessageBox::warning(this, tr("MuseScore"),
                   tr("Plugin \"%1\" has changes.\n"
                   "Save before closing?").arg(path),
                   QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel,
                   QMessageBox::Save);
                if (n == QMessageBox::Save)
                      savePlugin();
                else if (n == QMessageBox::Cancel) {
                      ev->ignore();
                      return;
                      }
                }
          emit closed(false);
          QWidget::closeEvent(ev);
          }

    //---------------------------------------------------------
    //   qmlMsgHandler
    //---------------------------------------------------------

    static void qmlMsgHandler(QtMsgType type, const QMessageLogContext &, const QString & msg)
          {
          QString s;
          switch(type) {
                case QtDebugMsg:
                      s = QString("Debug: %1\n").arg(msg);
                      break;
                case QtWarningMsg:
                      s = QString("Warning: %1\n").arg(msg);
                      break;
                case QtCriticalMsg:
                      s = QString("Critical: %1\n").arg(msg);
                      break;
                case QtFatalMsg:
                      s = QString("Fatal: %1\n").arg(msg);
                      break;
                default:
                      s = QString("Info: %1\n").arg(msg);
                      break;
                }
          mscore->pluginCreator()->msg(s);
          }

    //---------------------------------------------------------
    //   runClicked
    //---------------------------------------------------------

    void PluginCreator::runClicked()
          {
          log->clear();
          QQmlEngine* qml = Ms::MScore::qml();
          connect(qml, SIGNAL(warnings(const QList<QQmlError>&)),
             SLOT(qmlWarnings(const QList<QQmlError>&)));

          item = 0;
          QQmlComponent component(qml);
          component.setData(textEdit->toPlainText().toUtf8(), QUrl());
          QObject* obj = component.create();
          if (obj == 0) {
                msg("creating component failed\n");
                foreach(QQmlError e, component.errors())
                      msg(QString("   line %1: %2\n").arg(e.line()).arg(e.description()));
                stop->setEnabled(false);
                return;
                }
          qInstallMessageHandler(qmlMsgHandler);
          stop->setEnabled(true);
          run->setEnabled(false);

          item = qobject_cast<QmlPlugin*>(obj);
          if(MuseScoreCore::mscoreCore->currentScore() == nullptr && item->requiresScore() == true) {
                QMessageBox::information(0,
                      QMessageBox::tr("MuseScore"),
                      QMessageBox::tr("No score open.\n"
                      "This plugin requires an open score to run.\n"),
                      QMessageBox::Ok, QMessageBox::NoButton);
                delete obj;
                item = nullptr;
                closePlugin();
                return;
                }
          item->setFilePath(path.isEmpty() ? QString() : path.section('/', 0, -2));

          if (item->pluginType() == "dock" || item->pluginType() == "dialog") {
                view = new QQuickView(qml, 0);
                view->setTitle(item->menuPath().mid(item->menuPath().lastIndexOf(".") + 1));
                view->setColor(QApplication::palette().color(QPalette::Window));
                view->setResizeMode(QQuickView::SizeRootObjectToView);
                view->setWidth(item->width());
                view->setHeight(item->height());
                item->setParentItem(view->contentItem());

                if (item->pluginType() == "dock") {
                      dock = new QDockWidget("Plugin", 0);
                      dock->setAttribute(Qt::WA_DeleteOnClose);
                      dock->setWidget(QWidget::createWindowContainer(view));
                      dock->widget()->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
                      Qt::DockWidgetArea area = Qt::RightDockWidgetArea;
                      if (item->dockArea() == "left")
                            area = Qt::LeftDockWidgetArea;
                      else if (item->dockArea() == "top")
                            area = Qt::TopDockWidgetArea;
                      else if (item->dockArea() == "bottom")
                            area = Qt::BottomDockWidgetArea;
                      addDockWidget(area, dock);
                      connect(dock, SIGNAL(destroyed()), SLOT(closePlugin()));
                      dock->widget()->setAttribute(Qt::WA_DeleteOnClose);
                      dock->show();
                      }
                view->show();
                view->raise();
                connect(view, SIGNAL(destroyed()), SLOT(closePlugin()));
                }

          connect(qml,  SIGNAL(quit()), SLOT(closePlugin()));

          if (mscore->currentScore() && item->pluginType() != "dock")
                mscore->currentScore()->startCmd();
          item->runPlugin();
          if (mscore->currentScore() && item->pluginType() != "dock")
                mscore->currentScore()->endCmd();
          mscore->endCmd();
          }

    //---------------------------------------------------------
    //   closePlugin
    //---------------------------------------------------------

    void PluginCreator::closePlugin()
          {
          stop->setEnabled(false);
          run->setEnabled(true);
          if (view)
                view->close();
          if (dock)
                dock->close();
          qInstallMessageHandler(0);
          }

    //---------------------------------------------------------
    //   stopClicked
    //---------------------------------------------------------

    void PluginCreator::stopClicked()
          {
          closePlugin();
          }

    //---------------------------------------------------------
    //   loadPlugin
    //---------------------------------------------------------

    void PluginCreator::loadPlugin()
          {
          if (state == PCState::DIRTY) {
                QMessageBox::StandardButton n = QMessageBox::warning(this, tr("MuseScore"),
                   tr("Plugin \"%1\" has changes.\n"
                   "Save before closing?").arg(path),
                   QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel,
                   QMessageBox::Save);
                if (n == QMessageBox::Save)
                      savePlugin();
                else if (n == QMessageBox::Cancel)
                      return;
                }
          path = mscore->getPluginFilename(true);
          load();
          }

    void PluginCreator::load()
          {
          if (path.isEmpty())
                return;
          QFile f(path);
          QFileInfo fi(f);
          if (f.open(QIODevice::ReadOnly)) {
                textEdit->setPlainText(f.readAll());
                run->setEnabled(true);
                f.close();
                }
          else {
                path = QString();
                }
          created = false;
          setState(PCState::CLEAN);
          setTitle( fi.completeBaseName() );
          setToolTip(path);
          raise();
          }

    //---------------------------------------------------------
    //   savePlugin
    //---------------------------------------------------------

    void PluginCreator::savePlugin()
          {
          if (created) {
                path = mscore->getPluginFilename(false);
                if (path.isEmpty())
                      return;
                }
          QFile f(path);
          QFileInfo fi(f);
          if(fi.suffix() != "qml" ) {
                QMessageBox::critical(mscore, tr("Save Plugin"), tr("Cannot determine file type"));
                return;
          }

          if (f.open(QIODevice::WriteOnly)) {
                f.write(textEdit->toPlainText().toUtf8());
                f.close();
                textEdit->document()->setModified(false);
                created = false;
                setState(PCState::CLEAN);
                setTitle( fi.completeBaseName() );
                setToolTip(path);
                }
          else {
                // TODO
                }
          raise();
          }

    //---------------------------------------------------------
    //   newPlugin
    //---------------------------------------------------------

    void PluginCreator::newPlugin()
          {
          if (state == PCState::DIRTY) {
                QMessageBox::StandardButton n = QMessageBox::warning(this, tr("MuseScore"),
                   tr("Plugin \"%1\" has changes.\n"
                   "Save before closing?").arg(path),
                   QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel,
                   QMessageBox::Save);
                if (n == QMessageBox::Save)
                      savePlugin();
                else if (n == QMessageBox::Cancel)
                      return;
                }
          path    = tr("untitled");
          created = true;
          QString s(
             "import QtQuick 2.0\n"
             "import MuseScore 1.0\n"
             "\n"
             "MuseScore {\n"
             "      menuPath: \"Plugins.pluginName\"\n"
             "      onRun: {\n"
             "            console.log(\"hello world\")\n"
             "            Qt.quit()\n"
             "            }\n"
             "      }\n");
          textEdit->setPlainText(s);
          setState(PCState::CLEAN);
          setTitle(path);
          setToolTip(path);
          raise();
          }

    //---------------------------------------------------------
    //   textChanged
    //---------------------------------------------------------

    void PluginCreator::textChanged()
          {
          actionSave->setEnabled(textEdit->document()->isModified());
          setState(PCState::DIRTY);
          }

    //---------------------------------------------------------
    //   qmlWarnings
    //---------------------------------------------------------

    void PluginCreator::qmlWarnings(const QList<QQmlError>& el)
          {
          foreach(const QQmlError& e, el)
                msg(QString("%1:%2: %3\n").arg(e.line()).arg(e.column()).arg(e.description()));
          }

    //---------------------------------------------------------
    //   msg
    //---------------------------------------------------------

    void PluginCreator::msg(const QString& s)
          {
          log->moveCursor(QTextCursor::End);
          log->textCursor().insertText(s);
          }

    //---------------------------------------------------------
    //   showManual
    //---------------------------------------------------------

    void PluginCreator::showManual()
          {
          if (helpBrowser == 0) {
                helpBrowser = new HelpBrowser;
                manualDock = new QDockWidget(tr("Manual"), 0);
                manualDock->setObjectName("Manual");

                manualDock->setWidget(helpBrowser);
                Qt::DockWidgetArea area = Qt::RightDockWidgetArea;
                addDockWidget(area, manualDock);
                helpBrowser->setContent(manualPath());
                }
          manualDock->setVisible(!manualDock->isVisible());
          }
    }

↑ V523 The 'then' statement is equivalent to the 'else' statement.