1 //=============================================================================
2 //  MuseScore
3 //  Music Composition & Notation
4 //
5 //  Copyright (C) 2015 Werner Schweer & others
6 //
7 //  This program is free software; you can redistribute it and/or modify
8 //  it under the terms of the GNU General Public License version 2
9 //  as published by the Free Software Foundation and appearing in
10 //  the file LICENCE.GPL
11 //=============================================================================
12 
13 #include <QtTest/QtTest>
14 #include "mtest/testutils.h"
15 #include "libmscore/chord.h"
16 #include "libmscore/excerpt.h"
17 #include "libmscore/glissando.h"
18 #include "libmscore/layoutbreak.h"
19 #include "libmscore/lyrics.h"
20 #include "libmscore/measure.h"
21 #include "libmscore/part.h"
22 #include "libmscore/staff.h"
23 #include "libmscore/score.h"
24 #include "libmscore/system.h"
25 #include "libmscore/undo.h"
26 #include "libmscore/line.h"
27 
28 #define DIR QString("libmscore/spanners/")
29 
30 using namespace Ms;
31 
32 //---------------------------------------------------------
33 //   TestSpanners
34 //---------------------------------------------------------
35 
36 class TestSpanners : public QObject, public MTest
37       {
38       Q_OBJECT
39 
40    private slots:
41       void initTestCase();
42       void spanners01();            // adding glissandos in several contexts
43       void spanners02();            // loading back existing cross-staff glissando from lower to higher staff
44       void spanners03();            // adding glissandos from/to grace notes
45       void spanners04();            // linking a staff to a staff containing a glissando
46       void spanners05();            // creating part from an existing staff containing a glissando
47       void spanners06();            // add a glissando to a staff with a linked staff
48       void spanners07();            // add a glissando to a staff with an excerpt attached
49 //      void spanners08();            // delete a lyrics with separator and undo
50       void spanners09();            // remove a measure containing the end point of a LyricsLine and undo
51       void spanners10();            // remove a measure containing the start point of a LyricsLine and undo
52       void spanners11();            // remove a measure entirely containing a LyricsLine and undo
53       void spanners12();            // remove a measure containing the middle portion of a LyricsLine and undo
54 //      void spanners13();            // drop a line break at the middle of a LyricsLine and check LyricsLineSegments
55       void spanners14();            // creating part from an existing grand staff containing a cross staff glissando
56       void spanners15();            // change the color & min distance of a line and save it
57       void spanners16();            // read lines with manual adjustments on a small staff and save
58       };
59 
60 //---------------------------------------------------------
61 //   initTestCase
62 //---------------------------------------------------------
63 
initTestCase()64 void TestSpanners::initTestCase()
65       {
66       initMTest();
67       }
68 
69 //---------------------------------------------------------
70 ///  spanners01
71 ///   Adds glissandi in several contexts.
72 //---------------------------------------------------------
73 
spanners01()74 void TestSpanners::spanners01()
75       {
76       EditData    dropData(0);
77       Glissando*  gliss;
78 
79       MasterScore* score = readScore(DIR + "glissando01.mscx");
80       QVERIFY(score);
81 
82       // SIMPLE CASE: GLISSANDO FROM A NOTE TO THE FOLLOWING
83       // go to top note of first chord
84       Measure*    msr   = score->firstMeasure();
85       QVERIFY(msr);
86       Segment*    seg   = msr->findSegment(SegmentType::ChordRest, Fraction(0,1));
87       QVERIFY(seg);
88       Ms::Chord*      chord = static_cast<Ms::Chord*>(seg->element(0));
89       QVERIFY(chord && chord->type() == ElementType::CHORD);
90       Note*       note  = chord->upNote();
91       QVERIFY(note);
92       // drop a glissando on note
93       gliss             = new Glissando(score); // create a new element each time, as drop() will eventually delete it
94       dropData.pos      = note->pagePos();
95       dropData.dropElement  = gliss;
96       note->drop(dropData);
97 
98       // GLISSANDO FROM TOP STAFF TO BOTTOM STAFF
99       // go to top note of first chord of next measure
100       msr   = msr->nextMeasure();
101       QVERIFY(msr);
102       seg   = msr->first();
103       QVERIFY(seg);
104       chord = static_cast<Ms::Chord*>(seg->element(0));   // voice 0 of staff 0
105       QVERIFY(chord && chord->type() == ElementType::CHORD);
106       note  = chord->upNote();
107       QVERIFY(note);
108       // drop a glissando on note
109       gliss             = new Glissando(score);
110       dropData.pos      = note->pagePos();
111       dropData.dropElement  = gliss;
112       note->drop(dropData);
113 
114       // GLISSANDO FROM BOTTOM STAFF TO TOP STAFF
115       // go to bottom note of first chord of next measure
116       msr   = msr->nextMeasure();
117       QVERIFY(msr);
118       seg   = msr->first();
119       QVERIFY(seg);
120       chord = static_cast<Ms::Chord*>(seg->element(4));   // voice 0 of staff 1
121       QVERIFY(chord && chord->type() == ElementType::CHORD);
122       note  = chord->upNote();
123       QVERIFY(note);
124       // drop a glissando on note
125       gliss             = new Glissando(score);
126       dropData.pos      = note->pagePos();
127       dropData.dropElement  = gliss;
128       note->drop(dropData);
129 
130       // GLISSANDO OVER INTERVENING NOTES IN ANOTHER VOICE
131       // go to top note of first chord of next measure
132       msr   = msr->nextMeasure();
133       QVERIFY(msr);
134       seg   = msr->first();
135       QVERIFY(seg);
136       chord = static_cast<Ms::Chord*>(seg->element(0));   // voice 0 of staff 0
137       QVERIFY(chord && chord->type() == ElementType::CHORD);
138       note  = chord->upNote();
139       QVERIFY(note);
140       // drop a glissando on note
141       gliss             = new Glissando(score);
142       dropData.pos      = note->pagePos();
143       dropData.dropElement  = gliss;
144       note->drop(dropData);
145 
146       // GLISSANDO OVER INTERVENING NOTES IN ANOTHER STAFF
147       // go to top note of first chord of next measure
148       msr   = msr->nextMeasure()->nextMeasure();
149       QVERIFY(msr);
150       seg   = msr->first();
151       QVERIFY(seg);
152       chord = static_cast<Ms::Chord*>(seg->element(0));   // voice 0 of staff 0
153       QVERIFY(chord && chord->type() == ElementType::CHORD);
154       note  = chord->upNote();
155       QVERIFY(note);
156       // drop a glissando on note
157       gliss             = new Glissando(score);
158       dropData.pos      = note->pagePos();
159       dropData.dropElement  = gliss;
160       note->drop(dropData);
161 
162       QVERIFY(saveCompareScore(score, "glissando01.mscx", DIR + "glissando01-ref.mscx"));
163       delete score;
164       }
165 
166 //---------------------------------------------------------
167 ///  spanners02
168 ///   Check loading of score with a glissando from a lower to a higher staff:
169 //    A score with:
170 //          grand staff,
171 //          glissando from a bass staff note to a treble staff note
172 //    is loaded and laid out and saved: should be round-trip safe.
173 //---------------------------------------------------------
174 
spanners02()175 void TestSpanners::spanners02()
176       {
177       MasterScore* score = readScore(DIR + "glissando-crossstaff01.mscx");
178       QVERIFY(score);
179 
180       QVERIFY(saveCompareScore(score, "glissando-crossstaff01.mscx", DIR + "glissando-crossstaff01-ref.mscx"));
181       delete score;
182       }
183 
184 //---------------------------------------------------------
185 ///  spanners03
186 ///   Loads a score with before- and after-grace notes and adds several glissandi from/to them.
187 //---------------------------------------------------------
188 
spanners03()189 void TestSpanners::spanners03()
190       {
191       EditData    dropData(0);
192       Glissando*  gliss;
193 
194       MasterScore* score = readScore(DIR + "glissando-graces01.mscx");
195       QVERIFY(score);
196 
197       // GLISSANDO FROM MAIN NOTE TO AFTER-GRACE
198       // go to top note of first chord
199       Measure*    msr   = score->firstMeasure();
200       QVERIFY(msr);
201       Segment*    seg   = msr->findSegment(SegmentType::ChordRest, Fraction(0,1));
202       QVERIFY(seg);
203       Ms::Chord*      chord = static_cast<Ms::Chord*>(seg->element(0));
204       QVERIFY(chord && chord->type() == ElementType::CHORD);
205       Note*       note  = chord->upNote();
206       QVERIFY(note);
207       // drop a glissando on note
208       gliss             = new Glissando(score); // create a new element each time, as drop() will eventually delete it
209       dropData.pos      = note->pagePos();
210       dropData.dropElement  = gliss;
211       note->drop(dropData);
212 
213       // GLISSANDO FROM AFTER-GRACE TO BEFORE-GRACE OF NEXT CHORD
214       // go to last after-grace of chord and drop a glissando on it
215       Ms::Chord*      grace = chord->graceNotesAfter().last();
216       QVERIFY(grace && grace->type() == ElementType::CHORD);
217       note              = grace->upNote();
218       QVERIFY(note);
219       gliss             = new Glissando(score);
220       dropData.pos      = note->pagePos();
221       dropData.dropElement  = gliss;
222       note->drop(dropData);
223 
224       // GLISSANDO FROM MAIN NOTE TO BEFORE-GRACE OF NEXT CHORD
225       // go to next chord
226       seg               = seg->nextCR(0);
227       QVERIFY(seg);
228       chord             = static_cast<Ms::Chord*>(seg->element(0));
229       QVERIFY(chord && chord->type() == ElementType::CHORD);
230       note              = chord->upNote();
231       QVERIFY(note);
232       gliss             = new Glissando(score);
233       dropData.pos      = note->pagePos();
234       dropData.dropElement  = gliss;
235       note->drop(dropData);
236 
237       // GLISSANDO FROM BEFORE-GRACE TO MAIN NOTE
238       // go to next chord
239       seg               = seg->nextCR(0);
240       QVERIFY(seg);
241       chord             = static_cast<Ms::Chord*>(seg->element(0));
242       QVERIFY(chord && chord->type() == ElementType::CHORD);
243       // go to its last before-grace note
244       grace             = chord->graceNotesBefore().last();
245       QVERIFY(grace && grace->type() == ElementType::CHORD);
246       note              = grace->upNote();
247       QVERIFY(note);
248       gliss             = new Glissando(score);
249       dropData.pos      = note->pagePos();
250       dropData.dropElement  = gliss;
251       note->drop(dropData);
252 
253       QVERIFY(saveCompareScore(score, "glissando-graces01.mscx", DIR + "glissando-graces01-ref.mscx"));
254       delete score;
255       }
256 
257 //---------------------------------------------------------
258 ///  spanners04
259 ///   Linking a staff to an existing staff containing a glissando
260 //---------------------------------------------------------
261 
spanners04()262 void TestSpanners::spanners04()
263       {
264       MasterScore* score = readScore(DIR + "glissando-cloning01.mscx");
265       QVERIFY(score);
266 
267       // add a linked staff to the existing staff
268       // (copied and adapted from void MuseScore::editInstrList() in mscore/instrdialog.cpp)
269       Staff* oldStaff   = score->staff(0);
270       Staff* newStaff   = new Staff(score);
271       newStaff->setPart(oldStaff->part());
272       newStaff->initFromStaffType(oldStaff->staffType(Fraction(0,1)));
273       newStaff->setDefaultClefType(ClefTypeList(ClefType::G));
274 
275       KeySigEvent ke;
276       ke.setKey(Key::C);
277       newStaff->setKey(Fraction(0,1), ke);
278 
279       score->undoInsertStaff(newStaff, 1, false);
280       Excerpt::cloneStaff(oldStaff, newStaff);
281 
282       QVERIFY(saveCompareScore(score, "glissando-cloning01.mscx", DIR + "glissando-cloning01-ref.mscx"));
283       delete score;
284       }
285 
286 //---------------------------------------------------------
287 ///  spanners05
288 ///   Creating part from an existing staff containing a glissando
289 //---------------------------------------------------------
290 
spanners05()291 void TestSpanners::spanners05()
292       {
293       MasterScore* score = readScore(DIR + "glissando-cloning02.mscx");
294       QVERIFY(score);
295 
296       // create parts
297       // (copied and adapted from void TestParts::createParts() in mtest/libmscore/parts/tst_parts.cpp)
298       QList<Part*> parts;
299       parts.append(score->parts().at(0));
300       Score* nscore = new Score(score);
301 
302       Excerpt* ex = new Excerpt(score);
303       ex->setPartScore(nscore);
304       ex->setTitle(parts.front()->longName());
305       ex->setParts(parts);
306       Excerpt::createExcerpt(ex);
307       QVERIFY(nscore);
308 
309 //      nscore->setName(parts.front()->partName());
310 
311 //      QMultiMap<int, int> tracks;
312       score->Score::undo(new AddExcerpt(ex));
313 
314       QVERIFY(saveCompareScore(score, "glissando-cloning02.mscx", DIR + "glissando-cloning02-ref.mscx"));
315       delete score;
316       }
317 
318 //---------------------------------------------------------
319 ///  spanners06
320 ///   Drop a glissando on a staff with a linked staff
321 //---------------------------------------------------------
322 
spanners06()323 void TestSpanners::spanners06()
324       {
325       EditData    dropData(0);
326       Glissando*  gliss;
327 
328       MasterScore* score = readScore(DIR + "glissando-cloning03.mscx");
329       QVERIFY(score);
330 
331       // DROP A GLISSANDO ON FIRST NOTE
332       Measure*    msr   = score->firstMeasure();
333       QVERIFY(msr);
334       Segment*    seg   = msr->findSegment(SegmentType::ChordRest, Fraction(0,1));
335       QVERIFY(seg);
336       Ms::Chord*      chord = static_cast<Ms::Chord*>(seg->element(0));
337       QVERIFY(chord && chord->type() == ElementType::CHORD);
338       Note*       note  = chord->upNote();
339       QVERIFY(note);
340       // drop a glissando on note
341       gliss             = new Glissando(score);
342       dropData.pos      = note->pagePos();
343       dropData.dropElement  = gliss;
344       note->drop(dropData);
345 
346       QVERIFY(saveCompareScore(score, "glissando-cloning03.mscx", DIR + "glissando-cloning03-ref.mscx"));
347       delete score;
348       }
349 
350 //---------------------------------------------------------
351 ///  spanners07
352 ///   Drop a glissando on a staff with an excerpt
353 //---------------------------------------------------------
354 
spanners07()355 void TestSpanners::spanners07()
356       {
357       EditData    dropData(0);
358       Glissando*  gliss;
359 
360       MasterScore* score = readScore(DIR + "glissando-cloning04.mscx");
361       QVERIFY(score);
362 
363       // DROP A GLISSANDO ON FIRST NOTE
364       Measure*    msr   = score->firstMeasure();
365       QVERIFY(msr);
366       Segment*    seg   = msr->findSegment(SegmentType::ChordRest, Fraction(0,1));
367       QVERIFY(seg);
368       Ms::Chord*      chord = static_cast<Ms::Chord*>(seg->element(0));
369       QVERIFY(chord && chord->type() == ElementType::CHORD);
370       Note*       note  = chord->upNote();
371       QVERIFY(note);
372       // drop a glissando on note
373       gliss             = new Glissando(score);
374       dropData.pos      = note->pagePos();
375       dropData.dropElement  = gliss;
376       note->drop(dropData);
377 
378       QVERIFY(saveCompareScore(score, "glissando-cloning04.mscx", DIR + "glissando-cloning04-ref.mscx"));
379       delete score;
380       }
381 #if 0
382 //---------------------------------------------------------
383 ///  spanners08
384 ///   Delete a lyrics with separator and undo
385 //---------------------------------------------------------
386 
387 void TestSpanners::spanners08()
388       {
389       MasterScore* score = readScore(DIR + "lyricsline01.mscx");
390       QVERIFY(score);
391 
392       // verify initial LyricsLine setup
393       System* sys = score->systems().at(0);
394       QVERIFY(sys->spannerSegments().size() == 1);
395       QVERIFY(score->unmanagedSpanners().size() == 1);
396 
397       // DELETE LYRICS
398       Measure*    msr   = score->firstMeasure();
399       QVERIFY(msr);
400       Segment*    seg   = msr->findSegment(SegmentType::ChordRest, 0);
401       QVERIFY(seg);
402       Ms::Chord*      chord = static_cast<Ms::Chord*>(seg->element(0));
403       QVERIFY(chord && chord->type() == ElementType::CHORD);
404       QVERIFY(chord->lyrics().size() > 0);
405       Lyrics*     lyr   = chord->lyrics(0, Element::Placement::BELOW);
406       score->startCmd();
407       score->undoRemoveElement(lyr);
408       score->endCmd();
409 
410       // verify setup after deletion
411       QVERIFY(sys->spannerSegments().size() == 0);
412       QVERIFY(score->unmanagedSpanners().size() == 0);
413 
414       // save and verify score after deletion
415       QVERIFY(saveCompareScore(score, "lyricsline01.mscx", DIR + "lyricsline01-ref.mscx"));
416 
417       // UNDO
418       score->undoStack()->undo();
419       score->doLayout();
420 
421       // verify setup after undo
422       QVERIFY(sys->spannerSegments().size() == 1);
423       QVERIFY(score->unmanagedSpanners().size() == 1);
424 
425       // save and verify score after undo
426       QVERIFY(saveCompareScore(score, "lyricsline01.mscx", DIR + "lyricsline01.mscx"));
427       delete score;
428       }
429 #endif
430 //---------------------------------------------------------
431 ///  spanners09
432 ///   Remove a measure containing the end point of a LyricsLine and undo
433 //
434 //  +---spanner---+
435 //         +---remove----+
436 //
437 //---------------------------------------------------------
438 
spanners09()439 void TestSpanners::spanners09()
440       {
441       MasterScore* score = readScore(DIR + "lyricsline02.mscx");
442       QVERIFY(score);
443 
444       // DELETE SECOND MEASURE AND VERIFY
445       Measure* msr   = score->firstMeasure();
446       QVERIFY(msr);
447       msr = msr->nextMeasure();
448       QVERIFY(msr);
449       score->startCmd();
450       score->select(msr);
451       score->cmdTimeDelete();
452       score->endCmd();
453       QVERIFY(saveCompareScore(score, "lyricsline02.mscx", DIR + "lyricsline02-ref.mscx"));
454 
455       // UNDO AND VERIFY
456       score->undoStack()->undo(&ed);
457       score->doLayout(); // measure needs to be renumbered
458       QVERIFY(saveCompareScore(score, "lyricsline02.mscx", DIR + "lyricsline02.mscx"));
459       delete score;
460       }
461 
462 //---------------------------------------------------------
463 ///  spanners10
464 ///   Remove a measure containing the start point of a LyricsLine and undo
465 //
466 //         +---spanner---+
467 //  +---remove----+
468 //
469 //---------------------------------------------------------
470 
spanners10()471 void TestSpanners::spanners10()
472       {
473       MasterScore* score = readScore(DIR + "lyricsline03.mscx");
474       QVERIFY(score);
475 
476       // DELETE SECOND MEASURE AND VERIFY
477       Measure*    msr   = score->firstMeasure();
478       QVERIFY(msr);
479       msr = msr->nextMeasure();
480       QVERIFY(msr);
481       score->startCmd();
482       score->select(msr);
483       score->cmdTimeDelete();
484       score->endCmd();
485       QVERIFY(saveCompareScore(score, "lyricsline03.mscx", DIR + "lyricsline03-ref.mscx"));
486 
487       // UNDO AND VERIFY
488       score->undoStack()->undo(&ed);
489       score->doLayout(); // measure needs to be renumbered
490       QVERIFY(saveCompareScore(score, "lyricsline03.mscx", DIR + "lyricsline03.mscx"));
491       delete score;
492       }
493 
494 //---------------------------------------------------------
495 ///  spanners11
496 ///   Remove a measure entirely containing a LyricsLine and undo
497 //
498 //         +---spanner---+
499 //  +-----------remove------------+
500 //
501 //---------------------------------------------------------
502 
spanners11()503 void TestSpanners::spanners11()
504       {
505       MasterScore* score = readScore(DIR + "lyricsline04.mscx");
506       QVERIFY(score);
507 
508       // DELETE SECOND MEASURE AND VERIFY
509       Measure*    msr   = score->firstMeasure();
510       QVERIFY(msr);
511       msr = msr->nextMeasure();
512       QVERIFY(msr);
513       score->startCmd();
514       score->select(msr);
515       score->cmdTimeDelete();
516       score->endCmd();
517       QVERIFY(saveCompareScore(score, "lyricsline04.mscx", DIR + "lyricsline04-ref.mscx"));
518 
519       // UNDO AND VERIFY
520       score->undoStack()->undo(&ed);
521       score->doLayout(); // measure needs to be renumbered
522       QVERIFY(saveCompareScore(score, "lyricsline04.mscx", DIR + "lyricsline04.mscx"));
523       delete score;
524       }
525 
526 //---------------------------------------------------------
527 ///  spanners12
528 ///   Remove a measure containing the middle portion of a LyricsLine and undo
529 //
530 //  +-----------spanner-----------+
531 //          +---remove----+
532 //
533 //---------------------------------------------------------
534 
spanners12()535 void TestSpanners::spanners12()
536       {
537       MasterScore* score = readScore(DIR + "lyricsline05.mscx");
538       QVERIFY(score);
539 
540       // DELETE SECOND MEASURE AND VERIFY
541       Measure*    msr   = score->firstMeasure();
542       QVERIFY(msr);
543       msr = msr->nextMeasure();
544       QVERIFY(msr);
545       score->startCmd();
546       score->select(msr);
547       score->cmdTimeDelete();
548       score->endCmd();
549       QVERIFY(saveCompareScore(score, "lyricsline05.mscx", DIR + "lyricsline05-ref.mscx"));
550 
551       // UNDO AND VERIFY
552       score->undoStack()->undo(&ed);
553       score->doLayout(); // measure needs to be renumbered
554       QVERIFY(saveCompareScore(score, "lyricsline05.mscx", DIR + "lyricsline05.mscx"));
555       delete score;
556       }
557 #if 0
558 //---------------------------------------------------------
559 ///  spanners13
560 ///   Drop a line break at a bar line in the middle of a LyricsLine and check LyricsLineSegments are correct
561 //
562 //---------------------------------------------------------
563 
564 void TestSpanners::spanners13()
565       {
566       EditData          dropData(0);
567       LayoutBreak*      brk;
568 
569       MasterScore* score = readScore(DIR + "lyricsline06.mscx");
570       QVERIFY(score);
571 
572       // DROP A BREAK AT FIRST MEASURE AND VERIFY
573       Measure*    msr   = score->firstMeasure();
574       QVERIFY(msr);
575       brk               = new LayoutBreak(score);
576       brk->setLayoutBreakType(LayoutBreak::Type::LINE);
577       dropData.pos      = msr->pagePos();
578       dropData.dropElement  = brk;
579       score->startCmd();
580       msr->drop(dropData);
581       score->endCmd();
582       // VERIFY SEGMENTS IN SYSTEMS AND THEN SCORE
583       for (System* sys : score->systems())
584             QVERIFY(sys->spannerSegments().size() == 1);
585       QVERIFY(saveCompareScore(score, "lyricsline06.mscx", DIR + "lyricsline06-ref.mscx"));
586 
587       // UNDO AND VERIFY
588       score->undoStack()->undo();
589       score->doLayout();      // systems need to be re-computed
590       QVERIFY(saveCompareScore(score, "lyricsline06.mscx", DIR + "lyricsline06.mscx"));
591       delete score;
592       }
593 #endif
594 
595 //---------------------------------------------------------
596 ///  spanners14
597 ///   creating part from an existing grand staff containing a cross staff glissando
598 //---------------------------------------------------------
599 
spanners14()600 void TestSpanners::spanners14()
601       {
602       MasterScore* score = readScore(DIR + "glissando-cloning05.mscx");
603       QVERIFY(score);
604 
605       // create parts
606       // (copied and adapted from void TestParts::createParts() in mtest/libmscore/parts/tst_parts.cpp)
607       QList<Part*> parts;
608       parts.append(score->parts().at(0));
609       Score* nscore = new Score(score);
610 
611       Excerpt* ex = new Excerpt(score);
612       ex->setPartScore(nscore);
613       ex->setTitle(parts.front()->longName());
614       ex->setParts(parts);
615       Excerpt::createExcerpt(ex);
616       QVERIFY(nscore);
617 
618 //      nscore->setName(parts.front()->partName());
619 
620 //      QMultiMap<int, int> tracks;
621       score->Score::undo(new AddExcerpt(ex));
622 
623       QVERIFY(saveCompareScore(score, "glissando-cloning05.mscx", DIR + "glissando-cloning05-ref.mscx"));
624       delete score;
625       }
626 
627 //---------------------------------------------------------
628 ///  spanners15
629 ///   set the color of a spanner and save
630 //---------------------------------------------------------
631 
spanners15()632 void TestSpanners::spanners15()
633       {
634       MasterScore* score = readScore(DIR + "linecolor01.mscx");
635       QVERIFY(score);
636 
637       for (auto it = score->spanner().cbegin(); it != score->spanner().cend(); ++it) {
638             Spanner* spanner = (*it).second;
639             SLine* sl = static_cast<SLine*>(spanner);
640             sl->setProperty(Pid::COLOR, QVariant::fromValue(QColor(255, 0, 0, 255)));
641             for (auto ss : sl->spannerSegments()) {
642                   ss->setProperty(Pid::MIN_DISTANCE, 0.0);
643                   ss->setPropertyFlags(Pid::MIN_DISTANCE, PropertyFlags::UNSTYLED);
644                   }
645             }
646 
647       QVERIFY(saveCompareScore(score, "linecolor01.mscx", DIR + "linecolor01-ref.mscx"));
648       delete score;
649       }
650 
651 //---------------------------------------------------------
652 ///  spanners16
653 ///   read manually adjusted lines on a small staff and save
654 //---------------------------------------------------------
655 
spanners16()656 void TestSpanners::spanners16()
657       {
658       MasterScore* score = readScore(DIR + "smallstaff01.mscx");
659       QVERIFY(score);
660 
661       QVERIFY(saveCompareScore(score, "smallstaff01.mscx", DIR + "smallstaff01-ref.mscx"));
662       delete score;
663       }
664 
665 
666 
667 QTEST_MAIN(TestSpanners)
668 #include "tst_spanners.moc"
669 
670