Merge pull request #3862 from dmitrio95/scorecmp_tool

GSoC 2018: Score comparison tool
This commit is contained in:
anatoly-os 2018-10-30 14:55:42 +02:00 committed by GitHub
commit e32ff8e44a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
110 changed files with 4006 additions and 452 deletions

1
all.h
View file

@ -218,6 +218,7 @@
// Undefined problematic #def'd macros in Microsoft headers
#undef STRING_NONE
#undef small
#undef DELETE
#endif
#endif // __cplusplus

View file

@ -38,6 +38,10 @@ else (NOT MSVC)
set(_all_h_file "${PROJECT_SOURCE_DIR}/all.h")
endif (NOT MSVC)
include_directories(
${PROJECT_SOURCE_DIR}/thirdparty/diff
)
add_library (
libmscore STATIC
${_all_h_file}
@ -99,6 +103,11 @@ add_library (
lyricsline.cpp
layoutlinear.cpp
connector.cpp location.cpp skyline.cpp
scorediff.cpp
)
target_link_libraries(libmscore
diff_match_patch
)
##

View file

@ -187,7 +187,7 @@ void Accidental::read(XmlReader& e)
void Accidental::write(XmlWriter& xml) const
{
xml.stag(name());
xml.stag(this);
writeProperty(xml, Pid::ACCIDENTAL_BRACKET);
writeProperty(xml, Pid::ROLE);
writeProperty(xml, Pid::SMALL);
@ -440,6 +440,20 @@ bool Accidental::setProperty(Pid propertyId, const QVariant& v)
return true;
}
//---------------------------------------------------------
// propertyUserValue
//---------------------------------------------------------
QString Accidental::propertyUserValue(Pid pid) const
{
switch(pid) {
case Pid::SUBTYPE:
return subtypeUserName();
default:
return Element::propertyUserValue(pid);
}
}
//---------------------------------------------------------
// accessibleInfo
//---------------------------------------------------------

View file

@ -211,6 +211,7 @@ class Accidental final : public Element {
virtual QVariant getProperty(Pid propertyId) const override;
virtual bool setProperty(Pid propertyId, const QVariant&) override;
virtual QVariant propertyDefault(Pid propertyId) const override;
virtual QString propertyUserValue(Pid) const;
static AccidentalVal subtype2value(AccidentalType); // return effective pitch offset
static const char* subtype2name(AccidentalType);

View file

@ -182,7 +182,7 @@ void Ambitus::setBottomTpc(int val)
void Ambitus::write(XmlWriter& xml) const
{
xml.stag("Ambitus");
xml.stag(this);
xml.tag(Pid::HEAD_GROUP, int(_noteHeadGroup), int(NOTEHEADGROUP_DEFAULT));
xml.tag(Pid::HEAD_TYPE, int(_noteHeadType), int(NOTEHEADTYPE_DEFAULT));
xml.tag(Pid::MIRROR_HEAD,int(_dir), int(DIR_DEFAULT));

View file

@ -56,7 +56,7 @@ void Arpeggio::write(XmlWriter& xml) const
{
if (!xml.canWrite(this))
return;
xml.stag("Arpeggio");
xml.stag(this);
Element::writeProperties(xml);
xml.tag("subtype", int(_arpeggioType));
if (_userLen1 != 0.0)

View file

@ -143,7 +143,7 @@ void Articulation::write(XmlWriter& xml) const
{
if (!xml.canWrite(this))
return;
xml.stag("Articulation");
xml.stag(this);
if (!_channelName.isEmpty())
xml.tagE(QString("channel name=\"%1\"").arg(_channelName));
writeProperty(xml, Pid::DIRECTION);

View file

@ -357,7 +357,7 @@ noteList BagpipeEmbellishment::getNoteList() const
void BagpipeEmbellishment::write(XmlWriter& xml) const
{
xml.stag(name());
xml.stag(this);
xml.tag("subtype", _embelType);
xml.etag();
}

View file

@ -505,7 +505,7 @@ void BarLine::drawEditMode(QPainter* p, EditData& ed)
void BarLine::write(XmlWriter& xml) const
{
xml.stag("BarLine");
xml.stag(this);
writeProperty(xml, Pid::BARLINE_TYPE);
writeProperty(xml, Pid::BARLINE_SPAN);

View file

@ -1989,7 +1989,7 @@ void Beam::write(XmlWriter& xml) const
{
if (_elements.empty())
return;
xml.stag(name());
xml.stag(this);
Element::writeProperties(xml);
writeProperty(xml, Pid::STEM_DIRECTION);

View file

@ -280,7 +280,7 @@ void Bend::draw(QPainter* painter) const
void Bend::write(XmlWriter& xml) const
{
xml.stag("Bend");
xml.stag(this);
for (const PitchValue& v : _points) {
xml.tagE(QString("point time=\"%1\" pitch=\"%2\" vibrato=\"%3\"")
.arg(v.time).arg(v.pitch).arg(v.vibrato));

View file

@ -189,7 +189,7 @@ void Box::updateGrips(EditData& ed) const
void Box::write(XmlWriter& xml) const
{
xml.stag(name());
xml.stag(this);
writeProperties(xml);
xml.etag();
}

View file

@ -446,16 +446,16 @@ void Bracket::write(XmlWriter& xml) const
{
switch (_bi->bracketType()) {
case BracketType::BRACE:
xml.stag("Bracket type=\"Brace\"");
xml.stag(this, "type=\"Brace\"");
break;
case BracketType::NORMAL:
xml.stag("Bracket");
xml.stag(this);
break;
case BracketType::SQUARE:
xml.stag("Bracket type=\"Square\"");
xml.stag(this, "type=\"Square\"");
break;
case BracketType::LINE:
xml.stag("Bracket type=\"Line\"");
xml.stag(this, "type=\"Line\"");
break;
case BracketType::NO_BRACKET:
break;

View file

@ -76,7 +76,7 @@ void Breath::write(XmlWriter& xml) const
{
if (!xml.canWrite(this))
return;
xml.stag("Breath");
xml.stag(this);
writeProperty(xml, Pid::SYMBOL);
writeProperty(xml, Pid::PAUSE);
Element::writeProperties(xml);

View file

@ -908,7 +908,7 @@ void Chord::write(XmlWriter& xml) const
c->write(xml);
}
writeBeam(xml);
xml.stag("Chord");
xml.stag(this);
ChordRest::writeProperties(xml);
for (const Articulation* a : _articulations)
a->write(xml);

View file

@ -207,7 +207,7 @@ void ChordLine::read(XmlReader& e)
void ChordLine::write(XmlWriter& xml) const
{
xml.stag(name());
xml.stag(this);
xml.tag("subtype", int(_chordLineType));
xml.tag("straight", _straight, false);
xml.tag("lengthX", _lengthX, 0.0);

View file

@ -310,7 +310,7 @@ void Clef::read(XmlReader& e)
void Clef::write(XmlWriter& xml) const
{
xml.stag(name());
xml.stag(this);
if (_clefTypes._concertClef != ClefType::INVALID)
xml.tag("concertClefType", ClefInfo::tag(_clefTypes._concertClef));
if (_clefTypes._transposingClef != ClefType::INVALID)

View file

@ -147,6 +147,8 @@ void Score::startCmd()
void Score::undoRedo(bool undo, EditData* ed)
{
if (readOnly())
return;
deselectAll();
cmdState().reset();
if (undo)
@ -170,7 +172,7 @@ void Score::endCmd(bool rollback)
update();
return;
}
if (MScore::_error != MS_NO_ERROR)
if (readOnly() || MScore::_error != MS_NO_ERROR)
rollback = true;
if (rollback)

View file

@ -49,7 +49,7 @@ QVariant ElementW::get(const QString& s) const
{
QVariant val;
if (e) {
Pid pid = propertyId(s);
Pid pid = propertyIdQml(s);
val = e->getProperty(pid);
if (propertyType(pid) == P_TYPE::FRACTION) {
Fraction f(val.value<Fraction>());

View file

@ -122,7 +122,7 @@ void Dynamic::write(XmlWriter& xml) const
{
if (!xml.canWrite(this))
return;
xml.stag("Dynamic");
xml.stag(this);
xml.tag("subtype", dynamicTypeName());
writeProperty(xml, Pid::VELOCITY);
writeProperty(xml, Pid::DYNAMIC_RANGE);

View file

@ -507,13 +507,15 @@ void Element::writeProperties(XmlWriter& xml) const
xml.etag(); // </linked>
}
}
if ((track() != xml.curTrack()) && (track() != -1) && !isBeam()) {
if ((xml.writeTrack() || track() != xml.curTrack())
&& (track() != -1) && !isBeam()) {
// Writing track number for beams is redundant as it is calculated
// during layout.
int t;
t = track() + xml.trackDiff();
int t = track() + xml.trackDiff();
xml.tag("track", t);
}
if (xml.writePosition())
xml.tag(Pid::POSITION, rfrac());
if (_tag != 0x1) {
for (int i = 1; i < MAX_TAGS; i++) {
if (_tag == ((unsigned)1 << i)) {
@ -668,7 +670,7 @@ bool Element::readProperties(XmlReader& e)
void Element::write(XmlWriter& xml) const
{
xml.stag(name());
xml.stag(this);
writeProperties(xml);
xml.etag();
}
@ -1066,6 +1068,10 @@ QVariant Element::getProperty(Pid propertyId) const
switch (propertyId) {
case Pid::TRACK:
return track();
case Pid::VOICE:
return voice();
case Pid::POSITION:
return rfrac();
case Pid::GENERATED:
return generated();
case Pid::COLOR:
@ -1101,6 +1107,9 @@ bool Element::setProperty(Pid propertyId, const QVariant& v)
case Pid::TRACK:
setTrack(v.toInt());
break;
case Pid::VOICE:
setVoice(v.toInt());
break;
case Pid::GENERATED:
setGenerated(v.toBool());
break;
@ -1172,6 +1181,31 @@ QVariant Element::propertyDefault(Pid pid) const
}
}
//---------------------------------------------------------
// propertyId
//---------------------------------------------------------
Pid Element::propertyId(const QStringRef& name) const
{
if (name == "pos" || name == "offset")
return Pid::OFFSET;
return ScoreElement::propertyId(name);
}
//---------------------------------------------------------
// propertyUserValue
//---------------------------------------------------------
QString Element::propertyUserValue(Pid pid) const
{
switch(pid) {
case Pid::SUBTYPE:
return subtypeName();
default:
return ScoreElement::propertyUserValue(pid);
}
}
//---------------------------------------------------------
// custom
// check if property is != default

View file

@ -179,6 +179,8 @@ class Element : public ScoreElement {
MeasureBase* findMeasureBase();
const MeasureBase* findMeasureBase() const;
virtual bool isElement() const override { return true; }
qreal spatium() const;
inline void setFlag(ElementFlag f, bool v) { if (v) _flags |= f; else _flags &= ~ElementFlags(f); }
@ -407,6 +409,8 @@ class Element : public ScoreElement {
virtual QVariant getProperty(Pid) const override;
virtual bool setProperty(Pid, const QVariant&) override;
virtual QVariant propertyDefault(Pid) const override;
virtual Pid propertyId(const QStringRef& xmlName) const override;
virtual QString propertyUserValue(Pid) const override;
virtual Element* propertyDelegate(Pid) { return 0; } // return Spanner for SpannerSegment for some properties
bool custom(Pid) const;

View file

@ -105,7 +105,7 @@ void Fermata::write(XmlWriter& xml) const
qDebug("%s not written", name());
return;
}
xml.stag("Fermata");
xml.stag(this);
xml.tag("subtype", Sym::id2name(_symId));
writeProperty(xml, Pid::TIME_STRETCH);
writeProperty(xml, Pid::PLAY);

View file

@ -405,7 +405,7 @@ QString FiguredBassItem::normalizedText() const
void FiguredBassItem::write(XmlWriter& xml) const
{
xml.stag("FiguredBassItem");
xml.stag("FiguredBassItem", this);
xml.tagE(QString("brackets b0=\"%1\" b1=\"%2\" b2=\"%3\" b3=\"%4\" b4=\"%5\"")
.arg(int(parenth[0])) .arg(int(parenth[1])) .arg(int(parenth[2])) .arg(int(parenth[3])) .arg(int(parenth[4])) );
if (_prefix != Modifier::NONE)
@ -1016,7 +1016,7 @@ void FiguredBass::write(XmlWriter& xml) const
{
if (!xml.canWrite(this))
return;
xml.stag("FiguredBass");
xml.stag(this);
if(!onNote())
xml.tag("onNote", onNote());
if (ticks() > 0)

View file

@ -75,6 +75,7 @@ class Fraction {
bool operator!=(const Fraction&) const;
QString print() const { return QString("%1/%2").arg(_numerator).arg(_denominator); }
QString toString() const { return print(); }
operator QVariant() const { return QVariant::fromValue(*this); }
};

View file

@ -394,7 +394,7 @@ void FretDiagram::write(XmlWriter& xml) const
{
if (!xml.canWrite(this))
return;
xml.stag("FretDiagram");
xml.stag(this);
Element::writeProperties(xml);
writeProperty(xml, Pid::FRET_STRINGS);

View file

@ -370,7 +370,7 @@ void Glissando::write(XmlWriter& xml) const
{
if (!xml.canWrite(this))
return;
xml.stag(name());
xml.stag(this);
if (_showText && !_text.isEmpty())
xml.tag("text", _text);

View file

@ -500,7 +500,7 @@ void Hairpin::write(XmlWriter& xml) const
{
if (!xml.canWrite(this))
return;
xml.stag(name());
xml.stag(this);
xml.tag("subtype", int(_hairpinType));
writeProperty(xml, Pid::VELO_CHANGE);
writeProperty(xml, Pid::HAIRPIN_CIRCLEDTIP);

View file

@ -200,7 +200,7 @@ void Harmony::write(XmlWriter& xml) const
{
if (!xml.canWrite(this))
return;
xml.stag("Harmony");
xml.stag(this);
if (_leftParen)
xml.tagE("leftParen");
if (_rootTpc != Tpc::TPC_INVALID || _baseTpc != Tpc::TPC_INVALID) {

View file

@ -21,7 +21,7 @@ namespace Ms {
void Icon::write(XmlWriter& xml) const
{
xml.stag(name());
xml.stag(this);
xml.tag("subtype", int(_iconType));
if (!_action.isEmpty())
xml.tag("action", _action.data());

View file

@ -214,7 +214,7 @@ void Image::write(XmlWriter& xml) const
if (relativeFilePath.isEmpty())
relativeFilePath = _linkPath;
xml.stag("Image");
xml.stag(this);
BSymbol::writeProperties(xml);
// keep old "path" tag, for backward compatibility and because it is used elsewhere
// (for instance by Box:read(), Measure:read(), Note:read(), ...)

View file

@ -73,7 +73,7 @@ void InstrumentChange::setInstrument(const Instrument& i)
void InstrumentChange::write(XmlWriter& xml) const
{
xml.stag(name());
xml.stag(this);
_instrument->write(xml, part());
TextBase::writeProperties(xml);
xml.etag();

View file

@ -131,7 +131,7 @@ void Jump::read(XmlReader& e)
void Jump::write(XmlWriter& xml) const
{
xml.stag(name());
xml.stag(this);
TextBase::writeProperties(xml);
xml.tag("jumpTo", _jumpTo);
xml.tag("playUntil", _playUntil);

View file

@ -329,7 +329,7 @@ void KeySig::setKey(Key key)
void KeySig::write(XmlWriter& xml) const
{
xml.stag(name());
xml.stag(this);
Element::writeProperties(xml);
if (_sig.isAtonal()) {
xml.tag("custom", 1);

View file

@ -48,7 +48,7 @@ LayoutBreak::LayoutBreak(const LayoutBreak& lb)
void LayoutBreak::write(XmlWriter& xml) const
{
xml.stag(name());
xml.stag(this);
Element::writeProperties(xml);
writeProperty(xml, Pid::LAYOUT_BREAK);

View file

@ -87,7 +87,7 @@ void LetRing::write(XmlWriter& xml) const
{
if (!xml.canWrite(this))
return;
xml.stag(name());
xml.stag(this);
for (const StyledProperty& spp : *styledProperties()) {
if (!isStyled(spp.pid))

View file

@ -1040,7 +1040,7 @@ void SLine::writeProperties(XmlWriter& xml) const
//
qreal _spatium = spatium();
for (const SpannerSegment* seg : spannerSegments()) {
xml.stag("Segment");
xml.stag("Segment", seg);
xml.tag("subtype", int(seg->spannerSegmentType()));
xml.tag("offset", seg->offset() / _spatium);
xml.tag("off2", seg->userOff2() / _spatium);
@ -1128,7 +1128,7 @@ const QRectF& SLine::bbox() const
void SLine::write(XmlWriter& xml) const
{
xml.stag(name());
xml.stag(this);
SLine::writeProperties(xml);
xml.etag();
}

View file

@ -135,33 +135,12 @@ void Location::fillPositionForElement(const Element* e, bool absfrac)
qWarning("Location::fillPositionForElement: element is nullptr");
return;
}
if (track() == absDefaults.track()) {
const int track = e->track();
setTrack(track);
if (track < 0) {
const MeasureBase* mb = e->findMeasureBase();
if (mb && !mb->isMeasure()) {
// Such elements are written in the first staff,
// see writeMeasure() in scorefile.cpp
setTrack(0);
}
}
}
if (track() == absDefaults.track())
setTrack(track(e));
if (frac() == absDefaults.frac())
setFrac(absfrac ? e->afrac() : e->rfrac());
if (measure() == absDefaults.measure()) {
if (absfrac)
setMeasure(0);
else {
const Measure* m = toMeasure(e->findMeasure());
if (m)
setMeasure(m->measureIndex());
else {
qWarning("Location::fillFor: cannot find element's measure (%s)", e->name());
setMeasure(0);
}
}
}
if (measure() == absDefaults.measure())
setMeasure(absfrac ? 0 : measure(e));
}
//---------------------------------------------------------
@ -180,26 +159,8 @@ void Location::fillForElement(const Element* e, bool absfrac)
}
fillPositionForElement(e, absfrac);
if (e->isChord() || (e->parent() && e->parent()->isChord())) {
const Chord* ch = e->isChord() ? toChord(e) : toChord(e->parent());
if (ch->isGrace())
setGraceIndex(ch->graceIndex());
}
if (e->isNote()) {
const Note* n = toNote(e);
const std::vector<Note*>& notes = n->chord()->notes();
if (notes.size() == 1)
setNote(0);
else {
int noteIdx;
for (noteIdx = 0; noteIdx < int(notes.size()); ++noteIdx) {
if (n == notes.at(noteIdx))
break;
}
setNote(noteIdx);
}
}
setGraceIndex(graceIndex(e));
setNote(note(e));
}
//---------------------------------------------------------
@ -224,6 +185,96 @@ Location Location::positionForElement(const Element* e, bool absfrac)
return i;
}
//---------------------------------------------------------
// Location::track
//---------------------------------------------------------
int Location::track(const Element* e)
{
int track = e->track();
if (track < 0) {
const MeasureBase* mb = e->findMeasureBase();
if (mb && !mb->isMeasure()) {
// Such elements are written in the first staff,
// see writeMeasure() in scorefile.cpp
track = 0;
}
}
return track;
}
//---------------------------------------------------------
// Location::measure
//---------------------------------------------------------
int Location::measure(const Element* e)
{
const Measure* m = toMeasure(e->findMeasure());
if (m)
return m->measureIndex();
qWarning("Location::measure: cannot find element's measure (%s)", e->name());
return 0;
}
//---------------------------------------------------------
// Location::graceIndex
//---------------------------------------------------------
int Location::graceIndex(const Element* e)
{
if (e->isChord() || (e->parent() && e->parent()->isChord())) {
const Chord* ch = e->isChord() ? toChord(e) : toChord(e->parent());
if (ch->isGrace())
return ch->graceIndex();
}
return absDefaults.graceIndex();
}
//---------------------------------------------------------
// Location::note
//---------------------------------------------------------
int Location::note(const Element* e)
{
if (e->isNote()) {
const Note* n = toNote(e);
const std::vector<Note*>& notes = n->chord()->notes();
if (notes.size() == 1)
return 0;
int noteIdx;
for (noteIdx = 0; noteIdx < int(notes.size()); ++noteIdx) {
if (n == notes.at(noteIdx))
break;
}
return noteIdx;
}
return absDefaults.note();
}
//---------------------------------------------------------
// Location::getLocationProperty
//---------------------------------------------------------
QVariant Location::getLocationProperty(Pid pid, const Element* start, const Element* end)
{
switch(pid) {
case Pid::LOCATION_STAVES:
return (track(start) / VOICES) - (track(end) / VOICES);
case Pid::LOCATION_VOICES:
return (track(start) % VOICES) - (track(end) / VOICES);
case Pid::LOCATION_MEASURES:
return measure(end) - measure(start);
case Pid::LOCATION_FRACTIONS:
return end->rfrac() - start->rfrac();
case Pid::LOCATION_GRACE:
return graceIndex(end) - graceIndex(end);
case Pid::LOCATION_NOTE:
return note(start) - note(end);
default:
return QVariant();
}
}
//---------------------------------------------------------
// Location::operator==
//---------------------------------------------------------

View file

@ -23,6 +23,8 @@ class Element;
class XmlReader;
class XmlWriter;
enum class Pid;
class Location {
int _staff;
int _voice;
@ -32,6 +34,11 @@ class Location {
int _note;
bool _rel;
static int track(const Element* e);
static int measure(const Element* e);
static int graceIndex(const Element* e);
static int note(const Element* e);
public:
constexpr Location(int staff, int voice, int measure, Fraction frac, int graceIndex, int note, bool rel)
: _staff(staff), _voice(voice), _measure(measure), _frac(frac), _graceIndex(graceIndex), _note(note), _rel(rel) {}
@ -67,6 +74,7 @@ class Location {
void fillPositionForElement(const Element* e, bool absfrac = true);
static Location forElement(const Element* e, bool absfrac = true);
static Location positionForElement(const Element* e, bool absfrac = true);
static QVariant getLocationProperty(Pid pid, const Element* start, const Element* end);
bool operator==(const Location& other) const;
bool operator!=(const Location& other) const { return !(*this == other); }

View file

@ -85,7 +85,7 @@ void Lyrics::write(XmlWriter& xml) const
{
if (!xml.canWrite(this))
return;
xml.stag("Lyrics");
xml.stag(this);
writeProperty(xml, Pid::VERSE);
if (_syllabic != Syllabic::SINGLE) {
static const char* sl[] = {

View file

@ -204,7 +204,7 @@ void Marker::read(XmlReader& e)
void Marker::write(XmlWriter& xml) const
{
xml.stag(name());
xml.stag(this);
TextBase::writeProperties(xml);
xml.tag("label", _label);
xml.etag();

View file

@ -1760,10 +1760,10 @@ void Measure::write(XmlWriter& xml, int staff, bool writeSystemElements, bool fo
}
if (_len != _timesig) {
// this is an irregular measure
xml.stag(QString("Measure len=\"%1/%2\"").arg(_len.numerator()).arg(_len.denominator()));
xml.stag(this, QString("len=\"%1/%2\"").arg(_len.numerator()).arg(_len.denominator()));
}
else
xml.stag("Measure");
xml.stag(this);
xml.setCurTick(tick());
xml.setCurTrack(staff * VOICES);
@ -1784,7 +1784,7 @@ void Measure::write(XmlWriter& xml, int staff, bool writeSystemElements, bool fo
qreal _spatium = spatium();
MStaff* mstaff = _mstaves[staff];
if (mstaff->noText() && !mstaff->noText()->generated()) {
xml.stag("MeasureNumber");
xml.stag("MeasureNumber", mstaff->noText());
mstaff->noText()->writeProperties(xml);
xml.etag();
}

View file

@ -258,6 +258,9 @@ void MScore::init()
#endif
qRegisterMetaType<Fraction>("Fraction");
if (!QMetaType::registerConverter<Fraction, QString>(&Fraction::toString))
qFatal("registerConverter Fraction::toString failed");
#ifdef Q_OS_WIN
QDir dir(QCoreApplication::applicationDirPath() + QString("/../" INSTALL_NAME));
_globalShare = dir.absolutePath() + "/";

View file

@ -1177,7 +1177,7 @@ void Note::draw(QPainter* painter) const
void Note::write(XmlWriter& xml) const
{
xml.stag("Note");
xml.stag(this);
Element::writeProperties(xml);
if (_accidental)
@ -2665,6 +2665,27 @@ QVariant Note::propertyDefault(Pid propertyId) const
return Element::propertyDefault(propertyId);
}
//---------------------------------------------------------
// propertyUserValue
//---------------------------------------------------------
QString Note::propertyUserValue(Pid pid) const
{
switch(pid) {
case Pid::PITCH:
return tpcUserName();
case Pid::TPC1:
case Pid::TPC2:
{
int idx = (pid == Pid::TPC1) ? 0 : 1;
int tpc = _tpc[idx];
return tpc2name(tpc, NoteSpellingType::STANDARD, NoteCaseType::AUTO, false);
}
default:
return Element::propertyUserValue(pid);
}
}
//---------------------------------------------------------
// undoSetFret
//---------------------------------------------------------

View file

@ -465,6 +465,7 @@ class Note final : public Element {
virtual QVariant getProperty(Pid propertyId) const override;
virtual bool setProperty(Pid propertyId, const QVariant&) override;
virtual QVariant propertyDefault(Pid) const override;
virtual QString propertyUserValue(Pid) const override;
bool mark() const { return _mark; }
void setMark(bool v) const { _mark = v; }

View file

@ -255,7 +255,7 @@ void Ottava::write(XmlWriter& xml) const
{
if (!xml.canWrite(this))
return;
xml.stag(name());
xml.stag(this);
xml.tag("subtype", ottavaDefault[int(ottavaType())].name);
// for (const StyledProperty& spp : *styledProperties())
// writeProperty(xml, spp.pid);

View file

@ -418,7 +418,7 @@ bool Page::isOdd() const
void Page::write(XmlWriter& xml) const
{
xml.stag("Page");
xml.stag(this);
foreach(System* system, _systems) {
system->write(xml);
}

View file

@ -106,7 +106,7 @@ void PalmMute::write(XmlWriter& xml) const
{
if (!xml.canWrite(this))
return;
xml.stag(name());
xml.stag(this);
for (const StyledProperty& spp : *styledProperties())
writeProperty(xml, spp.pid);

View file

@ -109,7 +109,7 @@ void Part::read(XmlReader& e)
void Part::write(XmlWriter& xml) const
{
xml.stag("Part");
xml.stag(this);
foreach(const Staff* staff, _staves)
staff->write(xml);
if (!_show)

View file

@ -122,7 +122,7 @@ void Pedal::write(XmlWriter& xml) const
{
if (!xml.canWrite(this))
return;
xml.stag(name());
xml.stag(this);
for (auto i : {
Pid::END_HOOK_TYPE,

View file

@ -32,6 +32,7 @@ struct PropertyMetaData {
bool link; // link this property for linked elements
const char* name; // xml name of property
P_TYPE type;
const char* userName; // user-visible name of property
};
//
@ -39,278 +40,288 @@ struct PropertyMetaData {
//
//
static constexpr PropertyMetaData propertyList[] = {
{ Pid::SUBTYPE, "subtype", false, "subtype", P_TYPE::INT },
{ Pid::SELECTED, "selected", false, "selected", P_TYPE::BOOL },
{ Pid::GENERATED, "generated", false, "generated", P_TYPE::BOOL },
{ Pid::COLOR, "color", false, "color", P_TYPE::COLOR },
{ Pid::VISIBLE, "visible", false, "visible", P_TYPE::BOOL },
{ Pid::Z, "z", false, "z", P_TYPE::INT },
{ Pid::SMALL, "small", false, "small", P_TYPE::BOOL },
{ Pid::SHOW_COURTESY, "show_courtesy", false, "showCourtesy", P_TYPE::INT },
{ Pid::LINE_TYPE, "line_type", false, "lineType", P_TYPE::INT },
{ Pid::PITCH, "pitch", true, "pitch", P_TYPE::INT },
{ Pid::SUBTYPE, "subtype", false, "subtype", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "subtype") },
{ Pid::SELECTED, "selected", false, "selected", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "selected") },
{ Pid::GENERATED, "generated", false, "generated", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "generated") },
{ Pid::COLOR, "color", false, "color", P_TYPE::COLOR, QT_TRANSLATE_NOOP("propertyName", "color") },
{ Pid::VISIBLE, "visible", false, "visible", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "visible") },
{ Pid::Z, "z", false, "z", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "z") },
{ Pid::SMALL, "small", false, "small", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "small") },
{ Pid::SHOW_COURTESY, "show_courtesy", false, "showCourtesy", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "show courtesy") },
{ Pid::LINE_TYPE, "line_type", false, "lineType", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "line type") },
{ Pid::PITCH, "pitch", true, "pitch", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "pitch") },
{ Pid::TPC1, "tpc1", true, "tpc", P_TYPE::INT },
{ Pid::TPC2, "tpc2", true, "tpc2", P_TYPE::INT },
{ Pid::LINE, "line", false, "line", P_TYPE::INT },
{ Pid::FIXED, "fixed", false, "fixed", P_TYPE::BOOL },
{ Pid::FIXED_LINE, "fixed_line", false, "fixedLine", P_TYPE::INT },
{ Pid::HEAD_TYPE, "head_type", false, "headType", P_TYPE::HEAD_TYPE },
{ Pid::HEAD_GROUP, "head_group", false, "head", P_TYPE::HEAD_GROUP },
{ Pid::VELO_TYPE, "velo_type", false, "veloType", P_TYPE::VALUE_TYPE },
{ Pid::VELO_OFFSET, "velo_offset", false, "velocity", P_TYPE::INT },
{ Pid::ARTICULATION_ANCHOR, "articulation_anchor", false, "anchor", P_TYPE::INT },
{ Pid::TPC1, "tpc1", true, "tpc", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "tonal pitch class") },
{ Pid::TPC2, "tpc2", true, "tpc2", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "tonal pitch class") },
{ Pid::LINE, "line", false, "line", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "line") },
{ Pid::FIXED, "fixed", false, "fixed", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "fixed") },
{ Pid::FIXED_LINE, "fixed_line", false, "fixedLine", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "fixed line") },
{ Pid::HEAD_TYPE, "head_type", false, "headType", P_TYPE::HEAD_TYPE, QT_TRANSLATE_NOOP("propertyName", "head type") },
{ Pid::HEAD_GROUP, "head_group", false, "head", P_TYPE::HEAD_GROUP, QT_TRANSLATE_NOOP("propertyName", "head") },
{ Pid::VELO_TYPE, "velo_type", false, "veloType", P_TYPE::VALUE_TYPE, QT_TRANSLATE_NOOP("propertyName", "velocity type") },
{ Pid::VELO_OFFSET, "velo_offset", false, "velocity", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "velocity") },
{ Pid::ARTICULATION_ANCHOR, "articulation_anchor", false, "anchor", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "anchor") },
{ Pid::DIRECTION, "direction", false, "direction", P_TYPE::DIRECTION },
{ Pid::STEM_DIRECTION, "stem_direction", false, "StemDirection", P_TYPE::DIRECTION },
{ Pid::NO_STEM, "no_stem", false, "noStem", P_TYPE::INT },
{ Pid::SLUR_DIRECTION, "slur_direction", false, "up", P_TYPE::DIRECTION },
{ Pid::LEADING_SPACE, "leading_space", false, "leadingSpace", P_TYPE::SPATIUM },
{ Pid::DISTRIBUTE, "distribute", false, "distribute", P_TYPE::BOOL },
{ Pid::MIRROR_HEAD, "mirror_head", false, "mirror", P_TYPE::DIRECTION_H },
{ Pid::DOT_POSITION, "dot_position", false, "dotPosition", P_TYPE::DIRECTION },
{ Pid::TUNING, "tuning", false, "tuning", P_TYPE::REAL },
{ Pid::PAUSE, "pause", true, "pause", P_TYPE::REAL },
{ Pid::DIRECTION, "direction", false, "direction", P_TYPE::DIRECTION, QT_TRANSLATE_NOOP("propertyName", "direction") },
{ Pid::STEM_DIRECTION, "stem_direction", false, "StemDirection", P_TYPE::DIRECTION, QT_TRANSLATE_NOOP("propertyName", "stem direction") },
{ Pid::NO_STEM, "no_stem", false, "noStem", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "no stem") },
{ Pid::SLUR_DIRECTION, "slur_direction", false, "up", P_TYPE::DIRECTION, QT_TRANSLATE_NOOP("propertyName", "up") },
{ Pid::LEADING_SPACE, "leading_space", false, "leadingSpace", P_TYPE::SPATIUM, QT_TRANSLATE_NOOP("propertyName", "leading space") },
{ Pid::DISTRIBUTE, "distribute", false, "distribute", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "distributed") },
{ Pid::MIRROR_HEAD, "mirror_head", false, "mirror", P_TYPE::DIRECTION_H, QT_TRANSLATE_NOOP("propertyName", "mirror") },
{ Pid::DOT_POSITION, "dot_position", false, "dotPosition", P_TYPE::DIRECTION, QT_TRANSLATE_NOOP("propertyName", "dot position") },
{ Pid::TUNING, "tuning", false, "tuning", P_TYPE::REAL, QT_TRANSLATE_NOOP("propertyName", "tuning") },
{ Pid::PAUSE, "pause", true, "pause", P_TYPE::REAL, QT_TRANSLATE_NOOP("propertyName", "pause") },
{ Pid::BARLINE_TYPE, "barline_type", false, "subtype", P_TYPE::BARLINE_TYPE },
{ Pid::BARLINE_SPAN, "barline_span", false, "span", P_TYPE::BOOL },
{ Pid::BARLINE_SPAN_FROM, "barline_span_from", false, "spanFromOffset", P_TYPE::INT },
{ Pid::BARLINE_SPAN_TO, "barline_span_to", false, "spanToOffset", P_TYPE::INT },
{ Pid::OFFSET, "offset", false, "offset", P_TYPE::POINT_SP_MM },
{ Pid::FRET, "fret", true, "fret", P_TYPE::INT },
{ Pid::STRING, "string", true, "string", P_TYPE::INT },
{ Pid::GHOST, "ghost", true, "ghost", P_TYPE::BOOL },
{ Pid::PLAY, "play", false, "play", P_TYPE::BOOL },
{ Pid::TIMESIG_NOMINAL, "timesig_nominal", false, 0, P_TYPE::FRACTION },
{ Pid::BARLINE_TYPE, "barline_type", false, "subtype", P_TYPE::BARLINE_TYPE, QT_TRANSLATE_NOOP("propertyName", "subtype") },
{ Pid::BARLINE_SPAN, "barline_span", false, "span", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "span") },
{ Pid::BARLINE_SPAN_FROM, "barline_span_from", false, "spanFromOffset", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "span from") },
{ Pid::BARLINE_SPAN_TO, "barline_span_to", false, "spanToOffset", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "span to") },
{ Pid::OFFSET, "offset", false, "offset", P_TYPE::POINT_SP_MM, QT_TRANSLATE_NOOP("propertyName", "offset") },
{ Pid::FRET, "fret", true, "fret", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "fret") },
{ Pid::STRING, "string", true, "string", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "string") },
{ Pid::GHOST, "ghost", true, "ghost", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "ghost") },
{ Pid::PLAY, "play", false, "play", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "played") },
{ Pid::TIMESIG_NOMINAL, "timesig_nominal", false, 0, P_TYPE::FRACTION, QT_TRANSLATE_NOOP("propertyName", "nominal time signature") },
{ Pid::TIMESIG_ACTUAL, "timesig_actual", true, 0, P_TYPE::FRACTION },
{ Pid::NUMBER_TYPE, "number_type", false, "numberType", P_TYPE::INT },
{ Pid::BRACKET_TYPE, "bracket_type", false, "bracketType", P_TYPE::INT },
{ Pid::NORMAL_NOTES, "normal_notes", false, "normalNotes", P_TYPE::INT },
{ Pid::ACTUAL_NOTES, "actual_notes", false, "actualNotes", P_TYPE::INT },
{ Pid::P1, "p1", false, "p1", P_TYPE::POINT_SP },
{ Pid::P2, "p2", false, "p2", P_TYPE::POINT_SP },
{ Pid::GROW_LEFT, "grow_left", false, "growLeft", P_TYPE::REAL },
{ Pid::GROW_RIGHT, "grow_right", false, "growRight", P_TYPE::REAL },
{ Pid::BOX_HEIGHT, "box_height", false, "height", P_TYPE::SPATIUM },
{ Pid::TIMESIG_ACTUAL, "timesig_actual", true, 0, P_TYPE::FRACTION, QT_TRANSLATE_NOOP("propertyName", "actual time signature") },
{ Pid::NUMBER_TYPE, "number_type", false, "numberType", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "number type") },
{ Pid::BRACKET_TYPE, "bracket_type", false, "bracketType", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "bracket type") },
{ Pid::NORMAL_NOTES, "normal_notes", false, "normalNotes", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "normal notes") },
{ Pid::ACTUAL_NOTES, "actual_notes", false, "actualNotes", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "actual notes") },
{ Pid::P1, "p1", false, "p1", P_TYPE::POINT_SP, QT_TRANSLATE_NOOP("propertyName", "p1") },
{ Pid::P2, "p2", false, "p2", P_TYPE::POINT_SP, QT_TRANSLATE_NOOP("propertyName", "p2") },
{ Pid::GROW_LEFT, "grow_left", false, "growLeft", P_TYPE::REAL, QT_TRANSLATE_NOOP("propertyName", "grow left") },
{ Pid::GROW_RIGHT, "grow_right", false, "growRight", P_TYPE::REAL, QT_TRANSLATE_NOOP("propertyName", "grow right") },
{ Pid::BOX_HEIGHT, "box_height", false, "height", P_TYPE::SPATIUM, QT_TRANSLATE_NOOP("propertyName", "height") },
{ Pid::BOX_WIDTH, "box_width", false, "width", P_TYPE::SPATIUM },
{ Pid::TOP_GAP, "top_gap", false, "topGap", P_TYPE::SP_REAL },
{ Pid::BOTTOM_GAP, "bottom_gap", false, "bottomGap", P_TYPE::SP_REAL },
{ Pid::LEFT_MARGIN, "left_margin", false, "leftMargin", P_TYPE::REAL },
{ Pid::RIGHT_MARGIN, "right_margin", false, "rightMargin", P_TYPE::REAL },
{ Pid::TOP_MARGIN, "top_margin", false, "topMargin", P_TYPE::REAL },
{ Pid::BOTTOM_MARGIN, "bottom_margin", false, "bottomMargin", P_TYPE::REAL },
{ Pid::LAYOUT_BREAK, "layout_break", false, "subtype", P_TYPE::LAYOUT_BREAK },
{ Pid::AUTOSCALE, "autoscale", false, "autoScale", P_TYPE::BOOL },
{ Pid::SIZE, "size", false, "size", P_TYPE::SIZE },
{ Pid::BOX_WIDTH, "box_width", false, "width", P_TYPE::SPATIUM, QT_TRANSLATE_NOOP("propertyName", "width") },
{ Pid::TOP_GAP, "top_gap", false, "topGap", P_TYPE::SP_REAL, QT_TRANSLATE_NOOP("propertyName", "top gap") },
{ Pid::BOTTOM_GAP, "bottom_gap", false, "bottomGap", P_TYPE::SP_REAL, QT_TRANSLATE_NOOP("propertyName", "bottom gap") },
{ Pid::LEFT_MARGIN, "left_margin", false, "leftMargin", P_TYPE::REAL, QT_TRANSLATE_NOOP("propertyName", "left margin") },
{ Pid::RIGHT_MARGIN, "right_margin", false, "rightMargin", P_TYPE::REAL, QT_TRANSLATE_NOOP("propertyName", "right margin") },
{ Pid::TOP_MARGIN, "top_margin", false, "topMargin", P_TYPE::REAL, QT_TRANSLATE_NOOP("propertyName", "top margin") },
{ Pid::BOTTOM_MARGIN, "bottom_margin", false, "bottomMargin", P_TYPE::REAL, QT_TRANSLATE_NOOP("propertyName", "bottom margin") },
{ Pid::LAYOUT_BREAK, "layout_break", false, "subtype", P_TYPE::LAYOUT_BREAK, QT_TRANSLATE_NOOP("propertyName", "subtype") },
{ Pid::AUTOSCALE, "autoscale", false, "autoScale", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "autoscale") },
{ Pid::SIZE, "size", false, "size", P_TYPE::SIZE, QT_TRANSLATE_NOOP("propertyName", "size") },
{ Pid::SCALE, "scale", false, "scale", P_TYPE::SCALE },
{ Pid::LOCK_ASPECT_RATIO, "lock_aspect_ratio", false, "lockAspectRatio", P_TYPE::BOOL },
{ Pid::SIZE_IS_SPATIUM, "size_is_spatium", false, "sizeIsSpatium", P_TYPE::BOOL },
{ Pid::TEXT, "text", true, 0, P_TYPE::STRING },
{ Pid::HTML_TEXT, "html_text", false, 0, P_TYPE::STRING },
{ Pid::USER_MODIFIED, "user_modified", false, 0, P_TYPE::BOOL },
{ Pid::BEAM_POS, "beam_pos", false, 0, P_TYPE::POINT },
{ Pid::BEAM_MODE, "beam_mode", true, "BeamMode", P_TYPE::BEAM_MODE },
{ Pid::BEAM_NO_SLOPE, "beam_no_slope", true, "noSlope", P_TYPE::BOOL },
{ Pid::USER_LEN, "user_len", false, "userLen", P_TYPE::SP_REAL },
{ Pid::SCALE, "scale", false, "scale", P_TYPE::SCALE, QT_TRANSLATE_NOOP("propertyName", "scale") },
{ Pid::LOCK_ASPECT_RATIO, "lock_aspect_ratio", false, "lockAspectRatio", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "aspect ratio locked") },
{ Pid::SIZE_IS_SPATIUM, "size_is_spatium", false, "sizeIsSpatium", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "size is spatium") },
{ Pid::TEXT, "text", true, 0, P_TYPE::STRING, QT_TRANSLATE_NOOP("propertyName", "text") },
{ Pid::HTML_TEXT, "html_text", false, 0, P_TYPE::STRING, "" },
{ Pid::USER_MODIFIED, "user_modified", false, 0, P_TYPE::BOOL, "" },
{ Pid::BEAM_POS, "beam_pos", false, 0, P_TYPE::POINT, QT_TRANSLATE_NOOP("propertyName", "beam position") },
{ Pid::BEAM_MODE, "beam_mode", true, "BeamMode", P_TYPE::BEAM_MODE, QT_TRANSLATE_NOOP("propertyName", "beam mode") },
{ Pid::BEAM_NO_SLOPE, "beam_no_slope", true, "noSlope", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "without slope") },
{ Pid::USER_LEN, "user_len", false, "userLen", P_TYPE::SP_REAL, QT_TRANSLATE_NOOP("propertyName", "length") },
{ Pid::SPACE, "space", false, "space", P_TYPE::SP_REAL },
{ Pid::TEMPO, "tempo", true, "tempo", P_TYPE::TEMPO },
{ Pid::TEMPO_FOLLOW_TEXT, "tempo_follow_text", true, "followText", P_TYPE::BOOL },
{ Pid::ACCIDENTAL_BRACKET, "accidental_bracket", false, "bracket", P_TYPE::INT },
{ Pid::NUMERATOR_STRING, "numerator_string", false, "textN", P_TYPE::STRING },
{ Pid::DENOMINATOR_STRING, "denominator_string", false, "textD", P_TYPE::STRING },
{ Pid::FBPREFIX, "fbprefix", false, "prefix", P_TYPE::INT },
{ Pid::FBDIGIT, "fbdigit", false, "digit", P_TYPE::INT },
{ Pid::FBSUFFIX, "fbsuffix", false, "suffix", P_TYPE::INT },
{ Pid::FBCONTINUATIONLINE, "fbcontinuationline", false, "continuationLine", P_TYPE::INT },
{ Pid::SPACE, "space", false, "space", P_TYPE::SP_REAL, QT_TRANSLATE_NOOP("propertyName", "space") },
{ Pid::TEMPO, "tempo", true, "tempo", P_TYPE::TEMPO, QT_TRANSLATE_NOOP("propertyName", "tempo") },
{ Pid::TEMPO_FOLLOW_TEXT, "tempo_follow_text", true, "followText", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "following text") },
{ Pid::ACCIDENTAL_BRACKET, "accidental_bracket", false, "bracket", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "bracket") },
{ Pid::NUMERATOR_STRING, "numerator_string", false, "textN", P_TYPE::STRING, QT_TRANSLATE_NOOP("propertyName", "numerator string") },
{ Pid::DENOMINATOR_STRING, "denominator_string", false, "textD", P_TYPE::STRING, QT_TRANSLATE_NOOP("propertyName", "denominator string") },
{ Pid::FBPREFIX, "fbprefix", false, "prefix", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "prefix") },
{ Pid::FBDIGIT, "fbdigit", false, "digit", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "digit") },
{ Pid::FBSUFFIX, "fbsuffix", false, "suffix", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "suffix") },
{ Pid::FBCONTINUATIONLINE, "fbcontinuationline", false, "continuationLine", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "continuation line") },
{ Pid::FBPARENTHESIS1, "fbparenthesis1", false, "", P_TYPE::INT },
{ Pid::FBPARENTHESIS2, "fbparenthesis2", false, "", P_TYPE::INT },
{ Pid::FBPARENTHESIS3, "fbparenthesis3", false, "", P_TYPE::INT },
{ Pid::FBPARENTHESIS4, "fbparenthesis4", false, "", P_TYPE::INT },
{ Pid::FBPARENTHESIS5, "fbparenthesis5", false, "", P_TYPE::INT },
{ Pid::OTTAVA_TYPE, "ottava_type", true, "", P_TYPE::INT },
{ Pid::NUMBERS_ONLY, "numbers_only", false, "numbersOnly", P_TYPE::BOOL },
{ Pid::TRILL_TYPE, "trill_type", false, "", P_TYPE::INT },
{ Pid::VIBRATO_TYPE, "vibrato_type", false, "", P_TYPE::INT },
{ Pid::HAIRPIN_CIRCLEDTIP, "hairpin_circledtip", false, "hairpinCircledTip", P_TYPE::BOOL },
{ Pid::FBPARENTHESIS1, "fbparenthesis1", false, "", P_TYPE::INT, "" },
{ Pid::FBPARENTHESIS2, "fbparenthesis2", false, "", P_TYPE::INT, "" },
{ Pid::FBPARENTHESIS3, "fbparenthesis3", false, "", P_TYPE::INT, "" },
{ Pid::FBPARENTHESIS4, "fbparenthesis4", false, "", P_TYPE::INT, "" },
{ Pid::FBPARENTHESIS5, "fbparenthesis5", false, "", P_TYPE::INT, "" },
{ Pid::OTTAVA_TYPE, "ottava_type", true, "", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "ottava type") },
{ Pid::NUMBERS_ONLY, "numbers_only", false, "numbersOnly", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "numbers only") },
{ Pid::TRILL_TYPE, "trill_type", false, "", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "trill type") },
{ Pid::VIBRATO_TYPE, "vibrato_type", false, "", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "vibrato type") },
{ Pid::HAIRPIN_CIRCLEDTIP, "hairpin_circledtip", false, "hairpinCircledTip", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "hairpin with circled tip") },
{ Pid::HAIRPIN_TYPE, "hairpin_type", true, "", P_TYPE::INT },
{ Pid::HAIRPIN_HEIGHT, "hairpin_height", false, "hairpinHeight", P_TYPE::SPATIUM },
{ Pid::HAIRPIN_CONT_HEIGHT, "hairpin_cont_height", false, "hairpinContHeight", P_TYPE::SPATIUM },
{ Pid::VELO_CHANGE, "velo_change", true, "veloChange", P_TYPE::INT },
{ Pid::DYNAMIC_RANGE, "dynamic_range", true, "dynType", P_TYPE::INT },
{ Pid::PLACEMENT, "placement", false, "placement", P_TYPE::PLACEMENT },
{ Pid::VELOCITY, "velocity", false, "velocity", P_TYPE::INT },
{ Pid::JUMP_TO, "jump_to", true, "jumpTo", P_TYPE::STRING },
{ Pid::PLAY_UNTIL, "play_until", true, "playUntil", P_TYPE::STRING },
{ Pid::CONTINUE_AT, "continue_at", true, "continueAt", P_TYPE::STRING },
{ Pid::HAIRPIN_TYPE, "hairpin_type", true, "", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "hairpin type") },
{ Pid::HAIRPIN_HEIGHT, "hairpin_height", false, "hairpinHeight", P_TYPE::SPATIUM, QT_TRANSLATE_NOOP("propertyName", "hairpin height") },
{ Pid::HAIRPIN_CONT_HEIGHT, "hairpin_cont_height", false, "hairpinContHeight", P_TYPE::SPATIUM, QT_TRANSLATE_NOOP("propertyName", "hairpin cont height") },
{ Pid::VELO_CHANGE, "velo_change", true, "veloChange", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "velocity change") },
{ Pid::DYNAMIC_RANGE, "dynamic_range", true, "dynType", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "dynamic range") },
{ Pid::PLACEMENT, "placement", false, "placement", P_TYPE::PLACEMENT, QT_TRANSLATE_NOOP("propertyName", "placement") },
{ Pid::VELOCITY, "velocity", false, "velocity", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "velocity") },
{ Pid::JUMP_TO, "jump_to", true, "jumpTo", P_TYPE::STRING, QT_TRANSLATE_NOOP("propertyName", "jump to") },
{ Pid::PLAY_UNTIL, "play_until", true, "playUntil", P_TYPE::STRING, QT_TRANSLATE_NOOP("propertyName", "play until") },
{ Pid::CONTINUE_AT, "continue_at", true, "continueAt", P_TYPE::STRING, QT_TRANSLATE_NOOP("propertyName", "continue at") },
//100
{ Pid::LABEL, "label", true, "label", P_TYPE::STRING },
{ Pid::MARKER_TYPE, "marker_type", true, 0, P_TYPE::INT },
{ Pid::ARP_USER_LEN1, "arp_user_len1", false, 0, P_TYPE::REAL },
{ Pid::ARP_USER_LEN2, "arp_user_len2", false, 0, P_TYPE::REAL },
{ Pid::REPEAT_END, "repeat_end", true, 0, P_TYPE::BOOL },
{ Pid::REPEAT_START, "repeat_start", true, 0, P_TYPE::BOOL },
{ Pid::REPEAT_JUMP, "repeat_jump", true, 0, P_TYPE::BOOL },
{ Pid::MEASURE_NUMBER_MODE, "measure_number_mode", false, "measureNumberMode", P_TYPE::INT },
{ Pid::GLISS_TYPE, "gliss_type", false, "subtype", P_TYPE::INT },
{ Pid::GLISS_TEXT, "gliss_text", false, 0, P_TYPE::STRING },
{ Pid::LABEL, "label", true, "label", P_TYPE::STRING, QT_TRANSLATE_NOOP("propertyName", "label") },
{ Pid::MARKER_TYPE, "marker_type", true, 0, P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "marker type") },
{ Pid::ARP_USER_LEN1, "arp_user_len1", false, 0, P_TYPE::REAL, QT_TRANSLATE_NOOP("propertyName", "length 1") },
{ Pid::ARP_USER_LEN2, "arp_user_len2", false, 0, P_TYPE::REAL, QT_TRANSLATE_NOOP("propertyName", "length 2") },
{ Pid::REPEAT_END, "repeat_end", true, 0, P_TYPE::BOOL, "" },
{ Pid::REPEAT_START, "repeat_start", true, 0, P_TYPE::BOOL, "" },
{ Pid::REPEAT_JUMP, "repeat_jump", true, 0, P_TYPE::BOOL, "" },
{ Pid::MEASURE_NUMBER_MODE, "measure_number_mode", false, "measureNumberMode", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "measure number mode") },
{ Pid::GLISS_TYPE, "gliss_type", false, "subtype", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "subtype") },
{ Pid::GLISS_TEXT, "gliss_text", false, 0, P_TYPE::STRING, QT_TRANSLATE_NOOP("propertyName", "text") },
{ Pid::GLISS_SHOW_TEXT, "gliss_show_text", false, 0, P_TYPE::BOOL },
{ Pid::DIAGONAL, "diagonal", false, 0, P_TYPE::BOOL },
{ Pid::GROUPS, "groups", false, 0, P_TYPE::GROUPS },
{ Pid::LINE_STYLE, "line_style", false, "lineStyle", P_TYPE::INT },
{ Pid::LINE_COLOR, "line_color", false, 0, P_TYPE::COLOR },
{ Pid::LINE_WIDTH, "line_width", false, "lineWidth", P_TYPE::SP_REAL },
{ Pid::LASSO_POS, "lasso_pos", false, 0, P_TYPE::POINT_MM },
{ Pid::LASSO_SIZE, "lasso_size", false, 0, P_TYPE::SIZE_MM },
{ Pid::TIME_STRETCH, "time_stretch", true, "timeStretch", P_TYPE::REAL },
{ Pid::ORNAMENT_STYLE, "ornament_style", true, "ornamentStyle", P_TYPE::ORNAMENT_STYLE },
{ Pid::GLISS_SHOW_TEXT, "gliss_show_text", false, 0, P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "showing text") },
{ Pid::DIAGONAL, "diagonal", false, 0, P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "diagonal") },
{ Pid::GROUPS, "groups", false, 0, P_TYPE::GROUPS, QT_TRANSLATE_NOOP("propertyName", "groups") },
{ Pid::LINE_STYLE, "line_style", false, "lineStyle", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "line style") },
{ Pid::LINE_COLOR, "line_color", false, 0, P_TYPE::COLOR, QT_TRANSLATE_NOOP("propertyName", "line color") },
{ Pid::LINE_WIDTH, "line_width", false, "lineWidth", P_TYPE::SP_REAL, QT_TRANSLATE_NOOP("propertyName", "line width") },
{ Pid::LASSO_POS, "lasso_pos", false, 0, P_TYPE::POINT_MM, QT_TRANSLATE_NOOP("propertyName", "lasso position") },
{ Pid::LASSO_SIZE, "lasso_size", false, 0, P_TYPE::SIZE_MM, QT_TRANSLATE_NOOP("propertyName", "lasso size") },
{ Pid::TIME_STRETCH, "time_stretch", true, "timeStretch", P_TYPE::REAL, QT_TRANSLATE_NOOP("propertyName", "time stretch") },
{ Pid::ORNAMENT_STYLE, "ornament_style", true, "ornamentStyle", P_TYPE::ORNAMENT_STYLE, QT_TRANSLATE_NOOP("propertyName", "ornament style") },
{ Pid::TIMESIG, "timesig", false, 0, P_TYPE::FRACTION },
{ Pid::TIMESIG_GLOBAL, "timesig_global", false, 0, P_TYPE::FRACTION },
{ Pid::TIMESIG_STRETCH, "timesig_stretch", false, 0, P_TYPE::FRACTION },
{ Pid::TIMESIG_TYPE, "timesig_type", true, "subtype", P_TYPE::INT },
{ Pid::SPANNER_TICK, "spanner_tick", true, "tick", P_TYPE::INT },
{ Pid::SPANNER_TICKS, "spanner_ticks", true, "ticks", P_TYPE::INT },
{ Pid::SPANNER_TRACK2, "spanner_track2", true, "track2", P_TYPE::INT },
{ Pid::OFFSET2, "user_off2", false, "userOff2", P_TYPE::POINT_SP },
{ Pid::BREAK_MMR, "break_mmr", false, "breakMultiMeasureRest", P_TYPE::BOOL },
{ Pid::REPEAT_COUNT, "repeat_count", true, "endRepeat", P_TYPE::INT },
{ Pid::TIMESIG, "timesig", false, 0, P_TYPE::FRACTION, QT_TRANSLATE_NOOP("propertyName", "time signature") },
{ Pid::TIMESIG_GLOBAL, "timesig_global", false, 0, P_TYPE::FRACTION, QT_TRANSLATE_NOOP("propertyName", "global time signature") },
{ Pid::TIMESIG_STRETCH, "timesig_stretch", false, 0, P_TYPE::FRACTION, QT_TRANSLATE_NOOP("propertyName", "time signature stretch") },
{ Pid::TIMESIG_TYPE, "timesig_type", true, "subtype", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "subtype") },
{ Pid::SPANNER_TICK, "spanner_tick", true, "tick", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "tick") },
{ Pid::SPANNER_TICKS, "spanner_ticks", true, "ticks", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "ticks") },
{ Pid::SPANNER_TRACK2, "spanner_track2", true, "track2", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "track2") },
{ Pid::OFFSET2, "user_off2", false, "userOff2", P_TYPE::POINT_SP, QT_TRANSLATE_NOOP("propertyName", "offset2") },
{ Pid::BREAK_MMR, "break_mmr", false, "breakMultiMeasureRest", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "breaking multimeasure rest")},
{ Pid::REPEAT_COUNT, "repeat_count", true, "endRepeat", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "end repeat") },
{ Pid::USER_STRETCH, "user_stretch", false, "stretch", P_TYPE::REAL },
{ Pid::NO_OFFSET, "no_offset", false, "noOffset", P_TYPE::INT },
{ Pid::IRREGULAR, "irregular", true, "irregular", P_TYPE::BOOL },
{ Pid::ANCHOR, "anchor", false, "anchor", P_TYPE::INT },
{ Pid::SLUR_UOFF1, "slur_uoff1", false, "o1", P_TYPE::POINT_SP },
{ Pid::SLUR_UOFF2, "slur_uoff2", false, "o2", P_TYPE::POINT_SP },
{ Pid::SLUR_UOFF3, "slur_uoff3", false, "o3", P_TYPE::POINT_SP },
{ Pid::SLUR_UOFF4, "slur_uoff4", false, "o4", P_TYPE::POINT_SP },
{ Pid::STAFF_MOVE, "staff_move", true, "staffMove", P_TYPE::INT },
{ Pid::VERSE, "verse", true, "no", P_TYPE::ZERO_INT },
{ Pid::USER_STRETCH, "user_stretch", false, "stretch", P_TYPE::REAL, QT_TRANSLATE_NOOP("propertyName", "stretch") },
{ Pid::NO_OFFSET, "no_offset", false, "noOffset", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "numbering offset") },
{ Pid::IRREGULAR, "irregular", true, "irregular", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "irregular") },
{ Pid::ANCHOR, "anchor", false, "anchor", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "anchor") },
{ Pid::SLUR_UOFF1, "slur_uoff1", false, "o1", P_TYPE::POINT_SP, QT_TRANSLATE_NOOP("propertyName", "o1") },
{ Pid::SLUR_UOFF2, "slur_uoff2", false, "o2", P_TYPE::POINT_SP, QT_TRANSLATE_NOOP("propertyName", "o2") },
{ Pid::SLUR_UOFF3, "slur_uoff3", false, "o3", P_TYPE::POINT_SP, QT_TRANSLATE_NOOP("propertyName", "o3") },
{ Pid::SLUR_UOFF4, "slur_uoff4", false, "o4", P_TYPE::POINT_SP, QT_TRANSLATE_NOOP("propertyName", "o4") },
{ Pid::STAFF_MOVE, "staff_move", true, "staffMove", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "staff move") },
{ Pid::VERSE, "verse", true, "no", P_TYPE::ZERO_INT, QT_TRANSLATE_NOOP("propertyName", "verse") },
{ Pid::SYLLABIC, "syllabic", true, "syllabic", P_TYPE::INT },
{ Pid::LYRIC_TICKS, "lyric_ticks", true, "ticks", P_TYPE::INT },
{ Pid::VOLTA_ENDING, "volta_ending", true, "endings", P_TYPE::INT_LIST },
{ Pid::LINE_VISIBLE, "line_visible", true, "lineVisible", P_TYPE::BOOL },
{ Pid::MAG, "mag", false, "mag", P_TYPE::REAL },
{ Pid::USE_DRUMSET, "use_drumset", false, "useDrumset", P_TYPE::BOOL },
{ Pid::PART_VOLUME, "part_volume", false, "volume", P_TYPE::INT },
{ Pid::PART_MUTE, "part_mute", false, "mute", P_TYPE::BOOL },
{ Pid::PART_PAN, "part_pan", false, "pan", P_TYPE::INT },
{ Pid::PART_REVERB, "part_reverb", false, "reverb", P_TYPE::INT },
{ Pid::SYLLABIC, "syllabic", true, "syllabic", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "syllabic") },
{ Pid::LYRIC_TICKS, "lyric_ticks", true, "ticks", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "ticks") },
{ Pid::VOLTA_ENDING, "volta_ending", true, "endings", P_TYPE::INT_LIST, QT_TRANSLATE_NOOP("propertyName", "endings") },
{ Pid::LINE_VISIBLE, "line_visible", true, "lineVisible", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "visible line") },
{ Pid::MAG, "mag", false, "mag", P_TYPE::REAL, QT_TRANSLATE_NOOP("propertyName", "mag") },
{ Pid::USE_DRUMSET, "use_drumset", false, "useDrumset", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "using drumset") },
{ Pid::PART_VOLUME, "part_volume", false, "volume", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "volume") },
{ Pid::PART_MUTE, "part_mute", false, "mute", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "mute") },
{ Pid::PART_PAN, "part_pan", false, "pan", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "pan") },
{ Pid::PART_REVERB, "part_reverb", false, "reverb", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "reverb") },
{ Pid::PART_CHORUS, "part_chorus", false, "chorus", P_TYPE::INT },
{ Pid::DURATION, "duration", false, 0, P_TYPE::FRACTION },
{ Pid::DURATION_TYPE, "duration_type", false, 0, P_TYPE::TDURATION },
{ Pid::ROLE, "role", false, "role", P_TYPE::INT },
{ Pid::TRACK, "track", false, 0, P_TYPE::INT },
{ Pid::GLISSANDO_STYLE, "glissando_style", true, "glissandoStyle", P_TYPE::GLISSANDO_STYLE },
{ Pid::FRET_STRINGS, "fret_strings", false, "strings", P_TYPE::INT },
{ Pid::FRET_FRETS, "fret_frets", false, "frets", P_TYPE::INT },
{ Pid::FRET_BARRE, "fret_barre", false, "barre", P_TYPE::INT },
{ Pid::FRET_OFFSET, "fret_offset", false, "fretOffset", P_TYPE::INT },
{ Pid::PART_CHORUS, "part_chorus", false, "chorus", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "chorus") },
{ Pid::DURATION, "duration", false, 0, P_TYPE::FRACTION, QT_TRANSLATE_NOOP("propertyName", "duration") },
{ Pid::DURATION_TYPE, "duration_type", false, 0, P_TYPE::TDURATION, QT_TRANSLATE_NOOP("propertyName", "duration type") },
{ Pid::ROLE, "role", false, "role", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "role") },
{ Pid::TRACK, "track", false, 0, P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "track") },
{ Pid::GLISSANDO_STYLE, "glissando_style", true, "glissandoStyle", P_TYPE::GLISSANDO_STYLE, QT_TRANSLATE_NOOP("propertyName", "glissando style") },
{ Pid::FRET_STRINGS, "fret_strings", false, "strings", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "strings") },
{ Pid::FRET_FRETS, "fret_frets", false, "frets", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "frets") },
{ Pid::FRET_BARRE, "fret_barre", false, "barre", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "barre") },
{ Pid::FRET_OFFSET, "fret_offset", false, "fretOffset", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "fret offset") },
{ Pid::FRET_NUM_POS, "fret_num_pos", false, "fretNumPos", P_TYPE::INT },
{ Pid::SYSTEM_BRACKET, "system_bracket", false, "type", P_TYPE::INT },
{ Pid::GAP, "gap", false, 0, P_TYPE::BOOL },
{ Pid::AUTOPLACE, "autoplace", false, "autoplace", P_TYPE::BOOL },
{ Pid::DASH_LINE_LEN, "dash_line_len", false, "dashLineLength", P_TYPE::REAL },
{ Pid::DASH_GAP_LEN, "dash_gap_len", false, "dashGapLength", P_TYPE::REAL },
{ Pid::TICK, "tick", false, 0, P_TYPE::INT },
{ Pid::PLAYBACK_VOICE1, "playback_voice1", false, "playbackVoice1", P_TYPE::BOOL },
{ Pid::PLAYBACK_VOICE2, "playback_voice2", false, "playbackVoice2", P_TYPE::BOOL },
{ Pid::PLAYBACK_VOICE3, "playback_voice3", false, "playbackVoice3", P_TYPE::BOOL },
{ Pid::FRET_NUM_POS, "fret_num_pos", false, "fretNumPos", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "fret number position") },
{ Pid::SYSTEM_BRACKET, "system_bracket", false, "type", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "type") },
{ Pid::GAP, "gap", false, 0, P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "gap") },
{ Pid::AUTOPLACE, "autoplace", false, "autoplace", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "autoplace") },
{ Pid::DASH_LINE_LEN, "dash_line_len", false, "dashLineLength", P_TYPE::REAL, QT_TRANSLATE_NOOP("propertyName", "dash line length") },
{ Pid::DASH_GAP_LEN, "dash_gap_len", false, "dashGapLength", P_TYPE::REAL, QT_TRANSLATE_NOOP("propertyName", "dash gap length") },
{ Pid::TICK, "tick", false, 0, P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "tick") },
{ Pid::PLAYBACK_VOICE1, "playback_voice1", false, "playbackVoice1", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "playback voice 1") },
{ Pid::PLAYBACK_VOICE2, "playback_voice2", false, "playbackVoice2", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "playback voice 2") },
{ Pid::PLAYBACK_VOICE3, "playback_voice3", false, "playbackVoice3", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "playback voice 3") },
{ Pid::PLAYBACK_VOICE4, "playback_voice4", false, "playbackVoice4", P_TYPE::BOOL },
{ Pid::SYMBOL, "symbol", true, "symbol", P_TYPE::SYMID },
{ Pid::PLAY_REPEATS, "play_repeats", true, "playRepeats", P_TYPE::BOOL },
{ Pid::CREATE_SYSTEM_HEADER, "create_system_header", false, "createSystemHeader", P_TYPE::BOOL },
{ Pid::STAFF_LINES, "staff_lines", true, "lines", P_TYPE::INT },
{ Pid::LINE_DISTANCE, "line_distance", true, "lineDistance", P_TYPE::SPATIUM },
{ Pid::STEP_OFFSET, "step_offset", true, "stepOffset", P_TYPE::INT },
{ Pid::STAFF_SHOW_BARLINES, "staff_show_barlines", false, "", P_TYPE::BOOL },
{ Pid::STAFF_SHOW_LEDGERLINES, "staff_show_ledgerlines", false, "", P_TYPE::BOOL },
{ Pid::STAFF_SLASH_STYLE, "staff_slash_style", false, "", P_TYPE::BOOL },
{ Pid::PLAYBACK_VOICE4, "playback_voice4", false, "playbackVoice4", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "playback voice 4") },
{ Pid::SYMBOL, "symbol", true, "symbol", P_TYPE::SYMID, QT_TRANSLATE_NOOP("propertyName", "symbol") },
{ Pid::PLAY_REPEATS, "play_repeats", true, "playRepeats", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "playing repeats") },
{ Pid::CREATE_SYSTEM_HEADER, "create_system_header", false, "createSystemHeader", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "creating system header") },
{ Pid::STAFF_LINES, "staff_lines", true, "lines", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "lines") },
{ Pid::LINE_DISTANCE, "line_distance", true, "lineDistance", P_TYPE::SPATIUM, QT_TRANSLATE_NOOP("propertyName", "line distance") },
{ Pid::STEP_OFFSET, "step_offset", true, "stepOffset", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "step offset") },
{ Pid::STAFF_SHOW_BARLINES, "staff_show_barlines", false, "", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "showing barlines") },
{ Pid::STAFF_SHOW_LEDGERLINES, "staff_show_ledgerlines", false, "", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "showing ledgerlines") },
{ Pid::STAFF_SLASH_STYLE, "staff_slash_style", false, "", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "slash style") },
{ Pid::STAFF_NOTEHEAD_SCHEME, "staff_notehead_scheme", false, "", P_TYPE::INT },
{ Pid::STAFF_GEN_CLEF, "staff_gen_clef", false, "", P_TYPE::BOOL },
{ Pid::STAFF_GEN_TIMESIG, "staff_gen_timesig", false, "", P_TYPE::BOOL },
{ Pid::STAFF_GEN_KEYSIG, "staff_gen_keysig", false, "", P_TYPE::BOOL },
{ Pid::STAFF_YOFFSET, "staff_yoffset", false, "", P_TYPE::SPATIUM },
{ Pid::STAFF_USERDIST, "staff_userdist", false, "distOffset", P_TYPE::SP_REAL },
{ Pid::STAFF_BARLINE_SPAN, "staff_barline_span", false, "barLineSpan", P_TYPE::BOOL },
{ Pid::STAFF_BARLINE_SPAN_FROM, "staff_barline_span_from", false, "barLineSpanFrom", P_TYPE::INT },
{ Pid::STAFF_BARLINE_SPAN_TO, "staff_barline_span_to", false, "barLineSpanTo", P_TYPE::INT },
{ Pid::BRACKET_SPAN, "bracket_span", false, "bracketSpan", P_TYPE::INT },
{ Pid::STAFF_NOTEHEAD_SCHEME, "staff_notehead_scheme", false, "", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "notehead scheme") },
{ Pid::STAFF_GEN_CLEF, "staff_gen_clef", false, "", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "generating clefs") },
{ Pid::STAFF_GEN_TIMESIG, "staff_gen_timesig", false, "", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "generating time signature") },
{ Pid::STAFF_GEN_KEYSIG, "staff_gen_keysig", false, "", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "generating key signature") },
{ Pid::STAFF_YOFFSET, "staff_yoffset", false, "", P_TYPE::SPATIUM, QT_TRANSLATE_NOOP("propertyName", "y-offset") },
{ Pid::STAFF_USERDIST, "staff_userdist", false, "distOffset", P_TYPE::SP_REAL, QT_TRANSLATE_NOOP("propertyName", "distance offset") },
{ Pid::STAFF_BARLINE_SPAN, "staff_barline_span", false, "barLineSpan", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "barline span") },
{ Pid::STAFF_BARLINE_SPAN_FROM, "staff_barline_span_from", false, "barLineSpanFrom", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "barline span from") },
{ Pid::STAFF_BARLINE_SPAN_TO, "staff_barline_span_to", false, "barLineSpanTo", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "barline span to") },
{ Pid::BRACKET_SPAN, "bracket_span", false, "bracketSpan", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "bracket span") },
{ Pid::BRACKET_COLUMN, "bracket_column", false, "level", P_TYPE::INT },
{ Pid::INAME_LAYOUT_POSITION, "iname_layout_position", false, "layoutPosition", P_TYPE::INT },
{ Pid::SUB_STYLE, "sub_style", false, "style", P_TYPE::SUB_STYLE },
{ Pid::FONT_FACE, "font_face", false, "family", P_TYPE::FONT },
{ Pid::FONT_SIZE, "font_size", false, "size", P_TYPE::REAL },
{ Pid::FONT_BOLD, "font_bold", false, "bold", P_TYPE::BOOL },
{ Pid::FONT_ITALIC, "font_italic", false, "italic", P_TYPE::BOOL },
{ Pid::FONT_UNDERLINE, "font_underline", false, "underline", P_TYPE::BOOL },
{ Pid::FRAME_TYPE, "frame_type", false, "frameType", P_TYPE::INT },
{ Pid::FRAME_WIDTH, "frame_width", false, "frameWidth", P_TYPE::SPATIUM },
{ Pid::BRACKET_COLUMN, "bracket_column", false, "level", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "level") },
{ Pid::INAME_LAYOUT_POSITION, "iname_layout_position", false, "layoutPosition", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "layout position") },
{ Pid::SUB_STYLE, "sub_style", false, "style", P_TYPE::SUB_STYLE, QT_TRANSLATE_NOOP("propertyName", "style") },
{ Pid::FONT_FACE, "font_face", false, "family", P_TYPE::FONT, QT_TRANSLATE_NOOP("propertyName", "family") },
{ Pid::FONT_SIZE, "font_size", false, "size", P_TYPE::REAL, QT_TRANSLATE_NOOP("propertyName", "size") },
{ Pid::FONT_BOLD, "font_bold", false, "bold", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "bold") },
{ Pid::FONT_ITALIC, "font_italic", false, "italic", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "italic") },
{ Pid::FONT_UNDERLINE, "font_underline", false, "underline", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "underlined") },
{ Pid::FRAME_TYPE, "frame_type", false, "frameType", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "frame type") },
{ Pid::FRAME_WIDTH, "frame_width", false, "frameWidth", P_TYPE::SPATIUM, QT_TRANSLATE_NOOP("propertyName", "frame width") },
//200
{ Pid::FRAME_PADDING, "frame_padding", false, "framePadding", P_TYPE::SPATIUM },
{ Pid::FRAME_ROUND, "frame_round", false, "frameRound", P_TYPE::INT },
{ Pid::FRAME_FG_COLOR, "frame_fg_color", false, "frameFgColor", P_TYPE::COLOR },
{ Pid::FRAME_BG_COLOR, "frame_bg_color", false, "frameBgColor", P_TYPE::COLOR },
{ Pid::SIZE_SPATIUM_DEPENDENT, "size_spatium_dependent", false, "sizeIsSpatiumDependent",P_TYPE::BOOL },
{ Pid::ALIGN, "align", false, "align", P_TYPE::ALIGN },
{ Pid::SYSTEM_FLAG, "system_flag", false, "systemFlag", P_TYPE::BOOL },
{ Pid::BEGIN_TEXT, "begin_text", false, "beginText", P_TYPE::STRING },
{ Pid::FRAME_PADDING, "frame_padding", false, "framePadding", P_TYPE::SPATIUM, QT_TRANSLATE_NOOP("propertyName", "frame padding") },
{ Pid::FRAME_ROUND, "frame_round", false, "frameRound", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "frame round") },
{ Pid::FRAME_FG_COLOR, "frame_fg_color", false, "frameFgColor", P_TYPE::COLOR, QT_TRANSLATE_NOOP("propertyName", "frame foreground color") },
{ Pid::FRAME_BG_COLOR, "frame_bg_color", false, "frameBgColor", P_TYPE::COLOR, QT_TRANSLATE_NOOP("propertyName", "frame background color") },
{ Pid::SIZE_SPATIUM_DEPENDENT, "size_spatium_dependent", false, "sizeIsSpatiumDependent",P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "spatium dependent font") },
{ Pid::ALIGN, "align", false, "align", P_TYPE::ALIGN, QT_TRANSLATE_NOOP("propertyName", "align") },
{ Pid::SYSTEM_FLAG, "system_flag", false, "systemFlag", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "system flag") },
{ Pid::BEGIN_TEXT, "begin_text", false, "beginText", P_TYPE::STRING, QT_TRANSLATE_NOOP("propertyName", "begin text") },
{ Pid::BEGIN_TEXT_ALIGN, "begin_text_align", false, "beginTextAlign", P_TYPE::ALIGN },
{ Pid::BEGIN_TEXT_PLACE, "begin_text_place", false, "beginTextPlace", P_TYPE::TEXT_PLACE },
{ Pid::BEGIN_HOOK_TYPE, "begin_hook_type", false, "beginHookType", P_TYPE::INT },
{ Pid::BEGIN_HOOK_HEIGHT, "begin_hook_height", false, "beginHookHeight", P_TYPE::SPATIUM },
{ Pid::BEGIN_FONT_FACE, "begin_font_face", false, "beginFontFace", P_TYPE::FONT },
{ Pid::BEGIN_FONT_SIZE, "begin_font_size", false, "beginFontSize", P_TYPE::REAL },
{ Pid::BEGIN_FONT_BOLD, "begin_font_bold", false, "beginFontBold", P_TYPE::BOOL },
{ Pid::BEGIN_FONT_ITALIC, "begin_font_italic", false, "beginFontItalic", P_TYPE::BOOL },
{ Pid::BEGIN_FONT_UNDERLINE, "begin_font_underline", false, "beginFontUnderline", P_TYPE::BOOL },
{ Pid::BEGIN_TEXT_OFFSET, "begin_text_offset", false, "beginTextOffset", P_TYPE::POINT_SP },
{ Pid::BEGIN_TEXT_ALIGN, "begin_text_align", false, "beginTextAlign", P_TYPE::ALIGN, QT_TRANSLATE_NOOP("propertyName", "begin text align") },
{ Pid::BEGIN_TEXT_PLACE, "begin_text_place", false, "beginTextPlace", P_TYPE::TEXT_PLACE, QT_TRANSLATE_NOOP("propertyName", "begin text place") },
{ Pid::BEGIN_HOOK_TYPE, "begin_hook_type", false, "beginHookType", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "begin hook type") },
{ Pid::BEGIN_HOOK_HEIGHT, "begin_hook_height", false, "beginHookHeight", P_TYPE::SPATIUM, QT_TRANSLATE_NOOP("propertyName", "begin hook height") },
{ Pid::BEGIN_FONT_FACE, "begin_font_face", false, "beginFontFace", P_TYPE::FONT, QT_TRANSLATE_NOOP("propertyName", "begin font face") },
{ Pid::BEGIN_FONT_SIZE, "begin_font_size", false, "beginFontSize", P_TYPE::REAL, QT_TRANSLATE_NOOP("propertyName", "begin font size") },
{ Pid::BEGIN_FONT_BOLD, "begin_font_bold", false, "beginFontBold", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "begin font bold") },
{ Pid::BEGIN_FONT_ITALIC, "begin_font_italic", false, "beginFontItalic", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "begin font italic") },
{ Pid::BEGIN_FONT_UNDERLINE, "begin_font_underline", false, "beginFontUnderline", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "begin font underlined") },
{ Pid::BEGIN_TEXT_OFFSET, "begin_text_offset", false, "beginTextOffset", P_TYPE::POINT_SP, QT_TRANSLATE_NOOP("propertyName", "begin text offset") },
{ Pid::CONTINUE_TEXT, "continue_text", false, "continueText", P_TYPE::STRING },
{ Pid::CONTINUE_TEXT_ALIGN, "continue_text_align", false, "continueTextAlign", P_TYPE::ALIGN },
{ Pid::CONTINUE_TEXT_PLACE, "continue_text_place", false, "continueTextPlace", P_TYPE::TEXT_PLACE },
{ Pid::CONTINUE_FONT_FACE, "continue_font_face", false, "continueFontFace", P_TYPE::FONT },
{ Pid::CONTINUE_FONT_SIZE, "continue_font_size", false, "continueFontSize", P_TYPE::REAL },
{ Pid::CONTINUE_FONT_BOLD, "continue_font_bold", false, "continueFontBold", P_TYPE::BOOL },
{ Pid::CONTINUE_FONT_ITALIC, "continue_font_italic", false, "continueFontItalic", P_TYPE::BOOL },
{ Pid::CONTINUE_FONT_UNDERLINE, "continue_font_underline", false, "continueFontUnderline", P_TYPE::BOOL },
{ Pid::CONTINUE_TEXT_OFFSET, "continue_text_offset", false, "continueTextOffset", P_TYPE::POINT_SP },
{ Pid::END_TEXT, "end_text", false, "endText", P_TYPE::STRING },
{ Pid::CONTINUE_TEXT, "continue_text", false, "continueText", P_TYPE::STRING, QT_TRANSLATE_NOOP("propertyName", "continue text") },
{ Pid::CONTINUE_TEXT_ALIGN, "continue_text_align", false, "continueTextAlign", P_TYPE::ALIGN, QT_TRANSLATE_NOOP("propertyName", "continue text align") },
{ Pid::CONTINUE_TEXT_PLACE, "continue_text_place", false, "continueTextPlace", P_TYPE::TEXT_PLACE, QT_TRANSLATE_NOOP("propertyName", "continue text place") },
{ Pid::CONTINUE_FONT_FACE, "continue_font_face", false, "continueFontFace", P_TYPE::FONT, QT_TRANSLATE_NOOP("propertyName", "continue font face") },
{ Pid::CONTINUE_FONT_SIZE, "continue_font_size", false, "continueFontSize", P_TYPE::REAL, QT_TRANSLATE_NOOP("propertyName", "continue font size") },
{ Pid::CONTINUE_FONT_BOLD, "continue_font_bold", false, "continueFontBold", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "continue font bold") },
{ Pid::CONTINUE_FONT_ITALIC, "continue_font_italic", false, "continueFontItalic", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "continue font italic") },
{ Pid::CONTINUE_FONT_UNDERLINE, "continue_font_underline", false, "continueFontUnderline", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "continue font underlined") },
{ Pid::CONTINUE_TEXT_OFFSET, "continue_text_offset", false, "continueTextOffset", P_TYPE::POINT_SP, QT_TRANSLATE_NOOP("propertyName", "continue text offset") },
{ Pid::END_TEXT, "end_text", false, "endText", P_TYPE::STRING, QT_TRANSLATE_NOOP("propertyName", "end text") },
{ Pid::END_TEXT_ALIGN, "end_text_align", false, "endTextAlign", P_TYPE::ALIGN },
{ Pid::END_TEXT_PLACE, "end_text_place", false, "endTextPlace", P_TYPE::TEXT_PLACE },
{ Pid::END_HOOK_TYPE, "end_hook_type", false, "endHookType", P_TYPE::INT },
{ Pid::END_HOOK_HEIGHT, "end_hook_height", false, "endHookHeight", P_TYPE::SPATIUM },
{ Pid::END_FONT_FACE, "end_font_face", false, "endFontFace", P_TYPE::FONT },
{ Pid::END_FONT_SIZE, "end_font_size", false, "endFontSize", P_TYPE::REAL },
{ Pid::END_FONT_BOLD, "end_font_bold", false, "endFontBold", P_TYPE::BOOL },
{ Pid::END_FONT_ITALIC, "end_font_italic", false, "endFontItalic", P_TYPE::BOOL },
{ Pid::END_FONT_UNDERLINE, "end_font_underline", false, "endFontUnderline", P_TYPE::BOOL },
{ Pid::END_TEXT_OFFSET, "end_text_offset", false, "endTextOffset", P_TYPE::POINT_SP },
{ Pid::END_TEXT_ALIGN, "end_text_align", false, "endTextAlign", P_TYPE::ALIGN, QT_TRANSLATE_NOOP("propertyName", "end text align") },
{ Pid::END_TEXT_PLACE, "end_text_place", false, "endTextPlace", P_TYPE::TEXT_PLACE, QT_TRANSLATE_NOOP("propertyName", "end text place") },
{ Pid::END_HOOK_TYPE, "end_hook_type", false, "endHookType", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "end hook type") },
{ Pid::END_HOOK_HEIGHT, "end_hook_height", false, "endHookHeight", P_TYPE::SPATIUM, QT_TRANSLATE_NOOP("propertyName", "end hook height") },
{ Pid::END_FONT_FACE, "end_font_face", false, "endFontFace", P_TYPE::FONT, QT_TRANSLATE_NOOP("propertyName", "end font face") },
{ Pid::END_FONT_SIZE, "end_font_size", false, "endFontSize", P_TYPE::REAL, QT_TRANSLATE_NOOP("propertyName", "end font size") },
{ Pid::END_FONT_BOLD, "end_font_bold", false, "endFontBold", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "end font bold") },
{ Pid::END_FONT_ITALIC, "end_font_italic", false, "endFontItalic", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "end font italic") },
{ Pid::END_FONT_UNDERLINE, "end_font_underline", false, "endFontUnderline", P_TYPE::BOOL, QT_TRANSLATE_NOOP("propertyName", "end font underlined") },
{ Pid::END_TEXT_OFFSET, "end_text_offset", false, "endTextOffset", P_TYPE::POINT_SP, QT_TRANSLATE_NOOP("propertyName", "end text offset") },
{ Pid::POS_ABOVE, "pos_above", false, "posAbove", P_TYPE::SP_REAL },
{ Pid::POS_ABOVE, "pos_above", false, "posAbove", P_TYPE::SP_REAL, QT_TRANSLATE_NOOP("propertyName", "position above") },
{ Pid::END, "++end++", false, "++end++", P_TYPE::INT }
{ Pid::LOCATION_STAVES, 0, false, "staves", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "staves distance") },
{ Pid::LOCATION_VOICES, 0, false, "voices", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "voices distance") },
{ Pid::LOCATION_MEASURES, 0, false, "measures", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "measures distance") },
{ Pid::LOCATION_FRACTIONS, 0, false, "fractions", P_TYPE::FRACTION, QT_TRANSLATE_NOOP("propertyName", "position distance") },
{ Pid::LOCATION_GRACE, 0, false, "grace", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "grace note index") },
{ Pid::LOCATION_NOTE, 0, false, "note", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "note index") },
{ Pid::VOICE, 0, false, "voice", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "voice") },
{ Pid::POSITION, 0, false, "position", P_TYPE::FRACTION, QT_TRANSLATE_NOOP("propertyName", "position") },
{ Pid::END, "++end++", false, "++end++", P_TYPE::INT, QT_TRANSLATE_NOOP("propertyName", "<invalid property>") }
};
//---------------------------------------------------------
// propertyId
// propertyIdQml
//---------------------------------------------------------
Pid propertyId(const QString& s)
Pid propertyIdQml(const QStringRef& s)
{
for (const PropertyMetaData& pd : propertyList) {
if (pd.qml == s)
@ -319,6 +330,37 @@ Pid propertyId(const QString& s)
return Pid::END;
}
//---------------------------------------------------------
// propertyIdQml
//---------------------------------------------------------
Pid propertyIdQml(const QString& s)
{
return propertyIdQml(QStringRef(&s));
}
//---------------------------------------------------------
// propertyIdName
//---------------------------------------------------------
Pid propertyIdName(const QStringRef& s)
{
for (const PropertyMetaData& pd : propertyList) {
if (pd.name == s)
return pd.id;
}
return Pid::END;
}
//---------------------------------------------------------
// propertyId
//---------------------------------------------------------
Pid propertyIdName(const QString& s)
{
return propertyIdName(QStringRef(&s));
}
//---------------------------------------------------------
// propertyType
//---------------------------------------------------------
@ -355,6 +397,16 @@ const char* propertyQmlName(Pid id)
return propertyList[int(id)].qml;
}
//---------------------------------------------------------
// propertyUserName
//---------------------------------------------------------
QString propertyUserName(Pid id)
{
Q_ASSERT(propertyList[int(id)].id == id);
return QObject::tr(propertyList[int(id)].userName, "propertyName");
}
//---------------------------------------------------------
// readProperty
//---------------------------------------------------------

