1 //=============================================================================
2 //  MuseScore
3 //  Music Composition & Notation
4 //
5 //  Copyright (C) 2019 Werner Schweer and others
6 //
7 //  This program is free software; you can redistribute it and/or modify
8 //  it under the terms of the GNU General Public License version 2.
9 //
10 //  This program is distributed in the hope that it will be useful,
11 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //  GNU General Public License for more details.
14 //
15 //  You should have received a copy of the GNU General Public License
16 //  along with this program; if not, write to the Free Software
17 //  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 //=============================================================================
19 
20 #include "qmlpluginengine.h"
21 #include "api/qmlpluginapi.h"
22 #include "libmscore/score.h"
23 #include "musescore.h"
24 
25 namespace Ms {
26 
27 static constexpr int maxCmdCount = 10; // recursion prevention
28 
29 //---------------------------------------------------------
30 //   QmlPluginEngine
31 //---------------------------------------------------------
32 
QmlPluginEngine(QObject * parent)33 QmlPluginEngine::QmlPluginEngine(QObject* parent)
34    : MsQmlEngine(parent)
35       {
36       PluginAPI::PluginAPI::registerQmlTypes();
37       }
38 
39 //---------------------------------------------------------
40 //   QmlPluginEngine::beginEndCmd
41 //---------------------------------------------------------
42 
beginEndCmd(MuseScore * ms,bool inUndoRedo)43 void QmlPluginEngine::beginEndCmd(MuseScore* ms, bool inUndoRedo)
44       {
45       ++cmdCount;
46 
47       if (inUndoRedo)
48             undoRedo = true;
49 
50       const Score* cs = ms->currentScore();
51 
52       // score and excerpts have united undo stack so we are better to track master score
53       currScoreState = cs ? cs->masterScore()->state() : ScoreContentState();
54 
55       // TODO: most of plugins are never deleted so receivers usually never decrease
56       if (!receivers(SIGNAL(endCmd(const QMap<QString, QVariant>&))))
57             return;
58 
59       endCmdInfo["selectionChanged"] = !cs || cs->selectionChanged();
60       endCmdInfo["excerptsChanged"] = !cs || cs->masterScore()->excerptsChanged();
61       endCmdInfo["instrumentsChanged"] = !cs || cs->masterScore()->instrumentsChanged();
62 
63       endCmdInfo["startLayoutTick"] = cs ? cs->cmdState().startTick().ticks() : -1;
64       endCmdInfo["endLayoutTick"] = cs ? cs->cmdState().endTick().ticks() : -1;
65 
66       endCmdInfo["undoRedo"] = undoRedo;
67       }
68 
69 //---------------------------------------------------------
70 //   QmlPluginEngine::endEndCmd
71 //---------------------------------------------------------
72 
endEndCmd(MuseScore *)73 void QmlPluginEngine::endEndCmd(MuseScore*)
74       {
75       if (cmdCount >= maxCmdCount) {
76             QMessageBox::warning(mscore, tr("Plugin Error"), tr("Score update recursion limit reached (%1)").arg(maxCmdCount));
77             recursion = true;
78             }
79 
80       if (!recursion)
81             emit endCmd(endCmdInfo);
82 
83       --cmdCount;
84       if (!cmdCount) {
85             recursion = false;
86             undoRedo = false;
87             lastScoreState = currScoreState;
88             }
89       }
90 
91 //---------------------------------------------------------
92 //   QmlPluginEngine::inScoreChangeActionHandler
93 ///   Returns \p true if the engine is in process of
94 ///   handling endCmd() call which is a result of score
95 ///   change user action (not undo/redo or simple selection
96 ///   changes/mouse clicks etc.)
97 //---------------------------------------------------------
98 
inScoreChangeActionHandler() const99 bool QmlPluginEngine::inScoreChangeActionHandler() const
100       {
101       return cmdCount > 0 && !undoRedo && currScoreState.isNewerThan(lastScoreState);
102       }
103 }
104