MuseScore/mscore/pluginCreator.cpp

516 lines
17 KiB
C++
Raw Normal View History

2012-07-02 18:05:10 +02:00
//=============================================================================
// 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"
2014-04-25 18:43:25 +02:00
// #include "plugins.h"
2012-12-10 09:15:50 +01:00
#include "qmlplugin.h"
2012-07-05 14:31:03 +02:00
#include "icons.h"
#include "helpBrowser.h"
#include "preferences.h"
2014-04-25 18:43:25 +02:00
#include "libmscore/score.h"
2012-07-02 18:05:10 +02:00
2013-05-13 18:49:17 +02:00
namespace Ms {
2012-07-02 18:05:10 +02:00
extern bool useFactorySettings;
//static const char* states[] = {
// "S_INIT", "S_EMPTY", "S_CLEAN", "S_DIRTY"
// };
2012-07-05 14:31:03 +02:00
2012-07-02 18:05:10 +02:00
//---------------------------------------------------------
// PluginCreator
//---------------------------------------------------------
PluginCreator::PluginCreator(QWidget* parent)
: QMainWindow(parent)
{
state = S_INIT;
item = 0;
view = 0;
dock = 0;
manualDock = 0;
helpBrowser = 0;
setIconSize(QSize(preferences.iconWidth, preferences.iconHeight));
2012-07-02 18:05:10 +02:00
setupUi(this);
2012-07-05 14:31:03 +02:00
QToolBar* fileTools = addToolBar(tr("File Operations"));
2012-07-18 14:54:44 +02:00
fileTools->setObjectName("FileOperations");
2012-07-05 14:31:03 +02:00
actionNew->setIcon(*icons[int(Icons::fileNew_ICON)]);
2013-10-05 15:54:35 +02:00
actionNew->setShortcut(QKeySequence(QKeySequence::New));
2012-07-05 14:31:03 +02:00
fileTools->addAction(actionNew);
actionOpen->setIcon(*icons[int(Icons::fileOpen_ICON)]);
2013-10-05 15:54:35 +02:00
actionOpen->setShortcut(QKeySequence(QKeySequence::Open));
2012-07-05 14:31:03 +02:00
fileTools->addAction(actionOpen);
actionReload->setIcon(*icons[int(Icons::viewRefresh_ICON)]);
2013-10-05 17:30:30 +02:00
fileTools->addAction(actionReload);
actionSave->setIcon(*icons[int(Icons::fileSave_ICON)]);
2013-10-05 15:54:35 +02:00
actionSave->setShortcut(QKeySequence(QKeySequence::Save));
2012-07-05 14:31:03 +02:00
fileTools->addAction(actionSave);
2013-10-05 15:54:35 +02:00
actionQuit->setShortcut(QKeySequence(QKeySequence::Quit));
2012-07-18 14:54:44 +02:00
actionManual->setIcon(QIcon(*icons[int(Icons::helpContents_ICON)]));
2013-10-05 15:54:35 +02:00
actionManual->setShortcut(QKeySequence(QKeySequence::HelpContents));
2012-07-11 21:29:42 +02:00
fileTools->addAction(actionManual);
2012-07-18 14:54:44 +02:00
QToolBar* editTools = addToolBar(tr("Edit Operations"));
editTools->setObjectName("EditOperations");
actionUndo->setIcon(*icons[int(Icons::undo_ICON)]);
2013-10-05 15:54:35 +02:00
actionUndo->setShortcut(QKeySequence(QKeySequence::Undo));
2012-07-18 14:54:44 +02:00
editTools->addAction(actionUndo);
actionRedo->setIcon(*icons[int(Icons::redo_ICON)]);
2013-10-05 15:54:35 +02:00
actionRedo->setShortcut(QKeySequence(QKeySequence::Redo));
2012-07-18 14:54:44 +02:00
editTools->addAction(actionRedo);
actionUndo->setEnabled(false);
actionRedo->setEnabled(false);
2012-07-02 20:23:00 +02:00
log->setReadOnly(true);
log->setMaximumBlockCount(1000);
2012-07-02 18:05:10 +02:00
readSettings();
2012-07-05 14:31:03 +02:00
setState(S_EMPTY);
2012-07-18 14:54:44 +02:00
connect(run, SIGNAL(clicked()), SLOT(runClicked()));
connect(stop, SIGNAL(clicked()), SLOT(stopClicked()));
connect(actionOpen, SIGNAL(triggered()), SLOT(loadPlugin()));
2013-10-05 17:30:30 +02:00
connect(actionReload, SIGNAL(triggered()), SLOT(load()));
2012-07-18 14:54:44 +02:00
connect(actionSave, SIGNAL(triggered()), SLOT(savePlugin()));
connect(actionNew, SIGNAL(triggered()), SLOT(newPlugin()));
connect(actionQuit, SIGNAL(triggered()), SLOT(close()));
connect(actionManual, SIGNAL(triggered()), SLOT(showManual()));
2012-07-18 14:54:44 +02:00
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)));
2012-07-02 18:05:10 +02:00
connect(textEdit, SIGNAL(textChanged()), SLOT(textChanged()));
2012-07-05 14:31:03 +02:00
}
2012-07-11 21:29:42 +02:00
//---------------------------------------------------------
// manualPath
//---------------------------------------------------------
QString PluginCreator::manualPath()
{
QString path = mscoreGlobalShare;
path += "/manual/plugins/plugins.html";
2012-07-11 21:29:42 +02:00
return path;
}
2012-07-05 14:31:03 +02:00
//---------------------------------------------------------
// setState
//---------------------------------------------------------
void PluginCreator::setState(PCState newState)
{
if (state == newState)
return;
switch(state) {
case S_INIT:
switch(newState) {
case S_INIT:
break;
case S_EMPTY:
setTitle("");
actionSave->setEnabled(false);
run->setEnabled(false);
stop->setEnabled(false);
textEdit->setEnabled(false);
break;
case S_CLEAN:
case S_DIRTY:
break;
}
break;
case S_EMPTY:
switch(newState) {
case S_INIT:
case S_EMPTY:
break;
case S_CLEAN:
setTitle(path);
run->setEnabled(true);
textEdit->setEnabled(true);
break;
case S_DIRTY:
return;
}
break;
case S_CLEAN:
switch(newState) {
case S_INIT:
case S_EMPTY:
case S_CLEAN:
break;
case S_DIRTY:
actionSave->setEnabled(true);
break;
}
break;
case S_DIRTY:
switch(newState) {
case S_INIT:
case S_EMPTY:
case S_CLEAN:
actionSave->setEnabled(false);
case S_DIRTY:
break;
}
break;
}
state = newState;
2012-07-02 18:05:10 +02:00
}
//---------------------------------------------------------
// setTitle
//---------------------------------------------------------
void PluginCreator::setTitle(const QString& s)
{
2013-11-03 16:49:02 +01:00
QString t(tr("MuseScore Plugin Creator"));
2012-07-02 18:05:10 +02:00
if (s.isEmpty())
setWindowTitle(t);
else
setWindowTitle(t + " - " + s);
}
//---------------------------------------------------------
// writeSettings
//---------------------------------------------------------
void PluginCreator::writeSettings()
{
QSettings settings;
settings.beginGroup("PluginCreator");
settings.setValue("geometry", saveGeometry());
settings.setValue("windowState", saveState());
2012-07-02 18:05:10 +02:00
settings.setValue("splitter", splitter->saveState());
settings.endGroup();
}
//---------------------------------------------------------
// readSettings
//---------------------------------------------------------
void PluginCreator::readSettings()
{
if (!useFactorySettings) {
QSettings settings;
settings.beginGroup("PluginCreator");
splitter->restoreState(settings.value("splitter").toByteArray());
restoreGeometry(settings.value("geometry").toByteArray());
restoreState(settings.value("windowState").toByteArray());
2012-07-02 18:05:10 +02:00
settings.endGroup();
}
}
//---------------------------------------------------------
// closeEvent
//---------------------------------------------------------
void PluginCreator::closeEvent(QCloseEvent* ev)
{
if (state == S_DIRTY) {
QMessageBox::StandardButton n = QMessageBox::warning(this, tr("MuseScore"),
2014-03-05 17:08:56 +01:00
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);
2012-07-02 18:05:10 +02:00
QWidget::closeEvent(ev);
}
2012-07-02 20:23:00 +02:00
//---------------------------------------------------------
// qmlMsgHandler
//---------------------------------------------------------
static void qmlMsgHandler(QtMsgType type, const char* 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;
2013-11-25 16:19:31 +01:00
/* Qt5.2? case QtTraceMsg:
s = QString("Trace: %1\n").arg(msg);
break;
2013-11-25 16:19:31 +01:00
*/
2012-07-02 20:23:00 +02:00
}
mscore->getPluginCreator()->msg(s);
}
2012-07-02 18:05:10 +02:00
//---------------------------------------------------------
// runClicked
//---------------------------------------------------------
void PluginCreator::runClicked()
{
2012-07-18 14:54:44 +02:00
log->clear();
2014-04-25 18:43:25 +02:00
QQmlEngine* qml = Ms::MScore::qml();
2013-05-16 17:06:31 +02:00
connect(qml, SIGNAL(warnings(const QList<QQmlError>&)),
SLOT(qmlWarnings(const QList<QQmlError>&)));
2012-07-02 18:05:10 +02:00
item = 0;
2013-05-16 17:06:31 +02:00
QQmlComponent component(qml);
2012-07-02 18:05:10 +02:00
component.setData(textEdit->toPlainText().toUtf8(), QUrl());
QObject* obj = component.create();
if (obj == 0) {
2012-07-02 20:23:00 +02:00
msg("creating component failed\n");
2013-05-16 17:06:31 +02:00
foreach(QQmlError e, component.errors())
2012-07-02 20:23:00 +02:00
msg(QString(" line %1: %2\n").arg(e.line()).arg(e.description()));
2012-07-02 18:05:10 +02:00
stop->setEnabled(false);
return;
}
2012-07-02 20:23:00 +02:00
qInstallMsgHandler(qmlMsgHandler);
2012-07-02 18:05:10 +02:00
stop->setEnabled(true);
run->setEnabled(false);
item = qobject_cast<QmlPlugin*>(obj);
if (item->pluginType() == "dock" || item->pluginType() == "dialog") {
view = new QQuickView(qml, 0);
2013-07-23 22:13:49 +02:00
view->setTitle(item->menuPath().mid(item->menuPath().lastIndexOf(".") + 1));
view->setColor(QApplication::palette().color(QPalette::Window));
view->setResizeMode(QQuickView::SizeRootObjectToView);
2013-07-23 22:13:49 +02:00
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);
}
view->show();
view->raise();
connect(view, SIGNAL(destroyed()), SLOT(closePlugin()));
2012-07-02 18:05:10 +02:00
}
connect(qml, SIGNAL(quit()), SLOT(closePlugin()));
2012-07-02 18:05:10 +02:00
if (mscore->currentScore() && item->pluginType() != "dock")
2012-07-02 18:05:10 +02:00
mscore->currentScore()->startCmd();
item->runPlugin();
if (mscore->currentScore() && item->pluginType() != "dock")
2012-07-02 18:05:10 +02:00
mscore->currentScore()->endCmd();
mscore->endCmd();
}
//---------------------------------------------------------
// closePlugin
//---------------------------------------------------------
void PluginCreator::closePlugin()
{
stop->setEnabled(false);
run->setEnabled(true);
if (view)
view->close();
if (dock)
dock->close();
2012-07-02 20:23:00 +02:00
qInstallMsgHandler(0);
2012-07-02 18:05:10 +02:00
}
//---------------------------------------------------------
// stopClicked
//---------------------------------------------------------
void PluginCreator::stopClicked()
{
closePlugin();
}
//---------------------------------------------------------
// loadPlugin
//---------------------------------------------------------
void PluginCreator::loadPlugin()
{
if (state == S_DIRTY) {
2012-07-02 18:05:10 +02:00
QMessageBox::StandardButton n = QMessageBox::warning(this, tr("MuseScore"),
2014-03-05 17:08:56 +01:00
tr("Plugin \"%1\" has changes.\n"
"Save before closing?").arg(path),
2012-07-02 18:05:10 +02:00
QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel,
QMessageBox::Save);
if (n == QMessageBox::Save)
savePlugin();
else if (n == QMessageBox::Cancel)
return;
}
path = mscore->getPluginFilename(true);
2013-10-05 17:30:30 +02:00
load();
}
void PluginCreator::load()
{
2012-07-02 18:05:10 +02:00
if (path.isEmpty())
return;
QFile f(path);
if (f.open(QIODevice::ReadOnly)) {
textEdit->setPlainText(f.readAll());
run->setEnabled(true);
f.close();
}
else {
path = QString();
}
2012-07-05 14:31:03 +02:00
created = false;
2012-07-02 18:05:10 +02:00
setTitle(path);
2012-07-05 14:31:03 +02:00
setState(S_CLEAN);
2012-07-18 14:54:44 +02:00
raise();
2012-07-02 18:05:10 +02:00
}
//---------------------------------------------------------
// savePlugin
//---------------------------------------------------------
void PluginCreator::savePlugin()
{
2012-07-05 14:31:03 +02:00
if (created) {
path = mscore->getPluginFilename(false);
if (path.isEmpty())
return;
}
2012-07-02 18:05:10 +02:00
QFile f(path);
if (f.open(QIODevice::WriteOnly)) {
f.write(textEdit->toPlainText().toUtf8());
f.close();
textEdit->document()->setModified(false);
2012-07-05 14:31:03 +02:00
created = false;
setState(S_CLEAN);
2012-07-02 18:05:10 +02:00
}
else {
// TODO
}
2012-07-05 14:31:03 +02:00
raise();
2012-07-02 18:05:10 +02:00
}
//---------------------------------------------------------
// newPlugin
//---------------------------------------------------------
void PluginCreator::newPlugin()
{
if (state == S_DIRTY) {
2012-07-02 18:05:10 +02:00
QMessageBox::StandardButton n = QMessageBox::warning(this, tr("MuseScore"),
2014-03-05 17:08:56 +01:00
tr("Plugin \"%1\" has changes.\n"
"Save before closing?").arg(path),
2012-07-02 18:05:10 +02:00
QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel,
QMessageBox::Save);
if (n == QMessageBox::Save)
savePlugin();
else if (n == QMessageBox::Cancel)
return;
}
2012-07-05 14:31:03 +02:00
path = tr("untitled");
created = true;
2012-07-02 18:05:10 +02:00
QString s(
"import QtQuick 2.0\n"
2012-07-02 18:05:10 +02:00
"import MuseScore 1.0\n"
"\n"
"MuseScore {\n"
" menuPath: \"Plugins.pluginName\"\n"
" onRun: {\n"
" console.log(\"hello world\")\n"
2012-07-05 14:31:03 +02:00
" Qt.quit()\n"
2012-07-02 18:05:10 +02:00
" }\n"
" }\n");
textEdit->setPlainText(s);
2012-07-05 14:31:03 +02:00
setState(S_CLEAN);
raise();
2012-07-02 18:05:10 +02:00
}
//---------------------------------------------------------
// textChanged
//---------------------------------------------------------
void PluginCreator::textChanged()
{
actionSave->setEnabled(textEdit->document()->isModified());
2012-07-05 14:31:03 +02:00
setState(S_DIRTY);
2012-07-02 18:05:10 +02:00
}
2012-07-02 20:23:00 +02:00
//---------------------------------------------------------
// qmlWarnings
//---------------------------------------------------------
2013-05-16 17:06:31 +02:00
void PluginCreator::qmlWarnings(const QList<QQmlError>& el)
2012-07-02 20:23:00 +02:00
{
2013-05-16 17:06:31 +02:00
foreach(const QQmlError& e, el)
2012-07-02 20:23:00 +02:00
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;
2012-07-14 15:29:40 +02:00
manualDock = new QDockWidget(tr("Manual"), 0);
2012-07-18 14:54:44 +02:00
manualDock->setObjectName("Manual");
manualDock->setWidget(helpBrowser);
Qt::DockWidgetArea area = Qt::RightDockWidgetArea;
addDockWidget(area, manualDock);
2012-07-11 21:29:42 +02:00
helpBrowser->setContent(manualPath());
}
2012-07-18 14:54:44 +02:00
manualDock->setVisible(!manualDock->isVisible());
}
2013-05-13 18:49:17 +02:00
}