2012-05-26 14:26:10 +02:00
|
|
|
//=============================================================================
|
|
|
|
// MuseScore
|
|
|
|
// Music Composition & Notation
|
|
|
|
// $Id:$
|
|
|
|
//
|
2012-11-19 09:29:46 +01:00
|
|
|
// Copyright (C) 2011-2012 Werner Schweer and others
|
2012-05-26 14:26:10 +02:00
|
|
|
//
|
|
|
|
// 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 LICENSE.GPL
|
|
|
|
//=============================================================================
|
|
|
|
|
2012-07-16 15:49:24 +02:00
|
|
|
#include "config.h"
|
2012-05-26 14:26:10 +02:00
|
|
|
#include "score.h"
|
|
|
|
#include "xml.h"
|
|
|
|
#include "element.h"
|
|
|
|
#include "measure.h"
|
|
|
|
#include "segment.h"
|
|
|
|
#include "slur.h"
|
|
|
|
#include "chordrest.h"
|
2013-01-04 17:48:15 +01:00
|
|
|
#include "chord.h"
|
2012-05-26 14:26:10 +02:00
|
|
|
#include "tuplet.h"
|
|
|
|
#include "beam.h"
|
|
|
|
#include "revisions.h"
|
|
|
|
#include "page.h"
|
|
|
|
#include "part.h"
|
|
|
|
#include "staff.h"
|
|
|
|
#include "keysig.h"
|
|
|
|
#include "clef.h"
|
|
|
|
#include "text.h"
|
|
|
|
#include "ottava.h"
|
|
|
|
#include "volta.h"
|
|
|
|
#include "excerpt.h"
|
|
|
|
#include "mscore.h"
|
|
|
|
#include "stafftype.h"
|
2012-07-06 17:42:20 +02:00
|
|
|
#ifdef OMR
|
2012-05-26 14:26:10 +02:00
|
|
|
#include "omr/omr.h"
|
|
|
|
#include "omr/omrpage.h"
|
2012-07-06 17:42:20 +02:00
|
|
|
#endif
|
2012-05-26 14:26:10 +02:00
|
|
|
#include "sig.h"
|
|
|
|
#include "undo.h"
|
|
|
|
#include "imageStore.h"
|
|
|
|
#include "audio.h"
|
2012-10-20 20:32:40 +02:00
|
|
|
#include "barline.h"
|
2012-06-04 21:06:12 +02:00
|
|
|
#include "libmscore/qzipreader_p.h"
|
|
|
|
#include "libmscore/qzipwriter_p.h"
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// write
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::write(Xml& xml, bool selectionOnly)
|
|
|
|
{
|
|
|
|
xml.stag("Score");
|
|
|
|
|
2012-07-06 17:42:20 +02:00
|
|
|
#ifdef OMR
|
2012-05-26 14:26:10 +02:00
|
|
|
if (_omr && xml.writeOmr)
|
|
|
|
_omr->write(xml);
|
2012-07-06 17:42:20 +02:00
|
|
|
#endif
|
2012-05-26 14:26:10 +02:00
|
|
|
if (_showOmr && xml.writeOmr)
|
|
|
|
xml.tag("showOmr", _showOmr);
|
|
|
|
if (_audio && xml.writeOmr) {
|
|
|
|
xml.tag("playMode", int(_playMode));
|
|
|
|
_audio->write(xml);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < 32; ++i) {
|
|
|
|
if (!_layerTags[i].isEmpty()) {
|
|
|
|
xml.tag(QString("LayerTag id=\"%1\" tag=\"%2\"").arg(i).arg(_layerTags[i]),
|
|
|
|
_layerTagComments[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
int n = _layer.size();
|
|
|
|
for (int i = 1; i < n; ++i) { // dont save default variant
|
|
|
|
const Layer& l = _layer[i];
|
|
|
|
xml.tagE(QString("Layer name=\"%1\" mask=\"%2\"").arg(l.name).arg(l.tags));
|
|
|
|
}
|
|
|
|
xml.tag("currentLayer", _currentLayer);
|
|
|
|
|
|
|
|
if (!_testMode)
|
|
|
|
_syntiState.write(xml);
|
|
|
|
|
|
|
|
if (pageNumberOffset())
|
|
|
|
xml.tag("page-offset", pageNumberOffset());
|
|
|
|
xml.tag("Division", MScore::division);
|
|
|
|
xml.curTrack = -1;
|
|
|
|
|
|
|
|
_style.save(xml, true); // save only differences to buildin style
|
|
|
|
|
|
|
|
if (!parentScore()) {
|
|
|
|
int idx = 0;
|
2012-10-29 17:12:35 +01:00
|
|
|
foreach(StaffType** st, _staffTypes) {
|
|
|
|
if ((idx >= STAFF_TYPES) || !(*st)->isEqual(*::staffTypes[idx]))
|
|
|
|
(*st)->write(xml, idx);
|
2012-05-26 14:26:10 +02:00
|
|
|
++idx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
xml.tag("showInvisible", _showInvisible);
|
|
|
|
xml.tag("showUnprintable", _showUnprintable);
|
|
|
|
xml.tag("showFrames", _showFrames);
|
|
|
|
xml.tag("showMargins", _showPageborders);
|
|
|
|
|
|
|
|
QMapIterator<QString, QString> i(_metaTags);
|
|
|
|
while (i.hasNext()) {
|
|
|
|
i.next();
|
2013-02-06 16:25:27 +01:00
|
|
|
if (!_testMode || (i.key() != "platform" && i.key() != "creationDate"))
|
2012-05-26 14:26:10 +02:00
|
|
|
xml.tag(QString("metaTag name=\"%1\"").arg(i.key()), i.value());
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach(KeySig* ks, customKeysigs)
|
|
|
|
ks->write(xml);
|
|
|
|
|
|
|
|
if (!selectionOnly) {
|
|
|
|
xml.stag("PageList");
|
|
|
|
foreach(Page* page, _pages)
|
|
|
|
page->write(xml);
|
|
|
|
xml.etag();
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach(const Part* part, _parts)
|
|
|
|
part->write(xml);
|
|
|
|
|
|
|
|
xml.curTrack = 0;
|
|
|
|
int staffStart;
|
|
|
|
int staffEnd;
|
|
|
|
MeasureBase* measureStart;
|
|
|
|
MeasureBase* measureEnd;
|
|
|
|
|
|
|
|
if (selectionOnly) {
|
|
|
|
staffStart = _selection.staffStart();
|
|
|
|
staffEnd = _selection.staffEnd();
|
|
|
|
measureStart = _selection.startSegment()->measure();
|
|
|
|
// include title frames:
|
|
|
|
while (measureStart->prev() && !measureStart->prev()->sectionBreak())
|
|
|
|
measureStart = measureStart->prev();
|
|
|
|
measureEnd = _selection.endSegment()->measure()->next();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
staffStart = 0;
|
|
|
|
staffEnd = nstaves();
|
|
|
|
measureStart = first();
|
|
|
|
measureEnd = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
xml.trackDiff = -staffStart * VOICES;
|
|
|
|
for (int staffIdx = staffStart; staffIdx < staffEnd; ++staffIdx) {
|
|
|
|
xml.stag(QString("Staff id=\"%1\"").arg(staffIdx + 1));
|
|
|
|
xml.curTick = measureStart->tick();
|
|
|
|
xml.tickDiff = xml.curTick;
|
|
|
|
xml.curTrack = staffIdx * VOICES;
|
|
|
|
for (MeasureBase* m = measureStart; m != measureEnd; m = m->next()) {
|
2012-09-13 18:01:34 +02:00
|
|
|
if (m->type() == Element::MEASURE || staffIdx == 0)
|
2012-05-26 14:26:10 +02:00
|
|
|
m->write(xml, staffIdx, staffIdx == staffStart);
|
2012-09-13 18:01:34 +02:00
|
|
|
if (m->type() == Element::MEASURE)
|
2012-05-26 14:26:10 +02:00
|
|
|
xml.curTick = m->tick() + m->ticks();
|
|
|
|
}
|
|
|
|
xml.etag();
|
|
|
|
}
|
|
|
|
xml.curTrack = -1;
|
|
|
|
if (!selectionOnly) {
|
2012-12-18 09:09:11 +01:00
|
|
|
foreach(Excerpt* excerpt, _excerpts) {
|
|
|
|
if (excerpt->score() != this)
|
|
|
|
excerpt->score()->write(xml, false); // recursion
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
if (parentScore())
|
|
|
|
xml.tag("name", name());
|
|
|
|
xml.etag();
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// readStaff
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2013-01-11 18:10:18 +01:00
|
|
|
void Score::readStaff(XmlReader& e)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
MeasureBase* mb = first();
|
2013-01-11 18:10:18 +01:00
|
|
|
int staff = e.intAttribute("id", 1) - 1;
|
2013-01-21 20:21:41 +01:00
|
|
|
e.setTick(0);
|
|
|
|
e.setTrack(staff * VOICES);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2013-01-11 18:10:18 +01:00
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
const QStringRef& tag(e.name());
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
if (tag == "Measure") {
|
|
|
|
Measure* measure = 0;
|
|
|
|
if (staff == 0) {
|
|
|
|
measure = new Measure(this);
|
2013-01-21 20:21:41 +01:00
|
|
|
measure->setTick(e.tick());
|
2012-05-26 14:26:10 +02:00
|
|
|
add(measure);
|
|
|
|
if (_mscVersion < 115) {
|
|
|
|
const SigEvent& ev = sigmap()->timesig(measure->tick());
|
|
|
|
measure->setLen(ev.timesig());
|
|
|
|
measure->setTimesig(ev.nominal());
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
//
|
|
|
|
// inherit timesig from previous measure
|
|
|
|
//
|
|
|
|
Measure* m = measure->prevMeasure();
|
|
|
|
Fraction f(m ? m->timesig() : Fraction(4,4));
|
|
|
|
measure->setLen(f);
|
|
|
|
measure->setTimesig(f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
while (mb) {
|
2012-09-13 18:01:34 +02:00
|
|
|
if (mb->type() != Element::MEASURE) {
|
2012-05-26 14:26:10 +02:00
|
|
|
mb = mb->next();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
measure = (Measure*)mb;
|
|
|
|
mb = mb->next();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (measure == 0) {
|
|
|
|
qDebug("Score::readStaff(): missing measure!\n");
|
|
|
|
measure = new Measure(this);
|
2013-01-21 20:21:41 +01:00
|
|
|
measure->setTick(e.tick());
|
2012-05-26 14:26:10 +02:00
|
|
|
add(measure);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
measure->read(e, staff);
|
2013-01-21 20:21:41 +01:00
|
|
|
e.setTick(measure->tick() + measure->ticks());
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
else if (tag == "HBox" || tag == "VBox" || tag == "TBox" || tag == "FBox") {
|
2013-01-18 10:55:52 +01:00
|
|
|
MeasureBase* mb = static_cast<MeasureBase*>(Element::name2Element(tag, this));
|
2012-05-26 14:26:10 +02:00
|
|
|
mb->read(e);
|
2013-01-21 20:21:41 +01:00
|
|
|
mb->setTick(e.tick());
|
2012-05-26 14:26:10 +02:00
|
|
|
add(mb);
|
|
|
|
}
|
|
|
|
else
|
2013-01-11 18:10:18 +01:00
|
|
|
e.unknown();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// saveFile
|
|
|
|
/// If file has generated name, create a modal file save dialog
|
|
|
|
/// and ask filename.
|
|
|
|
/// Rename old file to backup file (.xxxx.msc?,).
|
|
|
|
/// Default is to save score in .mscz format,
|
|
|
|
/// Return true if OK and false on error.
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
bool Score::saveFile()
|
|
|
|
{
|
|
|
|
QString suffix = info.suffix();
|
|
|
|
if ((suffix != "mscx") && (suffix != "mscz")) {
|
|
|
|
QString s = info.filePath();
|
|
|
|
if (!suffix.isEmpty())
|
|
|
|
s = s.left(s.size() - suffix.size());
|
|
|
|
else
|
|
|
|
s += ".";
|
|
|
|
if (suffix == "msc")
|
|
|
|
suffix = "mscx"; // silently change to mscx
|
|
|
|
else
|
|
|
|
suffix = "mscz";
|
|
|
|
s += suffix;
|
|
|
|
info.setFile(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (info.exists() && !info.isWritable()) {
|
|
|
|
QString s = QT_TRANSLATE_NOOP("file", "The following file is locked: \n%1 \n\nTry saving to a different location.");
|
|
|
|
MScore::lastError = s.arg(info.filePath());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if file was already saved in this session
|
|
|
|
// save but don't overwrite backup again
|
|
|
|
|
|
|
|
if (saved()) {
|
|
|
|
try {
|
|
|
|
if (suffix == "msc" || suffix == "mscx")
|
|
|
|
saveFile(info);
|
|
|
|
else
|
|
|
|
saveCompressedFile(info, false);
|
|
|
|
}
|
|
|
|
catch (QString s) {
|
|
|
|
MScore::lastError = s;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
undo()->setClean();
|
|
|
|
setDirty(false);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// step 1
|
|
|
|
// save into temporary file to prevent partially overwriting
|
|
|
|
// the original file in case of "disc full"
|
|
|
|
//
|
|
|
|
|
|
|
|
QString tempName = info.filePath() + QString(".temp");
|
|
|
|
QFile temp(tempName);
|
|
|
|
if (!temp.open(QIODevice::WriteOnly)) {
|
|
|
|
MScore::lastError = QT_TRANSLATE_NOOP("file", "Open Temp File\n")
|
|
|
|
+ tempName + QT_TRANSLATE_NOOP("file", "\nfailed: ") + QString(strerror(errno));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
if (suffix == "msc" || suffix == "mscx")
|
|
|
|
saveFile(&temp, false);
|
|
|
|
else
|
|
|
|
saveCompressedFile(&temp, info, false);
|
|
|
|
}
|
|
|
|
catch (QString s) {
|
|
|
|
MScore::lastError = s;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (temp.error() != QFile::NoError) {
|
|
|
|
MScore::lastError = QT_TRANSLATE_NOOP("file",
|
|
|
|
"MuseScore: Save File failed: ") + temp.errorString();
|
|
|
|
temp.close();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
temp.close();
|
|
|
|
|
|
|
|
//
|
|
|
|
// step 2
|
|
|
|
// remove old backup file if exists
|
|
|
|
//
|
|
|
|
QDir dir(info.path());
|
|
|
|
QString backupName = QString(".") + info.fileName() + QString(",");
|
|
|
|
if (dir.exists(backupName)) {
|
|
|
|
if (!dir.remove(backupName)) {
|
|
|
|
// QMessageBox::critical(mscore, tr("MuseScore: Save File"),
|
|
|
|
// tr("removing old backup file ") + backupName + tr(" failed"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// step 3
|
|
|
|
// rename old file into backup
|
|
|
|
//
|
|
|
|
QString name(info.filePath());
|
|
|
|
if (dir.exists(name)) {
|
|
|
|
if (!dir.rename(name, backupName)) {
|
|
|
|
// QMessageBox::critical(mscore, tr("MuseScore: Save File"),
|
|
|
|
// tr("renaming old file <")
|
|
|
|
// + name + tr("> to backup <") + backupName + tr("> failed"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// step 4
|
|
|
|
// rename temp name into file name
|
|
|
|
//
|
|
|
|
if (!QFile::rename(tempName, name)) {
|
|
|
|
MScore::lastError = QT_TRANSLATE_NOOP("file", "renaming temp. file <")
|
|
|
|
+ tempName + QT_TRANSLATE_NOOP("file", "> to <") + name
|
|
|
|
+ QT_TRANSLATE_NOOP("file", "> failed:\n")
|
|
|
|
+ QString(strerror(errno));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// make file readable by all
|
|
|
|
QFile::setPermissions(name, QFile::ReadOwner | QFile::WriteOwner | QFile::ReadUser
|
|
|
|
| QFile::ReadGroup | QFile::ReadOther);
|
|
|
|
|
|
|
|
undo()->setClean();
|
|
|
|
setDirty(false);
|
|
|
|
setSaved(true);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// saveCompressedFile
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::saveCompressedFile(QFileInfo& info, bool onlySelection)
|
|
|
|
{
|
|
|
|
if (info.suffix().isEmpty())
|
|
|
|
info.setFile(info.filePath() + ".mscz");
|
|
|
|
|
|
|
|
QFile fp(info.filePath());
|
|
|
|
if (!fp.open(QIODevice::WriteOnly)) {
|
|
|
|
QString s = QString("Open File\n") + info.filePath() + QString("\nfailed: ")
|
|
|
|
+ QString(strerror(errno));
|
|
|
|
throw(s);
|
|
|
|
}
|
|
|
|
saveCompressedFile(&fp, info, onlySelection);
|
|
|
|
fp.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// saveCompressedFile
|
|
|
|
// file is already opened
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::saveCompressedFile(QIODevice* f, QFileInfo& info, bool onlySelection)
|
|
|
|
{
|
2012-06-04 21:06:12 +02:00
|
|
|
QZipWriter uz(f);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
QString fn = info.completeBaseName() + ".mscx";
|
|
|
|
QBuffer cbuf;
|
|
|
|
cbuf.open(QIODevice::ReadWrite);
|
|
|
|
Xml xml(&cbuf);
|
|
|
|
xml << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
|
|
|
xml.stag("container");
|
|
|
|
xml.stag("rootfiles");
|
|
|
|
xml.stag(QString("rootfile full-path=\"%1\"").arg(Xml::xmlString(fn)));
|
|
|
|
xml.etag();
|
|
|
|
foreach(ImageStoreItem* ip, imageStore) {
|
|
|
|
if (!ip->isUsed(this))
|
|
|
|
continue;
|
|
|
|
QString path = QString("Pictures/") + ip->hashName();
|
|
|
|
xml.tag("file", path);
|
|
|
|
}
|
|
|
|
|
|
|
|
xml.etag();
|
|
|
|
xml.etag();
|
|
|
|
cbuf.seek(0);
|
2012-06-04 21:06:12 +02:00
|
|
|
uz.addDirectory("META-INF");
|
|
|
|
uz.addFile("META-INF/container.xml", cbuf.data());
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
// save images
|
2012-06-04 21:06:12 +02:00
|
|
|
uz.addDirectory("Pictures");
|
2012-05-26 14:26:10 +02:00
|
|
|
foreach(ImageStoreItem* ip, imageStore) {
|
|
|
|
if (!ip->isUsed(this))
|
|
|
|
continue;
|
|
|
|
QString path = QString("Pictures/") + ip->hashName();
|
2012-06-23 11:42:40 +02:00
|
|
|
uz.addFile(path, ip->buffer());
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
#ifdef OMR
|
|
|
|
//
|
|
|
|
// save OMR page images
|
|
|
|
//
|
|
|
|
if (_omr) {
|
|
|
|
int n = _omr->numPages();
|
|
|
|
for (int i = 0; i < n; ++i) {
|
|
|
|
QString path = QString("OmrPages/page%1.png").arg(i+1);
|
|
|
|
QBuffer cbuf;
|
|
|
|
OmrPage* page = _omr->page(i);
|
|
|
|
QImage image = page->image();
|
|
|
|
if (!image.save(&cbuf, "PNG"))
|
|
|
|
throw(QString("cannot create image"));
|
2012-06-04 21:06:12 +02:00
|
|
|
uz.addFile(path, cbuf.data());
|
2012-05-26 14:26:10 +02:00
|
|
|
cbuf.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
//
|
|
|
|
// save audio
|
|
|
|
//
|
2012-06-23 11:42:40 +02:00
|
|
|
if (_audio)
|
|
|
|
uz.addFile("audio.ogg", _audio->data());
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
QBuffer dbuf;
|
|
|
|
dbuf.open(QIODevice::ReadWrite);
|
|
|
|
saveFile(&dbuf, true, onlySelection);
|
|
|
|
dbuf.seek(0);
|
2012-06-04 21:06:12 +02:00
|
|
|
uz.addFile(fn, dbuf.data());
|
|
|
|
uz.close();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// saveFile
|
|
|
|
// return true on success
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
bool Score::saveFile(QFileInfo& info)
|
|
|
|
{
|
|
|
|
if (info.suffix().isEmpty())
|
|
|
|
info.setFile(info.filePath() + ".mscx");
|
|
|
|
QFile fp(info.filePath());
|
|
|
|
if (!fp.open(QIODevice::WriteOnly)) {
|
|
|
|
QString s = QString("Open File\n") + info.filePath() + QString("\nfailed: ")
|
|
|
|
+ QString(strerror(errno));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
saveFile(&fp, false);
|
|
|
|
fp.close();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// loadStyle
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
bool Score::loadStyle(const QString& fn)
|
|
|
|
{
|
|
|
|
QFile f(fn);
|
|
|
|
if (f.open(QIODevice::ReadOnly)) {
|
|
|
|
MStyle st = _style;
|
|
|
|
if (st.load(&f)) {
|
|
|
|
_undo->push(new ChangeStyle(this, st));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
MScore::lastError = strerror(errno);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// saveStyle
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
bool Score::saveStyle(const QString& name)
|
|
|
|
{
|
|
|
|
QString ext(".mss");
|
|
|
|
QFileInfo info(name);
|
|
|
|
|
|
|
|
if (info.suffix().isEmpty())
|
|
|
|
info.setFile(info.filePath() + ext);
|
|
|
|
QFile f(info.filePath());
|
|
|
|
if (!f.open(QIODevice::WriteOnly)) {
|
|
|
|
MScore::lastError = QT_TRANSLATE_NOOP("file", "Open Style File\n")
|
|
|
|
+ f.fileName() + QT_TRANSLATE_NOOP("file", "\nfailed: ")
|
|
|
|
+ QString(strerror(errno));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Xml xml(&f);
|
|
|
|
xml.header();
|
|
|
|
xml.stag("museScore version=\"" MSC_VERSION "\"");
|
|
|
|
_style.save(xml, false); // save complete style
|
|
|
|
xml.etag();
|
|
|
|
if (f.error() != QFile::NoError) {
|
|
|
|
MScore::lastError = QT_TRANSLATE_NOOP("file", "Write Style failed: ")
|
|
|
|
+ f.errorString();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// saveFile
|
|
|
|
// return true on success
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
extern QString revision;
|
2013-02-06 15:48:37 +01:00
|
|
|
extern bool enableTestMode;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
void Score::saveFile(QIODevice* f, bool msczFormat, bool onlySelection)
|
|
|
|
{
|
2013-02-06 17:43:43 +01:00
|
|
|
if(!testMode())
|
|
|
|
setTestMode(enableTestMode);
|
2012-05-26 14:26:10 +02:00
|
|
|
Xml xml(f);
|
|
|
|
xml.writeOmr = msczFormat;
|
|
|
|
xml.header();
|
|
|
|
xml.stag("museScore version=\"" MSC_VERSION "\"");
|
|
|
|
if (!_testMode) {
|
|
|
|
xml.tag("programVersion", VERSION);
|
|
|
|
xml.tag("programRevision", revision);
|
|
|
|
}
|
|
|
|
write(xml, onlySelection);
|
|
|
|
xml.etag();
|
|
|
|
if (!parentScore())
|
|
|
|
_revisions->write(xml);
|
|
|
|
if(!onlySelection) {
|
|
|
|
//update version values for i.e. plugin access
|
|
|
|
_mscoreVersion = VERSION;
|
|
|
|
_mscoreRevision = revision.toInt();
|
|
|
|
_mscVersion = MSCVERSION;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// loadCompressedMsc
|
|
|
|
// return false on error
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2012-09-29 16:46:45 +02:00
|
|
|
Score::FileError Score::loadCompressedMsc(QString name, bool ignoreVersionError)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2012-06-04 21:06:12 +02:00
|
|
|
QZipReader uz(name);
|
2012-06-23 11:42:40 +02:00
|
|
|
if (!uz.exists()) {
|
|
|
|
qDebug("loadCompressedMsc: <%s> not found\n", qPrintable(name));
|
|
|
|
MScore::lastError = QT_TRANSLATE_NOOP("file", "file not found");
|
2012-09-29 16:46:45 +02:00
|
|
|
return FILE_NOT_FOUND;
|
2012-06-23 11:42:40 +02:00
|
|
|
}
|
2012-06-04 21:06:12 +02:00
|
|
|
QByteArray cbuf = uz.fileData("META-INF/container.xml");
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2013-01-11 18:10:18 +01:00
|
|
|
QString rootfile;
|
|
|
|
XmlReader e(cbuf);
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
const QStringRef& tag(e.name());
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2013-01-11 18:10:18 +01:00
|
|
|
if (tag == "rootfile") {
|
|
|
|
rootfile = e.attribute("full-path");
|
|
|
|
e.skipCurrentElement();
|
|
|
|
}
|
|
|
|
else if (tag == "file") {
|
|
|
|
QString image(e.readElementText());
|
|
|
|
QByteArray dbuf = uz.fileData(image);
|
|
|
|
imageStore.add(image, dbuf);
|
|
|
|
}
|
2012-06-23 11:42:40 +02:00
|
|
|
}
|
2013-01-11 18:10:18 +01:00
|
|
|
if (rootfile.isEmpty())
|
|
|
|
return FILE_NO_ROOTFILE;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2012-06-04 21:06:12 +02:00
|
|
|
QByteArray dbuf = uz.fileData(rootfile);
|
2012-06-11 12:15:21 +02:00
|
|
|
if (dbuf.isEmpty()) {
|
2012-06-23 11:42:40 +02:00
|
|
|
// qDebug("root file <%s> is empty", qPrintable(rootfile));
|
2012-06-11 12:15:21 +02:00
|
|
|
QList<QZipReader::FileInfo> fil = uz.fileInfoList();
|
|
|
|
foreach(const QZipReader::FileInfo& fi, fil) {
|
2012-06-23 14:20:03 +02:00
|
|
|
if (fi.filePath.endsWith(".mscx")) {
|
2012-06-11 12:15:21 +02:00
|
|
|
dbuf = uz.fileData(fi.filePath);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-01-11 18:10:18 +01:00
|
|
|
e.clear();
|
|
|
|
e.addData(dbuf);
|
|
|
|
e.setDocName(info.completeBaseName());
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2013-01-11 18:10:18 +01:00
|
|
|
FileError retval = read1(e, ignoreVersionError);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
#ifdef OMR
|
|
|
|
//
|
|
|
|
// load OMR page images
|
|
|
|
//
|
|
|
|
if (_omr) {
|
|
|
|
int n = _omr->numPages();
|
|
|
|
for (int i = 0; i < n; ++i) {
|
|
|
|
QString path = QString("OmrPages/page%1.png").arg(i+1);
|
2012-06-04 21:06:12 +02:00
|
|
|
QByteArray dbuf = uz.fileData(path);
|
|
|
|
OmrPage* page = _omr->page(i);
|
|
|
|
QImage image;
|
|
|
|
if (image.loadFromData(dbuf, "PNG")) {
|
|
|
|
page->setImage(image);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2012-06-04 21:06:12 +02:00
|
|
|
else
|
|
|
|
qDebug("load image failed");
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
//
|
|
|
|
// read audio
|
|
|
|
//
|
|
|
|
if (_audio) {
|
2012-06-04 21:06:12 +02:00
|
|
|
QByteArray dbuf = uz.fileData("audio.ogg");
|
|
|
|
_audio->setData(dbuf);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// loadMsc
|
|
|
|
// return true on success
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2012-09-29 16:46:45 +02:00
|
|
|
Score::FileError Score::loadMsc(QString name, bool ignoreVersionError)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
info.setFile(name);
|
2012-09-29 16:46:45 +02:00
|
|
|
|
|
|
|
if (name.endsWith(".mscz"))
|
|
|
|
return loadCompressedMsc(name, ignoreVersionError);
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
QFile f(name);
|
|
|
|
if (!f.open(QIODevice::ReadOnly)) {
|
|
|
|
MScore::lastError = f.errorString();
|
2012-09-29 16:46:45 +02:00
|
|
|
return FILE_OPEN_ERROR;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
2013-01-11 18:10:18 +01:00
|
|
|
XmlReader xml(&f);
|
|
|
|
return read1(xml, ignoreVersionError);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// parseVersion
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::parseVersion(const QString& val)
|
|
|
|
{
|
|
|
|
QRegExp re("(\\d+)\\.(\\d+)\\.(\\d+)");
|
|
|
|
int v1, v2, v3, rv1, rv2, rv3;
|
|
|
|
if (re.indexIn(VERSION) != -1) {
|
|
|
|
QStringList sl = re.capturedTexts();
|
|
|
|
if (sl.size() == 4) {
|
|
|
|
v1 = sl[1].toInt();
|
|
|
|
v2 = sl[2].toInt();
|
|
|
|
v3 = sl[3].toInt();
|
|
|
|
if (re.indexIn(val) != -1) {
|
|
|
|
sl = re.capturedTexts();
|
|
|
|
if (sl.size() == 4) {
|
|
|
|
rv1 = sl[1].toInt();
|
|
|
|
rv2 = sl[2].toInt();
|
|
|
|
rv3 = sl[3].toInt();
|
|
|
|
|
|
|
|
int currentVersion = v1 * 10000 + v2 * 100 + v3;
|
|
|
|
int readVersion = rv1 * 10000 + rv2 * 100 + rv3;
|
|
|
|
if (readVersion > currentVersion) {
|
|
|
|
qDebug("read future version\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
QRegExp re1("(\\d+)\\.(\\d+)");
|
|
|
|
if (re1.indexIn(val) != -1) {
|
|
|
|
sl = re.capturedTexts();
|
|
|
|
if (sl.size() == 3) {
|
|
|
|
rv1 = sl[1].toInt();
|
|
|
|
rv2 = sl[2].toInt();
|
|
|
|
|
|
|
|
int currentVersion = v1 * 10000 + v2 * 100 + v3;
|
|
|
|
int readVersion = rv1 * 10000 + rv2 * 100;
|
|
|
|
if (readVersion > currentVersion) {
|
|
|
|
qDebug("read future version\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
qDebug("1cannot parse <%s>\n", qPrintable(val));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
qDebug("2cannot parse <%s>\n", VERSION);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// read1
|
|
|
|
// return true on success
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2013-01-11 18:10:18 +01:00
|
|
|
Score::FileError Score::read1(XmlReader& e, bool ignoreVersionError)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
_elinks.clear();
|
2013-01-11 18:10:18 +01:00
|
|
|
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
if (e.name() == "museScore") {
|
2012-05-26 14:26:10 +02:00
|
|
|
const QString& version = e.attribute("version");
|
|
|
|
QStringList sl = version.split('.');
|
|
|
|
_mscVersion = sl[0].toInt() * 100 + sl[1].toInt();
|
2012-09-14 17:34:31 +02:00
|
|
|
|
2012-09-29 16:46:45 +02:00
|
|
|
if (!ignoreVersionError) {
|
|
|
|
QString message;
|
|
|
|
if (_mscVersion > MSCVERSION)
|
|
|
|
return FILE_TOO_NEW;
|
|
|
|
if (_mscVersion < 114)
|
|
|
|
return FILE_TOO_OLD;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2012-09-14 17:34:31 +02:00
|
|
|
|
2012-07-04 13:04:54 +02:00
|
|
|
if (_mscVersion <= 114)
|
2012-07-03 13:47:59 +02:00
|
|
|
return read114(e);
|
2013-01-11 18:10:18 +01:00
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
const QStringRef& tag(e.name());
|
2012-05-26 14:26:10 +02:00
|
|
|
if (tag == "programVersion") {
|
2013-01-11 18:10:18 +01:00
|
|
|
_mscoreVersion = e.readElementText();
|
|
|
|
parseVersion(_mscoreVersion);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2012-07-03 13:47:59 +02:00
|
|
|
else if (tag == "programRevision")
|
2013-01-11 18:10:18 +01:00
|
|
|
_mscoreRevision = e.readInt();
|
2012-07-03 13:47:59 +02:00
|
|
|
else if (tag == "Score")
|
2013-01-11 18:10:18 +01:00
|
|
|
read(e);
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (tag == "Revision") {
|
|
|
|
Revision* revision = new Revision;
|
|
|
|
revision->read(e);
|
|
|
|
_revisions->add(revision);
|
|
|
|
}
|
|
|
|
else
|
2013-01-11 18:10:18 +01:00
|
|
|
e.unknown();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2013-01-11 18:10:18 +01:00
|
|
|
e.unknown();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
int id = 1;
|
|
|
|
foreach(LinkedElements* le, _elinks)
|
|
|
|
le->setLid(this, id++);
|
|
|
|
_elinks.clear();
|
2012-10-02 17:07:28 +02:00
|
|
|
|
|
|
|
// _mscVersion is needed used during layout
|
|
|
|
// _mscVersion = MSCVERSION; // for later drag & drop usage
|
|
|
|
|
2012-09-29 16:46:45 +02:00
|
|
|
return FILE_NO_ERROR;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// read
|
|
|
|
// return false on error
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2013-01-11 18:10:18 +01:00
|
|
|
bool Score::read(XmlReader& e)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
if (parentScore())
|
|
|
|
setMscVersion(parentScore()->mscVersion());
|
2013-01-11 18:10:18 +01:00
|
|
|
|
|
|
|
while (e.readNextStartElement()) {
|
2013-01-21 20:21:41 +01:00
|
|
|
e.setTrack(-1);
|
2013-01-11 18:10:18 +01:00
|
|
|
const QStringRef& tag(e.name());
|
2012-05-26 14:26:10 +02:00
|
|
|
if (tag == "Staff")
|
2013-01-11 18:10:18 +01:00
|
|
|
readStaff(e);
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (tag == "KeySig") {
|
|
|
|
KeySig* ks = new KeySig(this);
|
2013-01-11 18:10:18 +01:00
|
|
|
ks->read(e);
|
2012-05-26 14:26:10 +02:00
|
|
|
customKeysigs.append(ks);
|
|
|
|
}
|
|
|
|
else if (tag == "StaffType") {
|
2013-01-11 18:10:18 +01:00
|
|
|
int idx = e.intAttribute("idx");
|
2012-10-29 17:12:35 +01:00
|
|
|
StaffType* ost = staffType(idx);
|
2012-05-26 14:26:10 +02:00
|
|
|
StaffType* st;
|
|
|
|
if (ost)
|
2012-10-30 23:45:20 +01:00
|
|
|
st = ost->clone();
|
2012-05-26 14:26:10 +02:00
|
|
|
else {
|
2013-01-11 18:10:18 +01:00
|
|
|
QString group = e.attribute("group", "pitched");
|
2012-05-26 14:26:10 +02:00
|
|
|
if (group == "percussion")
|
|
|
|
st = new StaffTypePercussion();
|
|
|
|
else if (group == "tablature")
|
|
|
|
st = new StaffTypeTablature();
|
|
|
|
else
|
|
|
|
st = new StaffTypePitched();
|
|
|
|
}
|
2013-01-11 18:10:18 +01:00
|
|
|
st->read(e);
|
2012-10-30 23:45:20 +01:00
|
|
|
st->setBuildin(false);
|
2012-10-29 17:12:35 +01:00
|
|
|
addStaffType(idx, st);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
else if (tag == "siglist")
|
2013-01-11 18:10:18 +01:00
|
|
|
_sigmap->read(e, _fileDivision);
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (tag == "programVersion") {
|
2013-01-11 18:10:18 +01:00
|
|
|
_mscoreVersion = e.readElementText();
|
|
|
|
parseVersion(_mscoreVersion);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
else if (tag == "programRevision")
|
2013-01-11 18:10:18 +01:00
|
|
|
_mscoreRevision = e.readInt();
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (tag == "Omr") {
|
|
|
|
#ifdef OMR
|
|
|
|
_omr = new Omr(this);
|
2013-01-11 18:10:18 +01:00
|
|
|
_omr->read(e);
|
2012-05-26 14:26:10 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else if (tag == "Audio") {
|
|
|
|
_audio = new Audio;
|
2013-01-11 18:10:18 +01:00
|
|
|
_audio->read(e);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
else if (tag == "showOmr")
|
2013-01-11 18:10:18 +01:00
|
|
|
_showOmr = e.readInt();
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (tag == "playMode")
|
2013-01-11 18:10:18 +01:00
|
|
|
_playMode = PlayMode(e.readInt());
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (tag == "LayerTag") {
|
2013-01-11 18:10:18 +01:00
|
|
|
int id = e.intAttribute("id");
|
|
|
|
const QString& tag = e.attribute("tag");
|
|
|
|
QString val(e.readElementText());
|
2012-05-26 14:26:10 +02:00
|
|
|
if (id >= 0 && id < 32) {
|
|
|
|
_layerTags[id] = tag;
|
|
|
|
_layerTagComments[id] = val;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (tag == "Layer") {
|
|
|
|
Layer layer;
|
2013-01-11 18:10:18 +01:00
|
|
|
layer.name = e.attribute("name");
|
|
|
|
layer.tags = e.attribute("mask").toUInt();
|
2012-05-26 14:26:10 +02:00
|
|
|
_layer.append(layer);
|
|
|
|
}
|
|
|
|
else if (tag == "currentLayer")
|
2013-01-11 18:10:18 +01:00
|
|
|
_currentLayer = e.readInt();
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (tag == "SyntiSettings") {
|
|
|
|
_syntiState.clear();
|
2013-01-11 18:10:18 +01:00
|
|
|
_syntiState.read(e);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
else if (tag == "Spatium")
|
2013-01-11 18:10:18 +01:00
|
|
|
_style.setSpatium (e.readDouble() * MScore::DPMM); // obsolete, moved to Style
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (tag == "page-offset") // obsolete, moved to Score
|
2013-01-11 18:10:18 +01:00
|
|
|
setPageNumberOffset(e.readInt());
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (tag == "Division")
|
2013-01-11 18:10:18 +01:00
|
|
|
_fileDivision = e.readInt();
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (tag == "showInvisible")
|
2013-01-11 18:10:18 +01:00
|
|
|
_showInvisible = e.readInt();
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (tag == "showUnprintable")
|
2013-01-11 18:10:18 +01:00
|
|
|
_showUnprintable = e.readInt();
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (tag == "showFrames")
|
2013-01-11 18:10:18 +01:00
|
|
|
_showFrames = e.readInt();
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (tag == "showMargins")
|
2013-01-11 18:10:18 +01:00
|
|
|
_showPageborders = e.readInt();
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (tag == "Style") {
|
|
|
|
qreal sp = _style.spatium();
|
2013-01-11 18:10:18 +01:00
|
|
|
_style.load(e);
|
2012-05-26 14:26:10 +02:00
|
|
|
// if (_layoutMode == LayoutFloat || _layoutMode == LayoutSystem) {
|
|
|
|
if (_layoutMode == LayoutFloat) {
|
|
|
|
// style should not change spatium in
|
|
|
|
// float mode
|
|
|
|
_style.setSpatium(sp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (tag == "copyright" || tag == "rights") {
|
|
|
|
Text* text = new Text(this);
|
2013-01-11 18:10:18 +01:00
|
|
|
text->read(e);
|
2013-02-26 15:50:36 +01:00
|
|
|
setMetaTag("copyright", text->text());
|
2012-05-26 14:26:10 +02:00
|
|
|
delete text;
|
|
|
|
}
|
|
|
|
else if (tag == "movement-number")
|
2013-01-11 18:10:18 +01:00
|
|
|
setMetaTag("movementNumber", e.readElementText());
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (tag == "movement-title")
|
2013-01-11 18:10:18 +01:00
|
|
|
setMetaTag("movementTitle", e.readElementText());
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (tag == "work-number")
|
2013-01-11 18:10:18 +01:00
|
|
|
setMetaTag("workNumber", e.readElementText());
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (tag == "work-title")
|
2013-01-11 18:10:18 +01:00
|
|
|
setMetaTag("workTitle", e.readElementText());
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (tag == "source")
|
2013-01-11 18:10:18 +01:00
|
|
|
setMetaTag("source", e.readElementText());
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (tag == "metaTag") {
|
2013-01-11 18:10:18 +01:00
|
|
|
QString name = e.attribute("name");
|
|
|
|
setMetaTag(name, e.readElementText());
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
else if (tag == "Part") {
|
|
|
|
Part* part = new Part(this);
|
2013-01-11 18:10:18 +01:00
|
|
|
part->read(e);
|
2012-05-26 14:26:10 +02:00
|
|
|
_parts.push_back(part);
|
|
|
|
}
|
|
|
|
else if (tag == "Slur") {
|
|
|
|
Slur* slur = new Slur(this);
|
2013-01-11 18:10:18 +01:00
|
|
|
slur->read(e);
|
2013-01-21 20:21:41 +01:00
|
|
|
e.addSpanner(slur);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
else if (tag == "Excerpt") {
|
2013-01-11 18:10:18 +01:00
|
|
|
Excerpt* ex = new Excerpt(this);
|
|
|
|
ex->read(e);
|
|
|
|
_excerpts.append(ex);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
else if (tag == "Beam") {
|
|
|
|
Beam* beam = new Beam(this);
|
2013-01-11 18:10:18 +01:00
|
|
|
beam->read(e);
|
2012-05-26 14:26:10 +02:00
|
|
|
beam->setParent(0);
|
|
|
|
// _beams.append(beam);
|
|
|
|
}
|
|
|
|
else if (tag == "Score") { // recursion
|
|
|
|
Score* s = new Score(style());
|
|
|
|
s->setParentScore(this);
|
2013-01-11 18:10:18 +01:00
|
|
|
s->read(e);
|
2012-05-26 14:26:10 +02:00
|
|
|
addExcerpt(s);
|
|
|
|
}
|
|
|
|
else if (tag == "PageList") {
|
2013-01-11 18:10:18 +01:00
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
if (e.name() == "Page") {
|
2012-05-26 14:26:10 +02:00
|
|
|
Page* page = new Page(this);
|
|
|
|
_pages.append(page);
|
|
|
|
page->read(e);
|
|
|
|
}
|
|
|
|
else
|
2013-01-11 18:10:18 +01:00
|
|
|
e.unknown();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (tag == "name")
|
2013-01-11 18:10:18 +01:00
|
|
|
setName(e.readElementText());
|
|
|
|
else if (tag == "page-layout") { // obsolete
|
|
|
|
if (_layoutMode != LayoutFloat && _layoutMode != LayoutSystem) {
|
|
|
|
PageFormat pf;
|
|
|
|
pf.copy(*pageFormat());
|
|
|
|
pf.read(e);
|
|
|
|
setPageFormat(pf);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
e.skipCurrentElement();
|
|
|
|
}
|
|
|
|
else if (tag == "cursorTrack")
|
|
|
|
e.skipCurrentElement();
|
2012-05-26 14:26:10 +02:00
|
|
|
else
|
2013-01-11 18:10:18 +01:00
|
|
|
e.unknown();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// check slurs
|
2013-01-21 20:21:41 +01:00
|
|
|
foreach(Spanner* s, e.spanner()) {
|
2012-12-10 14:00:17 +01:00
|
|
|
if (!s->startElement() || !s->endElement()) {
|
|
|
|
qDebug("remove incomplete Spanner %s", s->name());
|
|
|
|
switch (s->anchor()) {
|
|
|
|
case Spanner::ANCHOR_SEGMENT: {
|
|
|
|
if (s->startElement()) {
|
|
|
|
Segment* seg = static_cast<Segment*>(s->startElement());
|
|
|
|
seg->removeSpannerFor(s);
|
|
|
|
}
|
|
|
|
if (s->endElement()) {
|
|
|
|
Segment* seg = static_cast<Segment*>(s->endElement());
|
|
|
|
seg->removeSpannerBack(s);
|
|
|
|
}
|
|
|
|
Segment* seg = static_cast<Segment*>(s->parent());
|
|
|
|
if (seg->isEmpty())
|
|
|
|
seg->measure()->remove(seg);
|
|
|
|
delete s;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Spanner::ANCHOR_CHORD:
|
|
|
|
if (s->startElement()) {
|
|
|
|
ChordRest* cr = static_cast<ChordRest*>(s->startElement());
|
|
|
|
cr->removeSpannerFor(s);
|
|
|
|
}
|
|
|
|
if (s->endElement()) {
|
|
|
|
ChordRest* cr = static_cast<ChordRest*>(s->endElement());
|
|
|
|
cr->removeSpannerBack(s);
|
|
|
|
}
|
2013-02-12 09:57:37 +01:00
|
|
|
e.removeSpanner(s);
|
2012-12-10 14:00:17 +01:00
|
|
|
delete s;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Spanner::ANCHOR_NOTE:
|
|
|
|
case Spanner::ANCHOR_MEASURE:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2012-09-13 18:01:34 +02:00
|
|
|
if (s->type() != Element::SLUR)
|
2012-05-26 14:26:10 +02:00
|
|
|
continue;
|
2012-12-10 14:00:17 +01:00
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
Slur* slur = static_cast<Slur*>(s);
|
|
|
|
|
2012-12-10 14:00:17 +01:00
|
|
|
ChordRest* cr1 = (ChordRest*)(slur->startElement());
|
|
|
|
ChordRest* cr2 = (ChordRest*)(slur->endElement());
|
|
|
|
if (cr1->tick() > cr2->tick()) {
|
|
|
|
qDebug("Slur invalid start-end tick %d-%d\n", cr1->tick(), cr2->tick());
|
|
|
|
slur->setStartElement(cr2);
|
|
|
|
slur->setEndElement(cr1);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2013-01-03 16:56:56 +01:00
|
|
|
#if 1 // DEBUG
|
2012-12-10 14:00:17 +01:00
|
|
|
int n1 = 0;
|
|
|
|
int n2 = 0;
|
2013-01-03 16:56:56 +01:00
|
|
|
for (Spanner* s = cr1->spannerFor(); s; s = s->next()) {
|
2012-12-10 14:00:17 +01:00
|
|
|
if (s == slur)
|
|
|
|
++n1;
|
|
|
|
}
|
2013-01-03 16:56:56 +01:00
|
|
|
for (Spanner* s = cr2->spannerBack(); s; s = s->next()) {
|
2012-12-10 14:00:17 +01:00
|
|
|
if (s == slur)
|
|
|
|
++n2;
|
|
|
|
}
|
2013-01-03 16:56:56 +01:00
|
|
|
if (n1 != 1 || n2 != 1)
|
|
|
|
qDebug("Slur references bad: %d %d", n1, n2);
|
|
|
|
#endif
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
connectTies();
|
|
|
|
|
|
|
|
searchSelectedElements();
|
|
|
|
|
|
|
|
_fileDivision = MScore::division;
|
|
|
|
|
|
|
|
//
|
|
|
|
// sanity check for barLineSpan
|
|
|
|
//
|
2012-10-20 20:32:40 +02:00
|
|
|
foreach(Staff* st, _staves) {
|
|
|
|
int barLineSpan = st->barLineSpan();
|
|
|
|
int idx = staffIdx(st);
|
2012-05-26 14:26:10 +02:00
|
|
|
int n = nstaves();
|
|
|
|
if (idx + barLineSpan > n) {
|
|
|
|
qDebug("bad span: idx %d span %d staves %d\n", idx, barLineSpan, n);
|
2012-10-20 20:32:40 +02:00
|
|
|
st->setBarLineSpan(n - idx);
|
|
|
|
}
|
|
|
|
// check spanFrom
|
|
|
|
if(st->barLineFrom() < MIN_BARLINE_SPAN_FROMTO)
|
|
|
|
st->setBarLineFrom(MIN_BARLINE_SPAN_FROMTO);
|
|
|
|
if(st->barLineFrom() > st->lines()*2)
|
|
|
|
st->setBarLineFrom(st->lines()*2);
|
|
|
|
// check spanTo
|
|
|
|
Staff* stTo = st->barLineSpan() <= 1 ? st : staff(idx + st->barLineSpan() - 1);
|
2012-12-10 12:56:54 +01:00
|
|
|
// 1-line staves have special bar line spans
|
|
|
|
int maxBarLineTo = stTo->lines() == 1 ? BARLINE_SPAN_1LINESTAFF_TO : stTo->lines()*2;
|
|
|
|
int defaultBarLineTo = stTo->lines() == 1 ? BARLINE_SPAN_1LINESTAFF_TO : (stTo->lines() - 1) * 2;
|
2012-10-20 20:32:40 +02:00
|
|
|
if(st->barLineTo() == UNKNOWN_BARLINE_TO)
|
|
|
|
st->setBarLineTo(defaultBarLineTo);
|
|
|
|
if(st->barLineTo() < MIN_BARLINE_SPAN_FROMTO)
|
|
|
|
st->setBarLineTo(MIN_BARLINE_SPAN_FROMTO);
|
|
|
|
if(st->barLineTo() > maxBarLineTo)
|
|
|
|
st->setBarLineTo(maxBarLineTo);
|
|
|
|
// on single staff span, check spanFrom and spanTo are distant enough
|
|
|
|
if(st->barLineSpan() == 1) {
|
|
|
|
if(st->barLineTo() - st->barLineFrom() < MIN_BARLINE_FROMTO_DIST) {
|
|
|
|
st->setBarLineFrom(0);
|
|
|
|
st->setBarLineTo(defaultBarLineTo);
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_omr == 0)
|
|
|
|
_showOmr = false;
|
|
|
|
|
|
|
|
//
|
|
|
|
// check for soundfont,
|
|
|
|
// add default soundfont if none found
|
|
|
|
// (for compatibility with old scores)
|
|
|
|
//
|
|
|
|
bool hasSoundfont = false;
|
|
|
|
foreach(const SyntiParameter& sp, _syntiState) {
|
|
|
|
if (sp.name() == "soundfont") {
|
|
|
|
QFileInfo fi(sp.sval());
|
|
|
|
if(fi.exists())
|
|
|
|
hasSoundfont = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!hasSoundfont)
|
|
|
|
_syntiState.append(SyntiParameter("soundfont", MScore::soundFont));
|
|
|
|
|
|
|
|
fixTicks();
|
|
|
|
renumberMeasures();
|
|
|
|
rebuildMidiMapping();
|
|
|
|
updateChannel();
|
|
|
|
updateNotes(); // only for parts needed?
|
2012-11-19 09:29:46 +01:00
|
|
|
createPlayEvents();
|
2012-05-26 14:26:10 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// print
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::print(QPainter* painter, int pageNo)
|
|
|
|
{
|
|
|
|
_printing = true;
|
|
|
|
Page* page = pages().at(pageNo);
|
|
|
|
QRectF fr = page->abbox();
|
|
|
|
|
|
|
|
QList<const Element*> ell = page->items(fr);
|
|
|
|
qStableSort(ell.begin(), ell.end(), elementLessThan);
|
|
|
|
foreach(const Element* e, ell) {
|
|
|
|
e->itemDiscovered = 0;
|
|
|
|
if (!e->visible())
|
|
|
|
continue;
|
|
|
|
painter->save();
|
|
|
|
painter->translate(e->pagePos());
|
|
|
|
e->draw(painter);
|
|
|
|
painter->restore();
|
|
|
|
}
|
|
|
|
_printing = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// readCompressedToBuffer
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
QByteArray Score::readCompressedToBuffer()
|
|
|
|
{
|
2012-06-04 21:06:12 +02:00
|
|
|
QZipReader uz(filePath());
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2012-06-04 21:06:12 +02:00
|
|
|
QByteArray cbuf = uz.fileData("META-INF/container.xml");
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2013-01-11 18:10:18 +01:00
|
|
|
XmlReader e(cbuf);
|
|
|
|
QString rootfile;
|
2012-05-26 14:26:10 +02:00
|
|
|
QList<QString> images;
|
2013-01-11 18:10:18 +01:00
|
|
|
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
if (e.name() != "container") {
|
|
|
|
e.unknown();
|
2012-05-26 14:26:10 +02:00
|
|
|
continue;
|
|
|
|
}
|
2013-01-11 18:10:18 +01:00
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
if (e.name() != "rootfiles") {
|
|
|
|
e.unknown();
|
2012-05-26 14:26:10 +02:00
|
|
|
continue;
|
|
|
|
}
|
2013-01-11 18:10:18 +01:00
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
const QStringRef& tag(e.name());
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
if (tag == "rootfile") {
|
|
|
|
if (rootfile.isEmpty())
|
2013-01-11 18:10:18 +01:00
|
|
|
rootfile = e.attribute("full-path");
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
else if (tag == "file")
|
2013-01-11 18:10:18 +01:00
|
|
|
images.append(e.readElementText());
|
2012-05-26 14:26:10 +02:00
|
|
|
else
|
2013-01-11 18:10:18 +01:00
|
|
|
e.unknown();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// load images
|
|
|
|
//
|
|
|
|
foreach(const QString& s, images) {
|
2012-06-04 21:06:12 +02:00
|
|
|
QByteArray dbuf = uz.fileData(s);
|
|
|
|
imageStore.add(s, dbuf);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (rootfile.isEmpty()) {
|
|
|
|
qDebug("can't find rootfile in: %s\n", qPrintable(filePath()));
|
|
|
|
return QByteArray();
|
|
|
|
}
|
2012-06-04 21:06:12 +02:00
|
|
|
return uz.fileData(rootfile);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// readToBuffer
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
QByteArray Score::readToBuffer()
|
|
|
|
{
|
|
|
|
QByteArray ba;
|
|
|
|
QString cs = info.suffix();
|
|
|
|
|
|
|
|
if (cs == "mscz") {
|
|
|
|
ba = readCompressedToBuffer();
|
|
|
|
}
|
|
|
|
if (cs.toLower() == "msc" || cs.toLower() == "mscx") {
|
|
|
|
QFile f(filePath());
|
|
|
|
if (f.open(QIODevice::ReadOnly)) {
|
|
|
|
ba = f.readAll();
|
|
|
|
f.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ba;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// createRevision
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::createRevision()
|
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
qDebug("createRevision\n");
|
|
|
|
QBuffer dbuf;
|
|
|
|
dbuf.open(QIODevice::ReadWrite);
|
|
|
|
saveFile(&dbuf, false, false);
|
|
|
|
dbuf.close();
|
|
|
|
|
|
|
|
QByteArray ba1 = readToBuffer();
|
|
|
|
|
|
|
|
QString os = QString::fromUtf8(ba1.data(), ba1.size());
|
|
|
|
QString ns = QString::fromUtf8(dbuf.buffer().data(), dbuf.buffer().size());
|
|
|
|
|
|
|
|
diff_match_patch dmp;
|
|
|
|
Revision* r = new Revision();
|
|
|
|
r->setDiff(dmp.patch_toText(dmp.patch_make(ns, os)));
|
|
|
|
r->setId("1");
|
|
|
|
_revisions->add(r);
|
|
|
|
|
|
|
|
// qDebug("patch:\n%s\n==========\n", qPrintable(patch));
|
|
|
|
//
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// writeSegments
|
2013-01-07 15:39:28 +01:00
|
|
|
// ls - write upto this segment (excluding)
|
|
|
|
// can be zero
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2012-08-09 12:12:43 +02:00
|
|
|
void Score::writeSegments(Xml& xml, const Measure* m, int strack, int etrack,
|
2013-01-07 15:39:28 +01:00
|
|
|
Segment* fs, Segment* ls, bool writeSystemElements)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
for (int track = strack; track < etrack; ++track) {
|
|
|
|
for (Segment* segment = fs; segment && segment != ls; segment = segment->next1()) {
|
|
|
|
if (track == 0)
|
|
|
|
segment->setWritten(false);
|
|
|
|
Element* e = segment->element(track);
|
|
|
|
//
|
|
|
|
// special case: - barline span > 1
|
|
|
|
// - part (excerpt) staff starts after
|
|
|
|
// barline element
|
|
|
|
bool needTick = segment->tick() != xml.curTick;
|
2013-03-05 20:23:59 +01:00
|
|
|
if ((segment->segmentType() == Segment::SegEndBarLine)
|
2012-05-26 14:26:10 +02:00
|
|
|
&& (e == 0)
|
|
|
|
&& writeSystemElements
|
|
|
|
&& ((track % VOICES) == 0)) {
|
|
|
|
// search barline:
|
|
|
|
for (int idx = track - VOICES; idx >= 0; idx -= VOICES) {
|
|
|
|
if (segment->element(idx)) {
|
|
|
|
int oDiff = xml.trackDiff;
|
|
|
|
xml.trackDiff = idx; // staffIdx should be zero
|
|
|
|
segment->element(idx)->write(xml);
|
|
|
|
xml.trackDiff = oDiff;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
foreach (Element* e, segment->annotations()) {
|
|
|
|
if (e->track() != track || e->generated())
|
|
|
|
continue;
|
|
|
|
if (needTick) {
|
|
|
|
xml.tag("tick", segment->tick() - xml.tickDiff);
|
|
|
|
xml.curTick = segment->tick();
|
|
|
|
needTick = false;
|
|
|
|
}
|
|
|
|
e->write(xml);
|
|
|
|
}
|
2013-01-03 16:56:56 +01:00
|
|
|
for (Spanner* e = segment->spannerFor(); e; e = e->next()) {
|
2012-05-26 14:26:10 +02:00
|
|
|
if (e->track() == track && !e->generated()) {
|
|
|
|
if (needTick) {
|
|
|
|
xml.tag("tick", segment->tick() - xml.tickDiff);
|
|
|
|
xml.curTick = segment->tick();
|
|
|
|
needTick = false;
|
|
|
|
}
|
|
|
|
e->setId(++xml.spannerId);
|
|
|
|
e->write(xml);
|
|
|
|
}
|
|
|
|
}
|
2013-01-03 16:56:56 +01:00
|
|
|
for (Spanner* e = segment->spannerBack(); e; e = e->next()) {
|
2012-05-26 14:26:10 +02:00
|
|
|
if (e->track() == track && !e->generated()) {
|
|
|
|
if (needTick) {
|
|
|
|
xml.tag("tick", segment->tick() - xml.tickDiff);
|
|
|
|
xml.curTick = segment->tick();
|
|
|
|
needTick = false;
|
|
|
|
}
|
2013-01-24 14:38:35 +01:00
|
|
|
Q_ASSERT(e->id() != -1);
|
2012-05-26 14:26:10 +02:00
|
|
|
xml.tagE(QString("endSpanner id=\"%1\"").arg(e->id()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!e)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (e->generated()) {
|
|
|
|
if ((xml.curTick - xml.tickDiff) == 0) {
|
2012-09-13 18:01:34 +02:00
|
|
|
if (e->type() == Element::CLEF) {
|
2012-05-26 14:26:10 +02:00
|
|
|
if (needTick) {
|
|
|
|
xml.tag("tick", segment->tick() - xml.tickDiff);
|
|
|
|
xml.curTick = segment->tick();
|
|
|
|
needTick = false;
|
|
|
|
}
|
|
|
|
e->write(xml);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (needTick) {
|
|
|
|
xml.tag("tick", segment->tick() - xml.tickDiff);
|
|
|
|
xml.curTick = segment->tick();
|
|
|
|
needTick = false;
|
|
|
|
}
|
|
|
|
if (e->isChordRest()) {
|
|
|
|
ChordRest* cr = static_cast<ChordRest*>(e);
|
|
|
|
Beam* beam = cr->beam();
|
|
|
|
#ifndef NDEBUG
|
|
|
|
if (beam && beam->elements().front() == cr && (testMode() || !beam->generated())) {
|
|
|
|
beam->setId(xml.beamId++);
|
|
|
|
beam->write(xml);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if (beam && !beam->generated() && beam->elements().front() == cr) {
|
|
|
|
beam->setId(xml.beamId++);
|
|
|
|
beam->write(xml);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
cr->writeTuplet(xml);
|
2013-01-03 16:56:56 +01:00
|
|
|
for (Spanner* slur = cr->spannerFor(); slur; slur = slur->next()) {
|
2013-01-21 20:21:41 +01:00
|
|
|
if (!xml.spanner().contains(slur)) {
|
2013-01-07 15:39:28 +01:00
|
|
|
Q_ASSERT(slur->type() == Element::SLUR);
|
|
|
|
slur->setId(xml.spannerId++);
|
|
|
|
slur->write(xml);
|
2013-01-21 20:21:41 +01:00
|
|
|
xml.addSpanner(slur);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
2013-01-03 16:56:56 +01:00
|
|
|
for (Spanner* slur = cr->spannerBack(); slur; slur = slur->next()) {
|
2013-01-21 20:21:41 +01:00
|
|
|
if (!xml.spanner().contains(slur)) {
|
2013-01-07 15:39:28 +01:00
|
|
|
Q_ASSERT(slur->type() == Element::SLUR);
|
|
|
|
slur->setId(xml.spannerId++);
|
|
|
|
slur->write(xml);
|
2013-01-21 20:21:41 +01:00
|
|
|
xml.addSpanner(slur);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-03-05 20:23:59 +01:00
|
|
|
if ((segment->segmentType() == Segment::SegEndBarLine) && m && (m->multiMeasure() > 0)) {
|
2012-05-26 14:26:10 +02:00
|
|
|
xml.stag("BarLine");
|
|
|
|
xml.tag("subtype", m->endBarLineType());
|
|
|
|
xml.tag("visible", m->endBarLineVisible());
|
|
|
|
xml.etag();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
e->write(xml);
|
|
|
|
segment->write(xml); // write only once
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// searchTuplet
|
|
|
|
// search complete Dom for tuplet id
|
2013-01-17 14:55:04 +01:00
|
|
|
// last resort in case of error
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2013-01-11 18:10:18 +01:00
|
|
|
Tuplet* Score::searchTuplet(XmlReader& /*e*/, int /*id*/)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2013-01-11 18:10:18 +01:00
|
|
|
#if 0 // TODOx
|
2012-05-26 14:26:10 +02:00
|
|
|
QDomElement e = de;
|
|
|
|
QDomDocument doc = e.ownerDocument();
|
|
|
|
|
|
|
|
QString tag;
|
|
|
|
for (e = doc.documentElement(); !e.isNull(); e = e.nextSiblingElement()) {
|
|
|
|
tag = e.tagName();
|
|
|
|
if (tag == "museScore")
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (tag != "museScore") {
|
|
|
|
qDebug("Score::searchTuplet(): no museScore found");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (e = e.firstChildElement(); !e.isNull(); e = e.nextSiblingElement()) {
|
|
|
|
tag = e.tagName();
|
|
|
|
if (tag == "Score" || tag == "Part")
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (tag != "Score" && tag != "Part") {
|
|
|
|
qDebug("Score::searchTuplet(): no Score/Part found");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (tag == "Score")
|
|
|
|
e = e.firstChildElement();
|
|
|
|
else
|
|
|
|
e = e.nextSiblingElement();
|
|
|
|
for (; !e.isNull(); e = e.nextSiblingElement()) {
|
|
|
|
if (e.tagName() == "Staff") {
|
|
|
|
for (QDomElement ee = e.firstChildElement(); !ee.isNull(); ee = ee.nextSiblingElement()) {
|
|
|
|
if (ee.tagName() == "Measure") {
|
|
|
|
for (QDomElement eee = ee.firstChildElement(); !eee.isNull(); eee = eee.nextSiblingElement()) {
|
|
|
|
if (eee.tagName() == "Tuplet") {
|
|
|
|
Tuplet* tuplet = new Tuplet(this);
|
|
|
|
QList<Spanner*> spannerList;
|
|
|
|
QList<Tuplet*> tuplets;
|
2013-01-08 11:00:53 +01:00
|
|
|
tuplet->read(eee);
|
2012-05-26 14:26:10 +02:00
|
|
|
if (tuplet->id() == id)
|
|
|
|
return tuplet;
|
|
|
|
delete tuplet;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-01-11 18:10:18 +01:00
|
|
|
#endif
|
2012-05-26 14:26:10 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|