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