View file

@ -324,6 +324,16 @@ enum class Pid {
POS_ABOVE,
LOCATION_STAVES,
LOCATION_VOICES,
LOCATION_MEASURES,
LOCATION_FRACTIONS,
LOCATION_GRACE,
LOCATION_NOTE,
VOICE,
POSITION,
END
};
@ -371,7 +381,11 @@ extern P_TYPE propertyType(Pid);
extern const char* propertyName(Pid);
extern const char* propertyQmlName(Pid);
extern bool propertyLink(Pid id);
extern Pid propertyId(const QString&);
extern Pid propertyIdQml(const QString& qmlName);
extern Pid propertyIdQml(const QStringRef& qmlName);
extern Pid propertyIdName(const QString& name);
extern Pid propertyIdName(const QStringRef& name);
extern QString propertyUserName(Pid);
} // namespace Ms
#endif

View file

@ -850,7 +850,7 @@ void Rest::write(XmlWriter& xml) const
if (_gap)
return;
writeBeam(xml);
xml.stag(name());
xml.stag(this);
ChordRest::writeProperties(xml);
el().write(xml);
bool write_dots = false;

View file

@ -737,6 +737,15 @@ void Score::setMarkIrregularMeasures(bool v)
setUpdateAll();
}
//---------------------------------------------------------
// readOnly
//---------------------------------------------------------
bool Score::readOnly() const
{
return _masterScore->readOnly();
}
//---------------------------------------------------------
// dirty
//---------------------------------------------------------
@ -746,6 +755,15 @@ bool Score::dirty() const
return !undoStack()->isClean();
}
//---------------------------------------------------------
// state
//---------------------------------------------------------
ScoreContentState Score::state() const
{
return std::make_pair(this, undoStack()->state());
}
//---------------------------------------------------------
// spell
//---------------------------------------------------------
@ -1611,6 +1629,24 @@ MeasureBase* Score::measure(int idx) const
return mb;
}
//---------------------------------------------------------
// crMeasure
// Returns a measure containing chords an rests
// by its index skipping other MeasureBase descendants
//---------------------------------------------------------
Measure* Score::crMeasure(int idx) const
{
int i = -1;
for (MeasureBase* mb = _measures.first(); mb; mb = mb->next()) {
if (mb->isMeasure())
++i;
if (i == idx)
return toMeasure(mb);
}
return nullptr;
}
//---------------------------------------------------------
// lastMeasure
//---------------------------------------------------------

