Skip to content
Permalink
Browse files

fix #99146: File > Save Selection… leads to corrupt score if selectio…

…n is not 4/4 and does not start with time signature
  • Loading branch information
lasconic committed Mar 9, 2017
1 parent 1126ab7 commit 752bafc8e914de9fabdb75c4bb0ec66b5a931991
Showing with 56 additions and 13 deletions.
  1. +1 −1 libmscore/box.h
  2. +2 −2 libmscore/measure.cpp
  3. +1 −1 libmscore/measure.h
  4. +1 −1 libmscore/measurebase.h
  5. +1 −1 libmscore/score.h
  6. +49 −6 libmscore/scorefile.cpp
  7. +1 −1 libmscore/select.cpp
@@ -60,7 +60,7 @@ class Box : public MeasureBase {
virtual int grips() const override { return 1; }
virtual void layout() override;
virtual void write(XmlWriter&) const override;
virtual void write(XmlWriter& xml, int, bool) const override { write(xml); }
virtual void write(XmlWriter& xml, int, bool, bool) const override { write(xml); }
virtual void writeProperties(XmlWriter&) const override;
virtual bool readProperties(XmlReader&) override;
virtual void read(XmlReader&) override;
@@ -1738,7 +1738,7 @@ void Measure::adjustToLen(Fraction nf)
// write
//---------------------------------------------------------

void Measure::write(XmlWriter& xml, int staff, bool writeSystemElements) const
void Measure::write(XmlWriter& xml, int staff, bool writeSystemElements, bool forceTimeSig) const
{
int mno = no() + 1;
if (_len != _timesig) {
@@ -1792,7 +1792,7 @@ void Measure::write(XmlWriter& xml, int staff, bool writeSystemElements) const
}
Q_ASSERT(first());
Q_ASSERT(last());
score()->writeSegments(xml, strack, etrack, first(), last()->next1(), writeSystemElements, false, false);
score()->writeSegments(xml, strack, etrack, first(), last()->next1(), writeSystemElements, false, false, forceTimeSig);
xml.etag();
}

@@ -106,7 +106,7 @@ class Measure : public MeasureBase {
void read(XmlReader&, int idx);
void read(XmlReader& d) { read(d, 0); }
virtual void write(XmlWriter& xml) const override { Element::write(xml); }
void write(XmlWriter&, int, bool writeSystemElements) const;
void write(XmlWriter&, int, bool writeSystemElements, bool forceTimeSig) const;
void writeBox(XmlWriter&) const;
void readBox(XmlReader&);
virtual bool isEditable() const override { return false; }
@@ -104,7 +104,7 @@ class MeasureBase : public Element {
Ms::Measure* prevMeasureMM() const;

virtual void write(XmlWriter&) const override = 0;
virtual void write(XmlWriter&, int, bool) const = 0;
virtual void write(XmlWriter&, int, bool, bool) const = 0;

virtual void layout();

@@ -981,7 +981,7 @@ class Score : public QObject, ScoreElement {
MasterScore* masterScore() const { return _masterScore; }
void setMasterScore(MasterScore* s) { _masterScore = s; }
void createRevision();
void writeSegments(XmlWriter& xml, int strack, int etrack, Segment* first, Segment* last, bool, bool, bool);
void writeSegments(XmlWriter& xml, int strack, int etrack, Segment* first, Segment* last, bool, bool, bool, bool);

const QMap<QString, QString>& metaTags() const { return _metaTags; }
QMap<QString, QString>& metaTags() { return _metaTags; }
@@ -59,16 +59,16 @@ namespace Ms {
// writeMeasure
//---------------------------------------------------------

static void writeMeasure(XmlWriter& xml, MeasureBase* m, int staffIdx, bool writeSystemElements)
static void writeMeasure(XmlWriter& xml, MeasureBase* m, int staffIdx, bool writeSystemElements, bool forceTimeSig)
{
//
// special case multi measure rest
//
if (m->isMeasure() || staffIdx == 0)
m->write(xml, staffIdx, writeSystemElements);
m->write(xml, staffIdx, writeSystemElements, forceTimeSig);

if (m->score()->styleB(StyleIdx::createMultiMeasureRests) && m->isMeasure() && toMeasure(m)->mmRest())
toMeasure(m)->mmRest()->write(xml, staffIdx, writeSystemElements);
toMeasure(m)->mmRest()->write(xml, staffIdx, writeSystemElements, forceTimeSig);

xml.setCurTick(m->endTick());
}
@@ -212,8 +212,20 @@ void Score::writeMovement(XmlWriter& xml, bool selectionOnly)
xml.setTickDiff(xml.curTick());
xml.setCurTrack(staffIdx * VOICES);
bool writeSystemElements = (staffIdx == staffStart);
for (MeasureBase* m = measureStart; m != measureEnd; m = m->next())
writeMeasure(xml, m, staffIdx, writeSystemElements);
bool firstMeasureWritten = false;
bool forceTimeSig = false;
for (MeasureBase* m = measureStart; m != measureEnd; m = m->next()) {
// force timesig if first measure and selectionOnly
if (selectionOnly && m->isMeasure()) {
if (!firstMeasureWritten) {
forceTimeSig = true;
firstMeasureWritten = true;
}
else
forceTimeSig = false;
}
writeMeasure(xml, m, staffIdx, writeSystemElements, forceTimeSig);
}
xml.etag();
}
}
@@ -1040,7 +1052,7 @@ qDebug("createRevision");
//---------------------------------------------------------

void Score::writeSegments(XmlWriter& xml, int strack, int etrack,
Segment* fs, Segment* ls, bool writeSystemElements, bool clip, bool needFirstTick)
Segment* fs, Segment* ls, bool writeSystemElements, bool clip, bool needFirstTick, bool forceTimeSig)
{
int endTick = ls == 0 ? lastMeasure()->endTick() : ls->tick();
// in clipboard mode, ls might be in an mmrest
@@ -1065,6 +1077,11 @@ void Score::writeSegments(XmlWriter& xml, int strack, int etrack,
for (int track = strack; track < etrack; ++track) {
if (!xml.canWriteVoice(track))
continue;

bool timeSigWritten = false; // for forceTimeSig
bool crWritten = false; // for forceTimeSig
bool keySigWritten = false; // for forceTimeSig

for (Segment* segment = fs; segment && segment != ls; segment = segment->next1()) {
if (!segment->enabled())
continue;
@@ -1151,6 +1168,24 @@ void Score::writeSegments(XmlWriter& xml, int strack, int etrack,
continue;
if (e->generated())
continue;
if (forceTimeSig && track2voice(track) == 0 && segment->segmentType() == SegmentType::ChordRest && !timeSigWritten && !crWritten) {
// we will miss a key sig!
if (!keySigWritten) {
Key k = score()->staff(track2staff(track))->key(segment->tick());
KeySig* ks = new KeySig(this);
ks->setKey(k);
ks->write(xml);
delete ks;
keySigWritten = true;
}
// we will miss a time sig!
Fraction tsf = sigmap()->timesig(segment->tick()).timesig();
TimeSig* ts = new TimeSig(this);
ts->setSig(tsf);
ts->write(xml);
delete ts;
timeSigWritten = true;
}
if (needTick) {
// xml.tag("tick", segment->tick() - xml.tickDiff);
int tick = xml.clipboardmode() ? segment->tick() : segment->rtick();
@@ -1170,6 +1205,14 @@ void Score::writeSegments(XmlWriter& xml, int strack, int etrack,
// }
e->write(xml);
segment->write(xml); // write only once
if (forceTimeSig) {
if (segment->segmentType() == SegmentType::KeySig)
keySigWritten = true;
if (segment->segmentType() == SegmentType::TimeSig)
timeSigWritten = true;
if (segment->segmentType() == SegmentType::ChordRest)
crWritten = true;
}
}
//write spanner ending after the last segment, on the last tick
if (clip || ls == 0) {
@@ -706,7 +706,7 @@ QByteArray Selection::staffMimeData() const
xml.tag(QString("voice id=\"%1\"").arg(voice), offset);
}
}
_score->writeSegments(xml, startTrack, endTrack, seg1, seg2, false, true, true);
_score->writeSegments(xml, startTrack, endTrack, seg1, seg2, false, true, true, false);
xml.etag();
}

0 comments on commit 752bafc

Please sign in to comment.
You can’t perform that action at this time.