//============================================================================= // MuseScore // Linux Music Score Editor // // Copyright (C) 2011 Werner Schweer and others // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. //============================================================================= #include "workspace.h" #include "musescore.h" #include "libmscore/score.h" #include "libmscore/imageStore.h" #include "libmscore/xml.h" #include "thirdparty/qzip/qzipreader_p.h" #include "thirdparty/qzip/qzipwriter_p.h" #include "preferences.h" #include "palette.h" #include "palettebox.h" namespace Ms { bool Workspace::workspacesRead = false; Workspace* Workspace::currentWorkspace; Workspace Workspace::_advancedWorkspace { QT_TR_NOOP("Advanced"), QString("Advanced"), false, true }; Workspace Workspace::_basicWorkspace { QT_TR_NOOP("Basic"), QString("Basic"), false, true }; QList Workspace::_workspaces { &_basicWorkspace, &_advancedWorkspace }; //--------------------------------------------------------- // undoWorkspace //--------------------------------------------------------- void MuseScore::undoWorkspace() { Workspace::currentWorkspace->read(); Workspace::currentWorkspace->setDirty(false); } //--------------------------------------------------------- // showWorkspaceMenu //--------------------------------------------------------- void MuseScore::showWorkspaceMenu() { if (workspaces == 0) { workspaces = new QActionGroup(this); workspaces->setExclusive(true); connect(workspaces, SIGNAL(triggered(QAction*)), SLOT(changeWorkspace(QAction*))); } else { foreach(QAction* a, workspaces->actions()) workspaces->removeAction(a); } menuWorkspaces->clear(); const QList pl = Workspace::workspaces(); foreach (Workspace* p, pl) { QAction* a = workspaces->addAction(qApp->translate("Ms::Workspace", p->name().toUtf8())); a->setCheckable(true); a->setData(p->path()); a->setChecked(p->name() == preferences.workspace); menuWorkspaces->addAction(a); } menuWorkspaces->addSeparator(); QAction* a = new QAction(tr("New..."), this); connect(a, SIGNAL(triggered()), SLOT(createNewWorkspace())); menuWorkspaces->addAction(a); a = new QAction(tr("Delete"), this); a->setDisabled(Workspace::currentWorkspace->readOnly()); connect(a, SIGNAL(triggered()), SLOT(deleteWorkspace())); menuWorkspaces->addAction(a); a = new QAction(tr("Undo Changes"), this); a->setDisabled(Workspace::currentWorkspace->readOnly()); connect(a, SIGNAL(triggered()), SLOT(undoWorkspace())); menuWorkspaces->addAction(a); } //--------------------------------------------------------- // createNewWorkspace //--------------------------------------------------------- void MuseScore::createNewWorkspace() { QString s = QInputDialog::getText(this, tr("MuseScore: Read Workspace Name"), tr("Workspace name:")); if (s.isEmpty()) return; s = s.replace( QRegExp( "[" + QRegExp::escape( "\\/:*?\"<>|" ) + "]" ), "_" ); //FAT/NTFS special chars for (;;) { bool notFound = true; foreach(Workspace* p, Workspace::workspaces()) { if ((qApp->translate("Ms::Workspace", p->name().toUtf8()).toLower() == s.toLower()) || (s.toLower() == QString("basic")) || (s.toLower() == QString("advanced"))) { notFound = false; break; } } if (!notFound) { s = QInputDialog::getText(this, tr("MuseScore: Read Workspace Name"), tr("'%1' does already exist,\nplease choose a different name:").arg(s) ); if (s.isEmpty()) return; s = s.replace( QRegExp( "[" + QRegExp::escape( "\\/:*?\"<>|" ) + "]" ), "_" ); //FAT/NTFS special chars } else break; } if (Workspace::currentWorkspace->dirty()) Workspace::currentWorkspace->save(); Workspace::currentWorkspace = Workspace::createNewWorkspace(s); preferences.workspace = Workspace::currentWorkspace->name(); preferences.dirty = true; PaletteBox* paletteBox = mscore->getPaletteBox(); paletteBox->updateWorkspaces(); } //--------------------------------------------------------- // deleteWorkspace //--------------------------------------------------------- void MuseScore::deleteWorkspace() { if (!workspaces) return; QAction* a = workspaces->checkedAction(); if (!a) return; preferences.dirty = true; Workspace* workspace = 0; foreach(Workspace* p, Workspace::workspaces()) { if (p->name() == a->text()) { // no need for qApp->translate since "Basic" and "Advanced" are not deletable workspace = p; break; } } if (!workspace) return; Workspace::workspaces().removeOne(workspace); QFile f(workspace->path()); f.remove(); delete workspace; PaletteBox* paletteBox = mscore->getPaletteBox(); paletteBox->clear(); Workspace::currentWorkspace = Workspace::workspaces().first(); preferences.workspace = Workspace::currentWorkspace->name(); changeWorkspace(Workspace::currentWorkspace); paletteBox = mscore->getPaletteBox(); paletteBox->updateWorkspaces(); } //--------------------------------------------------------- // changeWorkspace //--------------------------------------------------------- void MuseScore::changeWorkspace(QAction* a) { foreach(Workspace* p, Workspace::workspaces()) { if (qApp->translate("Ms::Workspace", p->name().toUtf8()) == a->text()) { changeWorkspace(p); preferences.workspace = Workspace::currentWorkspace->name(); preferences.dirty = true; PaletteBox* paletteBox = mscore->getPaletteBox(); paletteBox->updateWorkspaces(); return; } } qDebug(" workspace \"%s\" not found", qPrintable(a->text())); } //--------------------------------------------------------- // changeWorkspace //--------------------------------------------------------- void MuseScore::changeWorkspace(Workspace* p) { Workspace::currentWorkspace->save(); p->read(); Workspace::currentWorkspace = p; } //--------------------------------------------------------- // initWorkspace //--------------------------------------------------------- void Workspace::initWorkspace() { foreach(Workspace* p, Workspace::workspaces()) { if (p->name() == preferences.workspace) { currentWorkspace = p; break; } } if (currentWorkspace == 0) currentWorkspace = Workspace::workspaces().at(0); } //--------------------------------------------------------- // writeFailed //--------------------------------------------------------- static void writeFailed(const QString& _path) { QString s = qApp->translate("Workspace", "Writing Workspace File\n%1\nfailed: "); QMessageBox::critical(mscore, qApp->translate("Workspace", "MuseScore: Writing Workspace File"), s.arg(_path)); } //--------------------------------------------------------- // Workspace //--------------------------------------------------------- Workspace::Workspace() : QObject(0) { _dirty = false; _readOnly = false; } //--------------------------------------------------------- // write //--------------------------------------------------------- void Workspace::write() { if (_path.isEmpty()) { QString ext(".workspace"); QDir dir; dir.mkpath(dataPath); _path = dataPath + "/workspaces"; dir.mkpath(_path); _path += "/" + _name + ext; } MQZipWriter f(_path); f.setCreationPermissions( QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner | QFile::ReadUser | QFile::WriteUser | QFile::ExeUser | QFile::ReadGroup | QFile::WriteGroup | QFile::ExeGroup | QFile::ReadOther | QFile::WriteOther | QFile::ExeOther); if (f.status() != MQZipWriter::NoError) { writeFailed(_path); return; } QBuffer cbuf; cbuf.open(QIODevice::ReadWrite); Xml xml(&cbuf); xml.header(); xml.stag("container"); xml.stag("rootfiles"); xml.stag(QString("rootfile full-path=\"%1\"").arg(Xml::xmlString("workspace.xml"))); xml.etag(); foreach (ImageStoreItem* ip, imageStore) { if (!ip->isUsed(gscore)) continue; QString dstPath = QString("Pictures/") + ip->hashName(); xml.tag("file", dstPath); } xml.etag(); xml.etag(); cbuf.seek(0); f.addFile("META-INF/container.xml", cbuf.data()); // save images foreach(ImageStoreItem* ip, imageStore) { if (!ip->isUsed(gscore)) continue; QString dstPath = QString("Pictures/") + ip->hashName(); f.addFile(dstPath, ip->buffer()); } { QBuffer cbuf; cbuf.open(QIODevice::ReadWrite); Xml xml(&cbuf); xml.clipboardmode = true; xml.header(); xml.stag("museScore version=\"" MSC_VERSION "\""); xml.stag("Workspace"); // xml.tag("name", _name); PaletteBox* pb = mscore->getPaletteBox(); pb->write(xml); xml.etag(); xml.etag(); f.addFile("workspace.xml", cbuf.data()); cbuf.close(); } if (f.status() != MQZipWriter::NoError) writeFailed(_path); } extern QString readRootFile(MQZipReader*, QList&); //--------------------------------------------------------- // read //--------------------------------------------------------- void Workspace::read() { if (_path == "Advanced") { mscore->setAdvancedPalette(); for (Palette* p : mscore->getPaletteBox()->palettes()) p->setSystemPalette(true); return; } if (_path == "Basic") { mscore->setBasicPalette(); for (Palette* p : mscore->getPaletteBox()->palettes()) p->setSystemPalette(true); return; } if (_path.isEmpty() || !QFile(_path).exists()) { qDebug("cannot read workspace <%s>", qPrintable(_path)); mscore->setAdvancedPalette(); // set default palette return; } QFileInfo fi(_path); _readOnly = !fi.isWritable(); MQZipReader f(_path); QList images; QString rootfile = readRootFile(&f, images); // // load images // foreach(const QString& s, images) imageStore.add(s, f.fileData(s)); if (rootfile.isEmpty()) { qDebug("can't find rootfile in: %s", qPrintable(_path)); return; } QByteArray ba = f.fileData(rootfile); XmlReader e(ba); while (e.readNextStartElement()) { if (e.name() == "museScore") { while (e.readNextStartElement()) { if (e.name() == "Workspace") read(e); else e.unknown(); } } } } void Workspace::read(XmlReader& e) { while (e.readNextStartElement()) { const QStringRef& tag(e.name()); if (tag == "name") e.readElementText(); else if (tag == "PaletteBox") { PaletteBox* paletteBox = mscore->getPaletteBox(); paletteBox->clear(); paletteBox->read(e); QList pl = paletteBox->palettes(); foreach (Palette* p, pl) { p->setSystemPalette(_readOnly); connect(paletteBox, SIGNAL(changed()), SLOT(setDirty())); } } else e.unknown(); } } //--------------------------------------------------------- // save //--------------------------------------------------------- void Workspace::save() { if (_readOnly) return; PaletteBox* pb = mscore->getPaletteBox(); if (pb) write(); } //--------------------------------------------------------- // workspaces //--------------------------------------------------------- QList& Workspace::workspaces() { if (!workspacesRead) { QStringList path; path << mscoreGlobalShare + "workspaces"; path << dataPath + "/workspaces"; QStringList nameFilters; nameFilters << "*.workspace"; foreach (const QString& s, path) { QDir dir(s); QStringList pl = dir.entryList(nameFilters, QDir::Files, QDir::Name); foreach (const QString& entry, pl) { Workspace* p = 0; QFileInfo fi(s + "/" + entry); QString name(fi.baseName()); foreach (Workspace* w, _workspaces) { if (w->name() == name) { p = w; break; } } if (!p) p = new Workspace; p->setPath(s + "/" + entry); p->setName(name); p->setReadOnly(!fi.isWritable()); _workspaces.append(p); } } workspacesRead = true; } return _workspaces; } //--------------------------------------------------------- // createNewWorkspace //--------------------------------------------------------- Workspace* Workspace::createNewWorkspace(const QString& name) { Workspace* p = new Workspace; p->setName(name); p->setPath(""); p->setDirty(false); p->setReadOnly(false); p->write(); // all palettes in new workspace are editable PaletteBox* paletteBox = mscore->getPaletteBox(); QList pl = paletteBox->palettes(); foreach (Palette* p, pl) { p->setSystemPalette(false); for (int i = 0; i < p->size(); ++i) p->setCellReadOnly(i, false); } _workspaces.append(p); return p; } }