MuseScore/mscore/plugins.cpp
2012-07-02 18:05:10 +02:00

512 lines
16 KiB
C++

//=============================================================================
// MuseScore
// Linux Music Score Editor
// $Id: plugins.cpp 5568 2012-04-22 10:08:43Z wschweer $
//
// Copyright (C) 2009-2010 Werner Schweer and others
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//=============================================================================
#include "musescore.h"
#include "libmscore/score.h"
#include "libmscore/undo.h"
#include "globals.h"
#include "config.h"
#include "preferences.h"
#include "libmscore/chord.h"
#include "libmscore/note.h"
#include "libmscore/utils.h"
#include "libmscore/mscore.h"
#include "libmscore/measurebase.h"
#include "libmscore/measure.h"
#include "libmscore/segment.h"
#include "libmscore/rest.h"
#include "libmscore/stafftext.h"
#include "plugins.h"
#include "libmscore/cursor.h"
#include "libmscore/page.h"
#include "libmscore/system.h"
//---------------------------------------------------------
// QmlPlugin
//---------------------------------------------------------
QmlPlugin::QmlPlugin(QDeclarativeItem* parent)
: QDeclarativeItem(parent)
{
}
QmlPlugin::~QmlPlugin()
{
}
//---------------------------------------------------------
// curScore
//---------------------------------------------------------
Score* QmlPlugin::curScore() const
{
return mscore->currentScore();
}
//---------------------------------------------------------
// scores
//---------------------------------------------------------
QDeclarativeListProperty<Score> QmlPlugin::scores()
{
return QDeclarativeListProperty<Score>(this, mscore->scores());
}
//---------------------------------------------------------
// registerPlugin
//---------------------------------------------------------
void MuseScore::registerPlugin(PluginDescription* plugin)
{
QString pluginPath = plugin->path;
QFileInfo np(pluginPath);
if (np.suffix() != "qml")
return;
QString baseName = np.baseName();
foreach(QString s, plugins) {
QFileInfo fi(s);
if (fi.baseName() == baseName) {
if (MScore::debugMode)
qDebug(" Plugin <%s> already registered\n", qPrintable(pluginPath));
return;
}
}
QFile f(pluginPath);
if (!f.open(QIODevice::ReadOnly)) {
if (MScore::debugMode)
qDebug("Loading Plugin <%s> failed\n", qPrintable(pluginPath));
return;
}
if (MScore::debugMode)
qDebug("Register Plugin <%s>", qPrintable(pluginPath));
f.close();
QObject* obj = 0;
QDeclarativeComponent component(qml(), QUrl::fromLocalFile(pluginPath));
obj = component.create();
if (obj == 0) {
qDebug("creating component <%s> failed", qPrintable(pluginPath));
foreach(QDeclarativeError e, component.errors()) {
qDebug(" line %d: %s", e.line(), qPrintable(e.description()));
}
return;
}
QmlPlugin* item = qobject_cast<QmlPlugin*>(obj);
QString menuPath = item->menuPath();
plugin->menuPath = menuPath;
plugins.append(pluginPath);
createMenuEntry(plugin);
QAction* a = plugin->shortcut.action();
pluginActions.append(a);
int pluginIdx = plugins.size() - 1; // plugin is already appended
connect(a, SIGNAL(triggered()), pluginMapper, SLOT(map()));
pluginMapper->setMapping(a, pluginIdx);
delete obj;
}
//---------------------------------------------------------
// qml
//---------------------------------------------------------
QDeclarativeEngine* MuseScore::qml()
{
if (_qml == 0) {
//-----------some qt bindings
_qml = new QDeclarativeEngine;
qmlRegisterType<MsProcess> ("MuseScore", 1, 0, "QProcess");
qmlRegisterType<MsFile> ("MuseScore", 1, 0, "QFile");
//-----------mscore bindings
qmlRegisterType<MsScoreView>("MuseScore", 1, 0, "ScoreView");
qmlRegisterType<QmlPlugin> ("MuseScore", 1, 0, "MuseScore");
qmlRegisterType<Score> ("MuseScore", 1, 0, "Score");
qmlRegisterType<Segment> ("MuseScore", 1, 0, "Segment");
qmlRegisterType<Chord> ("MuseScore", 1, 0, "Chord");
qmlRegisterType<Note> ("MuseScore", 1, 0, "Note");
qmlRegisterType<Rest> ("MuseScore", 1, 0, "Rest");
qmlRegisterType<Measure> ("MuseScore", 1, 0, "Measure");
qmlRegisterType<MScore> ("MuseScore", 1, 0, "MScore");
qmlRegisterType<Cursor> ("MuseScore", 1, 0, "Cursor");
qmlRegisterType<StaffText> ("MuseScore", 1, 0, "StaffText");
//-----------virtual classes
qmlRegisterType<Element>();
qmlRegisterType<ChordRest>();
}
return _qml;
}
//---------------------------------------------------------
// createMenuEntry
// syntax: "entry.entry.entry"
//---------------------------------------------------------
void MuseScore::createMenuEntry(PluginDescription* plugin)
{
if (!pluginMapper)
return;
QString menu = plugin->menuPath;
QStringList ml;
QString s;
bool escape = false;
foreach (QChar c, menu) {
if (escape) {
escape = false;
s += c;
}
else {
if (c == '\\')
escape = true;
else {
if (c == '.') {
ml += s;
s = "";
}
else {
s += c;
}
}
}
}
if (!s.isEmpty())
ml += s;
int n = ml.size();
QWidget* curMenu = menuBar();
for(int i = 0; i < n; ++i) {
QString m = ml[i];
bool found = false;
QList<QObject*> ol = curMenu->children();
foreach(QObject* o, ol) {
QMenu* menu = qobject_cast<QMenu*>(o);
if (!menu)
continue;
if (menu->objectName() == m || menu->title() == m) {
curMenu = menu;
found = true;
break;
}
}
if (!found) {
if (i == 0) {
curMenu = new QMenu(m, menuBar());
curMenu->setObjectName(m);
menuBar()->insertMenu(menuBar()->actions().back(), (QMenu*)curMenu);
if (MScore::debugMode)
qDebug("add Menu <%s>\n", qPrintable(m));
}
else if (i + 1 == n) {
QStringList sl = m.split(":");
QAction* a = plugin->shortcut.action();
QMenu* cm = static_cast<QMenu*>(curMenu);
if (sl.size() == 2) {
QList<QAction*> al = cm->actions();
QAction* ba = 0;
foreach(QAction* ia, al) {
if (ia->text() == sl[0]) {
ba = ia;
break;
}
}
a->setText(sl[1]);
cm->insertAction(ba, a);
}
else {
a->setText(m);
cm->addAction(a);
}
if (MScore::debugMode)
qDebug("add action <%s>\n", qPrintable(m));
}
else {
curMenu = ((QMenu*)curMenu)->addMenu(m);
if (MScore::debugMode)
qDebug("add menu <%s>\n", qPrintable(m));
}
}
}
}
//---------------------------------------------------------
// pluginIdxFromPath
//---------------------------------------------------------
int MuseScore::pluginIdxFromPath(QString pluginPath) {
QFileInfo np(pluginPath);
QString baseName = np.baseName();
int idx = 0;
foreach(QString s, plugins) {
QFileInfo fi(s);
if (fi.baseName() == baseName)
return idx;
idx++;
}
return -1;
}
//---------------------------------------------------------
// loadPlugins
//---------------------------------------------------------
void MuseScore::loadPlugins()
{
pluginMapper = new QSignalMapper(this);
connect(pluginMapper, SIGNAL(mapped(int)), SLOT(pluginTriggered(int)));
foreach(PluginDescription* d, preferences.pluginList) {
if (d->load)
registerPlugin(d);
}
}
//---------------------------------------------------------
// unloadPlugins
//---------------------------------------------------------
void MuseScore::unloadPlugins()
{
for (int idx = 0; idx < plugins.size() ; idx++) {
; // TODO
}
}
//---------------------------------------------------------
// loadPlugin
//---------------------------------------------------------
bool MuseScore::loadPlugin(const QString& filename)
{
bool result = false;
QDir pluginDir(mscoreGlobalShare + "plugins");
if (MScore::debugMode)
qDebug("Plugin Path <%s>\n", qPrintable(mscoreGlobalShare + "plugins"));
if (filename.endsWith(".qml")){
QFileInfo fi(pluginDir, filename);
if (fi.exists()) {
QString path(fi.filePath());
//TODO registerPlugin(path);
result = true;
}
}
return result;
}
//---------------------------------------------------------
// pluginTriggered
//---------------------------------------------------------
void MuseScore::pluginTriggered(int idx)
{
QString pp = plugins[idx];
QDeclarativeView* view = new QDeclarativeView;
view->setResizeMode(QDeclarativeView::SizeRootObjectToView);
view->setSource(QUrl::fromLocalFile(pp));
connect((QObject*)view->engine(), SIGNAL(quit()), view, SLOT(close()));
view->show();
QmlPlugin* p = (QmlPlugin*)(view->rootObject());
if (p->pluginType() == "dock") {
QDockWidget* dock = new QDockWidget("Plugin", 0);
dock->setAttribute(Qt::WA_DeleteOnClose);
dock->setWidget(view);
Qt::DockWidgetArea area = Qt::RightDockWidgetArea;
if (p->dockArea() == "left")
area = Qt::LeftDockWidgetArea;
else if (p->dockArea() == "top")
area = Qt::TopDockWidgetArea;
else if (p->dockArea() == "bottom")
area = Qt::BottomDockWidgetArea;
addDockWidget(area, dock);
connect((QObject*)view->engine(), SIGNAL(quit()), dock, SLOT(close()));
}
else {
connect((QObject*)view->engine(), SIGNAL(quit()), view, SLOT(close()));
}
if (cs)
cs->startCmd();
p->runPlugin();
if (cs)
cs->endCmd();
endCmd();
}
Element* QmlPlugin::newElement(int t)
{
Score* score = curScore();
if (score == 0)
return 0;
return Element::create(ElementType(t), score);
}
//---------------------------------------------------------
// newScore
//---------------------------------------------------------
Score* QmlPlugin::newScore(const QString& name, const QString& part, int measures)
{
if (mscore->currentScore()) {
mscore->currentScore()->endCmd();
mscore->endCmd();
}
Score* score = new Score(MScore::defaultStyle());
int view = mscore->appendScore(score);
mscore->setCurrentView(0, view);
qApp->processEvents();
score->setName(name);
score->appendPart(part);
score->appendMeasures(measures);
score->doLayout();
score->startCmd();
return score;
}
//---------------------------------------------------------
// cmd
//---------------------------------------------------------
void QmlPlugin::cmd(const QString& s)
{
Shortcut* sc = Shortcut::getShortcut(s.toAscii().data());
if (sc)
mscore->cmd(sc->action());
else
printf("QmlPlugin:cmd: not found <%s>\n", qPrintable(s));
}
//---------------------------------------------------------
// MsScoreView
//---------------------------------------------------------
MsScoreView::MsScoreView(QDeclarativeItem* parent)
: QDeclarativeItem(parent)
{
setFlag(QGraphicsItem::ItemHasNoContents, false);
setCacheMode(QGraphicsItem::ItemCoordinateCache);
setAcceptedMouseButtons(Qt::LeftButton);
score = 0;
}
//---------------------------------------------------------
// setScore
//---------------------------------------------------------
void MsScoreView::setScore(Score* s)
{
_currentPage = 0;
score = s;
score->doLayout();
Page* page = score->pages()[_currentPage];
QRectF pr(page->abbox());
qreal m1 = width() / pr.width();
qreal m2 = height() / pr.height();
mag = qMax(m1, m2);
_boundingRect = QRectF(0.0, 0.0, pr.width() * mag, pr.height() * mag);
setWidth(pr.width() * mag);
setHeight(pr.height() * mag);
update();
}
//---------------------------------------------------------
// paint
//---------------------------------------------------------
void MsScoreView::paint(QPainter* p, const QStyleOptionGraphicsItem*, QWidget*)
{
if (!score)
return;
p->setRenderHint(QPainter::Antialiasing, true);
p->setRenderHint(QPainter::TextAntialiasing, true);
p->fillRect(QRect(0, 0, width(), height()), _color);
p->scale(mag, mag);
Page* page = score->pages()[_currentPage];
QList<const Element*> el;
foreach(System* s, *page->systems()) {
foreach(MeasureBase* m, s->measures())
m->scanElements(&el, collectElements, false);
}
page->scanElements(&el, collectElements, false);
foreach(const Element* e, el) {
QPointF pos(e->pagePos());
p->translate(pos);
e->draw(p);
p->translate(-pos);
}
}
//---------------------------------------------------------
// setCurrentPage
//---------------------------------------------------------
void MsScoreView::setCurrentPage(int n)
{
if (score == 0)
return;
if (n < 0)
n = 0;
int nn = score->pages().size();
if (nn == 0)
return;
if (n >= nn)
n = nn - 1;
_currentPage = n;
update();
}
//---------------------------------------------------------
// nextPage
//---------------------------------------------------------
void MsScoreView::nextPage()
{
setCurrentPage(_currentPage + 1);
}
//---------------------------------------------------------
// prevPage
//---------------------------------------------------------
void MsScoreView::prevPage()
{
setCurrentPage(_currentPage - 1);
}
const QRectF& MsScoreView::getGrip(int) const
{
static const QRectF a;
return a;
}
const QTransform& MsScoreView::matrix() const
{
static const QTransform t;
return t; // _matrix;
}