void TestTools::undoSlashRhythm() { QString readFile(DIR + "undoSlashRhythm.mscx"); QString writeFile1("undoSlashRhythm01-test.mscx"); QString reference1(DIR + "undoSlashRhythm01-ref.mscx"); QString writeFile2("undoSlashRhythm02-test.mscx"); QString reference2(DIR + "undoSlashRhythm02-ref.mscx"); MasterScore* score = readScore(readFile); score->doLayout(); // select all score->startCmd(); score->cmdSelectAll(); score->endCmd(); // do score->startCmd(); score->cmdSlashRhythm(); score->endCmd(); QVERIFY(saveCompareScore(score, writeFile1, reference1)); // undo score->undoStack()->undo(&ed); QVERIFY(saveCompareScore(score, writeFile2, reference2)); delete score; }
void TestImplodeExplode::implode1() { QString readFile(DIR + "implode1.mscx"); QString writeFile1("implode1-test1.mscx"); QString writeFile2("implode1-test2.mscx"); QString reference(DIR + "implode1-ref.mscx"); MasterScore* score = readScore(readFile); score->doLayout(); // select all score->startCmd(); score->cmdSelectAll(); score->endCmd(); // do score->startCmd(); score->cmdImplode(); score->endCmd(); QVERIFY(saveCompareScore(score, writeFile1, reference)); // undo score->undoStack()->undo(); QVERIFY(saveCompareScore(score, writeFile2, readFile)); delete score; }
void TestMeasure::undoDelInitialVBox_269919() { MasterScore* score = readScore(DIR + "undoDelInitialVBox_269919.mscx"); // 1. delete initial VBox score->startCmd(); MeasureBase* initialVBox = score->measure(0); score->select(initialVBox); score->cmdDeleteSelection(); score->endCmd(); // 2. change duration of first chordrest score->startCmd(); Measure* m = score->firstMeasure(); ChordRest* cr = m->findChordRest(Fraction(0,1), 0); Fraction quarter(4, 1); score->changeCRlen(cr, quarter); score->endCmd(); // 3. Undo to restore first chordrest score->undoRedo(true, 0); // 4. Undo to restore initial VBox resulted in assert failure crash score->undoRedo(true, 0); QVERIFY(saveCompareScore(score, "undoDelInitialVBox_269919.mscx", DIR + "undoDelInitialVBox_269919-ref.mscx")); delete score; }
void TestMeasure::insertBfKeyChange() { MasterScore* score = readScore(DIR + "measure-insert_bf_key.mscx"); // 4th measure Measure* m = score->firstMeasure()->nextMeasure(); m = m->nextMeasure()->nextMeasure(); score->startCmd(); score->insertMeasure(ElementType::MEASURE, m); score->endCmd(); QVERIFY(score->checkKeys()); QVERIFY(saveCompareScore(score, "measure-insert_bf_key.mscx", DIR + "measure-insert_bf_key-ref.mscx")); score->undoRedo(true); QVERIFY(score->checkKeys()); QVERIFY(saveCompareScore(score, "measure-insert_bf_key_undo.mscx", DIR + "measure-insert_bf_key.mscx")); m = score->firstMeasure()->nextMeasure()->nextMeasure()->nextMeasure()->nextMeasure()->nextMeasure(); score->startCmd(); score->insertMeasure(ElementType::MEASURE, m); score->endCmd(); QVERIFY(score->checkKeys()); QVERIFY(saveCompareScore(score, "measure-insert_bf_key-2.mscx", DIR + "measure-insert_bf_key-2-ref.mscx")); score->undoRedo(true); QVERIFY(score->checkKeys()); QVERIFY(saveCompareScore(score, "measure-insert_bf_key_undo.mscx", DIR + "measure-insert_bf_key.mscx")); delete score; }
void TestTools::undoLockLineBreaks() { QString readFile(DIR + "undoLockLineBreaks.mscx"); QString writeFile1("undoLockLineBreaks01-test.mscx"); QString reference1(DIR + "undoLockLineBreaks01-ref.mscx"); QString writeFile2("undoLockLineBreaks02-test.mscx"); QString reference2(DIR + "undoLockLineBreaks02-ref.mscx"); MasterScore* score = readScore(readFile); score->doLayout(); // select all score->startCmd(); score->cmdSelectAll(); score->endCmd(); // do score->startCmd(); score->addRemoveBreaks(0, true); score->endCmd(); QVERIFY(saveCompareScore(score, writeFile1, reference1)); // undo score->undoStack()->undo(); QVERIFY(saveCompareScore(score, writeFile2, reference2)); delete score; }
void TestMeasure::gap() { MasterScore* score = readScore(DIR + "gaps.mscx"); Element* tst = 0; //Select and delete third quarter rest in first Measure (voice 2) score->startCmd(); Measure* m = score->firstMeasure(); Segment* s = m->undoGetSegment(SegmentType::ChordRest, Fraction::fromTicks(960)); Element* el = s->element(1); score->select(el); score->cmdDeleteSelection(); score->endCmd(); tst = s->element(1); Q_ASSERT(tst); QVERIFY(tst->isRest() && toRest(tst)->isGap() /*&& toRest(tst)->durationType() == TDuration::DurationType::V_QUARTER*/); //Select and delete second quarter rest in third Measure (voice 4) score->startCmd(); m = m->nextMeasure()->nextMeasure(); s = m->undoGetSegment(SegmentType::ChordRest, Fraction::fromTicks(4320)); el = s->element(3); score->select(el); score->cmdDeleteSelection(); score->endCmd(); tst = s->element(3); Q_ASSERT(tst); QVERIFY(tst->isRest() && toRest(tst)->isGap() /*&& toRest(tst)->durationType() == TDuration::DurationType::V_QUARTER*/); //Select and delete first quarter rest in third Measure (voice 4) score->startCmd(); s = m->undoGetSegment(SegmentType::ChordRest, Fraction::fromTicks(3840)); el = s->element(3); score->select(el); score->cmdDeleteSelection(); score->endCmd(); tst = s->element(3); Q_ASSERT(tst); QVERIFY(tst->isRest() && toRest(tst)->isGap() && toRest(tst)->actualTicks() == Fraction::fromTicks(960) /*&& toRest(tst)->durationType() == TDuration::DurationType::V_HALF*/ ); delete score; }
void TestTools::undoSlashFill() { QString readFile(DIR + "undoSlashFill.mscx"); QString writeFile1("undoSlashFill01-test.mscx"); QString reference1(DIR + "undoSlashFill01-ref.mscx"); QString writeFile2("undoSlashFill02-test.mscx"); QString reference2(DIR + "undoSlashFill02-ref.mscx"); MasterScore* score = readScore(readFile); // select Segment* s = score->firstMeasure()->findSegment(Segment::Type::ChordRest, MScore::division * 2); score->selection().setRange(s, score->lastSegment(), 0, 2); // do score->startCmd(); score->cmdSlashFill(); score->endCmd(); QVERIFY(saveCompareScore(score, writeFile1, reference1)); // undo score->undoStack()->undo(); QVERIFY(saveCompareScore(score, writeFile2, reference2)); delete score; }
void TestSpanners::spanners13() { DropData dropData; LayoutBreak* brk; MasterScore* score = readScore(DIR + "lyricsline06.mscx"); QVERIFY(score); score->doLayout(); // DROP A BREAK AT FIRST MEASURE AND VERIFY Measure* msr = score->firstMeasure(); QVERIFY(msr); brk = new LayoutBreak(score); brk->setLayoutBreakType(LayoutBreak::Type::LINE); dropData.pos = msr->pagePos(); dropData.element = brk; score->startCmd(); msr->drop(dropData); score->endCmd(); // VERIFY SEGMENTS IN SYSTEMS AND THEN SCORE for (System* sys : score->systems()) QVERIFY(sys->spannerSegments().size() == 1); QVERIFY(saveCompareScore(score, "lyricsline06.mscx", DIR + "lyricsline06-ref.mscx")); // UNDO AND VERIFY score->undoStack()->undo(); score->doLayout(); // systems need to be re-computed QVERIFY(saveCompareScore(score, "lyricsline06.mscx", DIR + "lyricsline06.mscx")); delete score; }
void TestNote::grace() { MasterScore* score = readScore(DIR + "grace.mscx"); score->doLayout(); Ms::Chord* chord = score->firstMeasure()->findChord(0, 0); Note* note = chord->upNote(); // create score->setGraceNote(chord, note->pitch(), NoteType::APPOGGIATURA, MScore::division/2); Ms::Chord* gc = chord->graceNotes().first(); Note* gn = gc->notes().front(); // Note* n = static_cast<Note*>(writeReadElement(gn)); // QCOMPARE(n->noteType(), NoteType::APPOGGIATURA); // delete n; // tie score->select(gn); score->cmdAddTie(); // n = static_cast<Note*>(writeReadElement(gn)); // QVERIFY(n->tieFor() != 0); // delete n; // tremolo score->startCmd(); Tremolo* tr = new Tremolo(score); tr->setTremoloType(TremoloType::R16); tr->setParent(gc); tr->setTrack(gc->track()); score->undoAddElement(tr); score->endCmd(); // Ms::Chord* c = static_cast<Ms::Chord*>(writeReadElement(gc)); // QVERIFY(c->tremolo() != 0); // delete c; // articulation score->startCmd(); Articulation* ar = new Articulation(SymId::articAccentAbove, score); ar->setParent(gc); ar->setTrack(gc->track()); score->undoAddElement(ar); score->endCmd(); // c = static_cast<Ms::Chord*>(writeReadElement(gc)); // QVERIFY(c->articulations().size() == 1); // delete c; QVERIFY(saveCompareScore(score, "grace-test.mscx", DIR + "grace-ref.mscx")); }
void TestChordSymbol::testTransposePart() { MasterScore* score = test_pre("transpose-part"); score->startCmd(); score->cmdSelectAll(); score->transpose(TransposeMode::BY_INTERVAL, TransposeDirection::UP, Key::C, 4, false, true, true); score->endCmd(); test_post(score, "transpose-part"); }
void TestMeasure::insertMeasureEnd() { MasterScore* score = readScore(DIR + "measure-1.mscx"); score->startCmd(); score->insertMeasure(ElementType::MEASURE, 0); score->endCmd(); QVERIFY(saveCompareScore(score, "measure-3.mscx", DIR + "measure-3-ref.mscx")); delete score; }
void TestMeasure::spanner_b() { MasterScore* score = readScore(DIR + "measure-4.mscx"); Measure* m = score->firstMeasure(); score->startCmd(); score->insertMeasure(ElementType::MEASURE, m); score->endCmd(); QVERIFY(saveCompareScore(score, "measure-5.mscx", DIR + "measure-5-ref.mscx")); delete score; }
void TestMeasure::spanner_A() { MasterScore* score = readScore(DIR + "measure-6.mscx"); score->select(score->firstMeasure()); score->startCmd(); score->localTimeDelete(); score->endCmd(); score->doLayout(); QVERIFY(saveCompareScore(score, "measure-6.mscx", DIR + "measure-6-ref.mscx")); delete score; }
void TestMeasure::insertMeasureBegin() { MasterScore* score = readScore(DIR + "measure-1.mscx"); score->startCmd(); Measure* m = score->firstMeasure(); score->insertMeasure(Element::Type::MEASURE, m); score->endCmd(); QVERIFY(saveCompareScore(score, "measure-2.mscx", DIR + "measure-2-ref.mscx")); delete score; }
void TestMeasure::deleteLast() { MasterScore* score = readScore(DIR + "measure-10.mscx"); score->startCmd(); Measure* m = score->lastMeasure(); score->select(m); score->cmdTimeDelete(); score->endCmd(); QVERIFY(saveCompareScore(score, "measure-10.mscx", DIR + "measure-10-ref.mscx")); delete score; }
void TestMeasure::spanner_C() { MasterScore* score = readScore(DIR + "measure-8.mscx"); Measure* m = score->firstMeasure()->nextMeasure(); score->select(m); score->startCmd(); score->localTimeDelete(); score->endCmd(); QVERIFY(saveCompareScore(score, "measure-8.mscx", DIR + "measure-8-ref.mscx")); delete score; }
void TestNote::tpcTranspose() { MasterScore* score = readScore(DIR + "tpc-transpose.mscx"); score->startCmd(); Measure* m = score->firstMeasure(); score->select(m, SelectType::SINGLE, 0); score->changeAccidental(AccidentalType::FLAT); score->endCmd(); score->startCmd(); m = m->nextMeasure(); score->select(m, SelectType::SINGLE, 0); score->upDown(false, UpDownMode::CHROMATIC); score->endCmd(); score->startCmd(); score->cmdConcertPitchChanged(true, true); score->endCmd(); QVERIFY(saveCompareScore(score, "tpc-transpose-test.mscx", DIR + "tpc-transpose-ref.mscx")); }
void TestInstrumentChange::testChange() { MasterScore* score = test_pre("change"); Measure* m = score->firstMeasure()->nextMeasure(); Segment* s = m->first(Segment::Type::ChordRest); InstrumentChange* ic = toInstrumentChange(s->annotations()[0]); Instrument* ni = score->staff(1)->part()->instrument(); ic->setInstrument(new Instrument(*ni)); score->startCmd(); ic->setXmlText("Instrument Oboe"); score->undo(new ChangeInstrument(ic, ic->instrument())); score->endCmd(); score->doLayout(); test_post(score, "change"); }
void TestBarline::deleteSkipBarlines() { MasterScore* score = readScore(DIR + "barlinedelete.mscx"); Measure* m1 = score->firstMeasure(); QVERIFY(m1); score->startCmd(); score->cmdSelectAll(); score->cmdDeleteSelection(); score->endCmd(); score->doLayout(); QVERIFY(saveCompareScore(score, QString("barlinedelete.mscx"), DIR + QString("barlinedelete-ref.mscx"))); delete score; }
void TestSpanners::spanners08() { MasterScore* score = readScore(DIR + "lyricsline01.mscx"); QVERIFY(score); score->doLayout(); // verify initial LyricsLine setup System* sys = score->systems().at(0); QVERIFY(sys->spannerSegments().size() == 1); QVERIFY(score->unmanagedSpanners().size() == 1); // DELETE LYRICS Measure* msr = score->firstMeasure(); QVERIFY(msr); Segment* seg = msr->findSegment(Segment::Type::ChordRest, 0); QVERIFY(seg); Ms::Chord* chord = static_cast<Ms::Chord*>(seg->element(0)); QVERIFY(chord && chord->type() == Element::Type::CHORD); QVERIFY(chord->lyrics().size() > 0); Lyrics* lyr = chord->lyrics(0, Element::Placement::BELOW); score->startCmd(); score->undoRemoveElement(lyr); score->endCmd(); // verify setup after deletion QVERIFY(sys->spannerSegments().size() == 0); QVERIFY(score->unmanagedSpanners().size() == 0); // save and verify score after deletion QVERIFY(saveCompareScore(score, "lyricsline01.mscx", DIR + "lyricsline01-ref.mscx")); // UNDO score->undoStack()->undo(); score->doLayout(); // verify setup after undo QVERIFY(sys->spannerSegments().size() == 1); QVERIFY(score->unmanagedSpanners().size() == 1); // save and verify score after undo QVERIFY(saveCompareScore(score, "lyricsline01.mscx", DIR + "lyricsline01.mscx")); delete score; }
void TestNote::tpcTranspose2() { MasterScore* score = readScore(DIR + "tpc-transpose2.mscx"); score->inputState().setTrack(0); score->inputState().setSegment(score->tick2segment(0, false, Segment::Type::ChordRest)); score->inputState().setDuration(TDuration::DurationType::V_QUARTER); score->inputState().setNoteEntryMode(true); int octave = 5 * 7; score->cmdAddPitch(octave + 3, false, false); score->startCmd(); score->cmdConcertPitchChanged(true, true); score->endCmd(); printf("================\n"); QVERIFY(saveCompareScore(score, "tpc-transpose2-test.mscx", DIR + "tpc-transpose2-ref.mscx")); }
void TestInstrumentChange::testMixer() { MasterScore* score = test_pre("mixer"); Measure* m = score->firstMeasure()->nextMeasure(); Segment* s = m->first(Segment::Type::ChordRest); InstrumentChange* ic = static_cast<InstrumentChange*>(s->annotations()[0]); int idx = score->staff(0)->channel(s->tick(), 0); Channel* c = score->staff(0)->part()->instrument(s->tick())->channel(idx); MidiPatch* mp = new MidiPatch; mp->bank = 0; mp->drum = false; mp->name = "Viola"; mp->prog = 41; mp->synti = "Fluid"; score->startCmd(); ic->setXmlText("Mixer Viola"); score->undo(new ChangePatch(score, c, mp)); score->endCmd(); score->doLayout(); test_post(score, "mixer"); }
void TestSpanners::spanners12() { MasterScore* score = readScore(DIR + "lyricsline05.mscx"); QVERIFY(score); score->doLayout(); // DELETE SECOND MEASURE AND VERIFY Measure* msr = score->firstMeasure(); QVERIFY(msr); msr = msr->nextMeasure(); QVERIFY(msr); score->startCmd(); score->select(msr); score->cmdTimeDelete(); score->endCmd(); QVERIFY(saveCompareScore(score, "lyricsline05.mscx", DIR + "lyricsline05-ref.mscx")); // UNDO AND VERIFY score->undoStack()->undo(); QVERIFY(saveCompareScore(score, "lyricsline05.mscx", DIR + "lyricsline05.mscx")); delete score; }
void TestTools::undoResequencePart() { QString readFile(DIR + "undoResequencePart.mscx"); QString writeFile1("undoResequencePart01-test.mscx"); QString reference1(DIR + "undoResequencePart01-ref.mscx"); QString writeFile2("undoResequencePart02-test.mscx"); QString reference2(DIR + "undoResequencePart02-ref.mscx"); MasterScore* score = readScore(readFile); score->doLayout(); // do score->startCmd(); score->cmdResequenceRehearsalMarks(); score->endCmd(); QVERIFY(saveCompareScore(score, writeFile1, reference1)); // undo score->undoStack()->undo(); QVERIFY(saveCompareScore(score, writeFile2, reference2)); delete score; }
void MuseScore::editInstrList() { if (cs == 0) return; if (!instrList) instrList = new InstrumentsDialog(this); else if (instrList->isVisible()) { instrList->done(0); return; } instrList->init(); MasterScore* masterScore = cs->masterScore(); instrList->genPartList(masterScore); masterScore->startCmd(); masterScore->deselectAll(); int rv = instrList->exec(); if (rv == 0) { masterScore->endCmd(); return; } ScoreView* csv = currentScoreView(); if (csv && csv->noteEntryMode()) { csv->cmd(getAction("escape")); qApp->processEvents(); updateInputState(csv->score()); } masterScore->inputState().setTrack(-1); // keep the keylist of the first pitched staff to apply it to new ones KeyList tmpKeymap; Staff* firstStaff = 0; for (Staff* s : masterScore->staves()) { KeyList* km = s->keyList(); if (!s->isDrumStaff(Fraction(0,1))) { // TODO tmpKeymap.insert(km->begin(), km->end()); firstStaff = s; break; } } Key normalizedC = Key::C; // normalize the keyevents to concert pitch if necessary if (firstStaff && !masterScore->styleB(Sid::concertPitch) && firstStaff->part()->instrument()->transpose().chromatic ) { int interval = firstStaff->part()->instrument()->transpose().chromatic; normalizedC = transposeKey(normalizedC, interval); for (auto i = tmpKeymap.begin(); i != tmpKeymap.end(); ++i) { int tick = i->first; Key oKey = i->second.key(); tmpKeymap[tick].setKey(transposeKey(oKey, interval)); } } // create initial keyevent for transposing instrument if necessary auto i = tmpKeymap.begin(); if (i == tmpKeymap.end() || i->first != 0) tmpKeymap[0].setKey(normalizedC); // // process modified partitur list // QTreeWidget* pl = instrList->partiturList(); Part* part = 0; int staffIdx = 0; QTreeWidgetItem* item = 0; for (int idx = 0; (item = pl->topLevelItem(idx)); ++idx) { PartListItem* pli = static_cast<PartListItem*>(item); // check if the part contains any remaining staves // mark to remove part if not QTreeWidgetItem* ci = 0; int staves = 0; for (int cidx = 0; (ci = pli->child(cidx)); ++cidx) { StaffListItem* sli = static_cast<StaffListItem*>(ci); if (sli->op() != ListItemOp::I_DELETE) ++staves; } if (staves == 0) pli->op = ListItemOp::I_DELETE; } item = 0; for (int idx = 0; (item = pl->topLevelItem(idx)); ++idx) { int rstaff = 0; PartListItem* pli = static_cast<PartListItem*>(item); if (pli->op == ListItemOp::I_DELETE) masterScore->cmdRemovePart(pli->part); else if (pli->op == ListItemOp::ADD) { const InstrumentTemplate* t = ((PartListItem*)item)->it; part = new Part(masterScore); part->initFromInstrTemplate(t); masterScore->undo(new InsertPart(part, staffIdx)); pli->part = part; QList<Staff*> linked; for (int cidx = 0; pli->child(cidx); ++cidx) { StaffListItem* sli = static_cast<StaffListItem*>(pli->child(cidx)); Staff* staff = new Staff(masterScore); staff->setPart(part); sli->setStaff(staff); staff->init(t, sli->staffType(), cidx); staff->setDefaultClefType(sli->defaultClefType()); if (staffIdx > 0) staff->setBarLineSpan(masterScore->staff(staffIdx - 1)->barLineSpan()); masterScore->undoInsertStaff(staff, cidx); ++staffIdx; Staff* linkedStaff = part->staves()->front(); if (sli->linked() && linkedStaff != staff) { Excerpt::cloneStaff(linkedStaff, staff); linked.append(staff); } } //insert keysigs int sidx = masterScore->staffIdx(part); int eidx = sidx + part->nstaves(); if (firstStaff) masterScore->adjustKeySigs(sidx, eidx, tmpKeymap); } else { part = pli->part; if (part->show() != pli->visible()) part->undoChangeProperty(Pid::VISIBLE, pli->visible()); for (int cidx = 0; pli->child(cidx); ++cidx) { StaffListItem* sli = static_cast<StaffListItem*>(pli->child(cidx)); if (sli->op() == ListItemOp::I_DELETE) { Staff* staff = sli->staff(); int sidx = staff->idx(); masterScore->cmdRemoveStaff(sidx); } else if (sli->op() == ListItemOp::ADD) { Staff* staff = new Staff(masterScore); staff->setPart(part); staff->initFromStaffType(sli->staffType()); sli->setStaff(staff); staff->setDefaultClefType(sli->defaultClefType()); if (staffIdx > 0) staff->setBarLineSpan(masterScore->staff(staffIdx - 1)->barLineSpan()); KeySigEvent ke; if (part->staves()->empty()) ke.setKey(Key::C); else ke = part->staff(0)->keySigEvent(Fraction(0,1)); staff->setKey(Fraction(0,1), ke); Staff* linkedStaff = 0; if (sli->linked()) { if (rstaff > 0) linkedStaff = part->staves()->front(); else { for (Staff* st : *part->staves()) { if (st != staff) { linkedStaff = st; break; } } } } if (linkedStaff) { // do not create a link if linkedStaff will be removed, for (int k = 0; pli->child(k); ++k) { StaffListItem* li = static_cast<StaffListItem*>(pli->child(k)); if (li->op() == ListItemOp::I_DELETE && li->staff() == linkedStaff) { linkedStaff = 0; break; } } } masterScore->undoInsertStaff(staff, rstaff, linkedStaff == 0); if (linkedStaff) Excerpt::cloneStaff(linkedStaff, staff); else { if (firstStaff) masterScore->adjustKeySigs(staffIdx, staffIdx+1, tmpKeymap); } ++staffIdx; ++rstaff; } else if (sli->op() == ListItemOp::UPDATE) { // check changes in staff type Staff* staff = sli->staff(); const StaffType* stfType = sli->staffType(); // use selected staff type if (stfType->name() != staff->staffType(Fraction(0,1))->name()) masterScore->undo(new ChangeStaffType(staff, *stfType)); } else { ++staffIdx; ++rstaff; } } } } // // sort staves // QList<Staff*> dst; for (int idx = 0; idx < pl->topLevelItemCount(); ++idx) { PartListItem* pli = (PartListItem*)pl->topLevelItem(idx); if (pli->op == ListItemOp::I_DELETE) continue; QTreeWidgetItem* ci = 0; for (int cidx = 0; (ci = pli->child(cidx)); ++cidx) { StaffListItem* sli = (StaffListItem*) ci; if (sli->op() == ListItemOp::I_DELETE) continue; dst.push_back(sli->staff()); } } QList<int> dl; int idx2 = 0; bool sort = false; for (Staff* staff : dst) { int idx = masterScore->staves().indexOf(staff); if (idx == -1) qDebug("staff in dialog(%p) not found in score", staff); else dl.push_back(idx); if (idx != idx2) sort = true; ++idx2; } if (sort) masterScore->undo(new SortStaves(masterScore, dl)); // // check for valid barLineSpan and bracketSpan // in all staves // for (Score* s : masterScore->scoreList()) { int n = s->nstaves(); int curSpan = 0; for (int j = 0; j < n; ++j) { Staff* staff = s->staff(j); int span = staff->barLineSpan(); int setSpan = -1; // determine if we need to update barline span if (curSpan == 0) { // no current span; this staff must start a new one if (span == 0) { // no span; this staff must have been within a span // update it to a span of 1 setSpan = j; } else if (span > (n - j)) { // span too big; staves must have been removed // reduce span to last staff setSpan = n - j; } else if (span > 1 && staff->barLineTo() > 0) { // TODO: check if span is still valid // (true if the last staff is the same as it was before this edit) // the code here fixes https://musescore.org/en/node/41786 // but by forcing an update, // we lose custom modifications to staff barLineTo // at least this happens only for span > 1, and not for Mensurstrich (barLineTo<=0) setSpan = span; // force update to pick up new barLineTo value } else { // this staff starts a span curSpan = span; } } else if (span && staff->barLineTo() > 0) { // within a current span; staff must have span of 0 // except for Mensurstrich (barLineTo<=0) // for consistency with Barline::endEdit, // don't special case 1-line staves //TODO s->undoChangeBarLineSpan(staff, 0, 0, (staff->lines() - 1) * 2); } // update barline span if necessary if (setSpan > 0) { // this staff starts a span curSpan = setSpan; // calculate spanFrom and spanTo values // int spanFrom = staff->lines() == 1 ? BARLINE_SPAN_1LINESTAFF_FROM : 0; // int linesTo = masterScore->staff(i + setSpan - 1)->lines(); // int spanTo = linesTo == 1 ? BARLINE_SPAN_1LINESTAFF_TO : (linesTo - 1) * 2; //TODO s->undoChangeBarLineSpan(staff, setSpan, spanFrom, spanTo); } // count off one from barline span --curSpan; // update brackets for (BracketItem* bi : staff->brackets()) { if ((bi->bracketSpan() > (n - j))) bi->undoChangeProperty(Pid::BRACKET_SPAN, n - j); } } } // // there should be at least one measure // if (masterScore->measures()->size() == 0) masterScore->insertMeasure(ElementType::MEASURE, 0, false); const QList<Excerpt*> excerpts(masterScore->excerpts()); // excerpts list may change in the loop below for (Excerpt* excerpt : excerpts) { QList<Staff*> sl = excerpt->partScore()->staves(); QMultiMap<int, int> tr = excerpt->tracks(); if (sl.size() == 0) masterScore->undo(new RemoveExcerpt(excerpt)); else { for (Staff* s : sl) { const LinkedElements* sll = s->links(); for (auto le : *sll) { Staff* ss = toStaff(le); if (ss->primaryStaff()) { for (int j = s->idx() * VOICES; j < (s->idx() + 1) * VOICES; j++) { int strack = tr.key(j, -1); if (strack != -1 && ((strack & ~3) == ss->idx())) break; else if (strack != -1) tr.insert(ss->idx() + strack % VOICES, tr.value(strack, -1)); } } } } } } masterScore->setLayoutAll(); masterScore->endCmd(); masterScore->rebuildAndUpdateExpressive(MuseScore::synthesizer("Fluid")); seq->initInstruments(); }
void TestLinks::test5LinkedParts_94911() { MCursor c; c.setTimeSig(Fraction(4,4)); c.createScore("test"); c.addPart("electric-guitar"); c.move(0, 0); // move to track 0 tick 0 c.addKeySig(Key(1)); c.addTimeSig(Fraction(4,4)); c.addChord(60, TDuration(TDuration::DurationType::V_WHOLE)); MasterScore* score = c.score(); score->addText("title", "Title"); score->doLayout(); // delete chord Measure* m = score->firstMeasure(); Segment* s = m->first(Segment::Type::ChordRest); Element* e = s->element(0); QVERIFY(e->type() == ElementType::CHORD); score->select(e); score->cmdDeleteSelection(); e = s->element(0); QVERIFY(e->type() == ElementType::REST); QVERIFY(e->links() == nullptr); // create parts// score->startCmd(); QList<Part*> parts; parts.append(score->parts().at(0)); Score* nscore = new Score(score); Excerpt ex(score); ex.setPartScore(nscore); ex.setTitle("Guitar"); ex.setParts(parts); Excerpt::createExcerpt(&ex); QVERIFY(nscore); score->undo(new AddExcerpt(&ex)); score->endCmd(); // we should have now 1 staff and 2 linked rests QVERIFY(score->staves().size() == 1); e = s->element(0); QVERIFY(e->type() == ElementType::REST); QVERIFY(e->links()->size() == 2); // add a linked staff score->startCmd(); Staff* oStaff = score->staff(0); Staff* staff = new Staff(score); staff->setPart(oStaff->part()); score->undoInsertStaff(staff, 1); Excerpt::cloneStaff(oStaff, staff); score->endCmd(); // we should have now 2 staves and 3 linked rests QCOMPARE(score->staves().size(), 2); QCOMPARE(nscore->staves().size(), 1); QVERIFY(score->staves()[0]->linkedStaves()->staves().size() == 3); e = s->element(0); QVERIFY(e->type() == ElementType::REST); QVERIFY(e->links()->size() == 3); e = s->element(4); QVERIFY(e->type() == ElementType::REST); QVERIFY(e->links()->size() == 3); QVERIFY(score->excerpts().size() == 1); // undo score->undoStack()->undo(); // we should have now 1 staves and 2 linked rests QVERIFY(score->staves().size() == 1); QVERIFY(score->staves()[0]->linkedStaves()->staves().size() == 2); e = s->element(0); QVERIFY(e->type() == ElementType::REST); QVERIFY(e->links()->size() == 2); QVERIFY(score->excerpts().size() == 1); // redo score->undoStack()->redo(); // we should have now 2 staves and 3 linked rests QVERIFY(score->staves().size() == 2); QVERIFY(score->staves()[0]->linkedStaves()->staves().size() == 3); e = s->element(0); QVERIFY(e->type() == ElementType::REST); QVERIFY(e->links()->size() == 3); e = s->element(4); QVERIFY(e->type() == ElementType::REST); QVERIFY(e->links()->size() == 3); QVERIFY(score->excerpts().size() == 1); }