Image external path written in score file on saving and given precedence over ImageStore data on loading.
This commit is contained in:
parent
53f6f8de09
commit
1683b6aa64
3 changed files with 140 additions and 64 deletions
|
@ -22,9 +22,9 @@
|
|||
// propertyList
|
||||
//---------------------------------------------------------
|
||||
|
||||
static bool defaultAutoScale = false;
|
||||
static bool defaultLockAspectRatio = true;
|
||||
static bool defaultSizeIsSpatium = true;
|
||||
static bool defaultAutoScale = false;
|
||||
static bool defaultLockAspectRatio = true;
|
||||
static bool defaultSizeIsSpatium = true;
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Image
|
||||
|
@ -40,6 +40,7 @@ Image::Image(Score* s)
|
|||
_autoScale = defaultAutoScale;
|
||||
_sizeIsSpatium = defaultSizeIsSpatium;
|
||||
setZ(IMAGE * 100);
|
||||
_linkIsValid = false;
|
||||
}
|
||||
|
||||
Image::Image(const Image& img)
|
||||
|
@ -53,6 +54,7 @@ Image::Image(const Image& img)
|
|||
_storeItem = img._storeItem;
|
||||
_sizeIsSpatium = img._sizeIsSpatium;
|
||||
_storeItem->reference(this);
|
||||
_linkIsValid = img._linkIsValid;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
|
@ -171,11 +173,11 @@ bool Image::setProperty(P_ID propertyId, const QVariant& v)
|
|||
QVariant Image::propertyDefault(P_ID id) const
|
||||
{
|
||||
switch(id) {
|
||||
case P_AUTOSCALE: return defaultAutoScale;
|
||||
case P_SIZE: break;
|
||||
case P_LOCK_ASPECT_RATIO: return defaultLockAspectRatio;
|
||||
case P_SIZE_IS_SPATIUM: return defaultSizeIsSpatium;
|
||||
default: return Element::propertyDefault(id);
|
||||
case P_AUTOSCALE: return defaultAutoScale;
|
||||
case P_SIZE: break;
|
||||
case P_LOCK_ASPECT_RATIO: return defaultLockAspectRatio;
|
||||
case P_SIZE_IS_SPATIUM: return defaultSizeIsSpatium;
|
||||
default: return Element::propertyDefault(id);
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
@ -237,9 +239,54 @@ void Image::write(Xml& xml, P_ID id) const
|
|||
|
||||
void Image::write(Xml& xml) const
|
||||
{
|
||||
// attempt to convert the _linkPath to a path relative to the score
|
||||
//
|
||||
// TODO : on Save As, _score->fileInfo() still contains the old path and fname
|
||||
// if the Save As path is different, image relative path will be wrong!
|
||||
//
|
||||
QString relativeFilePath= QString();
|
||||
if(!_linkPath.isEmpty() && _linkIsValid) {
|
||||
QFileInfo fi(_linkPath);
|
||||
// _score->fileInfo()->canonicalPath() would be better
|
||||
// but we are saving under a temp file name and the 'final' file
|
||||
// might not exist yet, so canonicalFilePath() may return only "/"
|
||||
// OTOH, the score 'final' file name is practically always canonical, at this point
|
||||
QString scorePath = _score->fileInfo()->absolutePath();
|
||||
QString imgFPath = fi.canonicalFilePath();
|
||||
// if imgFPath is in (or below) the directory of scorePath
|
||||
if(imgFPath.startsWith(scorePath, Qt::CaseSensitive)) {
|
||||
// relative img path is the part exceeding scorePath
|
||||
imgFPath.remove(0, scorePath.size());
|
||||
if(imgFPath.startsWith('/'))
|
||||
imgFPath.remove(0, 1);
|
||||
relativeFilePath = imgFPath;
|
||||
}
|
||||
// try 1 level up
|
||||
else {
|
||||
// reduce scorePath by one path level
|
||||
fi.setFile(scorePath);
|
||||
scorePath = fi.path();
|
||||
// if imgFPath is in (or below) the directory up the score directory
|
||||
if(imgFPath.startsWith(scorePath, Qt::CaseSensitive)) {
|
||||
// relative img path is the part exceeding new scorePath plus "../"
|
||||
imgFPath.remove(0, scorePath.size());
|
||||
if(!imgFPath.startsWith('/'))
|
||||
imgFPath.prepend('/');
|
||||
imgFPath.prepend("..");
|
||||
relativeFilePath = imgFPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
// if no match, use full _linkPath
|
||||
if(relativeFilePath.isEmpty())
|
||||
relativeFilePath = _linkPath;
|
||||
|
||||
xml.stag("Image");
|
||||
Element::writeProperties(xml);
|
||||
xml.tag("path", _storeItem ? _storeItem->hashName() : _path);
|
||||
// keep old "path" tag, for backward compatibility and because it is used elsewhere
|
||||
// (for instance by Box:read(), Measure:read(), Note:read(), ...)
|
||||
xml.tag("path", _storeItem ? _storeItem->hashName() : relativeFilePath);
|
||||
xml.tag("linkPath", relativeFilePath);
|
||||
|
||||
write(xml, P_AUTOSCALE);
|
||||
write(xml, P_SIZE);
|
||||
|
@ -268,17 +315,25 @@ void Image::read(const QDomElement& de)
|
|||
setProperty(P_LOCK_ASPECT_RATIO, ::getProperty(P_LOCK_ASPECT_RATIO, e));
|
||||
else if (tag == "sizeIsSpatium")
|
||||
setProperty(P_SIZE_IS_SPATIUM, ::getProperty(P_SIZE_IS_SPATIUM, e));
|
||||
else if (tag == "path") {
|
||||
_path = e.text();
|
||||
_storeItem = imageStore.getImage(_path);
|
||||
if (_storeItem)
|
||||
_storeItem->reference(this);
|
||||
else
|
||||
load(_path);
|
||||
}
|
||||
else if (tag == "path")
|
||||
_storePath = e.text();
|
||||
else if(tag == "linkPath")
|
||||
_linkPath = e.text();
|
||||
else if (!Element::readProperties(e))
|
||||
domError(e);
|
||||
}
|
||||
|
||||
// once all paths are read, load img or retrieve it from store
|
||||
// loading from file is tried first to update the stored image, if necessary
|
||||
if(_linkPath.isEmpty() || !load(_linkPath)) {
|
||||
// if could not load img from _linkPath, retrieve from store
|
||||
_storeItem = imageStore.getImage(_storePath);
|
||||
if (_storeItem)
|
||||
_storeItem->reference(this);
|
||||
// if not in store, try to load from _storePath for backward compatibility
|
||||
else
|
||||
load(_storePath);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
|
@ -289,12 +344,24 @@ void Image::read(const QDomElement& de)
|
|||
|
||||
bool Image::load(const QString& ss)
|
||||
{
|
||||
QFile f(ss);
|
||||
QString path(ss);
|
||||
// if file path is relative, prepend score path
|
||||
QFileInfo fi(path);
|
||||
if(fi.isRelative()) {
|
||||
path.prepend(_score->fileInfo()->absolutePath() + "/");
|
||||
fi.setFile(path);
|
||||
}
|
||||
|
||||
_linkIsValid = false; // assume link fname is invalid
|
||||
QFile f(path);
|
||||
if (!f.open(QIODevice::ReadOnly))
|
||||
return false;
|
||||
QByteArray ba = f.readAll();
|
||||
f.close();
|
||||
_storeItem = imageStore.add(ss, ba);
|
||||
|
||||
_linkIsValid = true;
|
||||
_linkPath = fi.canonicalFilePath();
|
||||
_storeItem = imageStore.add(_linkPath, ba);
|
||||
_storeItem->reference(this);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -29,7 +29,10 @@ class Image : public BSymbol {
|
|||
|
||||
protected:
|
||||
ImageStoreItem* _storeItem;
|
||||
QString _path;
|
||||
// QString _path;
|
||||
QString _storePath; // the path of the img in the ImageStore
|
||||
QString _linkPath; // the path of an external linked img
|
||||
bool _linkIsValid; // whether _linkPath file exists or not
|
||||
mutable QPixmap buffer; ///< cached rendering
|
||||
QSizeF _size; // in mm or spatium units
|
||||
bool _lockAspectRatio;
|
||||
|
|
|
@ -468,7 +468,7 @@ void MuseScore::newFile()
|
|||
continue;
|
||||
Measure* measure = static_cast<Measure*>(mb);
|
||||
int ticks = measure->ticks();
|
||||
for (int staffIdx = 0; staffIdx < score->nstaves(); ++staffIdx) {
|
||||
for (int staffIdx = 0; staffIdx < score->nstaves(); ++staffIdx) {
|
||||
Staff* staff = score->staff(staffIdx);
|
||||
if (tick == 0) {
|
||||
if (!staff->useTablature()) {
|
||||
|
@ -503,21 +503,21 @@ void MuseScore::newFile()
|
|||
QList<TDuration> dList = toDurationList(measure->len(), false);
|
||||
if (!dList.isEmpty()) {
|
||||
foreach(TDuration d, dList) {
|
||||
Rest* rest = new Rest(score, d);
|
||||
Rest* rest = new Rest(score, d);
|
||||
rest->setDuration(d.fraction());
|
||||
rest->setTrack(staffIdx * VOICES);
|
||||
Segment* s = measure->getSegment(rest, tick);
|
||||
s->add(rest);
|
||||
rest->setTrack(staffIdx * VOICES);
|
||||
Segment* s = measure->getSegment(rest, tick);
|
||||
s->add(rest);
|
||||
tick += rest->actualTicks();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
Rest* rest = new Rest(score, TDuration(TDuration::V_MEASURE));
|
||||
Rest* rest = new Rest(score, TDuration(TDuration::V_MEASURE));
|
||||
rest->setDuration(measure->len());
|
||||
rest->setTrack(staffIdx * VOICES);
|
||||
Segment* s = measure->getSegment(rest, tick);
|
||||
s->add(rest);
|
||||
rest->setTrack(staffIdx * VOICES);
|
||||
Segment* s = measure->getSegment(rest, tick);
|
||||
s->add(rest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -672,24 +672,24 @@ QString MuseScore::getSaveScoreName(const QString& title,
|
|||
QString& name, const QString& filter, QString* selectedFilter, bool selectFolder)
|
||||
{
|
||||
if (preferences.nativeDialogs) {
|
||||
if (!selectFolder) {
|
||||
QString fn = QFileDialog::getSaveFileName(this,
|
||||
title,
|
||||
name,
|
||||
filter,
|
||||
selectedFilter
|
||||
);
|
||||
return fn;
|
||||
if (!selectFolder) {
|
||||
QString fn = QFileDialog::getSaveFileName(this,
|
||||
title,
|
||||
name,
|
||||
filter,
|
||||
selectedFilter
|
||||
);
|
||||
return fn;
|
||||
} else {
|
||||
QString fn = QFileDialog::getSaveFileName(this,
|
||||
title,
|
||||
name,
|
||||
filter,
|
||||
selectedFilter,
|
||||
QFileDialog::ShowDirsOnly
|
||||
);
|
||||
return fn;
|
||||
}
|
||||
QString fn = QFileDialog::getSaveFileName(this,
|
||||
title,
|
||||
name,
|
||||
filter,
|
||||
selectedFilter,
|
||||
QFileDialog::ShowDirsOnly
|
||||
);
|
||||
return fn;
|
||||
}
|
||||
}
|
||||
|
||||
QFileInfo myScores(preferences.myScoresPath);
|
||||
|
@ -1513,21 +1513,21 @@ bool MuseScore::exportParts()
|
|||
|
||||
QSettings settings;
|
||||
if (lastSaveCopyDirectory.isEmpty())
|
||||
lastSaveCopyDirectory = settings.value("lastSaveCopyDirectory", preferences.myScoresPath).toString();
|
||||
lastSaveCopyDirectory = settings.value("lastSaveCopyDirectory", preferences.myScoresPath).toString();
|
||||
if (lastSaveDirectory.isEmpty())
|
||||
lastSaveDirectory = settings.value("lastSaveDirectory", preferences.myScoresPath).toString();
|
||||
lastSaveDirectory = settings.value("lastSaveDirectory", preferences.myScoresPath).toString();
|
||||
QString saveDirectory = lastSaveCopyDirectory;
|
||||
|
||||
if (saveDirectory.isEmpty()) {
|
||||
saveDirectory = preferences.myScoresPath;
|
||||
}
|
||||
saveDirectory = preferences.myScoresPath;
|
||||
}
|
||||
|
||||
QString selectedFilter;
|
||||
QString name = QString("");
|
||||
QString filter = fl.join(";;");
|
||||
QString fn = getSaveScoreName(saveDialogTitle, name, filter, &selectedFilter, true);
|
||||
if (fn.isEmpty())
|
||||
return false;
|
||||
return false;
|
||||
|
||||
lastSaveCopyDirectory = fn;
|
||||
|
||||
|
@ -1536,25 +1536,25 @@ bool MuseScore::exportParts()
|
|||
thisScore = thisScore->parentScore();
|
||||
|
||||
foreach(Excerpt* e, thisScore->excerpts()) {
|
||||
Score* pScore = e->score();
|
||||
Score* pScore = e->score();
|
||||
QString partfn = fn + QDir::separator() + thisScore->name() + "-" + pScore->name();
|
||||
QFileInfo fi(partfn);
|
||||
QString ext;
|
||||
QFileInfo fi(partfn);
|
||||
QString ext;
|
||||
if (selectedFilter.isEmpty())
|
||||
ext = fi.suffix();
|
||||
ext = fi.suffix();
|
||||
else {
|
||||
int idx = fl.indexOf(selectedFilter);
|
||||
if (idx != -1) {
|
||||
static const char* extensions[] = {
|
||||
"mscx", "xml", "mxl", "mid", "pdf", "ps", "png", "svg", "ly",
|
||||
int idx = fl.indexOf(selectedFilter);
|
||||
if (idx != -1) {
|
||||
static const char* extensions[] = {
|
||||
"mscx", "xml", "mxl", "mid", "pdf", "ps", "png", "svg", "ly",
|
||||
#ifdef HAS_AUDIOFILE
|
||||
"wav", "flac", "ogg",
|
||||
"wav", "flac", "ogg",
|
||||
#endif
|
||||
"mp3"
|
||||
};
|
||||
"mp3"
|
||||
};
|
||||
ext = extensions[idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ext.isEmpty()) {
|
||||
QMessageBox::critical(this, tr("MuseScore: Export Parts"), tr("cannot determine file type"));
|
||||
return false;
|
||||
|
@ -1587,6 +1587,10 @@ bool MuseScore::saveAs(Score* cs, bool saveCopy, const QString& path, const QStr
|
|||
// save as mscore *.msc[xz] file
|
||||
QFileInfo fi(fn);
|
||||
rv = true;
|
||||
// store new file and path into score fileInfo
|
||||
// to have it accessible to resources
|
||||
QString originalScoreFName(cs->absoluteFilePath());
|
||||
cs->fileInfo()->setFile(fn);
|
||||
try {
|
||||
if (ext == "mscz")
|
||||
cs->saveCompressedFile(fi, false);
|
||||
|
@ -1597,6 +1601,8 @@ bool MuseScore::saveAs(Score* cs, bool saveCopy, const QString& path, const QStr
|
|||
rv = false;
|
||||
QMessageBox::critical(this, tr("MuseScore: Save As"), s);
|
||||
}
|
||||
cs->fileInfo()->setFile(originalScoreFName); // restore original file name
|
||||
|
||||
if (rv && !saveCopy) {
|
||||
cs->fileInfo()->setFile(fn);
|
||||
setWindowTitle("MuseScore: " + cs->name());
|
||||
|
|
Loading…
Reference in a new issue