1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 2 3 /* 4 Rosegarden 5 A MIDI and audio sequencer and musical notation editor. 6 Copyright 2000-2021 the Rosegarden development team. 7 8 Other copyrights also apply to some parts of this work. Please 9 see the AUTHORS file and individual file headers for details. 10 11 This program is free software; you can redistribute it and/or 12 modify it under the terms of the GNU General Public License as 13 published by the Free Software Foundation; either version 2 of the 14 License, or (at your option) any later version. See the file 15 COPYING included with this distribution for more information. 16 */ 17 18 #include "NoteStyleFileReader.h" 19 20 #include <string> 21 #include "misc/Strings.h" 22 #include "NotationStrings.h" 23 #include "misc/Debug.h" 24 #include "gui/general/ResourceFinder.h" 25 #include "NoteStyle.h" 26 #include "document/io/XMLReader.h" 27 28 #include <QFileInfo> 29 #include <QDir> 30 31 32 33 namespace Rosegarden { 34 35 36 NoteStyleFileReader::NoteStyleFileReader(QString name) : 37 m_style(new NoteStyle(name)), 38 m_haveNote(false) 39 { 40 /*!!! 41 //QString styleDirectory = 42 // KGlobal::dirs()->findResource("appdata", "styles/"); 43 QString styleDirectory = IconLoader::getResourcePath( "styles" ); 44 45 QString styleFileName = 46 QString("%1/%2.xml").arg(styleDirectory).arg(name); 47 */ 48 QString styleFileName = ResourceFinder().getResourcePath 49 ("styles", QString("%1.xml").arg(name)); 50 51 QFileInfo fileInfo(styleFileName); 52 53 if (styleFileName == "" || !fileInfo.isReadable()) { 54 throw StyleFileReadFailed(tr("Can't open style file \"%1\" for style \"%2\"").arg(styleFileName).arg(name)); 55 } 56 57 QFile styleFile(styleFileName); 58 59 XMLReader reader; 60 reader.setHandler(this); 61 bool ok = reader.parse(styleFile); 62 styleFile.close(); 63 64 if (!ok) { 65 throw StyleFileReadFailed(m_errorString); 66 } 67 } 68 69 bool 70 NoteStyleFileReader::startElement(const QString &, const QString &, 71 const QString &qName, 72 const QXmlStreamAttributes &attributes) 73 { 74 QString lcName = qName.toLower(); 75 76 if (lcName == "rosegarden-note-style") { 77 78 QString s = attributes.value("base-style").toString(); 79 if ( !s.isEmpty() ) m_style->setBaseStyle(s); 80 81 } else if (lcName == "note") { 82 83 m_haveNote = true; 84 85 QString s = attributes.value("type").toString(); 86 if (s.isEmpty() ) { 87 m_errorString = tr("type is a required attribute of note"); 88 return false; 89 } 90 91 try { 92 Note::Type type = NotationStrings::getNoteForName(s).getNoteType(); 93 if (!setFromAttributes(type, attributes)) return false; 94 95 } catch (const NotationStrings::MalformedNoteName &n) { 96 m_errorString = tr("Unrecognised note name %1").arg(s); 97 return false; 98 } 99 100 } else if (lcName == "global") { 101 102 if (m_haveNote) { 103 m_errorString = tr("global element must precede note elements"); 104 return false; 105 } 106 107 for (Note::Type type = Note::Shortest; type <= Note::Longest; ++type) { 108 if (!setFromAttributes(type, attributes)) return false; 109 } 110 } 111 112 return true; 113 } 114 115 116 bool 117 NoteStyleFileReader::setFromAttributes(Note::Type type, 118 const QXmlStreamAttributes &attributes) 119 { 120 QString s; 121 bool haveShape = false; 122 123 s = attributes.value("shape").toString(); 124 if (!s.isEmpty() ) { 125 m_style->setShape(type, s.toLower()); 126 haveShape = true; 127 } 128 129 s = attributes.value("charname").toString(); 130 if (!s.isEmpty() ) { 131 if (haveShape) { 132 m_errorString = tr("global and note elements may have shape " 133 "or charname attribute, but not both"); 134 return false; 135 } 136 m_style->setShape(type, NoteStyle::CustomCharName); 137 m_style->setCharName(type, s); 138 } 139 140 s = attributes.value("filled").toString(); 141 if (!s.isEmpty() ) m_style->setFilled(type, s.toLower() == "true"); 142 143 s = attributes.value("stem").toString(); 144 if (!s.isEmpty() ) m_style->setStem(type, s.toLower() == "true"); 145 146 s = attributes.value("flags").toString(); 147 if (!s.isEmpty() ) m_style->setFlagCount(type, s.toInt()); 148 149 s = attributes.value("slashes").toString(); 150 if (!s.isEmpty() ) m_style->setSlashCount(type, s.toInt()); 151 152 NoteStyle::HFixPoint hfix; 153 NoteStyle::VFixPoint vfix; 154 m_style->getStemFixPoints(type, hfix, vfix); 155 bool haveHFix = false; 156 bool haveVFix = false; 157 158 s = attributes.value("hfixpoint").toString(); 159 if (!s.isEmpty() ) { 160 s = s.toLower(); 161 haveHFix = true; 162 if (s == "normal") hfix = NoteStyle::Normal; 163 else if (s == "central") hfix = NoteStyle::Central; 164 else if (s == "reversed") hfix = NoteStyle::Reversed; 165 else haveHFix = false; 166 } 167 168 s = attributes.value("vfixpoint").toString(); 169 if (!s.isEmpty() ) { 170 s = s.toLower(); 171 haveVFix = true; 172 if (s == "near") vfix = NoteStyle::Near; 173 else if (s == "middle") vfix = NoteStyle::Middle; 174 else if (s == "far") vfix = NoteStyle::Far; 175 else haveVFix = false; 176 } 177 178 if (haveHFix || haveVFix) { 179 m_style->setStemFixPoints(type, hfix, vfix); 180 // otherwise they inherit from base style, so avoid setting here 181 } 182 183 return true; 184 } 185 186 187 } 188 189