View file

@ -280,6 +280,12 @@ class UpdateState {
QList<ScoreElement*> _deleteList;
};
//---------------------------------------------------------
// ScoreContentState
//---------------------------------------------------------
typedef std::pair<const Score*, int> ScoreContentState;
class MasterScore;
//-----------------------------------------------------------------------------
@ -550,6 +556,7 @@ class Score : public QObject, public ScoreElement {
Score* clone();
virtual bool isMaster() const { return false; }
virtual bool readOnly() const;
virtual inline QList<Excerpt*>& excerpts();
virtual inline const QList<Excerpt*>& excerpts() const;
@ -796,6 +803,7 @@ class Score : public QObject, public ScoreElement {
void setImportedFilePath(const QString& filePath);
bool dirty() const;
ScoreContentState state() const;
void setCreated(bool val) { _created = val; }
bool created() const { return _created; }
bool savedCapture() const { return _savedCapture; }
@ -948,6 +956,7 @@ class Score : public QObject, public ScoreElement {
Ms::Measure* lastMeasure() const;
Ms::Measure* lastMeasureMM() const;
MeasureBase* measure(int idx) const;
Measure* crMeasure(int idx) const;
int endTick() const;
@ -1191,6 +1200,8 @@ class MasterScore : public Score {
MasterScore* _prev { 0 };
Movements* _movements { 0 };
bool _readOnly { false };
CmdState _cmdState; // modified during cmd processing
Omr* _omr { 0 };
@ -1210,6 +1221,7 @@ class MasterScore : public Score {
void removeDeletedMidiMapping();
int updateMidiMapping();
QFileInfo _sessionStartBackupInfo;
QFileInfo info;
bool read(XmlReader&);
@ -1223,6 +1235,8 @@ class MasterScore : public Score {
MasterScore* clone();
virtual bool isMaster() const override { return true; }
virtual bool readOnly() const override { return _readOnly; }
void setReadOnly(bool ro) { _readOnly = ro; }
virtual UndoStack* undoStack() const override { return _movements->undo(); }
virtual TimeSigMap* sigmap() const override { return _sigmap; }
virtual TempoMap* tempomap() const override { return _tempomap; }
@ -1296,6 +1310,8 @@ class MasterScore : public Score {
const QFileInfo* fileInfo() const { return &info; }
void setName(const QString&);
const QFileInfo& sessionStartBackupInfo() const { return _sessionStartBackupInfo; }
virtual QString title() const override;
virtual int pageIdx(Page* page) const override { return movements()->pageIdx(page); }

View file

@ -417,6 +417,34 @@ void ScoreElement::writeProperty(XmlWriter& xml, Pid id) const
}
}
//---------------------------------------------------------
// propertyId
//---------------------------------------------------------
Pid ScoreElement::propertyId(const QStringRef& xmlName) const
{
return propertyIdName(xmlName);
}
//---------------------------------------------------------
// propertyUserValue
//---------------------------------------------------------
QString ScoreElement::propertyUserValue(Pid id) const
{
QVariant val = getProperty(id);
switch (propertyType(id)) {
case P_TYPE::POINT_SP:
{
QPointF p = val.toPointF();
return QString("(%1, %2)").arg(p.x()).arg(p.y());
}
default:
break;
}
return val.toString();
}
//---------------------------------------------------------
// readStyledProperty
//---------------------------------------------------------
@ -689,12 +717,13 @@ QString ScoreElement::userName() const
// name2type
//---------------------------------------------------------
ElementType ScoreElement::name2type(const QStringRef& s)
ElementType ScoreElement::name2type(const QStringRef& s, bool silent)
{
for (int i = 0; i < int(ElementType::MAXTYPE); ++i) {
if (s == elementNames[i].name)
return ElementType(i);
}
if (!silent)
qDebug("unknown type <%s>", qPrintable(s.toString()));
return ElementType::INVALID;
}

View file

@ -191,7 +191,7 @@ class ScoreElement {
virtual QString userName() const;
virtual ElementType type() const = 0;
static ElementType name2type(const QStringRef&);
static ElementType name2type(const QStringRef&, bool silent = false);
static const char* name(ElementType);
virtual QVariant getProperty(Pid) const = 0;
@ -203,6 +203,9 @@ class ScoreElement {
virtual void reset(); // reset all properties & position to default
virtual Pid propertyId(const QStringRef& xmlName) const;
virtual QString propertyUserValue(Pid) const;
virtual void initElementStyle(const ElementStyle*);
virtual const ElementStyle* styledProperties() const { return _elementStyle; }
@ -342,10 +345,13 @@ class ScoreElement {
CONVERT(StaffText, STAFF_TEXT)
CONVERT(SystemText, SYSTEM_TEXT)
CONVERT(BracketItem, BRACKET_ITEM)
CONVERT(Score, SCORE)
CONVERT(Staff, STAFF)
CONVERT(Part, PART)
CONVERT(BagpipeEmbellishment, BAGPIPE_EMBELLISHMENT)
#undef CONVERT
virtual bool isElement() const { return false; } // overriden in element.h
bool isChordRest() const { return isRest() || isChord() || isRepeatMeasure(); }
bool isDurationElement() const { return isChordRest() || isTuplet(); }
bool isSlurTieSegment() const { return isSlurSegment() || isTieSegment(); }
@ -491,6 +497,7 @@ static inline const StaffTextBase* toStaffTextBase(const ScoreElement* e) {
static inline a* to##a(ScoreElement* e) { Q_ASSERT(e == 0 || e->is##a()); return (a*)e; } \
static inline const a* to##a(const ScoreElement* e) { Q_ASSERT(e == 0 || e->is##a()); return (const a*)e; }
CONVERT(Element)
CONVERT(Note)
CONVERT(Chord)
CONVERT(BarLine)
@ -580,7 +587,9 @@ static inline const a* to##a(const ScoreElement* e) { Q_ASSERT(e == 0 || e->is##
CONVERT(Page)
CONVERT(SystemText)
CONVERT(BracketItem)
CONVERT(Score)
CONVERT(Staff)
CONVERT(Part)
CONVERT(BagpipeEmbellishment)
#undef CONVERT

1432
libmscore/scorediff.cpp Normal file

File diff suppressed because it is too large Load diff

170
libmscore/scorediff.h Normal file
View file

@ -0,0 +1,170 @@
//=============================================================================
// MuseScore
// Music Composition & Notation
//
// Copyright (C) 2018 Werner Schweer
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2
// as published by the Free Software Foundation and appearing in
// the file LICENCE.GPL
//=============================================================================
#ifndef __SCOREDIFF_H__
#define __SCOREDIFF_H__
#include "score.h"
#include <vector>
namespace Ms {
enum class Pid;
class ScoreElement;
//---------------------------------------------------------
// ItemType
//---------------------------------------------------------
enum class ItemType {
ELEMENT,
PROPERTY,
MARKUP,
CONTEXTCHANGE
};
//---------------------------------------------------------
// DiffType
//---------------------------------------------------------
enum class DiffType {
EQUAL,
INSERT,
DELETE,
REPLACE
};
//---------------------------------------------------------
// TextDiff
// A structure similar to Diff from diff_match_patch
// but contains info on line numbers of the diff
//---------------------------------------------------------
struct TextDiff {
DiffType type;
QString text[2];
int start[2]; // starting line numbers in both texts
int end[2]; // ending line numbers in both texts
void merge(const TextDiff& other); // merge other diff into this one
QString toString(DiffType type, bool prefixLines = false) const;
QString toString(bool prefixLines = false) const { return toString(type, prefixLines); }
};
//---------------------------------------------------------
// BaseDiff
//---------------------------------------------------------
struct BaseDiff {
DiffType type;
const TextDiff* textDiff;
const ScoreElement* ctx[2];
const ScoreElement* before[2];
virtual ~BaseDiff() = default;
virtual ItemType itemType() const = 0;
virtual bool sameItem(const BaseDiff&) const;
virtual Fraction afrac(int score) const;
virtual QString toString() const = 0;
};
//---------------------------------------------------------
// ContextChange
// Dummy Diff for temporary storing information on
// context changes.
//---------------------------------------------------------
struct ContextChange : public BaseDiff {
ItemType itemType() const override { return ItemType::CONTEXTCHANGE; }
QString toString() const override;
};
//---------------------------------------------------------
// ElementDiff
//---------------------------------------------------------
struct ElementDiff : public BaseDiff {
const ScoreElement* el[2];
ItemType itemType() const override { return ItemType::ELEMENT; }
bool sameItem(const BaseDiff&) const override;
Fraction afrac(int score) const override;
QString toString() const override;
};
//---------------------------------------------------------
// PropertyDiff
//---------------------------------------------------------
struct PropertyDiff : public BaseDiff {
Pid pid;
ItemType itemType() const override { return ItemType::PROPERTY; }
bool sameItem(const BaseDiff&) const override;
QString toString() const override;
};
//---------------------------------------------------------
// MarkupDiff
//---------------------------------------------------------
struct MarkupDiff : public BaseDiff {
QString name;
QVariant info;
ItemType itemType() const override { return ItemType::MARKUP; }
bool sameItem(const BaseDiff&) const override;
QString toString() const override;
};
//---------------------------------------------------------
// ScoreDiff
//---------------------------------------------------------
class ScoreDiff {
std::vector<TextDiff> _textDiffs; // raw diff between MSCX code for scores
std::vector<const TextDiff*> _mergedTextDiffs; // extra diff items created after merging score diff items
std::vector<BaseDiff*> _diffs;
Score* _s1;
Score* _s2;
ScoreContentState _scoreState1;
ScoreContentState _scoreState2;
bool _textDiffOnly;
void processMarkupDiffs();
void mergeInsertDeleteDiffs();
void mergeElementDiffs();
void editPropertyDiffs();
public:
ScoreDiff(Score* s1, Score* s2, bool textDiffOnly = false);
ScoreDiff(const ScoreDiff&) = delete;
~ScoreDiff();
void update();
bool updated() const { return _scoreState1 == _s1->state() && _scoreState2 == _s2->state(); }
std::vector<BaseDiff*>& diffs() { return _diffs; }
const std::vector<TextDiff>& textDiffs() const { return _textDiffs; }
const Score* score1() const { return _s1; }
const Score* score2() const { return _s2; }
QString rawDiff(bool skipEqual = true) const;
QString userDiff() const;
};
} // namespace Ms
#endif

View file

@ -102,7 +102,7 @@ void Score::writeMovement(XmlWriter& xml, bool selectionOnly)
p->setShow(false);
}
xml.stag("Score");
xml.stag(this);
if (excerpt()) {
Excerpt* e = excerpt();
QMultiMap<int, int> trackList = e->tracks();
@ -208,7 +208,7 @@ void Score::writeMovement(XmlWriter& xml, bool selectionOnly)
xml.setTrackDiff(-staffStart * VOICES);
if (measureStart) {
for (int staffIdx = staffStart; staffIdx < staffEnd; ++staffIdx) {
xml.stag(QString("Staff id=\"%1\"").arg(staffIdx + 1 - staffStart));
xml.stag(staff(staffIdx), QString("id=\"%1\"").arg(staffIdx + 1 - staffStart));
xml.setCurTick(measureStart->tick());
xml.setTickDiff(xml.curTick());
xml.setCurTrack(staffIdx * VOICES);
@ -372,6 +372,8 @@ void Score::readStaff(XmlReader& e)
bool MasterScore::saveFile()
{
if (readOnly())
return false;
QString suffix = info.suffix();
if (info.exists() && !info.isWritable()) {
MScore::lastError = tr("The following file is locked: \n%1 \n\nTry saving to a different location.").arg(info.filePath());
@ -431,8 +433,11 @@ bool MasterScore::saveFile()
// tr("Renaming old file <%1> to backup <%2> failed").arg(name, backupname);
}
}
#ifdef Q_OS_WIN
QFileInfo fileBackup(dir, backupName);
_sessionStartBackupInfo = fileBackup;
#ifdef Q_OS_WIN
QString backupNativePath = QDir::toNativeSeparators(fileBackup.absoluteFilePath());
#if (defined (_MSCVER) || defined (_MSC_VER))
#if (defined (UNICODE))
@ -482,6 +487,8 @@ bool MasterScore::saveFile()
bool Score::saveCompressedFile(QFileInfo& info, bool onlySelection)
{
if (readOnly() && info == *masterScore()->fileInfo())
return false;
QFile fp(info.filePath());
if (!fp.open(QIODevice::WriteOnly)) {
MScore::lastError = tr("Open File\n%1\nfailed: %2").arg(info.filePath(), strerror(errno));
@ -627,6 +634,8 @@ bool Score::saveCompressedFile(QIODevice* f, QFileInfo& info, bool onlySelection
bool Score::saveFile(QFileInfo& info)
{
if (readOnly() && info == *masterScore()->fileInfo())
return false;
if (info.suffix().isEmpty())
info.setFile(info.filePath() + ".mscx");
QFile fp(info.filePath());

View file

@ -808,7 +808,7 @@ void Segment::write(XmlWriter& xml) const
setWritten(true);
if (_extraLeadingSpace.isZero())
return;
xml.stag(name());
xml.stag(this);
xml.tag("leadingSpace", _extraLeadingSpace.val());
xml.etag();
}

View file

@ -1003,7 +1003,7 @@ void Slur::write(XmlWriter& xml) const
}
if (!xml.canWrite(this))
return;
xml.stag(name());
xml.stag(this);
SlurTie::writeProperties(xml);
xml.etag();
}

View file

@ -283,7 +283,7 @@ void SlurTieSegment::writeSlur(XmlWriter& xml, int no) const
if (autoplace() && visible() && (color() == Qt::black))
return;
xml.stag(QString("%1 no=\"%2\"").arg(name()).arg(no));
xml.stag(this, QString("no=\"%1\"").arg(no));
qreal _spatium = spatium();
xml.tag("o1", ups(Grip::START).off / _spatium);

View file

@ -176,7 +176,7 @@ void Spacer::updateGrips(EditData& ed) const
void Spacer::write(XmlWriter& xml) const
{
xml.stag(name());
xml.stag(this);
xml.tag("subtype", int(_spacerType));
Element::writeProperties(xml);
xml.tag("space", _gap / spatium());

View file

@ -437,6 +437,16 @@ QVariant Spanner::getProperty(Pid propertyId) const
return track2();
case Pid::ANCHOR:
return int(anchor());
case Pid::LOCATION_STAVES:
return (track2() / VOICES) - (track() / VOICES);
case Pid::LOCATION_VOICES:
return (track2() % VOICES) - (track() / VOICES);
case Pid::LOCATION_FRACTIONS:
return Fraction::fromTicks(_ticks);
case Pid::LOCATION_MEASURES:
case Pid::LOCATION_GRACE:
case Pid::LOCATION_NOTE:
return Location::getLocationProperty(propertyId, startElement(), endElement());
default:
break;
}

View file

@ -576,7 +576,7 @@ int Staff::currentKeyTick(int tick) const
void Staff::write(XmlWriter& xml) const
{
int idx = this->idx();
xml.stag(QString("Staff id=\"%1\"").arg(idx + 1));
xml.stag(this, QString("id=\"%1\"").arg(idx + 1));
if (links()) {
Score* s = masterScore();
for (auto le : *links()) {

View file

@ -49,7 +49,7 @@ StaffState::~StaffState()
void StaffState::write(XmlWriter& xml) const
{
xml.stag(name());
xml.stag(this);
xml.tag("subtype", int(_staffStateType));
if (staffStateType() == StaffStateType::INSTRUMENT)
_instrument->write(xml, nullptr);

View file

@ -37,7 +37,7 @@ void StaffTextBase::write(XmlWriter& xml) const
{
if (!xml.canWrite(this))
return;
xml.stag(name());
xml.stag(this);
for (ChannelActions s : _channelActions) {
int channel = s.channel;

View file

@ -42,7 +42,7 @@ StaffTypeChange::StaffTypeChange(const StaffTypeChange& lb)
void StaffTypeChange::write(XmlWriter& xml) const
{
xml.stag(name());
xml.stag(this);
if (_staffType)
_staffType->write(xml);
Element::writeProperties(xml);

View file

@ -212,7 +212,7 @@ void Stem::draw(QPainter* painter) const
void Stem::write(XmlWriter& xml) const
{
xml.stag("Stem");
xml.stag(this);
Element::writeProperties(xml);
writeProperty(xml, Pid::USER_LEN);
writeProperty(xml, Pid::LINE_WIDTH);

View file

@ -97,7 +97,7 @@ void Symbol::draw(QPainter* p) const
void Symbol::write(XmlWriter& xml) const
{
xml.stag(name());
xml.stag(this);
xml.tag("name", Sym::id2name(_sym));
if (_scoreFont)
xml.tag("font", _scoreFont->name());
@ -199,7 +199,7 @@ void FSymbol::draw(QPainter* painter) const
void FSymbol::write(XmlWriter& xml) const
{
xml.stag(name());
xml.stag(this);
xml.tag("font", _font.family());
xml.tag("fontsize", _font.pointSizeF());
xml.tag("code", _code);

View file

@ -984,7 +984,7 @@ qreal System::staffCanvasYpage(int staffIdx) const
void System::write(XmlWriter& xml) const
{
xml.stag("System");
xml.stag(this);
if (_systemDividerLeft && _systemDividerLeft->isUserModified())
_systemDividerLeft->write(xml);
if (_systemDividerRight && _systemDividerRight->isUserModified())

View file

@ -87,9 +87,9 @@ QRectF SystemDivider::drag(EditData& ed)
void SystemDivider::write(XmlWriter& xml) const
{
if (dividerType() == SystemDivider::Type::LEFT)
xml.stag(QString("SystemDivider type=\"left\""));
xml.stag(this, "type=\"left\"");
else
xml.stag(QString("SystemDivider type=\"right\""));
xml.stag(this, "type=\"right\"");
writeProperties(xml);
xml.etag();
}

View file

@ -56,7 +56,7 @@ TempoText::TempoText(Score* s)
void TempoText::write(XmlWriter& xml) const
{
xml.stag(name());
xml.stag(this);
xml.tag("tempo", _tempo);
if (_followText)
xml.tag("followText", _followText);

View file

@ -1649,7 +1649,7 @@ void TextBase::write(XmlWriter& xml) const
{
if (!xml.canWrite(this))
return;
xml.stag(name());
xml.stag(this);
writeProperties(xml, true, true);
xml.etag();
}
@ -1687,13 +1687,7 @@ void TextBase::writeProperties(XmlWriter& xml, bool writeText, bool /*writeStyle
xml.writeXml("text", xmlText());
}
//---------------------------------------------------------
// readProperties
//---------------------------------------------------------
bool TextBase::readProperties(XmlReader& e)
{
static const std::array<Pid, 18> pids { {
static constexpr std::array<Pid, 18> pids { {
Pid::SUB_STYLE,
Pid::FONT_FACE,
Pid::FONT_SIZE,
@ -1709,6 +1703,12 @@ bool TextBase::readProperties(XmlReader& e)
Pid::ALIGN,
} };
//---------------------------------------------------------
// readProperties
//---------------------------------------------------------
bool TextBase::readProperties(XmlReader& e)
{
const QStringRef& tag(e.name());
for (Pid i :pids) {
if (readProperty(tag, e, i))
@ -1721,6 +1721,21 @@ bool TextBase::readProperties(XmlReader& e)
return true;
}
//---------------------------------------------------------
// propertyId
//---------------------------------------------------------
Pid TextBase::propertyId(const QStringRef& name) const
{
if (name == "text")
return Pid::TEXT;
for (Pid pid : pids) {
if (propertyName(pid) == name)
return pid;
}
return Element::propertyId(name);
}
//---------------------------------------------------------
// pageRectangle
//---------------------------------------------------------

View file

@ -335,6 +335,7 @@ class TextBase : public Element {
virtual QVariant getProperty(Pid propertyId) const override;
virtual bool setProperty(Pid propertyId, const QVariant& v) override;
virtual QVariant propertyDefault(Pid id) const override;
virtual Pid propertyId(const QStringRef& xmlName) const override;
virtual Sid getPropertyStyle(Pid) const;
virtual void styleChanged();

View file

@ -91,7 +91,7 @@ void TBox::layout()
void TBox::write(XmlWriter& xml) const
{
xml.stag(name());
xml.stag(this);
Box::writeProperties(xml);
_text->write(xml);
xml.etag();

View file

@ -395,7 +395,7 @@ void TextLineBase::write(XmlWriter& xml) const
{
if (!xml.canWrite(this))
return;
xml.stag(name());
xml.stag(this);
writeProperties(xml);
xml.etag();
}
@ -454,6 +454,19 @@ bool TextLineBase::readProperties(XmlReader& e)
return SLine::readProperties(e);
}
//---------------------------------------------------------
// TextLineBase::propertyId
//---------------------------------------------------------
Pid TextLineBase::propertyId(const QStringRef& name) const
{
for (Pid pid : pids) {
if (propertyName(pid) == name)
return pid;
}
return SLine::propertyId(name);
}
//---------------------------------------------------------
// getProperty
//---------------------------------------------------------

View file

@ -121,6 +121,7 @@ class TextLineBase : public SLine {
virtual QVariant getProperty(Pid id) const override;
virtual bool setProperty(Pid propertyId, const QVariant&) override;
virtual Pid propertyId(const QStringRef& xmlName) const override;
};
} // namespace Ms

View file

@ -519,7 +519,7 @@ Tie::Tie(Score* s)
void Tie::write(XmlWriter& xml) const
{
xml.stag(name());
xml.stag(this);
SlurTie::writeProperties(xml);
xml.etag();
}

View file

@ -125,7 +125,7 @@ void TimeSig::setDenominatorString(const QString& a)
void TimeSig::write(XmlWriter& xml) const
{
xml.stag("TimeSig");
xml.stag(this);
writeProperty(xml, Pid::TIMESIG_TYPE);
Element::writeProperties(xml);
@ -217,6 +217,23 @@ void TimeSig::read(XmlReader& e)
_stretch.reduce();
}
//---------------------------------------------------------
// propertyId
//---------------------------------------------------------
Pid TimeSig::propertyId(const QStringRef& name) const
{
if (name == "subtype")
return Pid::TIMESIG_TYPE;
if (name == "sigN" || name == "sigD")
return Pid::TIMESIG;
if (name == "stretchN" || name == "stretchD")
return Pid::TIMESIG_STRETCH;
if (name == "Groups")
return Pid::GROUPS;
return Element::propertyId(name);
}
//---------------------------------------------------------
// layout
//---------------------------------------------------------

View file

@ -112,6 +112,7 @@ class TimeSig final : public Element {
virtual QVariant getProperty(Pid propertyId) const override;
virtual bool setProperty(Pid propertyId, const QVariant&) override;
virtual QVariant propertyDefault(Pid id) const override;
virtual Pid propertyId(const QStringRef& xmlName) const override;
const Groups& groups() const { return _groups; }
void setGroups(const Groups& e) { _groups = e; }

View file

@ -358,7 +358,7 @@ void Tremolo::write(XmlWriter& xml) const
{
if (!xml.canWrite(this))
return;
xml.stag(name());
xml.stag(this);
xml.tag("subtype", tremoloTypeName());
Element::writeProperties(xml);
xml.etag();

View file

@ -86,7 +86,7 @@ void TremoloBar::draw(QPainter* painter) const
void TremoloBar::write(XmlWriter& xml) const
{
xml.stag("TremoloBar");
xml.stag(this);
writeProperty(xml, Pid::MAG);
writeProperty(xml, Pid::LINE_WIDTH);
writeProperty(xml, Pid::PLAY);

View file

@ -307,7 +307,7 @@ void Trill::write(XmlWriter& xml) const
{
if (!xml.canWrite(this))
return;
xml.stag(name());
xml.stag(this);
xml.tag("subtype", trillTypeName());
writeProperty(xml, Pid::PLAY);
writeProperty(xml, Pid::ORNAMENT_STYLE);

View file

@ -707,7 +707,7 @@ void Tuplet::scanElements(void* data, void (*func)(void*, Element*), bool all)
void Tuplet::write(XmlWriter& xml) const
{
xml.stag(name());
xml.stag(this);
Element::writeProperties(xml);
writeProperty(xml, Pid::DIRECTION);
@ -722,7 +722,7 @@ void Tuplet::write(XmlWriter& xml) const
xml.tag("baseNote", _baseLen.name());
if (_number) {
xml.stag("Number");
xml.stag("Number", _number);
_number->writeProperties(xml);
xml.etag();
}

View file

@ -186,7 +186,9 @@ UndoStack::UndoStack()
{
curCmd = 0;
curIdx = 0;
cleanIdx = 0;
cleanState = 0;
stateList.push_back(cleanState);
nextState = 1;
}
//---------------------------------------------------------
@ -267,17 +269,18 @@ void UndoStack::remove(int idx)
// remove redo stack
while (list.size() > curIdx) {
UndoCommand* cmd = list.takeLast();
stateList.pop_back();
cmd->cleanup(false); // delete elements for which UndoCommand() holds ownership
delete cmd;
// --curIdx;
}
while (list.size() > idx) {
UndoCommand* cmd = list.takeLast();
stateList.pop_back();
cmd->cleanup(true);
delete cmd;
}
curIdx = idx;
// TODO: handle cleanIdx
}
//---------------------------------------------------------
@ -325,10 +328,12 @@ void UndoStack::endMacro(bool rollback)
// remove redo stack
while (list.size() > curIdx) {
UndoCommand* cmd = list.takeLast();
stateList.pop_back();
cmd->cleanup(false); // delete elements for which UndoCommand() holds ownership
delete cmd;
}
list.append(curCmd);
stateList.push_back(nextState++);
++curIdx;
}
curCmd = 0;
@ -345,6 +350,7 @@ void UndoStack::reopen()
Q_ASSERT(curIdx > 0);
--curIdx;
curCmd = list.takeAt(curIdx);
stateList.erase(stateList.begin() + curIdx);
for (auto i : curCmd->commands()) {
qDebug(" <%s>", i->name());
}
@ -356,7 +362,7 @@ void UndoStack::reopen()
void UndoStack::setClean()
{
cleanIdx = curIdx;
cleanState = state();
}
//---------------------------------------------------------

View file

@ -119,8 +119,10 @@ class UndoCommand {
class UndoStack {
UndoCommand* curCmd;
QList<UndoCommand*> list;
std::vector<int> stateList;
int nextState;
int cleanState;
int curIdx;
int cleanIdx;
public:
UndoStack();
@ -135,7 +137,8 @@ class UndoStack {
void setClean();
bool canUndo() const { return curIdx > 0; }
bool canRedo() const { return curIdx < list.size(); }
bool isClean() const { return cleanIdx == curIdx; }
int state() const { return stateList[curIdx]; }
bool isClean() const { return cleanState == state(); }
int getCurIdx() const { return curIdx; }
void remove(int idx);
bool empty() const { return !canUndo() && !canRedo(); }

View file

@ -196,7 +196,7 @@ void Vibrato::write(XmlWriter& xml) const
{
if (!xml.canWrite(this))
return;
xml.stag(name());
xml.stag(this);
xml.tag("subtype", vibratoTypeName());
writeProperty(xml, Pid::PLAY);
SLine::writeProperties(xml);

View file

@ -151,7 +151,7 @@ void Volta::read(XmlReader& e)
void Volta::write(XmlWriter& xml) const
{
xml.stag(name());
xml.stag(this);
TextLineBase::writeProperties(xml);
QString s;
for (int i : _endings) {

View file

@ -216,12 +216,17 @@ class XmlWriter : public QTextStream {
bool _clipboardmode = { false }; // used to modify write() behaviour
bool _excerptmode = { false }; // true when writing a part
bool _writeOmr = { true }; // false if writing into *.msc file
bool _writeTrack = { false };
bool _writePosition = { false };
int _tupletId = { 1 };
int _beamId = { 1 };
LinksIndexer _linksIndexer;
QMap<int, int> _lidLocalIndices;
std::vector<std::pair<const ScoreElement*, QString>> _elements;
bool _recordElements = false;
void putLevel();
public:
@ -238,12 +243,16 @@ class XmlWriter : public QTextStream {
bool clipboardmode() const { return _clipboardmode; }
bool excerptmode() const { return _excerptmode; }
bool writeOmr() const { return _writeOmr; }
bool writeTrack() const { return _writeTrack; }
bool writePosition() const { return _writePosition; }
int nextTupletId() { return _tupletId++; }
int nextBeamId() { return _beamId++; }
void setClipboardmode(bool v) { _clipboardmode = v; }
void setExcerptmode(bool v) { _excerptmode = v; }
void setWriteOmr(bool v) { _writeOmr = v; }
void setWriteTrack(bool v) { _writeTrack= v; }
void setWritePosition(bool v) { _writePosition = v; }
void setTupletId(int v) { _tupletId = v; }
void setBeamId(int v) { _beamId = v; }
void setSpannerId(int v) { _spannerId = v; }
@ -262,6 +271,9 @@ class XmlWriter : public QTextStream {
void setLidLocalIndex(int lid, int localIndex) { _lidLocalIndices.insert(lid, localIndex); }
int lidLocalIndex(int lid) const { return _lidLocalIndices[lid]; }
const std::vector<std::pair<const ScoreElement*, QString>>& elements() const { return _elements; }
void setRecordElements(bool record) { _recordElements = record; }
void sTag(const char* name, Spatium sp) { XmlWriter::tag(name, QVariant(sp.val())); }
void pTag(const char* name, PlaceText);
@ -270,6 +282,9 @@ class XmlWriter : public QTextStream {
void stag(const QString&);
void etag();
void stag(const ScoreElement* se, const QString& attributes = QString());
void stag(const QString& name, const ScoreElement* se, const QString& attributes = QString());
void tagE(const QString&);
void tagE(const char* format, ...);
void ntag(const char* name);

View file

@ -93,6 +93,34 @@ void XmlWriter::stag(const QString& s)
stack.append(s.split(' ')[0]);
}
//---------------------------------------------------------
// stag
// <mops attribute="value">
//---------------------------------------------------------
void XmlWriter::stag(const ScoreElement* se, const QString& attributes)
{
stag(se->name(), se, attributes);
}
//---------------------------------------------------------
// stag
// <mops attribute="value">
//---------------------------------------------------------
void XmlWriter::stag(const QString& name, const ScoreElement* se, const QString& attributes)
{
putLevel();
*this << '<' << name;
if (!attributes.isEmpty())
*this << ' ' << attributes;
*this << '>' << endl;
stack.append(name);
if (_recordElements)
_elements.emplace_back(se, name);
}
//---------------------------------------------------------
// etag
// </mops>
@ -182,6 +210,7 @@ void XmlWriter::tag(Pid id, QVariant data, QVariant defaultData)
case P_TYPE::STRING:
case P_TYPE::FONT:
case P_TYPE::ALIGN:
case P_TYPE::FRACTION:
tag(name, data);
break;
case P_TYPE::ORNAMENT_STYLE:
@ -289,8 +318,6 @@ void XmlWriter::tag(Pid id, QVariant data, QVariant defaultData)
case P_TYPE::SUB_STYLE:
tag(name, textStyleName(Tid(data.toInt())));
break;
case P_TYPE::FRACTION:
qFatal("unknown: FRACTION");
case P_TYPE::POINT_MM:
qFatal("unknown: POINT_MM");
case P_TYPE::SIZE_MM:

View file

@ -56,6 +56,8 @@ QT5_WRAP_UI (ui_headers
importmidi/importmidi_panel.ui
scorecmp/scorecmp_tool.ui
debugger/barline.ui
debugger/harmony.ui
debugger/box.ui
@ -412,6 +414,7 @@ add_executable ( ${ExecutableName}
importmidi/importmidi_voice.cpp importmidi/importmidi_view.cpp importmidi/importmidi_key.cpp
importmidi/importmidi_tempo.cpp importmidi/importmidi_instrument.cpp
importmidi/importmidi_chordname.cpp
scorecmp/scorecmp.cpp scorecmp/scorediffmodel.cpp scorecmp/scorelistmodel.cpp
resourceManager.cpp downloadUtils.cpp
textcursor.cpp continuouspanel.cpp accessibletoolbutton.cpp scoreaccessibility.cpp
startcenter.cpp scoreBrowser.cpp scorePreview.cpp scoreInfo.cpp

View file

@ -74,6 +74,7 @@
#include "synthesizer/msynthesizer.h"
#include "svggenerator.h"
#include "scorePreview.h"
#include "scorecmp/scorecmp.h"
#include "extension.h"
#ifdef OMR
@ -272,7 +273,7 @@ bool MuseScore::checkDirty(MasterScore* s)
Handles the GUI's file-open action.
*/
void MuseScore::loadFiles()
void MuseScore::loadFiles(bool switchTab, bool singleFile)
{
QStringList files = getOpenScoreNames(
#ifdef OMR
@ -292,17 +293,18 @@ void MuseScore::loadFiles()
tr("Overture / Score Writer Files <experimental>") + " (*.ove *.scw);;" +
tr("Bagpipe Music Writer Files <experimental>") + " (*.bww);;" +
tr("Guitar Pro") + " (*.gtp *.gp3 *.gp4 *.gp5 *.gpx)",
tr("Load Score")
tr("Load Score"),
singleFile
);
for (const QString& s : files)
openScore(s);
openScore(s, switchTab);
}
//---------------------------------------------------------
// openScore
//---------------------------------------------------------
Score* MuseScore::openScore(const QString& fn)
Score* MuseScore::openScore(const QString& fn, bool switchTab)
{
//
// make sure we load a file only once
@ -317,7 +319,9 @@ Score* MuseScore::openScore(const QString& fn)
MasterScore* score = readScore(fn);
if (score) {
score->updateCapo();
setCurrentScoreView(appendScore(score));
const int tabIdx = appendScore(score);
if (switchTab)
setCurrentScoreView(tabIdx);
writeSessionFile(false);
}
return score;
@ -435,6 +439,7 @@ bool MuseScore::saveFile(MasterScore* score)
}
score->setCreated(false);
updateWindowTitle(score);
scoreCmpTool->updateScoreVersions(score);
int idx = scoreList.indexOf(score->masterScore());
tab1->setTabText(idx, score->fileInfo()->completeBaseName());
if (tab2)
@ -781,6 +786,61 @@ void MuseScore::newFile()
setCurrentScoreView(appendScore(score));
}
//---------------------------------------------------------
// copy
// Copy content of src file do dest file overwriting it.
// Implemented manually as QFile::copy refuses to
// overwrite existing files.
//---------------------------------------------------------
static bool copy(QFile& src, QFile& dest)
{
src.open(QIODevice::ReadOnly);
dest.open(QIODevice::WriteOnly);
constexpr qint64 size = 1024 * 1024;
char* buf = new char[size];
bool err = false;
while (qint64 r = src.read(buf, size)) {
if (r < 0) {
err = true;
break;
}
qint64 w = dest.write(buf, r);
if (w < r) {
err = true;
break;
}
}
dest.close();
src.close();
delete[] buf;
return !err;
}
//---------------------------------------------------------
// getTemporaryScoreFileCopy
// baseNameTemplate is the template to be passed to
// QTemporaryFile constructor but without suffix and
// directory --- they are defined automatically.
//---------------------------------------------------------
QTemporaryFile* MuseScore::getTemporaryScoreFileCopy(const QFileInfo& info, const QString& baseNameTemplate)
{
QString suffix(info.suffix());
if (suffix.endsWith(",")) // some backup files created by MuseScore
suffix.chop(1);
QTemporaryFile* f = new QTemporaryFile(
QDir::temp().absoluteFilePath(baseNameTemplate + '.' + suffix),
this
);
QFile src(info.absoluteFilePath());
if (!copy(src, *f)) {
delete f;
return nullptr;
}
return f;
}
//---------------------------------------------------------
// addScorePreview
// add a score preview to the file dialog
@ -815,7 +875,7 @@ static QList<QUrl> sidebarUrls()
// getOpenScoreNames
//---------------------------------------------------------
QStringList MuseScore::getOpenScoreNames(const QString& filter, const QString& title)
QStringList MuseScore::getOpenScoreNames(const QString& filter, const QString& title, bool singleFile)
{
QSettings set;
QString dir = set.value("lastOpenPath", preferences.getString(PREF_APP_PATHS_MYSCORES)).toString();
@ -834,7 +894,7 @@ QStringList MuseScore::getOpenScoreNames(const QString& filter, const QString& t
if (loadScoreDialog == 0) {
loadScoreDialog = new QFileDialog(this);
loadScoreDialog->setFileMode(QFileDialog::ExistingFiles);
loadScoreDialog->setFileMode(singleFile ? QFileDialog::ExistingFile : QFileDialog::ExistingFiles);
loadScoreDialog->setOption(QFileDialog::DontUseNativeDialog, true);
loadScoreDialog->setWindowTitle(title);
addScorePreview(loadScoreDialog);
@ -1879,6 +1939,7 @@ bool MuseScore::saveAs(Score* cs_, bool saveCopy, const QString& path, const QSt
cs_->undoStack()->setClean();
dirtyChanged(cs_);
cs_->setCreated(false);
scoreCmpTool->updateScoreVersions(cs_);
addRecentScore(cs_);
writeSessionFile(false);
}

View file

@ -58,6 +58,8 @@
#include "timeline.h"
#include "importmidi/importmidi_panel.h"
#include "importmidi/importmidi_operations.h"
#include "scorecmp/scorecmp.h"
#include "libmscore/scorediff.h"
#include "libmscore/chord.h"
#include "libmscore/segment.h"
#include "editraster.h"
@ -152,6 +154,8 @@ QString dataPath;
QString iconPath;
bool converterMode = false;
static bool rawDiffMode = false;
static bool diffMode = false;
bool processJob = false;
bool externalIcons = false;
bool pluginMode = false;
@ -1085,6 +1089,17 @@ MuseScore::MuseScore()
scorePageLayoutChanged();
showTimeline(false);
scoreCmpTool = new ScoreComparisonTool;
scoreCmpTool->setVisible(false);
{
QAction* a = getAction("toggle-scorecmp-tool");
connect(
scoreCmpTool, &ScoreComparisonTool::visibilityChanged,
a, &QAction::setChecked
);
}
addDockWidget(Qt::BottomDockWidgetArea, scoreCmpTool);
mainWindow->setStretchFactor(0, 1);
mainWindow->setStretchFactor(1, 0);
mainWindow->setSizes(QList<int>({500, 50}));
@ -1118,19 +1133,11 @@ MuseScore::MuseScore()
envelope->setSizes(QList<int>({550, 180}));
splitter = new QSplitter;
tab1 = new ScoreTab(&scoreList, this);
tab1->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
connect(tab1, SIGNAL(currentScoreViewChanged(ScoreView*)), SLOT(setCurrentScoreView(ScoreView*)));
connect(tab1, SIGNAL(tabCloseRequested(int)), SLOT(removeTab(int)));
connect(tab1, SIGNAL(actionTriggered(QAction*)), SLOT(cmd(QAction*)));
tab1 = createScoreTab();
splitter->addWidget(tab1);
if (splitScreen()) {
tab2 = new ScoreTab(&scoreList, this);
tab2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
connect(tab2, SIGNAL(currentScoreViewChanged(ScoreView*)), SLOT(setCurrentScoreView(ScoreView*)));
connect(tab2, SIGNAL(tabCloseRequested(int)), SLOT(removeTab(int)));
connect(tab2, SIGNAL(actionTriggered(QAction*)), SLOT(cmd(QAction*)));
tab2 = createScoreTab();
splitter->addWidget(tab2);
tab2->setVisible(false);
}
@ -1370,6 +1377,10 @@ MuseScore::MuseScore()
a->setCheckable(true);
menuView->addAction(a);
a = getAction("toggle-scorecmp-tool");
a->setCheckable(true);
menuView->addAction(a);
menuView->addSeparator();
menuView->addAction(getAction("zoomin"));
menuView->addAction(getAction("zoomout"));
@ -2100,15 +2111,9 @@ int MuseScore::appendScore(MasterScore* score)
}
}
scoreList.insert(index, score);
tab1->blockSignals(true);
if (tab2)
tab2->blockSignals(true);
tab1->insertTab(score);
if (tab2)
tab2->insertTab(score);
tab1->blockSignals(false);
if (tab2)
tab2->blockSignals(false);
return index;
}
@ -2375,6 +2380,30 @@ void MuseScore::setCurrentScoreView(ScoreView* view)
ScoreAccessibility::instance()->updateAccessibilityInfo();
}
//---------------------------------------------------------
// setCurrentScores
//---------------------------------------------------------
void MuseScore::setCurrentScores(Score* s1, Score* s2)
{
if (s1)
tab1->setCurrentScore(s1);
if (s2) {
setSplitScreen(true);
tab2->setCurrentScore(s2);
}
}
//---------------------------------------------------------
// setSplitScreen
//---------------------------------------------------------
void MuseScore::setSplitScreen(bool val)
{
if (splitScreen() != val)
splitWindow(_horizontalSplit);
}
//---------------------------------------------------------
// updateViewModeCombo
//---------------------------------------------------------
@ -2853,15 +2882,9 @@ void MuseScore::removeTab(int i)
midiPanelOnCloseFile(score->importedFilePath());
scoreList.removeAt(i);
tab1->blockSignals(true);
tab1->removeTab(i);
tab1->blockSignals(false);
if (tab2) {
tab2->blockSignals(true);
tab2->removeTab(i);
tab2->blockSignals(false);
}
tab1->removeTab(i, /* noCurrentChangedSignals */ true);
if (tab2)
tab2->removeTab(i, /* noCurrentChangedSignals */ true);
cs = 0;
cv = 0;
@ -3318,6 +3341,7 @@ static bool processNonGui(const QStringList& argv)
else
return convert(argv[0], outFileName);
}
if (!extensionName.isEmpty()) {
QFileInfo fi(extensionName);
QString suffix = fi.suffix().toLower();
@ -3328,6 +3352,25 @@ static bool processNonGui(const QStringList& argv)
return false;
}
}
if (rawDiffMode || diffMode) {
if (argv.size() != 2)
return false;
MasterScore* s1 = mscore->readScore(argv[0]);
MasterScore* s2 = mscore->readScore(argv[1]);
if (!s1 || !s2)
return false;
ScoreDiff diff(s1, s2, /* textDiffOnly */ !diffMode);
if (rawDiffMode)
QTextStream(stdout) << diff.rawDiff() << endl;
if (diffMode)
QTextStream(stdout) << diff.userDiff() << endl;
delete s1;
delete s2;
}
return true;
}
@ -4694,11 +4737,7 @@ void MuseScore::splitWindow(bool horizontal)
{
if (!_splitScreen) {
if (tab2 == 0) {
tab2 = new ScoreTab(&scoreList, this);
tab2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
connect(tab2, SIGNAL(currentScoreViewChanged(ScoreView*)), SLOT(setCurrentScoreView(ScoreView*)));
connect(tab2, SIGNAL(tabCloseRequested(int)), SLOT(removeTab(int)));
connect(tab2, SIGNAL(actionTriggered(QAction*)), SLOT(cmd(QAction*)));
tab2 = createScoreTab();
splitter->addWidget(tab2);
}
tab2->setVisible(true);
@ -4712,24 +4751,22 @@ void MuseScore::splitWindow(bool horizontal)
s->update();
setCurrentView(1, 0);
}
emit windowSplit(true);
}
else {
if (_horizontalSplit == horizontal) {
_splitScreen = false;
tab2->setVisible(false);
setCurrentView(0, tab1->currentIndex());
emit windowSplit(false);
}
else {
_horizontalSplit = horizontal;
QAction* a;
if (_horizontalSplit)
a = getAction("split-v");
else
a = getAction("split-h");
a->setChecked(false);
splitter->setOrientation(_horizontalSplit ? Qt::Horizontal : Qt::Vertical);
}
}
getAction("split-h")->setChecked(_splitScreen && _horizontalSplit);
getAction("split-v")->setChecked(_splitScreen && !_horizontalSplit);
}
//---------------------------------------------------------
@ -5309,6 +5346,7 @@ void MuseScore::endCmd()
updateInputState(cs);
updateUndoRedo();
dirtyChanged(cs);
scoreCmpTool->updateDiff();
Element* e = cs->selection().element();
// For multiple notes selected check if they all have same pitch and tuning
@ -5412,6 +5450,20 @@ void MuseScore::setPlayRepeats(bool repeat)
}
}
//---------------------------------------------------------
// createScoreTab
//---------------------------------------------------------
ScoreTab* MuseScore::createScoreTab()
{
ScoreTab* tab = new ScoreTab(&scoreList, this);
tab->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
connect(tab, SIGNAL(currentScoreViewChanged(ScoreView*)), SLOT(setCurrentScoreView(ScoreView*)));
connect(tab, SIGNAL(tabCloseRequested(int)), SLOT(removeTab(int)));
connect(tab, SIGNAL(actionTriggered(QAction*)), SLOT(cmd(QAction*)));
return tab;
}
//---------------------------------------------------------
// cmd
//---------------------------------------------------------
@ -5589,6 +5641,8 @@ void MuseScore::cmd(QAction* a, const QString& cmd)
;
else if (cmd == "toggle-piano")
showPianoKeyboard(a->isChecked());
else if (cmd == "toggle-scorecmp-tool")
scoreCmpTool->setVisible(a->isChecked());
else if (cmd == "plugin-creator")
showPluginCreator(a);
else if (cmd == "plugin-manager")
@ -6589,6 +6643,8 @@ int main(int argc, char* av[])
parser.addOption(QCommandLineOption({"f", "force"}, "Used with '-o <file>', ignore warnings reg. score being corrupted or from wrong version"));
parser.addOption(QCommandLineOption({"b", "bitrate"}, "Used with '-o <file>.mp3', sets bitrate, in kbps", "bitrate"));
parser.addOption(QCommandLineOption({"E", "install-extension"}, "Install an extension, load soundfont as default unless if -e is passed too", "extension file"));
parser.addOption(QCommandLineOption("raw-diff", "Print a raw diff for the given scores"));
parser.addOption(QCommandLineOption("diff", "Print a diff for the given scores"));
parser.addPositionalArgument("scorefiles", "The files to open", "[scorefile...]");
@ -6726,6 +6782,14 @@ int main(int argc, char* av[])
else
fprintf(stderr, "MP3 bitrate value '%s' not recognized, using default setting from preferences instead.\n", qPrintable(temp));
}
if (parser.isSet("raw-diff")) {
MScore::noGui = true;
rawDiffMode = true;
}
if (parser.isSet("diff")) {
MScore::noGui = true;
diffMode = true;
}
QStringList argv = parser.positionalArguments();
@ -6750,6 +6814,10 @@ int main(int argc, char* av[])
if (app->sendMessage(QString("")))
return 0;
}
if (rawDiffMode || diffMode) {
if (argv.size() != 2)
qFatal("Only two scores are needed for performing a comparison");
}
if (dataPath.isEmpty())
dataPath = QStandardPaths::writableLocation(QStandardPaths::DataLocation);

View file

@ -97,6 +97,7 @@ class SynthesizerState;
class Driver;
class Seq;
class ImportMidiPanel;
class ScoreComparisonTool;
class Startcenter;
class HelpBrowser;
class ToolbarEditor;
@ -243,6 +244,8 @@ class MuseScore : public QMainWindow, public MuseScoreCore {
QFrame* importmidiShowPanel;
QSplitter* mainWindow;
ScoreComparisonTool* scoreCmpTool { 0 };
MagBox* mag;
QComboBox* viewModeCombo;
QAction* playId;
@ -467,8 +470,13 @@ class MuseScore : public QMainWindow, public MuseScoreCore {
void switchLayoutMode(LayoutMode);
void setPlayRepeats(bool repeat);
ScoreTab* createScoreTab();
QString getUtmParameters(QString medium) const;
signals:
void windowSplit(bool);
private slots:
void cmd(QAction* a, const QString& cmd);
void autoSaveTimerTimeout();
@ -532,6 +540,7 @@ class MuseScore : public QMainWindow, public MuseScoreCore {
void handleMessage(const QString& message);
void setCurrentScoreView(ScoreView*);
void setCurrentScoreView(int);
void setCurrentScores(Score* s1, Score* s2 = nullptr);
void setNormalState() { changeState(STATE_NORMAL); }
void setPlayState() { changeState(STATE_PLAY); }
void setNoteEntryState() { changeState(STATE_NOTE_ENTRY); }
@ -600,6 +609,7 @@ class MuseScore : public QMainWindow, public MuseScoreCore {
void writeSessionFile(bool);
bool restoreSession(bool);
bool splitScreen() const { return _splitScreen; }
void setSplitScreen(bool val);
virtual void setCurrentView(int tabIdx, int idx);
void loadPlugins();
void unloadPlugins();
@ -617,8 +627,9 @@ class MuseScore : public QMainWindow, public MuseScoreCore {
MasterScore* getNewFile();
Q_INVOKABLE void loadFile(const QString& url);
void loadFile(const QUrl&);
QTemporaryFile* getTemporaryScoreFileCopy(const QFileInfo& info, const QString& baseNameTemplate);
QNetworkAccessManager* networkManager();
virtual Score* openScore(const QString& fn);
virtual Score* openScore(const QString& fn, bool switchTab = true);
bool hasToCheckForUpdate();
bool hasToCheckForExtensionsUpdate();
static bool unstable();
@ -632,7 +643,7 @@ class MuseScore : public QMainWindow, public MuseScoreCore {
ScoreTab* getTab2() const { return tab2; }
QList<LanguageItem>& languages() { return _languages; }
QStringList getOpenScoreNames(const QString& filter, const QString& title);
QStringList getOpenScoreNames(const QString& filter, const QString& title, bool singleFile = false);
QString getSaveScoreName(const QString& title, QString& name, const QString& filter, bool folder = false);
QString getStyleFilename(bool open, const QString& title = QString());
QString getFotoFilename(QString& filter, QString *selectedFilter);
@ -704,7 +715,7 @@ class MuseScore : public QMainWindow, public MuseScoreCore {
bool countIn() const { return countInAction->isChecked(); }
bool panDuringPlayback() const { return panAction->isChecked(); }
void noteTooShortForTupletDialog();
void loadFiles();
void loadFiles(bool switchTab = true, bool singleFile = false);
// midi panel functions
void midiPanelOnSwitchToFile(const QString &file);
void midiPanelOnCloseFile(const QString &file);

View file

@ -0,0 +1,518 @@
//=============================================================================
// MuseScore
// Music Composition & Notation
//
// Copyright (C) 2018 Werner Schweer
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2
// as published by the Free Software Foundation and appearing in
// the file LICENCE.GPL
//=============================================================================
#include "scorecmp.h"
#include "ui_scorecmp_tool.h"
#include "scorediffmodel.h"
#include "scorelistmodel.h"
#include "musescore.h"
#include "scoretab.h"
#include "scoreview.h"
#include "libmscore/scorediff.h"
namespace Ms {
//---------------------------------------------------------
// ScoreComparisonTool
//---------------------------------------------------------
ScoreComparisonTool::ScoreComparisonTool(QWidget* parent)
: QDockWidget(parent), _ui(new Ui::ScoreComparisonTool)
{
_ui->setupUi(this);
_mode = Mode::INTELLIGENT;
_ui->intelligentModeRadioButton->setChecked(true);
_ui->diffWidget->setCurrentWidget(_ui->pageIntelligentDiff);
connect(
_ui->score1ComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &ScoreComparisonTool::selectedVersionsChanged);
connect(
_ui->score2ComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &ScoreComparisonTool::selectedVersionsChanged);
}
//---------------------------------------------------------
// ~ScoreComparisonTool
//---------------------------------------------------------
ScoreComparisonTool::~ScoreComparisonTool()
{
delete _ui;
delete _diff;
}
//---------------------------------------------------------
// ScoreComparisonTool::changeEvent
//---------------------------------------------------------
void ScoreComparisonTool::changeEvent(QEvent* e)
{
QDockWidget::changeEvent(e);
switch(e->type()) {
case QEvent::LanguageChange:
_ui->retranslateUi(this);
break;
default:
break;
}
}
//---------------------------------------------------------
// ScoreComparisonTool::showEvent
//---------------------------------------------------------
void ScoreComparisonTool::showEvent(QShowEvent* e)
{
QDockWidget::showEvent(e);
if (e->spontaneous())
return;
e->accept();
if (!_scoreListModel) {
ScoreTab* tab = mscore->getTab1();
_scoreListModel = new ScoreListModel(&mscore->scores(), tab, this);
_ui->score1ComboBox->setModel(_scoreListModel);
_ui->score2ComboBox->setModel(_scoreListModel);
MasterScore* s = nullptr;
if (ScoreView* v = tab->view())
s = v->score()->masterScore();
_scoreVersionsModel1 = new ScoreVersionListModel(s, this);
_scoreVersionsModel2 = new ScoreVersionListModel(s, this);
_ui->version1ComboBox->setModel(_scoreVersionsModel1);
_ui->version2ComboBox->setModel(_scoreVersionsModel2);
selectedVersionsChanged();
_ui->score1ComboBox->setCurrentIndex(tab->currentIndex());
connect(tab->getTab(), &QTabBar::currentChanged,
_ui->score1ComboBox, &QComboBox::setCurrentIndex);
slotWindowSplit(mscore->splitScreen());
connect(mscore, &MuseScore::windowSplit,
this, &ScoreComparisonTool::slotWindowSplit);
}
updateDiff();
}
//---------------------------------------------------------
// ScoreComparisonTool::updateDiffView
//---------------------------------------------------------
void ScoreComparisonTool::updateDiffView(Mode mode)
{
switch(mode) {
case Mode::RAW:
if (!_rawModel && _diff) {
_rawModel = new RawScoreDiffModel(_diff, true, this);
connect(this, &ScoreComparisonTool::diffUpdated,
_rawModel, &RawScoreDiffModel::update);
_ui->rawDiffView->setModel(_rawModel);
}
break;
case Mode::INTELLIGENT:
if (!_intelligentModel && _diff) {
_intelligentModel = new ScoreDiffModel(_diff, this);
connect(this, &ScoreComparisonTool::diffAboutToBeUpdated,
_intelligentModel, &ScoreDiffModel::diffAboutToBeUpdated);
connect(this, &ScoreComparisonTool::diffUpdated,
_intelligentModel, &ScoreDiffModel::diffUpdated);
_ui->intelligentDiffView->setModel(_intelligentModel);
}
break;
}
}
//---------------------------------------------------------
// ScoreComparisonTool::updateDiffTitle
//---------------------------------------------------------
void ScoreComparisonTool::updateDiffTitle()
{
if (_diff)
_ui->diffWidgetBox->setTitle(
tr("Comparison of \"%1\" and \"%2\"")
.arg(_diff->score1()->title())
.arg(_diff->score2()->title())
);
else
_ui->diffWidgetBox->setTitle(tr("Comparison"));
}
//---------------------------------------------------------
// ScoreComparisonTool::setMode
//---------------------------------------------------------
void ScoreComparisonTool::setMode(Mode mode)
{
if (_mode == mode)
return;
_mode = mode;
updateDiffView(mode);
switch(mode) {
case Mode::RAW:
if (!_ui->rawModeRadioButton->isChecked())
_ui->rawModeRadioButton->setChecked(true);
_ui->diffWidget->setCurrentWidget(_ui->pageRawDiff);
break;
case Mode::INTELLIGENT:
if (!_ui->intelligentModeRadioButton->isChecked())
_ui->intelligentModeRadioButton->setChecked(true);
_ui->diffWidget->setCurrentWidget(_ui->pageIntelligentDiff);
break;
}
}
//---------------------------------------------------------
// ScoreComparisonTool::compare
//---------------------------------------------------------
void ScoreComparisonTool::compare(Score* s1, Score* s2)
{
invalidateDiff();
if (!s1 || !s2)
return;
_diff = new ScoreDiff(s1, s2);
connect(s1, &QObject::destroyed, this, &ScoreComparisonTool::invalidateDiff);
connect(s2, &QObject::destroyed, this, &ScoreComparisonTool::invalidateDiff);
updateDiffView(_mode);
updateDiffTitle();
mscore->setCurrentScores(s1, s2);
}
//---------------------------------------------------------
// ScoreComparisonTool::invalidateDiff
//---------------------------------------------------------
void ScoreComparisonTool::invalidateDiff()
{
if (_rawModel) {
_rawModel->deleteLater();
_rawModel = nullptr;
}
if (_intelligentModel) {
_intelligentModel->deleteLater();
_intelligentModel = nullptr;
}
if (_diff) {
disconnect(_diff->score1(), 0, this, 0);
disconnect(_diff->score2(), 0, this, 0);
delete _diff;
_diff = nullptr;
}
updateDiffTitle();
}
//---------------------------------------------------------
// ScoreComparisonTool::updateDiff
//---------------------------------------------------------
void ScoreComparisonTool::updateDiff()
{
if (isVisible() && _diff && !_diff->updated()) {
emit diffAboutToBeUpdated();
_diff->update();
emit diffUpdated();
}
}
//---------------------------------------------------------
// ScoreComparisonTool::openScoreVersion
// Opens the proper score version if it is not opened
// and returns the score object. Does not switch active
// tab as the score comparison tool may need some
// specific tabs configuration.
//---------------------------------------------------------
Score* ScoreComparisonTool::openScoreVersion(const ScoreVersion& ver)
{
Score* s;
if (ver.recent) {
s = ver.score;
if (!s)
s = mscore->openScore(ver.fileInfo.absoluteFilePath(), /* switchTab */ false);
}
else {
QString baseName;
if (ver.score)
baseName = ver.score->masterScore()->fileInfo()->completeBaseName();
else
baseName = ver.fileInfo.completeBaseName();
QTemporaryFile* tmp = mscore->getTemporaryScoreFileCopy(
ver.fileInfo,
QString("[%1] %2.XXXXXX").arg(ver.name).arg(baseName)
);
if (tmp) {
s = mscore->openScore(tmp->fileName(), /* switchTab */ false);
if (s)
s->masterScore()->setReadOnly(true);
delete tmp;
// let the score know about the temporary file deletion
s->masterScore()->fileInfo()->refresh();
updateScoreVersions(s);
}
}
return s;
}
//---------------------------------------------------------
// ScoreComparisonTool::on_compareButton_clicked
//---------------------------------------------------------
void ScoreComparisonTool::on_compareButton_clicked()
{
const int idx1 = _ui->version1ComboBox->currentIndex();
const int idx2 = _ui->version2ComboBox->currentIndex();
if (idx1 < 0 || idx2 < 0) // no scores to compare
return;
const ScoreVersion& ver1 = _scoreVersionsModel1->getScoreVersion(idx1);
const ScoreVersion& ver2 = _scoreVersionsModel2->getScoreVersion(idx2);
Score* s1 = openScoreVersion(ver1);
Score* s2 = openScoreVersion(ver2);
compare(s1, s2);
}
//---------------------------------------------------------
// ScoreComparisonTool::selectedVersionsChanged
// Disables Compare button if there are no versions
// selected for comparison.
//---------------------------------------------------------
void ScoreComparisonTool::selectedVersionsChanged()
{
const int idx1 = _ui->version1ComboBox->currentIndex();
const int idx2 = _ui->version2ComboBox->currentIndex();
_ui->compareButton->setEnabled(idx1 >= 0 && idx2 >= 0);
}
//---------------------------------------------------------
// ScoreComparisonTool::updateScoreVersions
//---------------------------------------------------------
void ScoreComparisonTool::updateScoreVersions(const Score* s)
{
if (_scoreVersionsModel1 && _scoreVersionsModel1->score() == s) {
_scoreVersionsModel1->update();
resetVersion1ComboBox();
}
if (_scoreVersionsModel2 && _scoreVersionsModel2->score() == s) {
_scoreVersionsModel2->update();
resetVersion2ComboBox();
}
}
//---------------------------------------------------------
// ScoreComparisonTool::on_browseFileButton_clicked
//---------------------------------------------------------
void ScoreComparisonTool::on_browseFileButton_clicked()
{
Score* prevScore = mscore->currentScore();
mscore->loadFiles(/* switchTab */ true, /* singleFile */ true);
Score* loadedScore = mscore->currentScore();
if (loadedScore == prevScore) // we didn't load anything?
return;
// ensure that we display this score in split-screen mode
mscore->setCurrentScores(loadedScore, loadedScore);
}
//---------------------------------------------------------
// ScoreComparisonTool::resetVersion1ComboBox
//---------------------------------------------------------
void ScoreComparisonTool::resetVersion1ComboBox()
{
if (_scoreVersionsModel1) {
_ui->version1ComboBox->setCurrentIndex(
_scoreVersionsModel1->getPosition(ScoreVersion::INDEX_CURRENT));
}
}
//---------------------------------------------------------
// ScoreComparisonTool::on_score1ComboBox_currentIndexChanged
//---------------------------------------------------------
void ScoreComparisonTool::on_score1ComboBox_currentIndexChanged(int idx)
{
if (_scoreVersionsModel1) {
Score* s = _scoreListModel->getScore(idx);
_scoreVersionsModel1->setScore(s ? s->masterScore() : nullptr);
resetVersion1ComboBox();
}
}
//---------------------------------------------------------
// ScoreComparisonTool::resetVersion2ComboBox
//---------------------------------------------------------
void ScoreComparisonTool::resetVersion2ComboBox()
{
if (_scoreVersionsModel2) {
int index = -1;
if (!mscore->splitScreen())
index = _scoreVersionsModel2->getPosition(ScoreVersion::INDEX_SESSION_START);
if (index < 0)
index = _scoreVersionsModel2->getPosition(ScoreVersion::INDEX_CURRENT);
_ui->version2ComboBox->setCurrentIndex(index);
}
}
//---------------------------------------------------------
// ScoreComparisonTool::on_score2ComboBox_currentIndexChanged
//---------------------------------------------------------
void ScoreComparisonTool::on_score2ComboBox_currentIndexChanged(int idx)
{
if (_scoreVersionsModel2) {
Score* s = _scoreListModel->getScore(idx);
_scoreVersionsModel2->setScore(s ? s->masterScore() : nullptr);
resetVersion2ComboBox();
}
}
//---------------------------------------------------------
// ScoreComparisonTool::on_rawModeRadioButton_toggled
//---------------------------------------------------------
void ScoreComparisonTool::on_rawModeRadioButton_toggled(bool checked)
{
if (checked)
setMode(Mode::RAW);
}
//---------------------------------------------------------
// ScoreComparisonTool::on_intelligentModeRadioButton_toggled
//---------------------------------------------------------
void ScoreComparisonTool::on_intelligentModeRadioButton_toggled(bool checked)
{
if (checked)
setMode(Mode::INTELLIGENT);
}
//---------------------------------------------------------
// ScoreComparisonTool::on_intelligentDiffView_activated
//---------------------------------------------------------
void ScoreComparisonTool::on_intelligentDiffView_activated(const QModelIndex& index)
{
const BaseDiff* diff = _intelligentModel->diffItem(index);
const ScoreElement* el[2];
bool select[2] { true, true };
switch(diff->itemType()) {
case ItemType::ELEMENT:
{
const ElementDiff* elDiff = static_cast<const ElementDiff*>(diff);
for (int i = 0; i < 2; ++i) {
if (elDiff->el[i])
el[i] = elDiff->el[i];
else {
if (elDiff->ctx[i]->isElement() || !elDiff->before[i])
el[i] = elDiff->ctx[i];
else
el[i] = elDiff->before[i];
select[i] = false;
}
}
}
break;
default:
std::copy(diff->ctx, diff->ctx + 2, el);
break;
}
showElement(el[0], select[0]);
showElement(el[1], select[1]);
}
//---------------------------------------------------------
// ScoreComparisonTool::showElement
//---------------------------------------------------------
void ScoreComparisonTool::showElement(const ScoreElement* se, bool select)
{
if (!se)
return;
ScoreView* sv1 = mscore->getTab1()->view();
Score* score1 = (sv1 && sv1->isVisible()) ? sv1->score() : nullptr;
ScoreView* sv2 = mscore->getTab2() ? mscore->getTab2()->view() : nullptr;
Score* score2 = (sv2 && sv2->isVisible()) ? sv2->score() : nullptr;
const Element* e = se->isElement() ? toElement(se) : nullptr;
Score* score = se->score();
score->deselectAll();
if (select && e && (score1 == score || score2 == score)) {
Element* el = const_cast<Element*>(e);
if (el->isChordRest())
score->select(el, SelectType::RANGE);
else
score->select(el);
}
if (score1 == score) {
bool move = sv1->moveWhenInactive(true);
if (e) {
sv1->adjustCanvasPosition(e, false);
sv1->update();
}
sv1->moveWhenInactive(move);
}
if (score2 == score) {
bool move = sv2->moveWhenInactive(true);
if (e) {
sv2->adjustCanvasPosition(e, false);
sv2->update();
}
sv2->moveWhenInactive(move);
}
}
//---------------------------------------------------------
// ScoreComparisonTool::slotWindowSplit
//---------------------------------------------------------
void ScoreComparisonTool::slotWindowSplit(bool split)
{
ScoreTab* tab1 = mscore->getTab1();
if (ScoreTab* tab2 = mscore->getTab2()) {
if (split) {
disconnect(tab1->getTab(), &QTabBar::currentChanged,
_ui->score2ComboBox, &QComboBox::setCurrentIndex);
_ui->score2ComboBox->setCurrentIndex(tab2->currentIndex());
connect(tab2->getTab(), &QTabBar::currentChanged,
_ui->score2ComboBox, &QComboBox::setCurrentIndex,
Qt::UniqueConnection
);
}
else
disconnect(tab2->getTab(), &QTabBar::currentChanged,
_ui->score2ComboBox, &QComboBox::setCurrentIndex);
}
if (!split) {
_ui->score2ComboBox->setCurrentIndex(tab1->currentIndex());
connect(tab1->getTab(), &QTabBar::currentChanged,
_ui->score2ComboBox, &QComboBox::setCurrentIndex,
Qt::UniqueConnection
);
}
}
}

View file

@ -0,0 +1,95 @@
//=============================================================================
// MuseScore
// Music Composition & Notation
//
// Copyright (C) 2018 Werner Schweer
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2
// as published by the Free Software Foundation and appearing in
// the file LICENCE.GPL
//=============================================================================
#ifndef __SCORECMP_H__
#define __SCORECMP_H__
namespace Ui {
class ScoreComparisonTool;
}
namespace Ms {
class Score;
class ScoreElement;
class ScoreDiff;
class RawScoreDiffModel;
class ScoreDiffModel;
class ScoreListModel;
struct ScoreVersion;
class ScoreVersionListModel;
//---------------------------------------------------------
// ScoreComparisonTool
//---------------------------------------------------------
class ScoreComparisonTool : public QDockWidget {
Q_OBJECT
public:
enum class Mode { RAW, INTELLIGENT };
private:
Ui::ScoreComparisonTool* _ui;
Mode _mode;
ScoreListModel* _scoreListModel = nullptr;
ScoreVersionListModel* _scoreVersionsModel1 = nullptr;
ScoreVersionListModel* _scoreVersionsModel2 = nullptr;
ScoreDiff* _diff = nullptr;
RawScoreDiffModel* _rawModel = nullptr;
ScoreDiffModel* _intelligentModel = nullptr;
void updateDiffView(Mode mode);
void updateDiffTitle();
void resetVersion1ComboBox();
void resetVersion2ComboBox();
Score* openScoreVersion(const ScoreVersion& ver);
void showElement(const ScoreElement* se, bool select);
private slots:
void on_compareButton_clicked();
void on_browseFileButton_clicked();
void on_score1ComboBox_currentIndexChanged(int);
void on_score2ComboBox_currentIndexChanged(int);
void on_rawModeRadioButton_toggled(bool);
void on_intelligentModeRadioButton_toggled(bool);
void on_intelligentDiffView_activated(const QModelIndex&);
void selectedVersionsChanged();
protected:
void changeEvent(QEvent* e) override;
void showEvent(QShowEvent* e) override;
signals:
void diffAboutToBeUpdated();
void diffUpdated();
public:
explicit ScoreComparisonTool(QWidget* parent = nullptr);
~ScoreComparisonTool();
void setMode(Mode mode);
Mode mode() const { return _mode; }
void compare(Score* s1, Score* s2);
public slots:
void slotWindowSplit(bool);
void invalidateDiff();
void updateDiff();
void updateScoreVersions(const Score*);
};
} // namespace Ms
#endif

View file

@ -0,0 +1,226 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ScoreComparisonTool</class>
<widget class="QDockWidget" name="ScoreComparisonTool">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>858</width>
<height>247</height>
</rect>
</property>
<property name="accessibleName">
<string>Score Comparison Tool</string>
</property>
<property name="accessibleDescription">
<string>A tool to examine differences between the chosen scores</string>
</property>
<property name="windowTitle">
<string>Score Comparison Tool</string>
</property>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0" colspan="2">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Choose scores to compare:</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="score1Label">
<property name="text">
<string>Score 1:</string>
</property>
<property name="buddy">
<cstring>score1ComboBox</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="score1ComboBox">
<property name="accessibleName">
<string>Score 1</string>
</property>
<property name="accessibleDescription">
<string>Choose the first score to compare</string>
</property>
<property name="minimumContentsLength">
<number>20</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="score2Label">
<property name="text">
<string>Score 2:</string>
</property>
<property name="buddy">
<cstring>score2ComboBox</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="score2ComboBox">
<property name="accessibleName">
<string>Score 2</string>
</property>
<property name="accessibleDescription">
<string>Choose the second score to compare</string>
</property>
<property name="minimumContentsLength">
<number>20</number>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QComboBox" name="version1ComboBox">
<property name="accessibleName">
<string>Score version 1</string>
</property>
<property name="accessibleDescription">
<string>Choose a version of the first score to compare</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QComboBox" name="version2ComboBox">
<property name="accessibleName">
<string>Score version 2</string>
</property>
<property name="accessibleDescription">
<string>Choose a version of the second score to compare</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QPushButton" name="browseFileButton">
<property name="toolTip">
<string>Browse files for comparison</string>
</property>
<property name="text">
<string>Browse</string>
</property>
</widget>
</item>
<item row="2" column="1" colspan="2">
<widget class="QPushButton" name="compareButton">
<property name="toolTip">
<string>Perform comparison of chosen scores</string>
</property>
<property name="text">
<string>Compare</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="2">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Diff mode</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QRadioButton" name="rawModeRadioButton">
<property name="text">
<string>Raw</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="intelligentModeRadioButton">
<property name="text">
<string>Intelligent</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="3">
<widget class="QGroupBox" name="diffWidgetBox">
<property name="title">
<string>Comparison</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QStackedWidget" name="diffWidget">
<property name="currentIndex">
<number>1</number>
</property>
<widget class="QWidget" name="pageRawDiff">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QListView" name="rawDiffView">
<property name="textElideMode">
<enum>Qt::ElideNone</enum>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="pageIntelligentDiff">
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QListView" name="intelligentDiffView"/>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
<tabstops>
<tabstop>score1ComboBox</tabstop>
<tabstop>version1ComboBox</tabstop>
<tabstop>score2ComboBox</tabstop>
<tabstop>version2ComboBox</tabstop>
<tabstop>browseFileButton</tabstop>
<tabstop>compareButton</tabstop>
<tabstop>rawModeRadioButton</tabstop>
<tabstop>intelligentModeRadioButton</tabstop>
<tabstop>intelligentDiffView</tabstop>
<tabstop>rawDiffView</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View file

@ -0,0 +1,132 @@
//=============================================================================
// MuseScore
// Music Composition & Notation
//
// Copyright (C) 2018 Werner Schweer
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2
// as published by the Free Software Foundation and appearing in
// the file LICENCE.GPL
//=============================================================================
#include "scorediffmodel.h"
#include "libmscore/scorediff.h"
namespace Ms {
//---------------------------------------------------------
// RawScoreDiffModel::RawScoreDiffModel
//---------------------------------------------------------
RawScoreDiffModel::RawScoreDiffModel(ScoreDiff* d, bool skipEqual, QObject* parent)
: QAbstractListModel(parent), _diff(d), _skipEqual(skipEqual)
{
update();
}
//---------------------------------------------------------
// RawScoreDiffModel::update
//---------------------------------------------------------
void RawScoreDiffModel::update() {
beginResetModel();
_textDiffs.clear();
for (const TextDiff& diff : _diff->textDiffs()) {
if (_skipEqual && diff.type == DiffType::EQUAL)
continue;
if (diff.type == DiffType::REPLACE) {
// Push this item twice. First will be shown as DELETE,
// second as INSERT.
_textDiffs.push_back(&diff);
}
_textDiffs.push_back(&diff);
}
endResetModel();
}
//---------------------------------------------------------
// RawScoreDiffModel::rowCount
//---------------------------------------------------------
int RawScoreDiffModel::rowCount(const QModelIndex& parent) const
{
if (parent.isValid())
return 0;
return _textDiffs.size();
}
//---------------------------------------------------------
// RawScoreDiffModel::data
//---------------------------------------------------------
QVariant RawScoreDiffModel::data(const QModelIndex& index, int role) const
{
const int row = index.row();
if (row < 0 || row >= int(_textDiffs.size()))
return QVariant();
const TextDiff& diff = *_textDiffs[row];
switch(role) {
case Qt::DisplayRole:
{
DiffType type = diff.type;
if (diff.type == DiffType::REPLACE)
type = (row == 0 || _textDiffs[row - 1] != &diff) ? DiffType::DELETE : DiffType::INSERT;
return diff.toString(type);
}
case Qt::BackgroundRole:
switch(diff.type) {
case DiffType::DELETE:
return QBrush(Qt::red);
case DiffType::INSERT:
return QBrush(Qt::green);
default:
return QVariant();
}
}
return QVariant();
}
//---------------------------------------------------------
// ScoreDiffModel::rowCount
//---------------------------------------------------------
int ScoreDiffModel::rowCount(const QModelIndex& parent) const
{
if (parent.isValid())
return 0;
return _diff->diffs().size();
}
//---------------------------------------------------------
// ScoreDiffModel::data
//---------------------------------------------------------
QVariant ScoreDiffModel::data(const QModelIndex& index, int role) const
{
const int row = index.row();
if (row < 0 || row >= int(_diff->diffs().size()))
return QVariant();
const BaseDiff& diff = *_diff->diffs()[row];
switch(role) {
case Qt::DisplayRole:
return diff.toString();
}
return QVariant();
}
//---------------------------------------------------------
// ScoreDiffModel::diffItem
//---------------------------------------------------------
const BaseDiff* ScoreDiffModel::diffItem(const QModelIndex& index) const
{
const int row = index.row();
if (row < 0 || row >= int(_diff->diffs().size()))
return nullptr;
return _diff->diffs()[row];
}
}

Some files were not shown because too many files have changed in this diff Show more