1 //=============================================================================
2 //  MuseScore
3 //  Music Composition & Notation
4 //
5 //  Copyright (C) 2002-2016 Werner Schweer
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 //  as published by the Free Software Foundation and appearing in
10 //  the file LICENCE.GPL
11 //=============================================================================
12 
13 /**
14  \file
15  Implementation of undo functions.
16 
17  The undo system requires calling startUndo() when starting a GUI command
18  and calling endUndo() when ending the command. All changes to a score
19  in response to a GUI command must be undoable/redoable by executing
20  a sequence of low-level undo operations. This sequence is built by the code
21  handling the command, by calling one or more undoOp()'s
22  between startUndo() and endUndo().
23 */
24 
25 #include "global/log.h"
26 #include "undo.h"
27 #include "element.h"
28 #include "note.h"
29 #include "score.h"
30 #include "segment.h"
31 #include "measure.h"
32 #include "system.h"
33 #include "select.h"
34 #include "input.h"
35 #include "slur.h"
36 #include "tie.h"
37 #include "clef.h"
38 #include "staff.h"
39 #include "chord.h"
40 #include "sig.h"
41 #include "key.h"
42 #include "barline.h"
43 #include "volta.h"
44 #include "tuplet.h"
45 #include "harmony.h"
46 #include "pitchspelling.h"
47 #include "part.h"
48 #include "beam.h"
49 #include "dynamic.h"
50 #include "page.h"
51 #include "keysig.h"
52 #include "image.h"
53 #include "hairpin.h"
54 #include "rest.h"
55 #include "bend.h"
56 #include "tremolobar.h"
57 #include "articulation.h"
58 #include "noteevent.h"
59 #include "slur.h"
60 #include "tempotext.h"
61 #include "instrchange.h"
62 #include "box.h"
63 #include "stafftype.h"
64 #include "accidental.h"
65 #include "layoutbreak.h"
66 #include "spanner.h"
67 #include "sequencer.h"
68 #include "breath.h"
69 #include "fingering.h"
70 #include "rehearsalmark.h"
71 #include "excerpt.h"
72 #include "stafftext.h"
73 #include "chordline.h"
74 #include "tremolo.h"
75 #include "sym.h"
76 #include "utils.h"
77 #include "glissando.h"
78 #include "stafflines.h"
79 #include "bracket.h"
80 #include "fret.h"
81 #include "textedit.h"
82 #include "textline.h"
83 
84 namespace Ms {
85 
86 extern Measure* tick2measure(int tick);
87 
88 //---------------------------------------------------------
89 //   updateNoteLines
90 //    compute line position of noteheads after
91 //    clef change
92 //---------------------------------------------------------
93 
updateNoteLines(Segment * segment,int track)94 void updateNoteLines(Segment* segment, int track)
95       {
96       Staff* staff = segment->score()->staff(track / VOICES);
97       if (staff->isDrumStaff(segment->tick()) || staff->isTabStaff(segment->tick()))
98             return;
99       for (Segment* s = segment->next1(); s; s = s->next1()) {
100             if ((s->segmentType() & (SegmentType::Clef | SegmentType::HeaderClef)) && s->element(track) && !s->element(track)->generated())
101                   break;
102             if (!s->isChordRestType())
103                   continue;
104             for (int t = track; t < track + VOICES; ++t) {
105                   Element* e = s->element(t);
106                   if (e && e->isChord()) {
107                         Chord* chord = toChord(e);
108                         for (Note* n : chord->notes())
109                               n->updateLine();
110                         chord->sortNotes();
111                         for (Chord* gc : chord->graceNotes()) {
112                               for (Note* gn : gc->notes())
113                                     gn->updateLine();
114                               gc->sortNotes();
115                               }
116                         }
117                   }
118             }
119       }
120 
121 //---------------------------------------------------------
122 //   UndoCommand
123 //---------------------------------------------------------
124 
~UndoCommand()125 UndoCommand::~UndoCommand()
126       {
127       for (auto c : qAsConst(childList))
128             delete c;
129       }
130 
131 //---------------------------------------------------------
132 //   UndoCommand::cleanup
133 //---------------------------------------------------------
134 
cleanup(bool undo)135 void UndoCommand::cleanup(bool undo)
136       {
137       for (auto c : qAsConst(childList))
138             c->cleanup(undo);
139       }
140 
141 //---------------------------------------------------------
142 //   undo
143 //---------------------------------------------------------
144 
undo(EditData * ed)145 void UndoCommand::undo(EditData* ed)
146       {
147       int n = childList.size();
148       for (int i = n-1; i >= 0; --i) {
149             qCDebug(undoRedo) << "<" << childList[i]->name() << ">";
150             childList[i]->undo(ed);
151             }
152       flip(ed);
153       }
154 
155 //---------------------------------------------------------
156 //   redo
157 //---------------------------------------------------------
158 
redo(EditData * ed)159 void UndoCommand::redo(EditData* ed)
160       {
161       int n = childList.size();
162       for (int i = 0; i < n; ++i) {
163             qCDebug(undoRedo) << "<" << childList[i]->name() << ">";
164             childList[i]->redo(ed);
165             }
166       flip(ed);
167       }
168 
169 //---------------------------------------------------------
170 //   appendChildren
171 ///   Append children of \p other into this UndoCommand.
172 ///   Ownership over child commands of \p other is
173 ///   transferred to this UndoCommand.
174 //---------------------------------------------------------
175 
appendChildren(UndoCommand * other)176 void UndoCommand::appendChildren(UndoCommand* other)
177       {
178       childList.append(other->childList);
179       other->childList.clear();
180       }
181 
182 //---------------------------------------------------------
183 //   hasFilteredChildren
184 //---------------------------------------------------------
185 
hasFilteredChildren(UndoCommand::Filter f,const Element * target) const186 bool UndoCommand::hasFilteredChildren(UndoCommand::Filter f, const Element* target) const
187       {
188       for (UndoCommand* cmd : childList) {
189             if (cmd->isFiltered(f, target))
190                   return true;
191             }
192       return false;
193       }
194 
195 //---------------------------------------------------------
196 //   hasUnfilteredChildren
197 //---------------------------------------------------------
198 
hasUnfilteredChildren(const std::vector<UndoCommand::Filter> & filters,const Element * target) const199 bool UndoCommand::hasUnfilteredChildren(const std::vector<UndoCommand::Filter>& filters, const Element* target) const
200       {
201       for (UndoCommand* cmd : childList) {
202             bool filtered = false;
203             for (UndoCommand::Filter f : filters) {
204                   if (cmd->isFiltered(f, target)) {
205                         filtered = true;
206                         break;
207                         }
208                   }
209             if (!filtered)
210                   return true;
211             }
212       return false;
213       }
214 
215 //---------------------------------------------------------
216 //   filterChildren
217 //---------------------------------------------------------
218 
filterChildren(UndoCommand::Filter f,Element * target)219 void UndoCommand::filterChildren(UndoCommand::Filter f, Element* target)
220       {
221       QList<UndoCommand*> acceptedList;
222       for (UndoCommand* cmd : qAsConst(childList)) {
223             if (cmd->isFiltered(f, target))
224                   delete cmd;
225             else
226                   acceptedList.push_back(cmd);
227             }
228       childList = std::move(acceptedList);
229       }
230 
231 //---------------------------------------------------------
232 //   unwind
233 //---------------------------------------------------------
234 
unwind()235 void UndoCommand::unwind()
236       {
237       while (!childList.empty()) {
238             UndoCommand* c = childList.takeLast();
239             qDebug("unwind <%s>", c->name());
240             c->undo(0);
241             delete c;
242             }
243       }
244 
245 //---------------------------------------------------------
246 //   UndoStack
247 //---------------------------------------------------------
248 
UndoStack()249 UndoStack::UndoStack()
250       {
251       curCmd   = 0;
252       curIdx   = 0;
253       cleanState = 0;
254       stateList.push_back(cleanState);
255       nextState = 1;
256       }
257 
258 //---------------------------------------------------------
259 //   UndoStack
260 //---------------------------------------------------------
261 
~UndoStack()262 UndoStack::~UndoStack()
263       {
264       int idx = 0;
265       for (auto c : qAsConst(list))
266             c->cleanup(idx++ < curIdx);
267       qDeleteAll(list);
268       }
269 
270 //---------------------------------------------------------
271 //   beginMacro
272 //---------------------------------------------------------
273 
beginMacro(Score * score)274 void UndoStack::beginMacro(Score* score)
275       {
276       if (curCmd) {
277             qWarning("already active");
278             return;
279             }
280       curCmd = new UndoMacro(score);
281       }
282 
283 //---------------------------------------------------------
284 //   push
285 //---------------------------------------------------------
286 
push(UndoCommand * cmd,EditData * ed)287 void UndoStack::push(UndoCommand* cmd, EditData* ed)
288       {
289       if (!curCmd) {
290             // this can happen for layout() outside of a command (load)
291             if (!ScoreLoad::loading())
292                   qDebug("no active command, UndoStack");
293 
294             cmd->redo(ed);
295             delete cmd;
296             return;
297             }
298 #ifndef QT_NO_DEBUG
299       if (!strcmp(cmd->name(), "ChangeProperty")) {
300             ChangeProperty* cp = static_cast<ChangeProperty*>(cmd);
301             qCDebug(undoRedo, "<%s> id %d %s", cmd->name(), int(cp->getId()), propertyName(cp->getId()));
302             }
303       else {
304             qCDebug(undoRedo, "<%s>", cmd->name());
305             }
306 #endif
307       curCmd->appendChild(cmd);
308       cmd->redo(ed);
309       }
310 
311 //---------------------------------------------------------
312 //   push1
313 //---------------------------------------------------------
314 
push1(UndoCommand * cmd)315 void UndoStack::push1(UndoCommand* cmd)
316       {
317       if (!curCmd) {
318             if (!ScoreLoad::loading())
319                   qWarning("no active command, UndoStack %p", this);
320             return;
321             }
322       curCmd->appendChild(cmd);
323       }
324 
325 //---------------------------------------------------------
326 //   remove
327 //---------------------------------------------------------
328 
remove(int idx)329 void UndoStack::remove(int idx)
330       {
331       Q_ASSERT(idx <= curIdx);
332       Q_ASSERT(curIdx >= 0);
333       // remove redo stack
334       while (list.size() > curIdx) {
335             UndoCommand* cmd = list.takeLast();
336             stateList.pop_back();
337             cmd->cleanup(false);  // delete elements for which UndoCommand() holds ownership
338             delete cmd;
339 //            --curIdx;
340             }
341       while (list.size() > idx) {
342             UndoCommand* cmd = list.takeLast();
343             stateList.pop_back();
344             cmd->cleanup(true);
345             delete cmd;
346             }
347       curIdx = idx;
348       }
349 
350 //---------------------------------------------------------
351 //   mergeCommands
352 //---------------------------------------------------------
353 
mergeCommands(int startIdx)354 void UndoStack::mergeCommands(int startIdx)
355       {
356       Q_ASSERT(startIdx <= curIdx);
357 
358       if (startIdx >= list.size())
359             return;
360 
361       UndoMacro* startMacro = list[startIdx];
362 
363       for (int idx = startIdx + 1; idx < curIdx; ++idx)
364             startMacro->append(std::move(*list[idx]));
365       remove(startIdx + 1); // TODO: remove from startIdx to curIdx only
366       }
367 
368 //---------------------------------------------------------
369 //   pop
370 //---------------------------------------------------------
371 
pop()372 void UndoStack::pop()
373       {
374       if (!curCmd) {
375             if (!ScoreLoad::loading())
376                   qWarning("no active command");
377             return;
378             }
379       UndoCommand* cmd = curCmd->removeChild();
380       cmd->undo(0);
381       }
382 
383 //---------------------------------------------------------
384 //   rollback
385 //---------------------------------------------------------
386 
rollback()387 void UndoStack::rollback()
388       {
389       qDebug("==");
390       Q_ASSERT(curCmd == 0);
391       Q_ASSERT(curIdx > 0);
392       int idx = curIdx - 1;
393       list[idx]->unwind();
394       remove(idx);
395       }
396 
397 //---------------------------------------------------------
398 //   endMacro
399 //---------------------------------------------------------
400 
endMacro(bool rollback)401 void UndoStack::endMacro(bool rollback)
402       {
403       if (curCmd == 0) {
404             qWarning("not active");
405             return;
406             }
407       if (rollback)
408             delete curCmd;
409       else {
410             // remove redo stack
411             while (list.size() > curIdx) {
412                   UndoCommand* cmd = list.takeLast();
413                   stateList.pop_back();
414                   cmd->cleanup(false);  // delete elements for which UndoCommand() holds ownership
415                   delete cmd;
416                   }
417             list.append(curCmd);
418             stateList.push_back(nextState++);
419             ++curIdx;
420             }
421       curCmd = 0;
422       }
423 
424 //---------------------------------------------------------
425 //   reopen
426 //---------------------------------------------------------
427 
reopen()428 void UndoStack::reopen()
429       {
430       qDebug("curIdx %d size %d", curIdx, list.size());
431       Q_ASSERT(curCmd == 0);
432       Q_ASSERT(curIdx > 0);
433       --curIdx;
434       curCmd = list.takeAt(curIdx);
435       stateList.erase(stateList.begin() + curIdx);
436       for (auto i : curCmd->commands()) {
437             qDebug("   <%s>", i->name());
438             }
439       }
440 
441 //---------------------------------------------------------
442 //   setClean
443 //---------------------------------------------------------
444 
setClean()445 void UndoStack::setClean()
446       {
447       cleanState = state();
448       }
449 
450 //---------------------------------------------------------
451 //   undo
452 //---------------------------------------------------------
453 
undo(EditData * ed)454 void UndoStack::undo(EditData* ed)
455       {
456       qCDebug(undoRedo) << "===";
457       // Are we currently editing text?
458       if (ed && ed->element && ed->element->isTextBase()) {
459             TextEditData* ted = static_cast<TextEditData*>(ed->getData(ed->element));
460             if (ted && ted->startUndoIdx == curIdx)
461                   // No edits to undo, so do nothing
462                   return;
463             }
464       if (curIdx) {
465             --curIdx;
466             Q_ASSERT(curIdx >= 0);
467             list[curIdx]->undo(ed);
468             }
469       }
470 
471 //---------------------------------------------------------
472 //   redo
473 //---------------------------------------------------------
474 
redo(EditData * ed)475 void UndoStack::redo(EditData* ed)
476       {
477       qCDebug(undoRedo) << "===";
478       if (canRedo())
479             list[curIdx++]->redo(ed);
480       }
481 
482 //---------------------------------------------------------
483 //   UndoMacro
484 //---------------------------------------------------------
485 
canRecordSelectedElement(const Element * e)486 bool UndoMacro::canRecordSelectedElement(const Element* e)
487       {
488       return e->isNote() || (e->isChordRest() && !e->isChord()) || (e->isTextBase() && !e->isInstrumentName()) || e->isFretDiagram();
489       }
490 
fillSelectionInfo(SelectionInfo & info,const Selection & sel)491 void UndoMacro::fillSelectionInfo(SelectionInfo& info, const Selection& sel)
492       {
493       info.staffStart = info.staffEnd = -1;
494       info.elements.clear();
495 
496       if (sel.isList()) {
497             for (Element* e : sel.elements()) {
498                   if (canRecordSelectedElement(e))
499                         info.elements.push_back(e);
500                   else {
501                         // don't remember selection we are unable to restore
502                         info.elements.clear();
503                         return;
504                         }
505                   }
506             }
507       else if (sel.isRange()) {
508             info.staffStart = sel.staffStart();
509             info.staffEnd = sel.staffEnd();
510             info.tickStart = sel.tickStart();
511             info.tickEnd = sel.tickEnd();
512             }
513       }
514 
applySelectionInfo(const SelectionInfo & info,Selection & sel)515 void UndoMacro::applySelectionInfo(const SelectionInfo& info, Selection& sel)
516       {
517       if (!info.elements.empty()) {
518             for (Element* e : info.elements)
519                   sel.add(e);
520             }
521       else if (info.staffStart != -1) {
522             sel.setRangeTicks(info.tickStart, info.tickEnd, info.staffStart, info.staffEnd);
523             }
524       }
525 
UndoMacro(Score * s)526 UndoMacro::UndoMacro(Score* s)
527    : undoInputState(s->inputState()), score(s)
528       {
529       fillSelectionInfo(undoSelectionInfo, s->selection());
530       }
531 
undo(EditData * ed)532 void UndoMacro::undo(EditData* ed)
533       {
534       redoInputState = score->inputState();
535       fillSelectionInfo(redoSelectionInfo, score->selection());
536       score->deselectAll();
537 
538       // Undo for child commands.
539       UndoCommand::undo(ed);
540 
541       score->setInputState(undoInputState);
542       if (undoSelectionInfo.isValid()) {
543             score->deselectAll();
544             applySelectionInfo(undoSelectionInfo, score->selection());
545             }
546       }
547 
redo(EditData * ed)548 void UndoMacro::redo(EditData* ed)
549       {
550       undoInputState = score->inputState();
551       fillSelectionInfo(undoSelectionInfo, score->selection());
552       score->deselectAll();
553 
554       // Redo for child commands.
555       UndoCommand::redo(ed);
556 
557       score->setInputState(redoInputState);
558       if (redoSelectionInfo.isValid()) {
559             score->deselectAll();
560             applySelectionInfo(redoSelectionInfo, score->selection());
561             }
562       }
563 
append(UndoMacro && other)564 void UndoMacro::append(UndoMacro&& other)
565       {
566       appendChildren(&other);
567       if (score == other.score) {
568             redoInputState = std::move(other.redoInputState);
569             redoSelectionInfo = std::move(other.redoSelectionInfo);
570             }
571       }
572 
573 //---------------------------------------------------------
574 //   CloneVoice
575 //---------------------------------------------------------
576 
CloneVoice(Segment * _sf,const Fraction & _lTick,Segment * _d,int _strack,int _dtrack,int _otrack,bool _linked)577 CloneVoice::CloneVoice(Segment* _sf, const Fraction& _lTick, Segment* _d, int _strack, int _dtrack, int _otrack, bool _linked)
578       {
579       sf      = _sf;          // first source segment
580       lTick   = _lTick;       // last tick to clone
581       d       = _d;           // first destination segment
582       strack  = _strack;
583       dtrack  = _dtrack;
584       otrack  = _otrack;      // old source track if -1 delete voice in strack after copy
585       linked  = _linked;      // if true  add elements in destination segment only
586                               // if false add elements in every linked staff
587       }
588 
undo(EditData *)589 void CloneVoice::undo(EditData*)
590       {
591       Score* s = d->score();
592       Fraction ticks = d->tick() + lTick - sf->tick();
593       int sTrack = otrack == -1 ? dtrack : otrack; // use the correct source / destination if deleting the source
594       int dTrack = otrack == -1 ? strack : dtrack;
595 
596       // Clear destination voice (in case of not linked and otrack = -1 we would delete our source
597       if (otrack != -1 && linked)
598             for (Segment* seg = d; seg && seg->tick() < ticks; seg = seg->next1()) {
599                   Element* el = seg->element(dTrack);
600                   if (el && el->isChordRest()) {
601                         el->unlink();
602                         seg->setElement(dTrack, 0);
603                         }
604                   }
605 
606       if (otrack == -1 && !linked) {
607             // On the first run get going the undo redo action for adding/deleting elements and slurs
608             if (first) {
609                   s->cloneVoice(sTrack, dTrack, sf, ticks, linked);
610                   auto spanners = s->spannerMap().findOverlapping(sf->tick().ticks(), lTick.ticks());
611                   for (auto i = spanners.begin(); i < spanners.end(); i++) {
612                         Spanner* sp = i->value;
613                         if (sp->isSlur() && (sp->track() == sTrack || sp->track2() == sTrack))
614                               s->undoRemoveElement(sp);
615                         }
616                   for (Segment* seg = d; seg && seg->tick() < ticks; seg = seg->next1()) {
617                         Element* el = seg->element(sTrack);
618                         if (el && el->isChordRest()) {
619                               s->undoRemoveElement(el);
620                               }
621                         }
622                   }
623             // Set rests if first voice in a staff
624             if (!(sTrack % VOICES))
625                   s->setRest(d->tick(), sTrack, ticks, false, 0);
626             }
627       else {
628             s->cloneVoice(sTrack, dTrack, sf, ticks, linked);
629             if (!linked && !(dTrack % VOICES))
630                   s->setRest(d->tick(), dTrack, ticks, false, 0);
631             }
632 
633       first = false;
634       }
635 
redo(EditData *)636 void CloneVoice::redo(EditData*)
637       {
638       Score* s = d->score();
639       Fraction ticks = d->tick() + lTick - sf->tick();
640 
641       // Clear destination voice (in case of not linked and otrack = -1 we would delete our source
642       if (otrack != -1 && linked)
643             for (Segment* seg = d; seg && seg->tick() < ticks; seg = seg->next1()) {
644                   Element* el = seg->element(dtrack);
645                   if (el && el->isChordRest()) {
646                         el->unlink();
647                         seg->setElement(dtrack, 0);
648                         }
649                   }
650 
651       if (otrack == -1 && !linked) {
652             // On the first run get going the undo redo action for adding/deleting elements and slurs
653             if (first) {
654                   s->cloneVoice(strack, dtrack, sf, ticks, linked);
655                   auto spanners = s->spannerMap().findOverlapping(sf->tick().ticks(), lTick.ticks());
656                   for (auto i = spanners.begin(); i < spanners.end(); i++) {
657                         Spanner* sp = i->value;
658                         if (sp->isSlur() && (sp->track() == strack || sp->track2() == strack))
659                               s->undoRemoveElement(sp);
660                         }
661                   for (Segment* seg = d; seg && seg->tick() < ticks; seg = seg->next1()) {
662                         Element* el = seg->element(strack);
663                         if (el && el->isChordRest()) {
664                               s->undoRemoveElement(el);
665                               }
666                         }
667                   }
668             // Set rests if first voice in a staff
669             if (!(strack % VOICES))
670                   s->setRest(d->tick(), strack, ticks, false, 0);
671             }
672       else
673             s->cloneVoice(strack, dtrack, sf, ticks, linked, first);
674       }
675 
676 //---------------------------------------------------------
677 //   AddElement
678 //---------------------------------------------------------
679 
AddElement(Element * e)680 AddElement::AddElement(Element* e)
681       {
682       element = e;
683       }
684 
685 //---------------------------------------------------------
686 //   AddElement::cleanup
687 //---------------------------------------------------------
688 
cleanup(bool undo)689 void AddElement::cleanup(bool undo)
690       {
691       if (!undo) {
692             delete element;
693             element = 0;
694             }
695       }
696 
697 //---------------------------------------------------------
698 //   undoRemoveTuplet
699 //---------------------------------------------------------
700 
undoRemoveTuplet(DurationElement * cr)701 static void undoRemoveTuplet(DurationElement* cr)
702       {
703       if (cr->tuplet()) {
704             cr->tuplet()->remove(cr);
705             if (cr->tuplet()->elements().empty())
706                   undoRemoveTuplet(cr->tuplet());
707             }
708       }
709 
710 //---------------------------------------------------------
711 //   undoAddTuplet
712 //---------------------------------------------------------
713 
undoAddTuplet(DurationElement * cr)714 static void undoAddTuplet(DurationElement* cr)
715       {
716       if (cr->tuplet()) {
717             cr->tuplet()->add(cr);
718             if (cr->tuplet()->elements().size() == 1)
719                   undoAddTuplet(cr->tuplet());
720             }
721       }
722 
723 //---------------------------------------------------------
724 //   endUndoRedo
725 //---------------------------------------------------------
726 
endUndoRedo(bool isUndo) const727 void AddElement::endUndoRedo(bool isUndo) const
728       {
729       if (element->isChordRest()) {
730             if (isUndo)
731                   undoRemoveTuplet(toChordRest(element));
732             else
733                   undoAddTuplet(toChordRest(element));
734             }
735       else if (element->isClef()) {
736             element->triggerLayout();
737             element->score()->setLayout(element->staff()->nextClefTick(element->tick()), element->staffIdx());
738             }
739       else if (element->isKeySig()) {
740             element->triggerLayout();
741             element->score()->setLayout(element->staff()->nextKeyTick(element->tick()), element->staffIdx());
742             }
743       }
744 
745 //---------------------------------------------------------
746 //   undo
747 //---------------------------------------------------------
748 
undo(EditData *)749 void AddElement::undo(EditData*)
750       {
751       if (!element->isTuplet())
752             element->score()->removeElement(element);
753       endUndoRedo(true);
754       }
755 
756 //---------------------------------------------------------
757 //   redo
758 //---------------------------------------------------------
759 
redo(EditData *)760 void AddElement::redo(EditData*)
761       {
762       if (!element->isTuplet())
763             element->score()->addElement(element);
764       endUndoRedo(false);
765       }
766 
767 //---------------------------------------------------------
768 //   name
769 //---------------------------------------------------------
770 
name() const771 const char* AddElement::name() const
772       {
773       static char buffer[64];
774       if (element->isTextBase())
775             snprintf(buffer, 64, "Add:    %s <%s> %p", element->name(),
776                qPrintable(toTextBase(element)->plainText()), element);
777       else if (element->isSegment())
778             snprintf(buffer, 64, "Add:    <%s-%s> %p", element->name(), toSegment(element)->subTypeName(), element);
779       else
780             snprintf(buffer, 64, "Add:    <%s> %p", element->name(), element);
781       return buffer;
782       }
783 
784 //---------------------------------------------------------
785 //   AddElement::isFiltered
786 //---------------------------------------------------------
787 
isFiltered(UndoCommand::Filter f,const Element * target) const788 bool AddElement::isFiltered(UndoCommand::Filter f, const Element* target) const
789       {
790       using Filter = UndoCommand::Filter;
791       switch (f) {
792             case Filter::AddElement:
793                   return target == element;
794             case Filter::AddElementLinked:
795                   return target->linkList().contains(element);
796             default:
797                   break;
798             }
799       return false;
800       }
801 
802 //---------------------------------------------------------
803 //   removeNote
804 //    Helper function for RemoveElement class
805 //---------------------------------------------------------
806 
removeNote(const Note * note)807 static void removeNote(const Note* note)
808       {
809       Score* score = note->score();
810       if (note->tieFor() && note->tieFor()->endNote())
811             score->undo(new RemoveElement(note->tieFor()));
812       if (note->tieBack())
813             score->undo(new RemoveElement(note->tieBack()));
814       for (Spanner* s : note->spannerBack()) {
815             score->undo(new RemoveElement(s));
816             }
817       for (Spanner* s : note->spannerFor()) {
818             score->undo(new RemoveElement(s));
819             }
820       }
821 
822 //---------------------------------------------------------
823 //   RemoveElement
824 //---------------------------------------------------------
825 
RemoveElement(Element * e)826 RemoveElement::RemoveElement(Element* e)
827       {
828       element = e;
829 
830       Score* score = element->score();
831       if (element->isChordRest()) {
832             ChordRest* cr = toChordRest(element);
833             if (cr->tuplet() && cr->tuplet()->elements().size() <= 1)
834                   score->undo(new RemoveElement(cr->tuplet()));
835             if (e->isChord()) {
836                   Chord* chord = toChord(e);
837                   // remove tremolo between 2 notes
838                   if (chord->tremolo()) {
839                         Tremolo* tremolo = chord->tremolo();
840                         if (tremolo->twoNotes())
841                               score->undo(new RemoveElement(tremolo));
842                         }
843                   for (const Note* note : chord->notes()) {
844                         removeNote(note);
845                         }
846                   }
847             }
848       else if (element->isNote()) {
849             // Removing an individual note within a chord
850             const Note* note = toNote(element);
851             removeNote(note);
852             }
853       }
854 
855 //---------------------------------------------------------
856 //   RemoveElement::cleanup
857 //---------------------------------------------------------
858 
cleanup(bool undo)859 void RemoveElement::cleanup(bool undo)
860       {
861       if (undo) {
862             delete element;
863             element = 0;
864             }
865       }
866 
867 //---------------------------------------------------------
868 //   undo
869 //---------------------------------------------------------
870 
undo(EditData *)871 void RemoveElement::undo(EditData*)
872       {
873       if (!element->isTuplet())
874             element->score()->addElement(element);
875       if (element->isChordRest()) {
876             if (element->isChord()) {
877                   Chord* chord = toChord(element);
878                   for (Note* note : chord->notes()) {
879                         note->connectTiedNotes();
880                         }
881                   }
882             undoAddTuplet(toChordRest(element));
883             }
884       else if (element->isClef())
885             element->score()->setLayout(element->staff()->nextClefTick(element->tick()), element->staffIdx());
886       else if (element->isKeySig())
887             element->score()->setLayout(element->staff()->nextKeyTick(element->tick()), element->staffIdx());
888       }
889 
890 //---------------------------------------------------------
891 //   redo
892 //---------------------------------------------------------
893 
redo(EditData *)894 void RemoveElement::redo(EditData*)
895       {
896       if (!element->isTuplet())
897             element->score()->removeElement(element);
898       if (element->isChordRest()) {
899             undoRemoveTuplet(toChordRest(element));
900             if (element->isChord()) {
901                   Chord* chord = toChord(element);
902                   for (Note* note : chord->notes()) {
903                         note->disconnectTiedNotes();
904                         }
905                   }
906             }
907       else if (element->isClef())
908             element->score()->setLayout(element->staff()->nextClefTick(element->tick()), element->staffIdx());
909       else if (element->isKeySig())
910             element->score()->setLayout(element->staff()->nextKeyTick(element->tick()), element->staffIdx());
911       }
912 
913 //---------------------------------------------------------
914 //   name
915 //---------------------------------------------------------
916 
name() const917 const char* RemoveElement::name() const
918       {
919       static char buffer[64];
920       if (element->isTextBase())
921             snprintf(buffer, 64, "Remove: %s <%s> %p", element->name(),
922                qPrintable(toTextBase(element)->plainText()), element);
923       else if (element->isSegment())
924             snprintf(buffer, 64, "Remove: <%s-%s> %p", element->name(), toSegment(element)->subTypeName(), element);
925       else
926             snprintf(buffer, 64, "Remove: %s %p", element->name(), element);
927       return buffer;
928       }
929 
930 //---------------------------------------------------------
931 //   RemoveElement::isFiltered
932 //---------------------------------------------------------
933 
isFiltered(UndoCommand::Filter f,const Element * target) const934 bool RemoveElement::isFiltered(UndoCommand::Filter f, const Element* target) const
935       {
936       using Filter = UndoCommand::Filter;
937       switch (f) {
938             case Filter::RemoveElement:
939                   return target == element;
940             case Filter::RemoveElementLinked:
941                   return target->linkList().contains(element);
942             default:
943                   break;
944             }
945       return false;
946       }
947 
948 //---------------------------------------------------------
949 //   InsertPart
950 //---------------------------------------------------------
951 
InsertPart(Part * p,int i)952 InsertPart::InsertPart(Part* p, int i)
953       {
954       part = p;
955       idx  = i;
956       }
957 
undo(EditData *)958 void InsertPart::undo(EditData*)
959       {
960       part->score()->removePart(part);
961       }
962 
redo(EditData *)963 void InsertPart::redo(EditData*)
964       {
965       part->score()->insertPart(part, idx);
966       }
967 
968 //---------------------------------------------------------
969 //   RemovePart
970 //---------------------------------------------------------
971 
RemovePart(Part * p,int i)972 RemovePart::RemovePart(Part* p, int i)
973       {
974       part = p;
975       idx  = i;
976       }
977 
undo(EditData *)978 void RemovePart::undo(EditData*)
979       {
980       part->score()->insertPart(part, idx);
981       }
982 
redo(EditData *)983 void RemovePart::redo(EditData*)
984       {
985       part->score()->removePart(part);
986       }
987 
988 //---------------------------------------------------------
989 //   InsertStaff
990 //---------------------------------------------------------
991 
InsertStaff(Staff * p,int _ridx)992 InsertStaff::InsertStaff(Staff* p, int _ridx)
993       {
994       staff = p;
995       ridx  = _ridx;
996       }
997 
undo(EditData *)998 void InsertStaff::undo(EditData*)
999       {
1000       staff->score()->removeStaff(staff);
1001       }
1002 
redo(EditData *)1003 void InsertStaff::redo(EditData*)
1004       {
1005       staff->score()->insertStaff(staff, ridx);
1006       }
1007 
1008 //---------------------------------------------------------
1009 //   RemoveStaff
1010 //---------------------------------------------------------
1011 
RemoveStaff(Staff * p)1012 RemoveStaff::RemoveStaff(Staff* p)
1013       {
1014       staff = p;
1015       ridx  = staff->rstaff();
1016       }
1017 
undo(EditData *)1018 void RemoveStaff::undo(EditData*)
1019       {
1020       staff->score()->insertStaff(staff, ridx);
1021       }
1022 
redo(EditData *)1023 void RemoveStaff::redo(EditData*)
1024       {
1025       staff->score()->removeStaff(staff);
1026       }
1027 
1028 //---------------------------------------------------------
1029 //   InsertMStaff
1030 //---------------------------------------------------------
1031 
InsertMStaff(Measure * m,MStaff * ms,int i)1032 InsertMStaff::InsertMStaff(Measure* m, MStaff* ms, int i)
1033       {
1034       measure = m;
1035       mstaff  = ms;
1036       idx     = i;
1037       }
1038 
undo(EditData *)1039 void InsertMStaff::undo(EditData*)
1040       {
1041       measure->removeMStaff(mstaff, idx);
1042       }
1043 
redo(EditData *)1044 void InsertMStaff::redo(EditData*)
1045       {
1046       measure->insertMStaff(mstaff, idx);
1047       }
1048 
1049 //---------------------------------------------------------
1050 //   RemoveMStaff
1051 //---------------------------------------------------------
1052 
RemoveMStaff(Measure * m,MStaff * ms,int i)1053 RemoveMStaff::RemoveMStaff(Measure* m, MStaff* ms, int i)
1054       {
1055       measure = m;
1056       mstaff  = ms;
1057       idx     = i;
1058       }
1059 
undo(EditData *)1060 void RemoveMStaff::undo(EditData*)
1061       {
1062       measure->insertMStaff(mstaff, idx);
1063       }
1064 
redo(EditData *)1065 void RemoveMStaff::redo(EditData*)
1066       {
1067       measure->removeMStaff(mstaff, idx);
1068       }
1069 
1070 //---------------------------------------------------------
1071 //   SortStaves
1072 //---------------------------------------------------------
1073 
SortStaves(Score * s,QList<int> l)1074 SortStaves::SortStaves(Score* s, QList<int> l)
1075       {
1076       score = s;
1077 
1078       for(int i=0 ; i < l.size(); i++) {
1079             rlist.append(l.indexOf(i));
1080             }
1081       list  = l;
1082       }
1083 
redo(EditData *)1084 void SortStaves::redo(EditData*)
1085       {
1086       score->sortStaves(list);
1087       }
1088 
undo(EditData *)1089 void SortStaves::undo(EditData*)
1090       {
1091       score->sortStaves(rlist);
1092       }
1093 
1094 //---------------------------------------------------------
1095 //   MapExcerptTracks
1096 //---------------------------------------------------------
1097 
MapExcerptTracks(Score * s,QList<int> l)1098 MapExcerptTracks::MapExcerptTracks(Score* s, QList<int> l)
1099       {
1100       score = s;
1101 
1102       /*
1103        *    In list l [x] represents the previous index of the staffIdx x.
1104        *    If the a staff x is a newly added staff, l[x] = -1.
1105        *    For the "undo" all staves which value -1 are *not* remapped since
1106        *    it is assumed this staves are removed later.
1107        */
1108       for (int i = 0; i < l.size(); ++i) {
1109             if (l[i] >= 0)
1110                   rlist.insert(l[i], i);
1111             }
1112       list = l;
1113       }
1114 
redo(EditData *)1115 void MapExcerptTracks::redo(EditData*)
1116       {
1117       score->mapExcerptTracks(list);
1118       }
1119 
undo(EditData *)1120 void MapExcerptTracks::undo(EditData*)
1121       {
1122       score->mapExcerptTracks(rlist);
1123       }
1124 
1125 //---------------------------------------------------------
1126 //   ChangePitch
1127 //---------------------------------------------------------
1128 
ChangePitch(Note * _note,int _pitch,int _tpc1,int _tpc2)1129 ChangePitch::ChangePitch(Note* _note, int _pitch, int _tpc1, int _tpc2)
1130       {
1131       note  = _note;
1132       pitch = _pitch;
1133       tpc1  = _tpc1;
1134       tpc2  = _tpc2;
1135       }
1136 
flip(EditData *)1137 void ChangePitch::flip(EditData*)
1138       {
1139       int f_pitch = note->pitch();
1140       int f_tpc1  = note->tpc1();
1141       int f_tpc2  = note->tpc2();
1142       // do not change unless necessary
1143       if (f_pitch == pitch && f_tpc1 == tpc1 && f_tpc2 == tpc2)
1144             return;
1145 
1146       note->setPitch(pitch, tpc1, tpc2);
1147       pitch = f_pitch;
1148       tpc1  = f_tpc1;
1149       tpc2  = f_tpc2;
1150 
1151       note->triggerLayout();
1152       }
1153 
1154 //---------------------------------------------------------
1155 //   ChangeFretting
1156 //
1157 //    To use with tablatures to force a specific note fretting;
1158 //    Pitch, string and fret must be changed all together; otherwise,
1159 //    if they are not consistent among themselves, the refretting algorithm may re-assign
1160 //    fret and string numbers for (potentially) all the notes of all the chords of a segment.
1161 //---------------------------------------------------------
1162 
ChangeFretting(Note * _note,int _pitch,int _string,int _fret,int _tpc1,int _tpc2)1163 ChangeFretting::ChangeFretting(Note* _note, int _pitch, int _string, int _fret, int _tpc1, int _tpc2)
1164       {
1165       note  = _note;
1166       pitch = _pitch;
1167       string= _string;
1168       fret  = _fret;
1169       tpc1  = _tpc1;
1170       tpc2  = _tpc2;
1171       }
1172 
flip(EditData *)1173 void ChangeFretting::flip(EditData*)
1174       {
1175       int f_pitch = note->pitch();
1176       int f_string= note->string();
1177       int f_fret  = note->fret();
1178       int f_tpc1  = note->tpc1();
1179       int f_tpc2  = note->tpc2();
1180       // do not change unless necessary
1181       if (f_pitch == pitch && f_string == string && f_fret == fret && f_tpc1 == tpc1 && f_tpc2 == tpc2) {
1182             return;
1183             }
1184 
1185       note->setPitch(pitch, tpc1, tpc2);
1186       note->setString(string);
1187       note->setFret(fret);
1188       pitch = f_pitch;
1189       string= f_string;
1190       fret  = f_fret;
1191       tpc1  = f_tpc1;
1192       tpc2  = f_tpc2;
1193       note->triggerLayout();
1194       }
1195 
1196 //---------------------------------------------------------
1197 //   ChangeElement
1198 //---------------------------------------------------------
1199 
ChangeElement(Element * oe,Element * ne)1200 ChangeElement::ChangeElement(Element* oe, Element* ne)
1201       {
1202       oldElement = oe;
1203       newElement = ne;
1204       }
1205 
flip(EditData *)1206 void ChangeElement::flip(EditData*)
1207       {
1208       const LinkedElements* links = oldElement->links();
1209       if (links) {
1210             newElement->linkTo(oldElement);
1211             oldElement->unlink();
1212             }
1213 
1214       Score* score = oldElement->score();
1215       if (!score->selection().isRange()) {
1216             if (oldElement->selected())
1217                   score->deselect(oldElement);
1218             if (newElement->selected())
1219                   score->select(newElement, SelectType::ADD);
1220             }
1221       if (oldElement->parent() == 0) {
1222             score->removeElement(oldElement);
1223             score->addElement(newElement);
1224             }
1225       else {
1226             oldElement->parent()->change(oldElement, newElement);
1227             }
1228 
1229       if (newElement->isKeySig()) {
1230             KeySig* ks = toKeySig(newElement);
1231             if (!ks->generated())
1232                   ks->staff()->setKey(ks->tick(), ks->keySigEvent());
1233             }
1234       else if (newElement->isDynamic())
1235             newElement->score()->addLayoutFlags(LayoutFlag::FIX_PITCH_VELO);
1236       else if (newElement->isTempoText()) {
1237             TempoText* t = toTempoText(oldElement);
1238             score->setTempo(t->segment(), t->tempo());
1239             }
1240 //      if (newElement->isSegmentFlag()) {
1241       if (newElement->isSpannerSegment()) {
1242             SpannerSegment* os = toSpannerSegment(oldElement);
1243             SpannerSegment* ns = toSpannerSegment(newElement);
1244             if (os->system())
1245                   os->system()->remove(os);
1246             if (ns->system())
1247                   ns->system()->add(ns);
1248             }
1249       qSwap(oldElement, newElement);
1250       oldElement->triggerLayout();
1251       newElement->triggerLayout();
1252       // score->setLayoutAll();
1253       }
1254 
1255 //---------------------------------------------------------
1256 //   InsertStaves
1257 //---------------------------------------------------------
1258 
InsertStaves(Measure * m,int _a,int _b)1259 InsertStaves::InsertStaves(Measure* m, int _a, int _b)
1260       {
1261       measure = m;
1262       a       = _a;
1263       b       = _b;
1264       }
1265 
undo(EditData *)1266 void InsertStaves::undo(EditData*)
1267       {
1268       measure->removeStaves(a, b);
1269       }
1270 
redo(EditData *)1271 void InsertStaves::redo(EditData*)
1272       {
1273       measure->insertStaves(a, b);
1274       }
1275 
1276 //---------------------------------------------------------
1277 //   RemoveStaves
1278 //---------------------------------------------------------
1279 
RemoveStaves(Measure * m,int _a,int _b)1280 RemoveStaves::RemoveStaves(Measure* m, int _a, int _b)
1281       {
1282       measure = m;
1283       a       = _a;
1284       b       = _b;
1285       }
1286 
undo(EditData *)1287 void RemoveStaves::undo(EditData*)
1288       {
1289       measure->insertStaves(a, b);
1290       }
1291 
redo(EditData *)1292 void RemoveStaves::redo(EditData*)
1293       {
1294       measure->removeStaves(a, b);
1295       }
1296 
1297 //---------------------------------------------------------
1298 //   ChangeKeySig
1299 //---------------------------------------------------------
1300 
ChangeKeySig(KeySig * k,KeySigEvent newKeySig,bool sc,bool addEvtToStaff)1301 ChangeKeySig::ChangeKeySig(KeySig* k, KeySigEvent newKeySig, bool sc, bool addEvtToStaff)
1302    : keysig(k), ks(newKeySig), showCourtesy(sc), evtInStaff(addEvtToStaff)
1303       {}
1304 
flip(EditData *)1305 void ChangeKeySig::flip(EditData*)
1306       {
1307       Segment* segment = keysig->segment();
1308       Fraction tick = segment->tick();
1309       Staff* staff = keysig->staff();
1310 
1311       const bool curEvtInStaff = (staff->currentKeyTick(tick) == tick);
1312       KeySigEvent curKey = keysig->keySigEvent();
1313       const bool curShowCourtesy = keysig->showCourtesy();
1314 
1315       keysig->setKeySigEvent(ks);
1316       keysig->setShowCourtesy(showCourtesy);
1317 
1318       // Add/remove the corresponding key events, if appropriate.
1319       if (evtInStaff)
1320             staff->setKey(tick, ks); // replace
1321       else if (curEvtInStaff)
1322             staff->removeKey(tick); // if nothing to add instead, just remove.
1323 
1324       // If no keysig event corresponds to the key signature then this keysig
1325       // is probably generated. Otherwise it is probably added manually.
1326       // Set segment flags according to this, layout will change it if needed.
1327       segment->setEnabled(evtInStaff);
1328       segment->setHeader(!evtInStaff && segment->rtick() == Fraction(0,1));
1329 
1330       showCourtesy = curShowCourtesy;
1331       ks           = curKey;
1332       evtInStaff   = curEvtInStaff;
1333       keysig->triggerLayout();
1334       keysig->score()->setLayout(keysig->staff()->nextKeyTick(tick), keysig->staffIdx());
1335       }
1336 
1337 //---------------------------------------------------------
1338 //   ChangeMeasureLen
1339 //---------------------------------------------------------
1340 
ChangeMeasureLen(Measure * m,Fraction l)1341 ChangeMeasureLen::ChangeMeasureLen(Measure* m, Fraction l)
1342       {
1343       measure     = m;
1344       len         = l;
1345       }
1346 
flip(EditData *)1347 void ChangeMeasureLen::flip(EditData*)
1348       {
1349       Fraction oLen = measure->ticks();
1350 
1351       //
1352       // move EndBarLine and TimeSigAnnounce
1353       // to end of measure:
1354       //
1355 
1356       std::list<Segment*> sl;
1357       for (Segment* s = measure->first(); s; s = s->next()) {
1358             if (!s->isEndBarLineType() && !s->isTimeSigAnnounceType())
1359                   continue;
1360             s->setRtick(len);
1361             sl.push_back(s);
1362             measure->remove(s);
1363             }
1364       measure->setTicks(len);
1365       measure->score()->fixTicks();
1366       len = oLen;
1367       }
1368 
1369 //---------------------------------------------------------
1370 //   TransposeHarmony
1371 //---------------------------------------------------------
1372 
TransposeHarmony(Harmony * h,int rtpc,int btpc)1373 TransposeHarmony::TransposeHarmony(Harmony* h, int rtpc, int btpc)
1374       {
1375       harmony = h;
1376       rootTpc = rtpc;
1377       baseTpc = btpc;
1378       }
1379 
flip(EditData *)1380 void TransposeHarmony::flip(EditData*)
1381       {
1382       harmony->realizedHarmony().setDirty(true); //harmony should be re-realized after transposition
1383       int baseTpc1 = harmony->baseTpc();
1384       int rootTpc1 = harmony->rootTpc();
1385       harmony->setBaseTpc(baseTpc);
1386       harmony->setRootTpc(rootTpc);
1387       harmony->setXmlText(harmony->harmonyName());
1388       harmony->render();
1389       rootTpc = rootTpc1;
1390       baseTpc = baseTpc1;
1391       }
1392 
1393 //---------------------------------------------------------
1394 //   ExchangeVoice
1395 //---------------------------------------------------------
1396 
ExchangeVoice(Measure * m,int _val1,int _val2,int _staff)1397 ExchangeVoice::ExchangeVoice(Measure* m, int _val1, int _val2, int _staff)
1398       {
1399       measure = m;
1400       val1    = _val1;
1401       val2    = _val2;
1402       staff   = _staff;
1403       }
1404 
undo(EditData *)1405 void ExchangeVoice::undo(EditData*)
1406       {
1407       measure->exchangeVoice(val2, val1, staff);
1408       measure->checkMultiVoices(staff);
1409       }
1410 
redo(EditData *)1411 void ExchangeVoice::redo(EditData*)
1412       {
1413       measure->exchangeVoice(val1, val2, staff);
1414       }
1415 
1416 //---------------------------------------------------------
1417 //   ChangeInstrumentShort
1418 //---------------------------------------------------------
1419 
ChangeInstrumentShort(const Fraction & _tick,Part * p,QList<StaffName> t)1420 ChangeInstrumentShort::ChangeInstrumentShort(const Fraction&_tick, Part* p, QList<StaffName> t)
1421       {
1422       tick = _tick;
1423       part = p;
1424       text = t;
1425       }
1426 
flip(EditData *)1427 void ChangeInstrumentShort::flip(EditData*)
1428       {
1429       QList<StaffName> s = part->shortNames(tick);
1430       part->setShortNames(text, tick);
1431       text = s;
1432       part->score()->setLayoutAll();
1433       }
1434 
1435 //---------------------------------------------------------
1436 //   ChangeInstrumentLong
1437 //---------------------------------------------------------
1438 
ChangeInstrumentLong(const Fraction & _tick,Part * p,QList<StaffName> t)1439 ChangeInstrumentLong::ChangeInstrumentLong(const Fraction& _tick, Part* p, QList<StaffName> t)
1440       {
1441       tick = _tick;
1442       part = p;
1443       text = t;
1444       }
1445 
flip(EditData *)1446 void ChangeInstrumentLong::flip(EditData*)
1447       {
1448       QList<StaffName> s = part->longNames(tick);
1449       part->setLongNames(text, tick);
1450       text = s;
1451       part->score()->setLayoutAll();
1452       }
1453 
1454 //---------------------------------------------------------
1455 //   EditText::undo
1456 //---------------------------------------------------------
1457 
undo(EditData *)1458 void EditText::undo(EditData*)
1459       {
1460 /*      if (!text->styled()) {
1461             for (int i = 0; i < undoLevel; ++i)
1462                   text->undo();
1463             }
1464       */
1465       undoRedo();
1466       }
1467 
1468 //---------------------------------------------------------
1469 //   EditText::redo
1470 //---------------------------------------------------------
1471 
redo(EditData *)1472 void EditText::redo(EditData*)
1473       {
1474 /*
1475       if (!text->styled()) {
1476             for (int i = 0; i < undoLevel; ++i)
1477                   text->redo();
1478             }
1479       */
1480       undoRedo();
1481       }
1482 
1483 //---------------------------------------------------------
1484 //   EditText::undoRedo
1485 //---------------------------------------------------------
1486 
undoRedo()1487 void EditText::undoRedo()
1488       {
1489       QString s = text->xmlText();
1490       text->setXmlText(oldText);
1491       oldText = s;
1492       text->triggerLayout();
1493       }
1494 
1495 //---------------------------------------------------------
1496 //   ChangePatch
1497 //---------------------------------------------------------
1498 
flip(EditData *)1499 void ChangePatch::flip(EditData*)
1500       {
1501       MidiPatch op;
1502       op.prog          = channel->program();
1503       op.bank          = channel->bank();
1504       op.synti         = channel->synti();
1505 
1506       channel->setProgram(patch.prog);
1507       channel->setBank(patch.bank);
1508       channel->setSynti(patch.synti);
1509 
1510       patch            = op;
1511 
1512       if (MScore::seq == 0) {
1513             qWarning("no seq");
1514             return;
1515             }
1516 
1517       NPlayEvent event;
1518       event.setType(ME_CONTROLLER);
1519       event.setChannel(channel->channel());
1520 
1521       int hbank = (channel->bank() >> 7) & 0x7f;
1522       int lbank = channel->bank() & 0x7f;
1523 
1524       event.setController(CTRL_HBANK);
1525       event.setValue(hbank);
1526       MScore::seq->sendEvent(event);
1527 
1528       event.setController(CTRL_LBANK);
1529       event.setValue(lbank);
1530       MScore::seq->sendEvent(event);
1531 
1532       event.setController(CTRL_PROGRAM);
1533       event.setValue(channel->program());
1534 
1535       score->setInstrumentsChanged(true);
1536 
1537       MScore::seq->sendEvent(event);
1538       }
1539 
1540 //---------------------------------------------------------
1541 //   SetUserBankController
1542 //---------------------------------------------------------
1543 
flip(EditData *)1544 void SetUserBankController::flip(EditData*)
1545       {
1546       bool oldVal = channel->userBankController();
1547       channel->setUserBankController(val);
1548       val = oldVal;
1549       }
1550 
1551 //---------------------------------------------------------
1552 //   ChangeStaff
1553 //---------------------------------------------------------
1554 
ChangeStaff(Staff * _staff,bool _invisible,ClefTypeList _clefType,qreal _userDist,Staff::HideMode _hideMode,bool _showIfEmpty,bool _cutaway,bool _hideSystemBarLine,bool _mergeMatchingRests)1555 ChangeStaff::ChangeStaff(Staff* _staff,  bool _invisible, ClefTypeList _clefType,
1556    qreal _userDist, Staff::HideMode _hideMode, bool _showIfEmpty, bool _cutaway,
1557    bool _hideSystemBarLine, bool  _mergeMatchingRests)
1558       {
1559       staff       = _staff;
1560       invisible   = _invisible;
1561       clefType    = _clefType;
1562       userDist    = _userDist;
1563       hideMode    = _hideMode;
1564       showIfEmpty = _showIfEmpty;
1565       cutaway     = _cutaway;
1566       hideSystemBarLine  = _hideSystemBarLine;
1567       mergeMatchingRests = _mergeMatchingRests;
1568       }
1569 
1570 //---------------------------------------------------------
1571 //   flip
1572 //---------------------------------------------------------
1573 
flip(EditData *)1574 void ChangeStaff::flip(EditData*)
1575       {
1576       bool invisibleChanged = staff->invisible(Fraction(0,1)) != invisible;
1577       ClefTypeList oldClefType = staff->defaultClefType();
1578       bool oldInvisible   = staff->invisible(Fraction(0,1));
1579       qreal oldUserDist   = staff->userDist();
1580       Staff::HideMode oldHideMode    = staff->hideWhenEmpty();
1581       bool oldShowIfEmpty = staff->showIfEmpty();
1582       bool oldCutaway     = staff->cutaway();
1583       bool oldHideSystemBarLine  = staff->hideSystemBarLine();
1584       bool oldMergeMatchingRests = staff->mergeMatchingRests();
1585 
1586       staff->setInvisible(Fraction(0,1),invisible);
1587       staff->setDefaultClefType(clefType);
1588       staff->setUserDist(userDist);
1589       staff->setHideWhenEmpty(hideMode);
1590       staff->setShowIfEmpty(showIfEmpty);
1591       staff->setCutaway(cutaway);
1592       staff->setHideSystemBarLine(hideSystemBarLine);
1593       staff->setMergeMatchingRests(mergeMatchingRests);
1594 
1595       invisible   = oldInvisible;
1596       clefType    = oldClefType;
1597       userDist    = oldUserDist;
1598       hideMode    = oldHideMode;
1599       showIfEmpty = oldShowIfEmpty;
1600       cutaway     = oldCutaway;
1601       hideSystemBarLine  = oldHideSystemBarLine;
1602       mergeMatchingRests = oldMergeMatchingRests;
1603 
1604       Score* score = staff->score();
1605       if (invisibleChanged) {
1606             int staffIdx = staff->idx();
1607             for (Measure* m = score->firstMeasure(); m; m = m->nextMeasure())
1608                   m->staffLines(staffIdx)->setVisible(!staff->invisible(Fraction(0,1)));
1609             }
1610       staff->triggerLayout();
1611       staff->masterScore()->rebuildMidiMapping();
1612       staff->score()->setPlaylistDirty();
1613       }
1614 
1615 //---------------------------------------------------------
1616 //   ChangeStaffType::flip
1617 //---------------------------------------------------------
1618 
flip(EditData *)1619 void ChangeStaffType::flip(EditData*)
1620       {
1621       StaffType st = *staff->staffType(Fraction(0,1));      // TODO
1622 
1623       staff->setStaffType(Fraction(0,1), staffType);
1624 
1625       staffType = st;
1626 
1627       staff->triggerLayout();
1628       }
1629 
1630 //---------------------------------------------------------
1631 //   ChangePart
1632 //---------------------------------------------------------
1633 
ChangePart(Part * _part,Instrument * i,const QString & s)1634 ChangePart::ChangePart(Part* _part, Instrument* i, const QString& s)
1635       {
1636       instrument = i;
1637       part       = _part;
1638       partName   = s;
1639       }
1640 
1641 //---------------------------------------------------------
1642 //   flip
1643 //---------------------------------------------------------
1644 
flip(EditData *)1645 void ChangePart::flip(EditData*)
1646       {
1647       Instrument* oi = part->instrument();  //tick?
1648       QString s      = part->partName();
1649       part->setInstrument(instrument);
1650       part->setPartName(partName);
1651 
1652       part->updateHarmonyChannels(false);
1653 
1654       Score* score = part->score();
1655       score->masterScore()->rebuildMidiMapping();
1656       score->setInstrumentsChanged(true);
1657       score->setPlaylistDirty();
1658 
1659       // check if notes need to be updated
1660       // true if changing into or away from TAB or from one TAB type to another
1661 
1662       score->setLayoutAll();
1663 
1664       partName   = s;
1665       instrument = oi;
1666       }
1667 
1668 //---------------------------------------------------------
1669 //   ChangeStyle
1670 //---------------------------------------------------------
1671 
ChangeStyle(Score * s,const MStyle & st,const bool overlapOnly)1672 ChangeStyle::ChangeStyle(Score* s, const MStyle& st, const bool overlapOnly)
1673    : score(s), style(st), overlap(overlapOnly)
1674       {
1675       }
1676 
1677 //---------------------------------------------------------
1678 //   flip
1679 //---------------------------------------------------------
1680 
flip(EditData *)1681 void ChangeStyle::flip(EditData*)
1682       {
1683       MStyle tmp = score->style();
1684 
1685       if (score->styleV(Sid::concertPitch) != style.value(Sid::concertPitch))
1686             score->cmdConcertPitchChanged(style.value(Sid::concertPitch).toBool(), true);
1687       if (score->styleV(Sid::MusicalSymbolFont) != style.value(Sid::MusicalSymbolFont)) {
1688             score->setScoreFont(ScoreFont::fontFactory(style.value(Sid::MusicalSymbolFont).toString()));
1689             }
1690 
1691       score->setStyle(style, overlap);
1692       score->styleChanged();
1693       style = tmp;
1694       }
1695 
undo(EditData * ed)1696 void ChangeStyle::undo(EditData* ed)
1697       {
1698       overlap = false;
1699       UndoCommand::undo(ed);
1700       }
1701 
1702 //---------------------------------------------------------
1703 //   ChangeStyleVal::flip
1704 //---------------------------------------------------------
1705 
flip(EditData *)1706 void ChangeStyleVal::flip(EditData*)
1707       {
1708       QVariant v = score->styleV(idx);
1709       if (v != value) {
1710             score->style().set(idx, value);
1711             switch (idx) {
1712                   case Sid::chordExtensionMag:
1713                   case Sid::chordExtensionAdjust:
1714                   case Sid::chordModifierMag:
1715                   case Sid::chordModifierAdjust:
1716                   case Sid::chordDescriptionFile: {
1717                         score->style().chordList()->unload();
1718                         qreal emag = score->styleD(Sid::chordExtensionMag);
1719                         qreal eadjust = score->styleD(Sid::chordExtensionAdjust);
1720                         qreal mmag = score->styleD(Sid::chordModifierMag);
1721                         qreal madjust = score->styleD(Sid::chordModifierAdjust);
1722                         score->style().chordList()->configureAutoAdjust(emag, eadjust, mmag, madjust);
1723                         if (score->styleB(Sid::chordsXmlFile))
1724                             score->style().chordList()->read("chords.xml");
1725                         score->style().chordList()->read(score->styleSt(Sid::chordDescriptionFile));
1726                         }
1727                         break;
1728                   case Sid::spatium:
1729                         score->spatiumChanged(v.toDouble(), value.toDouble());
1730                         break;
1731                   default:
1732                         break;
1733                   }
1734             score->styleChanged();
1735             }
1736       value = v;
1737       }
1738 
1739 //---------------------------------------------------------
1740 //   ChangePageNumberOffset::flip
1741 //---------------------------------------------------------
1742 
flip(EditData *)1743 void ChangePageNumberOffset::flip(EditData*)
1744       {
1745       int po = score->pageNumberOffset();
1746 
1747       score->setPageNumberOffset(pageOffset);
1748       score->setLayoutAll();
1749 
1750       pageOffset = po;
1751       }
1752 
1753 //---------------------------------------------------------
1754 //   ChangeChordStaffMove
1755 //---------------------------------------------------------
1756 
ChangeChordStaffMove(ChordRest * cr,int v)1757 ChangeChordStaffMove::ChangeChordStaffMove(ChordRest* cr, int v)
1758    : chordRest(cr), staffMove(v)
1759       {
1760       }
1761 
flip(EditData *)1762 void ChangeChordStaffMove::flip(EditData*)
1763       {
1764       int v = chordRest->staffMove();
1765       for (ScoreElement* e : chordRest->linkList()) {
1766             ChordRest* cr = toChordRest(e);
1767             cr->setStaffMove(staffMove);
1768             cr->triggerLayout();
1769             }
1770       staffMove = v;
1771       }
1772 
1773 //---------------------------------------------------------
1774 //   ChangeVelocity
1775 //---------------------------------------------------------
1776 
ChangeVelocity(Note * n,Note::ValueType t,int o)1777 ChangeVelocity::ChangeVelocity(Note* n, Note::ValueType t, int o)
1778    : note(n), veloType(t), veloOffset(o)
1779       {
1780       }
1781 
flip(EditData *)1782 void ChangeVelocity::flip(EditData*)
1783       {
1784       Note::ValueType t = note->veloType();
1785       int o       = note->veloOffset();
1786       note->setVeloType(veloType);
1787       note->setVeloOffset(veloOffset);
1788       veloType   = t;
1789       veloOffset = o;
1790       }
1791 
1792 //---------------------------------------------------------
1793 //   ChangeMStaffProperties
1794 //---------------------------------------------------------
1795 
ChangeMStaffProperties(Measure * m,int i,bool v,bool s)1796 ChangeMStaffProperties::ChangeMStaffProperties(Measure* m, int i, bool v, bool s)
1797    : measure(m), staffIdx(i), visible(v), stemless(s)
1798       {
1799       }
1800 
1801 //---------------------------------------------------------
1802 //   flip
1803 //---------------------------------------------------------
1804 
flip(EditData *)1805 void ChangeMStaffProperties::flip(EditData*)
1806       {
1807       bool v = measure->visible(staffIdx);
1808       bool s = measure->stemless(staffIdx);
1809       measure->setStaffVisible(staffIdx, visible);
1810       measure->setStaffStemless(staffIdx, stemless);
1811       visible    = v;
1812       stemless = s;
1813       }
1814 
1815 //---------------------------------------------------------
1816 //   getCourtesyClefs
1817 //    remember clefs at the end of previous measure
1818 //---------------------------------------------------------
1819 
getCourtesyClefs(Measure * m)1820 std::vector<Clef*> InsertRemoveMeasures::getCourtesyClefs(Measure* m)
1821       {
1822       Score* score = m->score();
1823       std::vector<Clef*> startClefs;
1824       if (m->prev() && m->prev()->isMeasure()) {
1825             Measure* prevMeasure = toMeasure(m->prev());
1826             const Segment* clefSeg = prevMeasure->findSegmentR(SegmentType::Clef | SegmentType::HeaderClef, prevMeasure->ticks());
1827             if (clefSeg) {
1828                   for (int st = 0; st < score->nstaves(); ++st) {
1829                         Element* clef = clefSeg->element(staff2track(st));
1830                         if (clef && clef->isClef())
1831                               startClefs.push_back(toClef(clef));
1832                         }
1833                   }
1834             }
1835       return startClefs;
1836       }
1837 
1838 //---------------------------------------------------------
1839 //   insertMeasures
1840 //---------------------------------------------------------
1841 
insertMeasures()1842 void InsertRemoveMeasures::insertMeasures()
1843       {
1844       Score* score = fm->score();
1845       QList<Clef*> clefs;
1846       std::vector<Clef*> prevMeasureClefs;
1847       QList<KeySig*> keys;
1848       Segment* fs = 0;
1849       Segment* ls = 0;
1850       if (fm->isMeasure()) {
1851             score->setPlaylistDirty();
1852             fs = toMeasure(fm)->first();
1853             ls = toMeasure(lm)->last();
1854             for (Segment* s = fs; s && s != ls; s = s->next1()) {
1855                   if (!s->enabled() || !(s->segmentType() & (SegmentType::Clef | SegmentType::HeaderClef | SegmentType::KeySig)))
1856                         continue;
1857                   for (int track = 0; track < score->ntracks(); track += VOICES) {
1858                         Element* e = s->element(track);
1859                         if (!e || e->generated())
1860                               continue;
1861                         if (e->isClef())
1862                               clefs.append(toClef(e));
1863                         else if (e->isKeySig())
1864                               keys.append(toKeySig(e));
1865                         }
1866                   }
1867             prevMeasureClefs = getCourtesyClefs(toMeasure(fm));
1868             }
1869       score->measures()->insert(fm, lm);
1870 
1871       if (fm->isMeasure()) {
1872             score->fixTicks();
1873             score->insertTime(fm->tick(), lm->endTick() - fm->tick());
1874 
1875             // move ownership of Instrument back to part
1876             for (Segment* s = fs; s && s != ls; s = s->next1()) {
1877                   for (Element* e : s->annotations()) {
1878                         if (e->isInstrumentChange()) {
1879                               e->part()->setInstrument(toInstrumentChange(e)->instrument(), s->tick());
1880                               }
1881                         }
1882                   }
1883             for (Clef* clef : prevMeasureClefs)
1884                   clef->staff()->setClef(clef);
1885             for (Clef* clef : clefs)
1886                   clef->staff()->setClef(clef);
1887             for (KeySig* key : keys)
1888                   key->staff()->setKey(key->segment()->tick(), key->keySigEvent());
1889             }
1890 
1891       score->setLayoutAll();
1892 
1893       //
1894       // connect ties
1895       //
1896 
1897       if (!fm->isMeasure() || !fm->prevMeasure())
1898             return;
1899       Measure* m = fm->prevMeasure();
1900       for (Segment* seg = m->first(); seg; seg = seg->next()) {
1901             for (int track = 0; track < score->ntracks(); ++track) {
1902                   Element* e = seg->element(track);
1903                   if (e == 0 || !e->isChord())
1904                         continue;
1905                   Chord* chord = toChord(e);
1906                   foreach (Note* n, chord->notes()) {
1907                         Tie* tie = n->tieFor();
1908                         if (!tie)
1909                               continue;
1910                         if (!tie->endNote() || tie->endNote()->chord()->segment()->measure() != m) {
1911                               Note* nn = searchTieNote(n);
1912                               if (nn) {
1913                                     tie->setEndNote(nn);
1914                                     nn->setTieBack(tie);
1915                                     }
1916                               }
1917                         }
1918                   }
1919             }
1920       }
1921 
1922 //---------------------------------------------------------
1923 //   removeMeasures
1924 //---------------------------------------------------------
1925 
removeMeasures()1926 void InsertRemoveMeasures::removeMeasures()
1927       {
1928       Score* score = fm->score();
1929 
1930       Fraction tick1 = fm->tick();
1931       Fraction tick2 = lm->endTick();
1932 
1933       QList<System*> systemList;
1934       for (MeasureBase* mb = lm;; mb = mb->prev()) {
1935             System* system = mb->system();
1936             if (system) {
1937                   if (!systemList.contains(system)) {
1938                         systemList.push_back(system);
1939                         }
1940                   system->removeMeasure(mb);
1941                   }
1942             if (mb == fm)
1943                   break;
1944             }
1945       score->measures()->remove(fm, lm);
1946 
1947       score->fixTicks();
1948       if (fm->isMeasure()) {
1949             score->setPlaylistDirty();
1950 
1951             // check if there is a clef at the end of last measure
1952             // remove clef from staff cleflist
1953 
1954             if (lm->isMeasure()) {
1955                   Measure* m = toMeasure(lm);
1956                   Segment* s = m->findSegment(SegmentType::Clef, tick2);
1957                   if (s) {
1958                         for (Element* e : s->elist()) {
1959                               Clef* clef = toClef(e);
1960                               if (clef)
1961                                     score->staff(clef->staffIdx())->removeClef(clef);
1962                               }
1963                         }
1964                   }
1965 
1966             // remember clefs at the end of previous measure
1967             const auto clefs = getCourtesyClefs(toMeasure(fm));
1968 
1969             if (score->firstMeasure())
1970                   score->insertTime(tick1, -(tick2 - tick1));
1971 
1972             // Restore clefs that were backed up. Events for them could be lost
1973             // as a result of the recent insertTime() call.
1974             for (Clef* clef : clefs)
1975                   clef->staff()->setClef(clef);
1976 
1977             for (Spanner* sp : score->unmanagedSpanners()) {
1978                   if ((sp->tick() >= tick1 && sp->tick() < tick2) || (sp->tick2() >= tick1 && sp->tick2() < tick2))
1979                         sp->removeUnmanaged();
1980                   }
1981             score->connectTies(true);   // ??
1982             }
1983 
1984       // remove empty systems
1985 
1986       for (System* s : systemList) {
1987             if (s->measures().empty()) {
1988                   Page* page = s->page();
1989                   if (page) {
1990                         // erase system from page
1991                         QList<System*>& sl = page->systems();
1992                         auto i = std::find(sl.begin(), sl.end(), s);
1993                         if (i != sl.end())
1994                               sl.erase(i);
1995                         // erase system from score
1996                         auto k = std::find(score->systems().begin(), score->systems().end(), s);
1997                         if (k != score->systems().end())
1998                               score->systems().erase(k);
1999                         // finally delete system
2000                         score->deleteLater(s);
2001                         }
2002                   }
2003             }
2004 
2005       score->setLayoutAll();
2006       }
2007 
2008 //---------------------------------------------------------
2009 //   AddExcerpt::undo
2010 //---------------------------------------------------------
2011 
undo(EditData *)2012 void AddExcerpt::undo(EditData*)
2013       {
2014       excerpt->oscore()->removeExcerpt(excerpt);
2015       }
2016 
2017 //---------------------------------------------------------
2018 //   AddExcerpt::redo
2019 //---------------------------------------------------------
2020 
redo(EditData *)2021 void AddExcerpt::redo(EditData*)
2022       {
2023       excerpt->oscore()->addExcerpt(excerpt);
2024       }
2025 
2026 //---------------------------------------------------------
2027 //   RemoveExcerpt::undo()
2028 //---------------------------------------------------------
2029 
undo(EditData *)2030 void RemoveExcerpt::undo(EditData*)
2031       {
2032       excerpt->oscore()->addExcerpt(excerpt);
2033       }
2034 
2035 //---------------------------------------------------------
2036 //   RemoveExcerpt::redo()
2037 //---------------------------------------------------------
2038 
redo(EditData *)2039 void RemoveExcerpt::redo(EditData*)
2040       {
2041       excerpt->oscore()->removeExcerpt(excerpt);
2042       }
2043 
2044 //---------------------------------------------------------
2045 //   SwapExcerpt::flip
2046 //---------------------------------------------------------
2047 
flip(EditData *)2048 void SwapExcerpt::flip(EditData*)
2049       {
2050       score->excerpts().swap(pos1, pos2);
2051       score->setExcerptsChanged(true);
2052       }
2053 
2054 //---------------------------------------------------------
2055 //   ChangeExcerptTitle::flip
2056 //---------------------------------------------------------
2057 
flip(EditData *)2058 void ChangeExcerptTitle::flip(EditData*)
2059       {
2060       QString s = title;
2061       title = excerpt->title();
2062       excerpt->setTitle(s);
2063       excerpt->oscore()->setExcerptsChanged(true);
2064       }
2065 
2066 //---------------------------------------------------------
2067 //   flip
2068 //---------------------------------------------------------
2069 
flip(EditData *)2070 void ChangeBend::flip(EditData*)
2071       {
2072       QList<PitchValue> pv = bend->points();
2073       bend->score()->addRefresh(bend->canvasBoundingRect());
2074       bend->setPoints(points);
2075       points = pv;
2076       bend->layout();
2077       bend->score()->addRefresh(bend->canvasBoundingRect());
2078       }
2079 
2080 //---------------------------------------------------------
2081 //   flip
2082 //---------------------------------------------------------
2083 
flip(EditData *)2084 void ChangeTremoloBar::flip(EditData*)
2085       {
2086       QList<PitchValue> pv = bend->points();
2087       bend->setPoints(points);
2088       points = pv;
2089       }
2090 
2091 //---------------------------------------------------------
2092 //   ChangeNoteEvents::flip
2093 //---------------------------------------------------------
2094 
flip(EditData *)2095 void ChangeNoteEvents::flip(EditData*)
2096       {
2097 /*TODO:      QList<NoteEvent*> e = chord->playEvents();
2098       chord->setPlayEvents(events);
2099       events = e;
2100       */
2101       }
2102 
2103 //---------------------------------------------------------
2104 //   ChangeNoteEventList::flip
2105 //---------------------------------------------------------
2106 
flip(EditData *)2107 void ChangeNoteEventList::flip(EditData*)
2108       {
2109       note->score()->setPlaylistDirty();
2110       // Get copy of current list.
2111       NoteEventList nel = note->playEvents();
2112       // Replace current copy with new list.
2113       note->setPlayEvents(newEvents);
2114       // Save copy of replaced list.
2115       newEvents = nel;
2116       // Get a copy of the current playEventType.
2117       PlayEventType petval = note->chord()->playEventType();
2118       // Replace current setting with new setting.
2119       note->chord()->setPlayEventType(newPetype);
2120       // Save copy of old setting.
2121       newPetype = petval;
2122       }
2123 
2124 //---------------------------------------------------------
2125 //   ChangeNoteEventList::flip
2126 //---------------------------------------------------------
2127 
flip(EditData *)2128 void ChangeChordPlayEventType::flip(EditData*)
2129       {
2130       chord->score()->setPlaylistDirty();
2131       // Flips data between NoteEventList's.
2132       size_t n = chord->notes().size();
2133       for (size_t i = 0; i < n; ++i) {
2134             Note* note = chord->notes()[i];
2135             note->playEvents().swap(events[int(i)]);
2136             }
2137       // Flips PlayEventType between chord and undo.
2138       PlayEventType curPetype = chord->playEventType();
2139       chord->setPlayEventType(petype);
2140       petype = curPetype;
2141       }
2142 
2143 //---------------------------------------------------------
2144 //   ChangeInstrument::flip
2145 //---------------------------------------------------------
2146 
flip(EditData *)2147 void ChangeInstrument::flip(EditData*)
2148       {
2149       Part* part = is->staff()->part();
2150       Fraction tickStart = is->segment()->tick();
2151       Instrument* oi = is->instrument();  //new Instrument(*is->instrument());
2152 
2153       // set instrument in both part and instrument change element
2154       is->setInstrument(instrument);      //*instrument
2155       part->setInstrument(instrument, tickStart);
2156 
2157       // update score
2158       is->masterScore()->rebuildMidiMapping();
2159       is->masterScore()->updateChannel();
2160       is->score()->setInstrumentsChanged(true);
2161       is->triggerLayoutAll();
2162 
2163       // remember original instrument
2164       instrument = oi;
2165       }
2166 
2167 //---------------------------------------------------------
2168 //   flip
2169 //---------------------------------------------------------
2170 
flip(EditData *)2171 void SwapCR::flip(EditData*)
2172       {
2173       Segment* s1 = cr1->segment();
2174       Segment* s2 = cr2->segment();
2175       int track = cr1->track();
2176 
2177       if (cr1->isChord() && cr2->isChord() && (toChord(cr1)->tremolo() == toChord(cr2)->tremolo())) {
2178             Tremolo* t = toChord(cr1)->tremolo();
2179             Chord* c1 = t->chord1();
2180             Chord* c2 = t->chord2();
2181             t->setParent(toChord(c2));
2182             t->setChords(toChord(c2), toChord(c1));
2183             }
2184 
2185       Element* cr = s1->element(track);
2186       s1->setElement(track, s2->element(track));
2187       s2->setElement(track, cr);
2188       cr1->score()->setLayout(s1->tick(), cr1->staffIdx(), cr1);
2189       cr1->score()->setLayout(s2->tick(), cr1->staffIdx(), cr1);
2190       }
2191 
2192 //---------------------------------------------------------
2193 //   ChangeClefType
2194 //---------------------------------------------------------
2195 
ChangeClefType(Clef * c,ClefType cl,ClefType tc)2196 ChangeClefType::ChangeClefType(Clef* c, ClefType cl, ClefType tc)
2197       {
2198       clef            = c;
2199       concertClef     = cl;
2200       transposingClef = tc;
2201       }
2202 
2203 //---------------------------------------------------------
2204 //   ChangeClefType::flip
2205 //---------------------------------------------------------
2206 
flip(EditData *)2207 void ChangeClefType::flip(EditData*)
2208       {
2209       ClefType ocl = clef->concertClef();
2210       ClefType otc = clef->transposingClef();
2211 
2212       clef->setConcertClef(concertClef);
2213       clef->setTransposingClef(transposingClef);
2214 
2215       clef->staff()->setClef(clef);
2216       Segment* segment = clef->segment();
2217       updateNoteLines(segment, clef->track());
2218       clef->triggerLayoutAll();      // TODO: reduce layout to clef range
2219 
2220       concertClef     = ocl;
2221       transposingClef = otc;
2222       // layout the clef to align the currentClefType with the actual one immediately
2223       clef->layout();
2224       }
2225 
2226 //---------------------------------------------------------
2227 //   flip
2228 //---------------------------------------------------------
2229 #if 0 // MoveStaff is commented out in mscore/instrwidget.cpp, not used anywhere else
2230 void MoveStaff::flip(EditData*)
2231       {
2232       Part* oldPart = staff->part();
2233       int idx = staff->rstaff();
2234       oldPart->removeStaff(staff);
2235       part->insertStaff(staff, rstaff);
2236       part = oldPart;
2237       rstaff = idx;
2238       staff->score()->setLayoutAll();
2239       }
2240 #endif
2241 
2242 //---------------------------------------------------------
2243 //   ChangeProperty::flip
2244 //---------------------------------------------------------
2245 
flip(EditData *)2246 void ChangeProperty::flip(EditData*)
2247       {
2248       qCDebug(undoRedo) << element->name() << int(id) << "(" << propertyName(id) << ")" << element->getProperty(id) << "->" << property;
2249 
2250       QVariant v       = element->getProperty(id);
2251       PropertyFlags ps = element->propertyFlags(id);
2252 
2253       element->setProperty(id, property);
2254       element->setPropertyFlags(id, flags);
2255       property = v;
2256       flags = ps;
2257       }
2258 
2259 //---------------------------------------------------------
2260 //   ChangeBracketProperty::flip
2261 //---------------------------------------------------------
2262 
flip(EditData * ed)2263 void ChangeBracketProperty::flip(EditData* ed)
2264       {
2265       element = staff->brackets()[level];
2266       ChangeProperty::flip(ed);
2267       level = toBracketItem(element)->column();
2268       }
2269 
2270 //---------------------------------------------------------
2271 //   ChangeTextLineProperty::flip
2272 //---------------------------------------------------------
2273 
flip(EditData * ed)2274 void ChangeTextLineProperty::flip(EditData* ed)
2275       {
2276       ChangeProperty::flip(ed);
2277       if (element->isTextLine())
2278             toTextLine(element)->initStyle();
2279       }
2280 
2281 //---------------------------------------------------------
2282 //   ChangeMetaText::flip
2283 //---------------------------------------------------------
2284 
flip(EditData *)2285 void ChangeMetaText::flip(EditData*)
2286       {
2287       QString s = score->metaTag(id);
2288       score->setMetaTag(id, text);
2289       text = s;
2290       }
2291 
2292 //---------------------------------------------------------
2293 //   ChangeSynthesizerState::flip
2294 //---------------------------------------------------------
2295 
flip(EditData *)2296 void ChangeSynthesizerState::flip(EditData*)
2297       {
2298       std::swap(state, score->_synthesizerState);
2299       }
2300 
redo(EditData *)2301 void AddBracket::redo(EditData*)
2302       {
2303       staff->setBracketType(level, type);
2304       staff->setBracketSpan(level, span);
2305       staff->triggerLayout();
2306       }
2307 
undo(EditData *)2308 void AddBracket::undo(EditData*)
2309       {
2310       staff->setBracketType(level, BracketType::NO_BRACKET);
2311       staff->triggerLayout();
2312       }
2313 
redo(EditData *)2314 void RemoveBracket::redo(EditData*)
2315       {
2316       staff->setBracketType(level, BracketType::NO_BRACKET);
2317       staff->triggerLayout();
2318       }
2319 
undo(EditData *)2320 void RemoveBracket::undo(EditData*)
2321       {
2322       staff->setBracketType(level, type);
2323       staff->setBracketSpan(level, span);
2324       staff->triggerLayout();
2325       }
2326 
2327 //---------------------------------------------------------
2328 //   ChangeSpannerElements
2329 //---------------------------------------------------------
2330 
flip(EditData *)2331 void ChangeSpannerElements::flip(EditData*)
2332       {
2333       Element*    oldStartElement   = spanner->startElement();
2334       Element*    oldEndElement     = spanner->endElement();
2335       if (spanner->anchor() == Spanner::Anchor::NOTE) {
2336             // be sure new spanner elements are of the right type
2337             if (!startElement || !startElement->isNote() || !endElement || !endElement->isNote())
2338                   return;
2339             Note* oldStartNote = toNote(oldStartElement);
2340             Note* oldEndNote = toNote(oldEndElement);
2341             Note* newStartNote = toNote(startElement);
2342             Note* newEndNote = toNote(endElement);
2343             // update spanner's start and end notes
2344             if (newStartNote && newEndNote) {
2345                   spanner->setNoteSpan(newStartNote, newEndNote);
2346                   if (spanner->isTie()) {
2347                         Tie* tie = toTie(spanner);
2348                         oldStartNote->setTieFor(nullptr);
2349                         oldEndNote->setTieBack(nullptr);
2350                         newStartNote->setTieFor(tie);
2351                         newEndNote->setTieBack(tie);
2352                         }
2353                   else {
2354                         oldStartNote->removeSpannerFor(spanner);
2355                         oldEndNote->removeSpannerBack(spanner);
2356                         newStartNote->addSpannerFor(spanner);
2357                         newEndNote->addSpannerBack(spanner);
2358                         if (spanner->isGlissando())
2359                               oldEndNote->chord()->updateEndsGlissando();
2360                         }
2361                   }
2362             }
2363       else {
2364             spanner->setStartElement(startElement);
2365             spanner->setEndElement(endElement);
2366             }
2367       startElement = oldStartElement;
2368       endElement   = oldEndElement;
2369       spanner->triggerLayout();
2370       }
2371 
2372 //---------------------------------------------------------
2373 //   ChangeParent
2374 //---------------------------------------------------------
2375 
flip(EditData *)2376 void ChangeParent::flip(EditData*)
2377       {
2378       Element* p = element->parent();
2379       int si = element->staffIdx();
2380       p->remove(element);
2381       element->setParent(parent);
2382       element->setTrack(staffIdx * VOICES);
2383       parent->add(element);
2384       staffIdx = si;
2385       parent = p;
2386       }
2387 
2388 //---------------------------------------------------------
2389 //   ChangeMMRest
2390 //---------------------------------------------------------
2391 
flip(EditData *)2392 void ChangeMMRest::flip(EditData*)
2393       {
2394       Measure* mmr = m->mmRest();
2395       m->setMMRest(mmrest);
2396       mmrest = mmr;
2397       }
2398 
2399 //---------------------------------------------------------
2400 //   InsertTime
2401 //---------------------------------------------------------
2402 
redo(EditData *)2403 void InsertTime::redo(EditData*)
2404       {
2405       score->insertTime(tick, len);
2406       }
2407 
undo(EditData *)2408 void InsertTime::undo(EditData*)
2409       {
2410       score->insertTime(tick, -len);
2411       }
2412 
2413 //---------------------------------------------------------
2414 //   InsertTimeUnmanagedSpanner::flip
2415 //---------------------------------------------------------
2416 
flip(EditData *)2417 void InsertTimeUnmanagedSpanner::flip(EditData*)
2418       {
2419       for (Score* s : score->scoreList()) {
2420             const auto unmanagedSpanners(s->unmanagedSpanners());
2421             for (Spanner* sp : unmanagedSpanners)
2422                   sp->insertTimeUnmanaged(tick, len);
2423             }
2424       len = -len;
2425       }
2426 
2427 //---------------------------------------------------------
2428 //   ChangeNoteEvent::flip
2429 //---------------------------------------------------------
2430 
flip(EditData *)2431 void ChangeNoteEvent::flip(EditData*)
2432       {
2433       note->score()->setPlaylistDirty();
2434       NoteEvent e = *oldEvent;
2435       *oldEvent   = newEvent;
2436       newEvent    = e;
2437       // Get a copy of the current playEventType.
2438       PlayEventType petval = note->chord()->playEventType();
2439       // Replace current setting with new setting.
2440       note->chord()->setPlayEventType(newPetype);
2441       // Save copy of old setting.
2442       newPetype = petval;
2443       }
2444 
2445 //---------------------------------------------------------
2446 //   LinkUnlink
2447 //---------------------------------------------------------
2448 
~LinkUnlink()2449 LinkUnlink::~LinkUnlink()
2450       {
2451       if (le && mustDelete) {
2452             Q_ASSERT(le->size() <= 1);
2453             delete le;
2454             }
2455       }
2456 
link()2457 void LinkUnlink::link()
2458       {
2459       if (le->size() == 1)
2460             le->front()->setLinks(le);
2461       mustDelete = false;
2462       le->append(e);
2463       e->setLinks(le);
2464       }
2465 
unlink()2466 void LinkUnlink::unlink()
2467       {
2468       Q_ASSERT(le->contains(e));
2469       le->removeOne(e);
2470       if (le->size() == 1) {
2471             le->front()->setLinks(0);
2472             mustDelete = true;
2473             }
2474 
2475       e->setLinks(0);
2476       }
2477 
2478 //---------------------------------------------------------
2479 //   Link
2480 //    link e1 to e2
2481 //---------------------------------------------------------
2482 
Link(ScoreElement * e1,ScoreElement * e2)2483 Link::Link(ScoreElement* e1, ScoreElement* e2)
2484       {
2485       Q_ASSERT(e1->links() == 0);
2486       le = e2->links();
2487       if (!le) {
2488             if (e1->isStaff())
2489                   le = new LinkedElements(e1->score(), -1);
2490             else
2491                   le = new LinkedElements(e1->score());
2492             le->push_back(e2);
2493             }
2494       e = e1;
2495       }
2496 
2497 //---------------------------------------------------------
2498 //   Link::isFiltered
2499 //---------------------------------------------------------
2500 
isFiltered(UndoCommand::Filter f,const Element * target) const2501 bool Link::isFiltered(UndoCommand::Filter f, const Element* target) const
2502       {
2503       using Filter = UndoCommand::Filter;
2504       if (f == Filter::Link)
2505             return e == target || le->contains(const_cast<Element*>(target));
2506       return false;
2507       }
2508 
2509 //---------------------------------------------------------
2510 //   Unlink
2511 //---------------------------------------------------------
2512 
Unlink(ScoreElement * _e)2513 Unlink::Unlink(ScoreElement* _e)
2514       {
2515       e  = _e;
2516       le = e->links();
2517       Q_ASSERT(le);
2518       }
2519 
2520 //---------------------------------------------------------
2521 //   ChangeStartEndSpanner::flip
2522 //---------------------------------------------------------
2523 
flip(EditData *)2524 void ChangeStartEndSpanner::flip(EditData*)
2525       {
2526       Element* s = spanner->startElement();
2527       Element* e = spanner->endElement();
2528       spanner->setStartElement(start);
2529       spanner->setEndElement(end);
2530       start = s;
2531       end   = e;
2532       }
2533 
2534 //---------------------------------------------------------
2535 //   ChangeMetaTags::flip
2536 //---------------------------------------------------------
2537 
flip(EditData *)2538 void ChangeMetaTags::flip(EditData*)
2539       {
2540       QMap<QString,QString> t = score->metaTags();
2541       score->setMetaTags(metaTags);
2542       metaTags = t;
2543       }
2544 
2545 //---------------------------------------------------------
2546 //   ChangeDrumset::flip
2547 //---------------------------------------------------------
2548 
flip(EditData *)2549 void ChangeDrumset::flip(EditData*)
2550       {
2551       Drumset d = *instrument->drumset();
2552       instrument->setDrumset(&drumset);
2553       drumset = d;
2554       }
2555 
2556 //---------------------------------------------------------
2557 //   FretDot
2558 //---------------------------------------------------------
2559 
redo(EditData *)2560 void FretDot::redo(EditData*)
2561       {
2562       undoData = FretUndoData(diagram);
2563 
2564       diagram->setDot(string, fret, add, dtype);
2565       diagram->triggerLayout();
2566       }
2567 
2568 
undo(EditData *)2569 void FretDot::undo(EditData*)
2570       {
2571       undoData.updateDiagram();
2572       diagram->triggerLayout();
2573       }
2574 
2575 //---------------------------------------------------------
2576 //   FretMarker
2577 //---------------------------------------------------------
2578 
redo(EditData *)2579 void FretMarker::redo(EditData*)
2580       {
2581       undoData = FretUndoData(diagram);
2582 
2583       diagram->setMarker(string, mtype);
2584       diagram->triggerLayout();
2585       }
2586 
undo(EditData *)2587 void FretMarker::undo(EditData*)
2588       {
2589       undoData.updateDiagram();
2590       diagram->triggerLayout();
2591       }
2592 
2593 //---------------------------------------------------------
2594 //   FretBarre
2595 //---------------------------------------------------------
2596 
redo(EditData *)2597 void FretBarre::redo(EditData*)
2598       {
2599       undoData = FretUndoData(diagram);
2600 
2601       diagram->setBarre(string, fret, add);
2602       diagram->triggerLayout();
2603       }
2604 
undo(EditData *)2605 void FretBarre::undo(EditData*)
2606       {
2607       undoData.updateDiagram();
2608       diagram->triggerLayout();
2609       }
2610 
2611 //---------------------------------------------------------
2612 //   FretClear
2613 //---------------------------------------------------------
2614 
redo(EditData *)2615 void FretClear::redo(EditData*)
2616       {
2617       undoData = FretUndoData(diagram);
2618 
2619       diagram->clear();
2620       diagram->triggerLayout();
2621       }
2622 
undo(EditData *)2623 void FretClear::undo(EditData*)
2624       {
2625       undoData.updateDiagram();
2626       diagram->triggerLayout();
2627       }
2628 
2629 //---------------------------------------------------------
2630 //   MoveTremolo
2631 //---------------------------------------------------------
2632 
redo(EditData *)2633 void MoveTremolo::redo(EditData*)
2634       {
2635       // Find new tremolo chords
2636       Measure* m1 = score->tick2measure(chord1Tick);
2637       Measure* m2 = score->tick2measure(chord2Tick);
2638       IF_ASSERT_FAILED(m1 && m2) {
2639             return;
2640             }
2641       Chord* c1 = m1->findChord(chord1Tick, track);
2642       Chord* c2 = m2->findChord(chord2Tick, track);
2643       IF_ASSERT_FAILED(c1 && c2) {
2644             return;
2645             }
2646 
2647       // Remember the old tremolo chords
2648       oldC1 = trem->chord1();
2649       oldC2 = trem->chord2();
2650 
2651       // Move tremolo away from old chords
2652       trem->chord1()->setTremolo(nullptr);
2653       trem->chord2()->setTremolo(nullptr);
2654 
2655       // Delete old tremolo on c1 and c2, if present
2656       if (c1->tremolo() && (c1->tremolo() != trem)) {
2657             if (c2->tremolo() == c1->tremolo())
2658                   c2->tremolo()->setChords(c1,c2);
2659             else
2660                   c1->tremolo()->setChords(c1,nullptr);
2661             Tremolo* oldTremolo  = c1->tremolo();
2662             c1->setTremolo(nullptr);
2663             delete oldTremolo;
2664             }
2665       if (c2->tremolo() && (c2->tremolo() != trem)) {
2666             c2->tremolo()->setChords(nullptr,c2);
2667             Tremolo* oldTremolo  = c2->tremolo();
2668             c2->setTremolo(nullptr);
2669             delete oldTremolo;
2670             }
2671 
2672       // Move tremolo to new chords
2673       c1->setTremolo(trem);
2674       c2->setTremolo(trem);
2675       trem->setChords(c1, c2);
2676       trem->setParent(c1);
2677 
2678       // Tremolo would cross barline, so remove it
2679       if (m1 != m2) {
2680             score->undoRemoveElement(trem);
2681             return;
2682             }
2683       // One of the notes crosses a barline, so remove the tremolo
2684       if (c1->ticks() != c2->ticks())
2685             score->undoRemoveElement(trem);
2686       }
2687 
undo(EditData *)2688 void MoveTremolo::undo(EditData*)
2689       {
2690       // Move tremolo to old position
2691       trem->chord1()->setTremolo(nullptr);
2692       trem->chord2()->setTremolo(nullptr);
2693       oldC1->setTremolo(trem);
2694       oldC2->setTremolo(trem);
2695       trem->setChords(oldC1, oldC2);
2696       trem->setParent(oldC1);
2697       }
2698 
2699 //---------------------------------------------------------
2700 //   ChangeScoreOrder
2701 //---------------------------------------------------------
2702 
flip(EditData *)2703 void ChangeScoreOrder::flip(EditData*)
2704       {
2705       ScoreOrder* s = score->scoreOrder();
2706       score->setScoreOrder(order);
2707       order = s;
2708       }
2709 
2710 }
2711