Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-Studio-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2021 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "tread.h"
24 :
25 : #include "iengravingconfiguration.h" // IWYU pragma: keep
26 :
27 : #include "../../types/typesconv.h"
28 : #include "../../types/symnames.h"
29 : #include "../../infrastructure/rtti.h"
30 :
31 : #include "../../compat/midi/event.h"
32 :
33 : #include "../../dom/accidental.h"
34 : #include "../../dom/actionicon.h"
35 : #include "../../dom/ambitus.h"
36 : #include "../../dom/arpeggio.h"
37 : #include "../../dom/articulation.h"
38 : #include "../../dom/bagpembell.h"
39 : #include "../../dom/barline.h"
40 : #include "../../dom/beam.h"
41 : #include "../../dom/bend.h"
42 : #include "../../dom/box.h"
43 : #include "../../dom/bracket.h"
44 : #include "../../dom/breath.h"
45 : #include "../../dom/capo.h"
46 : #include "../../dom/chord.h"
47 : #include "../../dom/chordline.h"
48 : #include "../../dom/chordlist.h"
49 : #include "../../dom/clef.h"
50 : #include "../../dom/drumset.h"
51 : #include "../../dom/dynamic.h"
52 : #include "../../dom/excerpt.h"
53 : #include "../../dom/expression.h"
54 : #include "../../dom/factory.h"
55 : #include "../../dom/fermata.h"
56 : #include "../../dom/figuredbass.h"
57 : #include "../../dom/fingering.h"
58 : #include "../../dom/fret.h"
59 : #include "../../dom/glissando.h"
60 : #include "../../dom/gradualtempochange.h"
61 : #include "../../dom/groups.h"
62 : #include "../../dom/guitarbend.h"
63 : #include "../../dom/hairpin.h"
64 : #include "../../dom/harmonicmark.h"
65 : #include "../../dom/harmony.h"
66 : #include "../../dom/harppedaldiagram.h"
67 : #include "../../dom/hook.h"
68 : #include "../../dom/image.h"
69 : #include "../../dom/instrchange.h"
70 : #include "../../dom/instrument.h"
71 : #include "../../dom/interval.h"
72 : #include "../../dom/jump.h"
73 : #include "../../dom/keysig.h"
74 : #include "../../dom/laissezvib.h"
75 : #include "../../dom/layoutbreak.h"
76 : #include "../../dom/ledgerline.h"
77 : #include "../../dom/letring.h"
78 : #include "../../dom/line.h"
79 : #include "../../dom/linkedobjects.h"
80 : #include "../../dom/lyrics.h"
81 : #include "../../dom/marker.h"
82 : #include "../../dom/masterscore.h"
83 : #include "../../dom/measurenumber.h"
84 : #include "../../dom/measurerepeat.h"
85 : #include "../../dom/mmrest.h"
86 : #include "../../dom/mmrestrange.h"
87 : #include "../../dom/mscore.h"
88 : #include "../../dom/note.h"
89 : #include "../../dom/notedot.h"
90 : #include "../../dom/noteline.h"
91 : #include "../../dom/ornament.h"
92 : #include "../../dom/ottava.h"
93 : #include "../../dom/page.h"
94 : #include "../../dom/palmmute.h"
95 : #include "../../dom/parenthesis.h"
96 : #include "../../dom/part.h"
97 : #include "../../dom/partialtie.h"
98 : #include "../../dom/pedal.h"
99 : #include "../../dom/playtechannotation.h"
100 : #include "../../dom/rasgueado.h"
101 : #include "../../dom/rehearsalmark.h"
102 : #include "../../dom/rest.h"
103 : #include "../../dom/score.h"
104 : #include "../../dom/segment.h"
105 : #include "../../dom/sig.h"
106 : #include "../../dom/slur.h"
107 : #include "../../dom/slurtie.h"
108 : #include "../../dom/soundflag.h"
109 : #include "../../dom/spacer.h"
110 : #include "../../dom/spanner.h"
111 : #include "../../dom/staff.h"
112 : #include "../../dom/staffstate.h"
113 : #include "../../dom/stafftext.h"
114 : #include "../../dom/stafftextbase.h"
115 : #include "../../dom/stafftype.h"
116 : #include "../../dom/stafftypechange.h"
117 : #include "../../dom/stem.h"
118 : #include "../../dom/stemslash.h"
119 : #include "../../dom/sticking.h"
120 : #include "../../dom/stringtunings.h"
121 : #include "../../dom/system.h"
122 : #include "../../dom/systemdivider.h"
123 : #include "../../dom/systemtext.h"
124 : #include "../../dom/tempotext.h"
125 : #include "../../dom/text.h"
126 : #include "../../dom/textline.h"
127 : #include "../../dom/textlinebase.h"
128 : #include "../../dom/tie.h"
129 : #include "../../dom/timesig.h"
130 : #include "../../dom/tremolobar.h"
131 : #include "../../dom/tremolosinglechord.h"
132 : #include "../../dom/tremolotwochord.h"
133 : #include "../../dom/trill.h"
134 : #include "../../dom/tuplet.h"
135 : #include "../../dom/vibrato.h"
136 : #include "../../dom/volta.h"
137 : #include "../../dom/whammybar.h"
138 :
139 : #include "../../editing/editstaffbrackets.h"
140 : #include "../../editing/transpose.h"
141 :
142 : #include "../xmlreader.h"
143 : #include "../read206/read206.h"
144 : #include "../read400/tread.h"
145 : #include "../read500/tread.h"
146 : #include "../compat/compatutils.h"
147 : #include "../compat/tremolocompat.h"
148 : #include "readcontext.h"
149 : #include "connectorinforeader.h"
150 :
151 : #include "log.h"
152 :
153 : using namespace muse::draw;
154 : using namespace mu::engraving;
155 : using namespace mu::engraving::read410;
156 :
157 382 : void TRead::readItem(EngravingItem* item, XmlReader& xml, ReadContext& ctx)
158 : {
159 382 : switch (item->type()) {
160 0 : case ElementType::ACCIDENTAL: read(item_cast<Accidental*>(item), xml, ctx);
161 0 : break;
162 0 : case ElementType::ACTION_ICON: read(item_cast<ActionIcon*>(item), xml, ctx);
163 0 : break;
164 0 : case ElementType::AMBITUS: read(item_cast<Ambitus*>(item), xml, ctx);
165 0 : break;
166 0 : case ElementType::ARPEGGIO: read(item_cast<Arpeggio*>(item), xml, ctx);
167 0 : break;
168 0 : case ElementType::ARTICULATION: read(item_cast<Articulation*>(item), xml, ctx);
169 0 : break;
170 0 : case ElementType::BAGPIPE_EMBELLISHMENT: read(item_cast<BagpipeEmbellishment*>(item), xml, ctx);
171 0 : break;
172 0 : case ElementType::BAR_LINE: read(item_cast<BarLine*>(item), xml, ctx);
173 0 : break;
174 0 : case ElementType::BEAM: read(item_cast<Beam*>(item), xml, ctx);
175 0 : break;
176 0 : case ElementType::BEND: read(item_cast<Bend*>(item), xml, ctx);
177 0 : break;
178 2 : case ElementType::HBOX: read(item_cast<HBox*>(item), xml, ctx);
179 2 : break;
180 57 : case ElementType::VBOX: read(item_cast<VBox*>(item), xml, ctx);
181 57 : break;
182 0 : case ElementType::FBOX: read(item_cast<FBox*>(item), xml, ctx);
183 0 : break;
184 1 : case ElementType::TBOX: read(item_cast<TBox*>(item), xml, ctx);
185 1 : break;
186 0 : case ElementType::BRACKET: read(item_cast<Bracket*>(item), xml, ctx);
187 0 : break;
188 0 : case ElementType::BREATH: read(item_cast<Breath*>(item), xml, ctx);
189 0 : break;
190 0 : case ElementType::CHORD: read(item_cast<Chord*>(item), xml, ctx);
191 0 : break;
192 0 : case ElementType::CHORDLINE: read(item_cast<ChordLine*>(item), xml, ctx);
193 0 : break;
194 0 : case ElementType::CLEF: read(item_cast<Clef*>(item), xml, ctx);
195 0 : break;
196 0 : case ElementType::CAPO: read(item_cast<Capo*>(item), xml, ctx);
197 0 : break;
198 0 : case ElementType::DYNAMIC: read(item_cast<Dynamic*>(item), xml, ctx);
199 0 : break;
200 0 : case ElementType::EXPRESSION: read(item_cast<Expression*>(item), xml, ctx);
201 0 : break;
202 0 : case ElementType::FERMATA: read(item_cast<Fermata*>(item), xml, ctx);
203 0 : break;
204 5 : case ElementType::FIGURED_BASS: read(item_cast<FiguredBass*>(item), xml, ctx);
205 5 : break;
206 0 : case ElementType::FINGERING: read(item_cast<Fingering*>(item), xml, ctx);
207 0 : break;
208 0 : case ElementType::FRET_DIAGRAM: read(item_cast<FretDiagram*>(item), xml, ctx);
209 0 : break;
210 18 : case ElementType::GLISSANDO: read(item_cast<Glissando*>(item), xml, ctx);
211 18 : break;
212 3 : case ElementType::GRADUAL_TEMPO_CHANGE: read(item_cast<GradualTempoChange*>(item), xml, ctx);
213 3 : break;
214 28 : case ElementType::GUITAR_BEND: read(item_cast<GuitarBend*>(item), xml, ctx);
215 28 : break;
216 41 : case ElementType::HAIRPIN: read(item_cast<Hairpin*>(item), xml, ctx);
217 41 : break;
218 0 : case ElementType::HARMONY: read(item_cast<Harmony*>(item), xml, ctx);
219 0 : break;
220 0 : case ElementType::HARMONIC_MARK: read(item_cast<HarmonicMark*>(item), xml, ctx);
221 0 : break;
222 6 : case ElementType::HARP_DIAGRAM: read(item_cast<HarpPedalDiagram*>(item), xml, ctx);
223 6 : break;
224 0 : case ElementType::HOOK: read(item_cast<Hook*>(item), xml, ctx);
225 0 : break;
226 0 : case ElementType::IMAGE: read(item_cast<Image*>(item), xml, ctx);
227 0 : break;
228 0 : case ElementType::INSTRUMENT_CHANGE: read(item_cast<InstrumentChange*>(item), xml, ctx);
229 0 : break;
230 12 : case ElementType::JUMP: read(item_cast<Jump*>(item), xml, ctx);
231 12 : break;
232 0 : case ElementType::KEYSIG: read(item_cast<KeySig*>(item), xml, ctx);
233 0 : break;
234 0 : case ElementType::LAISSEZ_VIB: read(item_cast<LaissezVib*>(item), xml, ctx);
235 0 : break;
236 0 : case ElementType::LAYOUT_BREAK: read(item_cast<LayoutBreak*>(item), xml, ctx);
237 0 : break;
238 0 : case ElementType::LEDGER_LINE: read(item_cast<LedgerLine*>(item), xml, ctx);
239 0 : break;
240 10 : case ElementType::LET_RING: read(item_cast<LetRing*>(item), xml, ctx);
241 10 : break;
242 0 : case ElementType::LYRICS: read(item_cast<Lyrics*>(item), xml, ctx);
243 0 : break;
244 17 : case ElementType::MARKER: read(item_cast<Marker*>(item), xml, ctx);
245 17 : break;
246 0 : case ElementType::MEASURE_NUMBER: read(item_cast<MeasureNumber*>(item), xml, ctx);
247 0 : break;
248 0 : case ElementType::MEASURE_REPEAT: read(item_cast<MeasureRepeat*>(item), xml, ctx);
249 0 : break;
250 0 : case ElementType::MMREST: read(item_cast<MMRest*>(item), xml, ctx);
251 0 : break;
252 0 : case ElementType::MMREST_RANGE: read(item_cast<MMRestRange*>(item), xml, ctx);
253 0 : break;
254 0 : case ElementType::NOTE: read(item_cast<Note*>(item), xml, ctx);
255 0 : break;
256 0 : case ElementType::NOTEDOT: read(item_cast<NoteDot*>(item), xml, ctx);
257 0 : break;
258 0 : case ElementType::NOTEHEAD: read(item_cast<NoteHead*>(item), xml, ctx);
259 0 : break;
260 0 : case ElementType::NOTELINE: read(item_cast<NoteLine*>(item), xml, ctx);
261 0 : break;
262 0 : case ElementType::PAGE: read(item_cast<Page*>(item), xml, ctx);
263 0 : break;
264 8 : case ElementType::PALM_MUTE: read(item_cast<PalmMute*>(item), xml, ctx);
265 8 : break;
266 0 : case ElementType::PARTIAL_LYRICSLINE: read(item_cast<PartialLyricsLine*>(item), xml, ctx);
267 0 : break;
268 0 : case ElementType::PARTIAL_TIE: read(item_cast<PartialTie*>(item), xml, ctx);
269 0 : break;
270 7 : case ElementType::PEDAL: read(item_cast<Pedal*>(item), xml, ctx);
271 7 : break;
272 7 : case ElementType::PLAYTECH_ANNOTATION: read(item_cast<PlayTechAnnotation*>(item), xml, ctx);
273 7 : break;
274 0 : case ElementType::RASGUEADO: read(item_cast<Rasgueado*>(item), xml, ctx);
275 0 : break;
276 1 : case ElementType::REHEARSAL_MARK: read(item_cast<RehearsalMark*>(item), xml, ctx);
277 1 : break;
278 0 : case ElementType::REST: read(item_cast<Rest*>(item), xml, ctx);
279 0 : break;
280 0 : case ElementType::ORNAMENT: read(item_cast<Ornament*>(item), xml, ctx);
281 0 : break;
282 4 : case ElementType::OTTAVA: read(item_cast<Ottava*>(item), xml, ctx);
283 4 : break;
284 0 : case ElementType::SEGMENT: read(item_cast<Segment*>(item), xml, ctx);
285 0 : break;
286 26 : case ElementType::SLUR: read(item_cast<Slur*>(item), xml, ctx);
287 26 : break;
288 0 : case ElementType::SPACER: read(item_cast<Spacer*>(item), xml, ctx);
289 0 : break;
290 0 : case ElementType::STAFF_STATE: read(item_cast<StaffState*>(item), xml, ctx);
291 0 : break;
292 0 : case ElementType::STAFF_TEXT: read(item_cast<StaffText*>(item), xml, ctx);
293 0 : break;
294 0 : case ElementType::STAFFTYPE_CHANGE: read(item_cast<StaffTypeChange*>(item), xml, ctx);
295 0 : break;
296 0 : case ElementType::STEM: read(item_cast<Stem*>(item), xml, ctx);
297 0 : break;
298 0 : case ElementType::STEM_SLASH: read(item_cast<StemSlash*>(item), xml, ctx);
299 0 : break;
300 15 : case ElementType::STICKING: read(item_cast<Sticking*>(item), xml, ctx);
301 15 : break;
302 0 : case ElementType::STRING_TUNINGS: read(item_cast<StringTunings*>(item), xml, ctx);
303 0 : break;
304 0 : case ElementType::SYMBOL: read(item_cast<Symbol*>(item), xml, ctx);
305 0 : break;
306 0 : case ElementType::SOUND_FLAG: read(item_cast<SoundFlag*>(item), xml, ctx);
307 0 : break;
308 0 : case ElementType::FSYMBOL: read(item_cast<FSymbol*>(item), xml, ctx);
309 0 : break;
310 0 : case ElementType::SYSTEM: read(item_cast<System*>(item), xml, ctx);
311 0 : break;
312 0 : case ElementType::SYSTEM_DIVIDER: read(item_cast<SystemDivider*>(item), xml, ctx);
313 0 : break;
314 5 : case ElementType::SYSTEM_TEXT: read(item_cast<SystemText*>(item), xml, ctx);
315 5 : break;
316 0 : case ElementType::TEMPO_TEXT: read(item_cast<TempoText*>(item), xml, ctx);
317 0 : break;
318 0 : case ElementType::TEXT: read(item_cast<Text*>(item), xml, ctx);
319 0 : break;
320 4 : case ElementType::TEXTLINE: read(item_cast<TextLine*>(item), xml, ctx);
321 4 : break;
322 82 : case ElementType::TIE: read(item_cast<Tie*>(item), xml, ctx);
323 82 : break;
324 0 : case ElementType::TIMESIG: read(item_cast<TimeSig*>(item), xml, ctx);
325 0 : break;
326 0 : case ElementType::TREMOLO_SINGLECHORD: read(item_cast<TremoloSingleChord*>(item), xml, ctx);
327 0 : break;
328 0 : case ElementType::TREMOLO_TWOCHORD: read(item_cast<TremoloTwoChord*>(item), xml, ctx);
329 0 : break;
330 0 : case ElementType::TREMOLOBAR: read(item_cast<TremoloBar*>(item), xml, ctx);
331 0 : break;
332 12 : case ElementType::TRILL: read(item_cast<Trill*>(item), xml, ctx);
333 12 : break;
334 0 : case ElementType::TUPLET: read(item_cast<Tuplet*>(item), xml, ctx);
335 0 : break;
336 0 : case ElementType::VIBRATO: read(item_cast<Vibrato*>(item), xml, ctx);
337 0 : break;
338 11 : case ElementType::VOLTA: read(item_cast<Volta*>(item), xml, ctx);
339 11 : break;
340 0 : case ElementType::WHAMMY_BAR: read(item_cast<WhammyBar*>(item), xml, ctx);
341 0 : break;
342 0 : default:
343 0 : UNREACHABLE;
344 : LOGE() << "Not implemented read for type: " << item->typeName();
345 : break;
346 : }
347 382 : }
348 :
349 578 : PropertyValue TRead::readPropertyValue(Pid id, XmlReader& e, ReadContext& ctx)
350 : {
351 578 : switch (propertyType(id)) {
352 30 : case P_TYPE::BOOL:
353 30 : return PropertyValue(bool(e.readInt()));
354 1 : case P_TYPE::INT:
355 1 : return PropertyValue(e.readInt());
356 65 : case P_TYPE::REAL:
357 65 : return PropertyValue(e.readDouble());
358 7 : case P_TYPE::SPATIUM: return PropertyValue(Spatium(e.readDouble()));
359 0 : case P_TYPE::ABSOLUTE: return PropertyValue(Spatium(e.readDouble())); //! NOTE type mm, but stored in xml as spatium
360 0 : case P_TYPE::TEMPO:
361 0 : return PropertyValue(e.readDouble());
362 0 : case P_TYPE::FRACTION:
363 0 : return PropertyValue::fromValue(e.readFraction());
364 :
365 0 : case P_TYPE::SYMID:
366 0 : return PropertyValue(TConv::fromXml(e.readAsciiText(), SymId::noSym));
367 7 : case P_TYPE::COLOR:
368 7 : return PropertyValue::fromValue(e.readColor());
369 0 : case P_TYPE::ORNAMENT_STYLE:
370 0 : return PropertyValue::fromValue(TConv::fromXml(e.readAsciiText(), OrnamentStyle::DEFAULT));
371 5 : case P_TYPE::ORNAMENT_INTERVAL:
372 5 : return PropertyValue(TConv::fromXml(e.readText(), DEFAULT_ORNAMENT_INTERVAL));
373 0 : case P_TYPE::ORNAMENT_SHOW_ACCIDENTAL:
374 0 : return OrnamentShowAccidental(e.readInt());
375 74 : case P_TYPE::POINT:
376 74 : return PropertyValue::fromValue(e.readPoint());
377 0 : case P_TYPE::SCALE:
378 0 : return PropertyValue::fromValue(e.readScale());
379 0 : case P_TYPE::SIZE:
380 0 : return PropertyValue::fromValue(e.readSize());
381 39 : case P_TYPE::STRING:
382 39 : return PropertyValue(e.readText());
383 :
384 0 : case P_TYPE::ALIGN:
385 0 : return PropertyValue(TConv::fromXml(e.readText(), Align()));
386 8 : case P_TYPE::PLACEMENT_V:
387 8 : return PropertyValue(TConv::fromXml(e.readAsciiText(), PlacementV::ABOVE));
388 0 : case P_TYPE::PLACEMENT_H:
389 0 : return PropertyValue(TConv::fromXml(e.readAsciiText(), PlacementH::LEFT));
390 0 : case P_TYPE::TEXT_PLACE:
391 0 : return PropertyValue(TConv::fromXml(e.readAsciiText(), TextPlace::AUTO));
392 62 : case P_TYPE::DIRECTION_V:
393 62 : return PropertyValue(TConv::fromXml(e.readAsciiText(), DirectionV::AUTO));
394 0 : case P_TYPE::DIRECTION_H:
395 0 : return PropertyValue(TConv::fromXml(e.readAsciiText(), DirectionH::AUTO));
396 0 : case P_TYPE::ORIENTATION:
397 0 : return PropertyValue(TConv::fromXml(e.readAsciiText(), Orientation::VERTICAL));
398 :
399 24 : case P_TYPE::LAYOUTBREAK_TYPE:
400 24 : return PropertyValue(TConv::fromXml(e.readAsciiText(), LayoutBreakType::NOBREAK));
401 0 : case P_TYPE::VELO_TYPE:
402 0 : return PropertyValue(TConv::fromXml(e.readAsciiText(), VeloType::OFFSET_VAL));
403 4 : case P_TYPE::GLISS_STYLE:
404 4 : return PropertyValue(TConv::fromXml(e.readAsciiText(), GlissandoStyle::CHROMATIC));
405 2 : case P_TYPE::GLISS_TYPE:
406 2 : return PropertyValue(TConv::fromXml(e.readAsciiText(), GlissandoType::STRAIGHT));
407 0 : case P_TYPE::BARLINE_TYPE:
408 0 : return PropertyValue(TConv::fromXml(e.readAsciiText(), BarLineType::NORMAL));
409 :
410 1 : case P_TYPE::NOTEHEAD_TYPE:
411 1 : return PropertyValue(TConv::fromXml(e.readAsciiText(), NoteHeadType::HEAD_AUTO));
412 0 : case P_TYPE::NOTEHEAD_SCHEME:
413 0 : return PropertyValue(TConv::fromXml(e.readAsciiText(), NoteHeadScheme::HEAD_AUTO));
414 166 : case P_TYPE::NOTEHEAD_GROUP:
415 166 : return PropertyValue(TConv::fromXml(e.readAsciiText(), NoteHeadGroup::HEAD_NORMAL));
416 :
417 0 : case P_TYPE::CLEF_TYPE:
418 0 : return PropertyValue(TConv::fromXml(e.readAsciiText(), ClefType::G));
419 0 : case P_TYPE::CLEF_TO_BARLINE_POS:
420 0 : return ClefToBarlinePosition(e.readInt());
421 :
422 0 : case P_TYPE::DYNAMIC_TYPE:
423 0 : return PropertyValue(TConv::fromXml(e.readAsciiText(), DynamicType::OTHER));
424 :
425 0 : case P_TYPE::LINE_TYPE:
426 0 : return PropertyValue(TConv::fromXml(e.readAsciiText(), LineType::SOLID));
427 19 : case P_TYPE::HOOK_TYPE:
428 19 : return PropertyValue(TConv::fromXml(e.readAsciiText(), HookType::NONE));
429 :
430 0 : case P_TYPE::KEY_MODE:
431 0 : return PropertyValue(TConv::fromXml(e.readAsciiText(), KeyMode::NONE));
432 :
433 32 : case P_TYPE::TEXT_STYLE:
434 32 : return PropertyValue(TConv::fromXml(e.readAsciiText(), TextStyleType::DEFAULT));
435 0 : case P_TYPE::SLUR_STYLE_TYPE:
436 0 : return SlurStyleType(e.readInt());
437 :
438 0 : case P_TYPE::CHANGE_METHOD:
439 0 : return PropertyValue(TConv::fromXml(e.readAsciiText(), ChangeMethod::NORMAL));
440 :
441 0 : case P_TYPE::BEAM_MODE:
442 0 : return PropertyValue(int(0));
443 0 : case P_TYPE::GROUPS: {
444 0 : Groups g;
445 0 : TRead::read(&g, e, ctx);
446 0 : return PropertyValue::fromValue(g.nodes());
447 0 : }
448 0 : case P_TYPE::DURATION_TYPE_WITH_DOTS:
449 : case P_TYPE::INT_VEC:
450 0 : return PropertyValue(TConv::fromXml(String(e.readText()), std::vector<int>()));
451 :
452 6 : case P_TYPE::PLAYTECH_TYPE:
453 6 : return PropertyValue(TConv::fromXml(e.readAsciiText(), PlayingTechniqueType::Natural));
454 3 : case P_TYPE::TEMPOCHANGE_TYPE:
455 3 : return PropertyValue(TConv::fromXml(e.readAsciiText(), GradualTempoChangeType::Undefined));
456 0 : case P_TYPE::TIE_PLACEMENT:
457 0 : return PropertyValue(TConv::fromXml(e.readAsciiText(), TiePlacement::AUTO));
458 10 : case P_TYPE::VOICE_ASSIGNMENT:
459 10 : return PropertyValue(TConv::fromXml(e.readAsciiText(), VoiceAssignment::ALL_VOICE_IN_INSTRUMENT));
460 0 : case P_TYPE::AUTO_ON_OFF:
461 0 : return PropertyValue(TConv::fromXml(e.readAsciiText(), AutoOnOff::AUTO));
462 13 : case P_TYPE::PARTIAL_SPANNER_DIRECTION:
463 13 : return PropertyValue(TConv::fromXml(e.readAsciiText(), PartialSpannerDirection::OUTGOING));
464 0 : case P_TYPE::MARKER_TYPE:
465 0 : return PropertyValue(TConv::fromXml(e.readAsciiText(), MarkerType::USER));
466 0 : default:
467 0 : ASSERT_X("unhandled PID type");
468 : break;
469 : }
470 : return PropertyValue();
471 : }
472 :
473 35061 : bool TRead::readProperty(EngravingItem* item, const AsciiStringView& tag, XmlReader& xml, ReadContext& ctx, Pid pid)
474 : {
475 35061 : if (tag == propertyName(pid)) {
476 375 : readProperty(item, xml, ctx, pid);
477 375 : return true;
478 : }
479 34686 : return false;
480 : }
481 :
482 578 : void TRead::readProperty(EngravingItem* item, XmlReader& xml, ReadContext& ctx, Pid pid)
483 : {
484 578 : double spatium = ctx.score() ? ctx.spatium() : item->spatium();
485 578 : PropertyValue v = readPropertyValue(pid, xml, ctx);
486 578 : switch (propertyType(pid)) {
487 0 : case P_TYPE::ABSOLUTE: //! NOTE type mm, but stored in xml as spatium
488 0 : v = v.value<Spatium>().toAbsolute(spatium);
489 0 : break;
490 74 : case P_TYPE::POINT:
491 74 : if (item->offsetIsSpatiumDependent()) {
492 74 : v = v.value<PointF>() * spatium;
493 : } else {
494 0 : v = v.value<PointF>() * DPMM;
495 : }
496 74 : break;
497 504 : default:
498 504 : break;
499 : }
500 :
501 : // Pre-4.4 compatibility: these items now use DIRECTION property
502 578 : if (pid == Pid::PLACEMENT && item->hasVoiceAssignmentProperties()) {
503 0 : pid = Pid::DIRECTION;
504 0 : v = v.value<PlacementV>() == PlacementV::ABOVE ? PropertyValue(DirectionV::UP) : PropertyValue(DirectionV::DOWN);
505 : }
506 :
507 578 : if (pid == Pid::OFFSET) {
508 70 : compat::CompatUtils::migrateOffset500(item, v);
509 : }
510 :
511 578 : if (!ctx.shouldSkipProperty(pid)) {
512 578 : item->setProperty(pid, v);
513 578 : if (item->isStyled(pid)) {
514 46 : item->setPropertyFlags(pid, PropertyFlags::UNSTYLED);
515 : }
516 : }
517 578 : }
518 :
519 4629 : bool TRead::readStyledProperty(EngravingItem* item, const AsciiStringView& tag, XmlReader& xml, ReadContext& ctx)
520 : {
521 12832 : for (const StyledProperty& spp : *item->styledProperties()) {
522 8220 : if (readProperty(item, tag, xml, ctx, spp.pid)) {
523 17 : return true;
524 : }
525 : }
526 4612 : return false;
527 : }
528 :
529 5845 : bool TRead::readItemProperties(EngravingItem* item, XmlReader& e, ReadContext& ctx)
530 : {
531 5845 : const AsciiStringView tag(e.name());
532 :
533 5845 : if (tag == "eid") {
534 4467 : AsciiStringView s = e.readAsciiText();
535 4467 : EID eid = EID::fromStdString(s);
536 4467 : if (eid.isValid()) {
537 2877 : item->setEID(eid);
538 : }
539 1378 : } else if (TRead::readProperty(item, tag, e, ctx, Pid::SIZE_SPATIUM_DEPENDENT)) {
540 1375 : } else if (TRead::readProperty(item, tag, e, ctx, Pid::OFFSET)) {
541 1305 : } else if (TRead::readProperty(item, tag, e, ctx, Pid::MIN_DISTANCE)) {
542 1305 : } else if (TRead::readProperty(item, tag, e, ctx, Pid::AUTOPLACE)) {
543 1305 : } else if (tag == "track") {
544 0 : item->setTrack(e.readInt() + ctx.trackOffset());
545 1305 : } else if (tag == "color") {
546 21 : item->setColor(e.readColor());
547 1284 : } else if (tag == "visible") {
548 3 : item->setVisible(e.readInt());
549 1281 : } else if ((tag == "linked") || (tag == "linkedMain")) {
550 1063 : Staff* s = item->staff();
551 1063 : if (!s) {
552 42 : s = ctx.score()->staff(ctx.track() / VOICES);
553 42 : if (!s) {
554 0 : LOGW("EngravingItem::readProperties: linked element's staff not found (%s)", item->typeName());
555 0 : e.skipCurrentElement();
556 0 : return true;
557 : }
558 : }
559 1063 : if (tag == "linkedMain") {
560 577 : item->setLinks(new LinkedObjects());
561 577 : item->links()->push_back(item);
562 :
563 577 : ctx.addLink(s, item->links(), ctx.location(true));
564 :
565 577 : e.readNext();
566 : } else {
567 486 : Staff* ls = s->links() ? toStaff(s->links()->mainElement()) : nullptr;
568 486 : bool linkedIsMaster = ls ? ls->score()->isMaster() : false;
569 486 : Location loc = ctx.location(true);
570 486 : if (ls) {
571 482 : loc.setStaff(static_cast<int>(ls->idx()));
572 : }
573 486 : Location mainLoc = Location::relative();
574 486 : bool locationRead = false;
575 486 : int localIndexDiff = 0;
576 503 : while (e.readNextStartElement()) {
577 17 : const AsciiStringView ntag(e.name());
578 :
579 17 : if (ntag == "score") {
580 0 : String val(e.readText());
581 0 : if (val == "same") {
582 0 : linkedIsMaster = item->score()->isMaster();
583 : }
584 17 : } else if (ntag == "location") {
585 3 : TRead::read(&mainLoc, e, ctx);
586 3 : mainLoc.toAbsolute(loc);
587 3 : locationRead = true;
588 14 : } else if (ntag == "indexDiff") {
589 14 : localIndexDiff = e.readInt();
590 : } else {
591 0 : e.unknown();
592 : }
593 : }
594 486 : if (!locationRead) {
595 483 : mainLoc = loc;
596 : }
597 486 : LinkedObjects* link = ctx.getLink(linkedIsMaster, mainLoc, localIndexDiff);
598 486 : if (link) {
599 485 : EngravingObject* linked = link->mainElement();
600 485 : if (linked->type() == item->type()) {
601 485 : item->linkTo(linked);
602 : } else {
603 0 : LOGW("EngravingItem::readProperties: linked elements have different types: %s, %s. Input file corrupted?",
604 : item->typeName(), linked->typeName());
605 : }
606 : }
607 486 : if (!item->links()) {
608 1 : LOGW("EngravingItem::readProperties: could not link %s at staff %d", item->typeName(), mainLoc.staff() + 1);
609 : }
610 : }
611 218 : } else if (TRead::readProperty(item, tag, e, ctx, Pid::POSITION_LINKED_TO_MASTER)) {
612 218 : } else if (TRead::readProperty(item, tag, e, ctx, Pid::APPEARANCE_LINKED_TO_MASTER)) {
613 218 : } else if (TRead::readProperty(item, tag, e, ctx, Pid::EXCLUDE_FROM_OTHER_PARTS)) {
614 215 : } else if (tag == "voice") {
615 0 : item->setVoice(e.readInt());
616 215 : } else if (tag == "tag") {
617 0 : e.skipCurrentElement();
618 215 : } else if (TRead::readProperty(item, tag, e, ctx, Pid::PLACEMENT)) {
619 207 : } else if (tag == "z") {
620 7 : item->setZ(e.readInt());
621 : } else {
622 200 : return false;
623 : }
624 5645 : return true;
625 : }
626 :
627 16 : void TRead::read(TextBase* t, XmlReader& xml, ReadContext& ctx)
628 : {
629 64 : while (xml.readNextStartElement()) {
630 32 : if (!readProperties(toTextBase(t), xml, ctx)) {
631 0 : xml.unknown();
632 : }
633 : }
634 16 : }
635 :
636 65 : void TRead::read(TempoText* t, XmlReader& e, ReadContext& ctx)
637 : {
638 242 : while (e.readNextStartElement()) {
639 177 : const AsciiStringView tag(e.name());
640 177 : if (readProperty(t, tag, e, ctx, Pid::PLAY)) {
641 177 : } else if (tag == "tempo") {
642 65 : t->setTempo(TConv::fromXml(e.readAsciiText(), Constants::DEFAULT_TEMPO));
643 112 : } else if (tag == "followText") {
644 21 : t->setFollowText(e.readInt());
645 91 : } else if (tag == "type") {
646 0 : auto type = e.readAsciiText();
647 0 : if (type == "aTempo") {
648 0 : t->setTempoTextType(TempoTextType::A_TEMPO);
649 0 : } else if (type == "tempoPrimo") {
650 0 : t->setTempoTextType(TempoTextType::TEMPO_PRIMO);
651 0 : } else if (type == "normal") {
652 0 : t->setTempoTextType(TempoTextType::NORMAL);
653 : } else {
654 0 : e.unknown();
655 : }
656 91 : } else if (!readProperties(toTextBase(t), e, ctx)) {
657 0 : e.unknown();
658 : }
659 : }
660 : // check sanity
661 65 : if (t->xmlText().isEmpty()) {
662 0 : t->setXmlText(String(u"<sym>metNoteQuarterUp</sym> = %1").arg(int(lrint(t->tempo().toBPM().val))));
663 0 : t->setVisible(false);
664 : }
665 :
666 65 : t->resetProperty(Pid::MUSIC_SYMBOL_SIZE);
667 65 : }
668 :
669 67 : void TRead::read(StaffText* t, XmlReader& xml, ReadContext& ctx)
670 : {
671 197 : while (xml.readNextStartElement()) {
672 130 : const AsciiStringView tag(xml.name());
673 130 : if (tag == "SoundFlag") {
674 9 : SoundFlag* flag = Factory::createSoundFlag(t);
675 9 : read(flag, xml, ctx);
676 9 : t->setSoundFlag(flag);
677 121 : } else if (!readProperties(static_cast<StaffTextBase*>(t), xml, ctx)) {
678 0 : xml.unknown();
679 : }
680 : }
681 67 : }
682 :
683 5 : void TRead::read(StaffTextBase* t, XmlReader& xml, ReadContext& ctx)
684 : {
685 5 : t->clear();
686 :
687 27 : while (xml.readNextStartElement()) {
688 17 : if (!readProperties(t, xml, ctx)) {
689 0 : xml.unknown();
690 : }
691 : }
692 5 : }
693 :
694 150 : bool TRead::readProperties(StaffTextBase* t, XmlReader& e, ReadContext& ctx)
695 : {
696 150 : const AsciiStringView tag(e.name());
697 :
698 150 : if (tag == "MidiAction") {
699 0 : int channel = e.intAttribute("channel", 0);
700 0 : String name = e.attribute("name");
701 0 : bool found = false;
702 0 : size_t n = t->channelActions().size();
703 0 : for (size_t i = 0; i < n; ++i) {
704 0 : ChannelActions* a = &t->channelActions()[i];
705 0 : if (a->channel == channel) {
706 0 : a->midiActionNames.append(name);
707 0 : found = true;
708 0 : break;
709 : }
710 : }
711 0 : if (!found) {
712 0 : ChannelActions a;
713 0 : a.channel = channel;
714 0 : a.midiActionNames.append(name);
715 0 : t->channelActions().push_back(a);
716 0 : }
717 0 : e.readNext();
718 150 : } else if (tag == "channelSwitch" || tag == "articulationChange") {
719 0 : voice_idx_t voice = static_cast<voice_idx_t>(e.intAttribute("voice", -1));
720 0 : if (voice < VOICES) {
721 0 : t->setChannelName(voice, e.attribute("name"));
722 0 : } else if (voice == muse::nidx) {
723 : // no voice applies channel to all voices for
724 : // compatibility
725 0 : for (voice_idx_t i = 0; i < VOICES; ++i) {
726 0 : t->setChannelName(i, e.attribute("name"));
727 : }
728 : }
729 0 : e.readNext();
730 150 : } else if (tag == "aeolus") {
731 0 : int group = e.intAttribute("group", -1);
732 0 : if (group >= 0 && group < 4) {
733 0 : t->setAeolusStop(group, e.readInt());
734 : } else {
735 0 : e.readNext();
736 : }
737 0 : t->setSetAeolusStops(true);
738 150 : } else if (tag == "swing") {
739 0 : DurationType swingUnit = TConv::fromXml(e.asciiAttribute("unit"), DurationType::V_INVALID);
740 0 : int unit = 0;
741 0 : if (swingUnit == DurationType::V_EIGHTH) {
742 0 : unit = Constants::DIVISION / 2;
743 0 : } else if (swingUnit == DurationType::V_16TH) {
744 0 : unit = Constants::DIVISION / 4;
745 0 : } else if (swingUnit == DurationType::V_ZERO) {
746 0 : unit = 0;
747 : }
748 0 : int ratio = e.intAttribute("ratio", 60);
749 0 : t->setSwing(true);
750 0 : t->setSwingParameters(unit, ratio);
751 0 : e.readNext();
752 150 : } else if (tag == "capo") {
753 0 : int fretId = e.intAttribute("fretId", 0);
754 0 : t->setCapo(fretId);
755 0 : e.readNext();
756 150 : } else if (!readProperties(toTextBase(t), e, ctx)) {
757 0 : return false;
758 : }
759 150 : return true;
760 : }
761 :
762 126 : void TRead::read(Dynamic* d, XmlReader& e, ReadContext& ctx)
763 : {
764 126 : int mscVersion = ctx.score()->mscVersion();
765 :
766 447 : while (e.readNextStartElement()) {
767 321 : const AsciiStringView tag = e.name();
768 321 : if (tag == "subtype") {
769 126 : d->setDynamicType(e.readText());
770 195 : } else if (tag == "velocity") {
771 126 : d->setVelocity(e.readInt());
772 69 : } else if (tag == "dynType") { // obsolete
773 0 : if (mscVersion < 440) {
774 0 : d->setVoiceAssignment(read206::Read206::readDynamicRange(e.readInt()));
775 : } else {
776 0 : e.skipCurrentElement();
777 : }
778 69 : } else if (tag == "veloChange") {
779 0 : d->setChangeInVelocity(e.readInt());
780 69 : } else if (tag == "veloChangeSpeed") {
781 0 : d->setVelChangeSpeed(TConv::fromXml(e.readAsciiText(), DynamicSpeed::NORMAL));
782 69 : } else if (tag == "play") {
783 0 : d->setPlayDynamic(e.readBool());
784 69 : } else if (tag == "dynamicsSize") {
785 0 : d->setSymbolScale(e.readDouble());
786 69 : } else if (readProperty(d, tag, e, ctx, Pid::AVOID_BARLINES)) {
787 69 : } else if (readProperty(d, tag, e, ctx, Pid::CENTER_ON_NOTEHEAD)) {
788 69 : } else if (readProperty(d, tag, e, ctx, Pid::ANCHOR_TO_END_OF_PREVIOUS)) {
789 68 : } else if (!readProperties(toTextBase(d), e, ctx)) {
790 0 : e.unknown();
791 : }
792 : }
793 126 : }
794 :
795 0 : void TRead::read(Expression* expr, XmlReader& xml, ReadContext& ctx)
796 : {
797 0 : while (xml.readNextStartElement()) {
798 0 : const AsciiStringView tag = xml.name();
799 0 : if (tag == "snapToDynamics") {
800 0 : readProperty(expr, xml, ctx, Pid::SNAP_TO_DYNAMICS);
801 0 : } else if (!readProperties(toTextBase(expr), xml, ctx)) {
802 0 : xml.unknown();
803 : }
804 : }
805 0 : }
806 :
807 0 : void TRead::read(FretDiagram* d, XmlReader& e, ReadContext& ctx)
808 : {
809 : // Read the old format first
810 0 : bool hasBarre = false;
811 0 : bool haveReadNew = false;
812 :
813 0 : while (e.readNextStartElement()) {
814 0 : const AsciiStringView tag(e.name());
815 :
816 : // Check for new format fret diagram
817 0 : if (haveReadNew) {
818 0 : e.skipCurrentElement();
819 0 : continue;
820 : }
821 0 : if (tag == "fretDiagram") {
822 : // Read new
823 0 : while (e.readNextStartElement()) {
824 0 : const AsciiStringView tag2(e.name());
825 :
826 0 : if (tag2 == "string") {
827 0 : int no = e.intAttribute("no");
828 0 : while (e.readNextStartElement()) {
829 0 : const AsciiStringView t(e.name());
830 0 : if (t == "dot") {
831 0 : int fret = e.intAttribute("fret", 0);
832 0 : FretDotType dtype = FretItem::nameToDotType(e.readText());
833 0 : d->setDot(no, fret, true, dtype);
834 0 : } else if (t == "marker") {
835 0 : FretMarkerType mtype = FretItem::nameToMarkerType(e.readText());
836 0 : d->setMarker(no, mtype);
837 0 : } else if (t == "fingering") {
838 0 : e.readText();
839 : /*setFingering(no, e.readInt()); NOTE:JT todo */
840 : } else {
841 0 : e.unknown();
842 : }
843 : }
844 0 : } else if (tag2 == "barre") {
845 0 : int start = e.intAttribute("start", -1);
846 0 : int end = e.intAttribute("end", -1);
847 0 : int fret = e.readInt();
848 :
849 0 : d->setBarre(start, end, fret);
850 0 : } else if (!readItemProperties(d, e, ctx)) {
851 0 : e.unknown();
852 : }
853 : }
854 0 : haveReadNew = true;
855 : }
856 : // Check for new properties
857 0 : else if (tag == "showNut") {
858 0 : TRead::readProperty(d, e, ctx, Pid::FRET_NUT);
859 0 : } else if (tag == "orientation") {
860 0 : TRead::readProperty(d, e, ctx, Pid::ORIENTATION);
861 : }
862 : // Then read the rest if there is no new format diagram (compatibility read)
863 0 : else if (tag == "strings") {
864 0 : TRead::readProperty(d, e, ctx, Pid::FRET_STRINGS);
865 0 : } else if (tag == "frets") {
866 0 : TRead::readProperty(d, e, ctx, Pid::FRET_FRETS);
867 0 : } else if (tag == "fretOffset") {
868 0 : TRead::readProperty(d, e, ctx, Pid::FRET_OFFSET);
869 0 : } else if (tag == "string") {
870 0 : int no = e.intAttribute("no");
871 0 : while (e.readNextStartElement()) {
872 0 : const AsciiStringView t(e.name());
873 0 : if (t == "dot") {
874 0 : d->setDot(no, e.readInt());
875 0 : } else if (t == "marker") {
876 0 : d->setMarker(no, Char(e.readInt()) == u'X' ? FretMarkerType::CROSS : FretMarkerType::CIRCLE);
877 : }
878 : /*else if (t == "fingering")
879 : setFingering(no, e.readInt());*/
880 : else {
881 0 : e.unknown();
882 : }
883 : }
884 0 : } else if (tag == "barre") {
885 0 : hasBarre = e.readBool();
886 0 : } else if (tag == "mag") {
887 0 : TRead::readProperty(d, e, ctx, Pid::MAG);
888 0 : } else if (tag == "Harmony") {
889 0 : Harmony* h = new Harmony(d->score()->dummy());
890 0 : read(h, e, ctx);
891 0 : if (h->chords().empty()) {
892 : // Invalid harmony
893 0 : delete h;
894 : } else {
895 0 : d->add(h);
896 : }
897 0 : } else if (readProperty(d, tag, e, ctx, Pid::FRET_SHOW_FINGERINGS)) {
898 0 : } else if (readProperty(d, tag, e, ctx, Pid::FRET_FINGERING)) {
899 0 : } else if (!readItemProperties(d, e, ctx)) {
900 0 : e.unknown();
901 : }
902 : }
903 :
904 : // Old handling of barres
905 0 : if (hasBarre) {
906 0 : for (int s = 0; s < d->strings(); ++s) {
907 0 : for (auto& dot : d->dot(s)) {
908 0 : if (dot.exists()) {
909 0 : d->setBarre(s, -1, dot.fret);
910 0 : return;
911 : }
912 0 : }
913 : }
914 : }
915 : }
916 :
917 7 : void TRead::read(TremoloBar* b, XmlReader& e, ReadContext& ctx)
918 : {
919 23 : while (e.readNextStartElement()) {
920 16 : auto tag = e.name();
921 16 : if (tag == "point") {
922 16 : PitchValue pv;
923 16 : pv.time = e.intAttribute("time");
924 16 : pv.pitch = e.intAttribute("pitch");
925 16 : pv.vibrato = e.intAttribute("vibrato");
926 16 : b->points().push_back(pv);
927 16 : e.readNext();
928 0 : } else if (tag == "mag") {
929 0 : b->setUserMag(e.readDouble(0.1, 10.0));
930 0 : } else if (TRead::readStyledProperty(b, tag, e, ctx)) {
931 0 : } else if (tag == "play") {
932 0 : b->setPlay(e.readInt());
933 0 : } else if (TRead::readProperty(b, tag, e, ctx, Pid::LINE_WIDTH)) {
934 0 : } else if (!readItemProperties(b, e, ctx)) {
935 0 : e.unknown();
936 : }
937 : }
938 7 : }
939 :
940 15 : void TRead::read(Sticking* s, XmlReader& xml, ReadContext& ctx)
941 : {
942 15 : read(toTextBase(s), xml, ctx);
943 15 : }
944 :
945 5 : void TRead::read(SystemText* t, XmlReader& xml, ReadContext& ctx)
946 : {
947 5 : read(static_cast<StaffTextBase*>(t), xml, ctx);
948 5 : }
949 :
950 7 : void TRead::read(PlayTechAnnotation* a, XmlReader& xml, ReadContext& ctx)
951 : {
952 25 : while (xml.readNextStartElement()) {
953 18 : const AsciiStringView tag(xml.name());
954 :
955 18 : if (TRead::readProperty(a, tag, xml, ctx, Pid::PLAY_TECH_TYPE)) {
956 6 : continue;
957 : }
958 :
959 12 : if (!readProperties(static_cast<StaffTextBase*>(a), xml, ctx)) {
960 0 : xml.unknown();
961 : }
962 : }
963 7 : }
964 :
965 1 : void TRead::read(RehearsalMark* m, XmlReader& xml, ReadContext& ctx)
966 : {
967 1 : read(toTextBase(m), xml, ctx);
968 1 : }
969 :
970 237 : void TRead::read(Instrument* item, XmlReader& e, ReadContext& ctx, Part* part)
971 : {
972 237 : bool customDrumset = false;
973 237 : bool readSingleNoteDynamics = false;
974 :
975 237 : item->clearChannels(); // remove default channel
976 237 : item->setId(e.attribute("id"));
977 3377 : while (e.readNextStartElement()) {
978 3140 : const AsciiStringView tag(e.name());
979 3140 : if (tag == "singleNoteDynamics") {
980 56 : item->setSingleNoteDynamics(e.readBool());
981 56 : readSingleNoteDynamics = true;
982 3084 : } else if (!readProperties(item, e, ctx, part, &customDrumset)) {
983 0 : e.unknown();
984 : }
985 : }
986 :
987 237 : item->updateInstrumentId();
988 :
989 237 : if (item->channel().empty()) { // for backward compatibility
990 1 : InstrChannel* fallbackChannel = new InstrChannel;
991 1 : fallbackChannel->setName(String::fromUtf8(InstrChannel::DEFAULT_NAME));
992 1 : fallbackChannel->setProgram(item->recognizeMidiProgram());
993 1 : item->appendChannel(fallbackChannel);
994 236 : } else if (item->channel(0)->program() == -1) {
995 0 : item->channel(0)->setProgram(item->recognizeMidiProgram());
996 : }
997 :
998 237 : if (!readSingleNoteDynamics) {
999 181 : item->setSingleNoteDynamicsFromTemplate();
1000 : }
1001 237 : }
1002 :
1003 3084 : bool TRead::readProperties(Instrument* item, XmlReader& e, ReadContext& ctx, Part* part, bool* customDrumset)
1004 : {
1005 3084 : PartAudioSettingsCompat partAudioSetting;
1006 3084 : InstrumentTrackId trackId;
1007 3084 : if (part && part->score()) {
1008 9252 : trackId = { part->score()->parts().size() + 1, item->id() };//part is not assigned to score, _id field is not correct
1009 : }
1010 3084 : partAudioSetting.instrumentId = trackId;
1011 :
1012 3084 : const AsciiStringView tag(e.name());
1013 3084 : if (tag == "soundId") {
1014 0 : item->setSoundId(e.readText());
1015 3084 : } else if (tag == "longName") {
1016 222 : item->setLongName(read500::TRead::readLegacyStaffName(e));
1017 2862 : } else if (tag == "shortName") {
1018 224 : item->setShortName(read500::TRead::readLegacyStaffName(e));
1019 2638 : } else if (tag == "trackName") {
1020 237 : item->setTrackName(e.readText());
1021 2401 : } else if (tag == "minPitchA") {
1022 188 : item->setMinPitchA(e.readInt());
1023 2213 : } else if (tag == "minPitchP") {
1024 188 : item->setMinPitchP(e.readInt());
1025 2025 : } else if (tag == "maxPitchA") {
1026 188 : item->setMaxPitchA(e.readInt());
1027 1837 : } else if (tag == "maxPitchP") {
1028 188 : item->setMaxPitchP(e.readInt());
1029 1649 : } else if (tag == "transposeChromatic") {
1030 55 : Interval transpose = item->transpose();
1031 55 : transpose.chromatic = e.readInt();
1032 55 : item->setTranspose(transpose);
1033 1594 : } else if (tag == "transposeDiatonic") {
1034 55 : Interval transpose = item->transpose();
1035 55 : transpose.diatonic = e.readInt();
1036 55 : item->setTranspose(transpose);
1037 1539 : } else if (tag == "instrumentId") {
1038 236 : item->setMusicXmlId(e.readText());
1039 1303 : } else if (tag == "useDrumset") {
1040 4 : item->setUseDrumset(e.readInt());
1041 4 : if (item->useDrumset()) {
1042 4 : item->setDrumset(new Drumset(*smDrumset));
1043 : }
1044 1299 : } else if (tag == "Drum") {
1045 : // if we see one of these tags, a custom drumset will be created
1046 92 : if (!item->drumset()) {
1047 0 : item->setDrumset(new Drumset(*smDrumset));
1048 : }
1049 92 : if (!(*customDrumset)) {
1050 4 : const_cast<Drumset*>(item->drumset())->clear();
1051 4 : *customDrumset = true;
1052 : }
1053 92 : const_cast<Drumset*>(item->drumset())->loadDrum(e);
1054 1207 : } else if (tag == "percussionPanelColumns") {
1055 : // if we see one of these tags, a custom drumset will be created
1056 0 : if (!item->drumset()) {
1057 0 : item->setDrumset(new Drumset(*smDrumset));
1058 : }
1059 0 : if (!(*customDrumset)) {
1060 0 : const_cast<Drumset*>(item->drumset())->clear();
1061 0 : *customDrumset = true;
1062 : }
1063 0 : item->drumset()->setPercussionPanelColumns(e.readInt());
1064 : }
1065 : // support tag "Tablature" for a while for compatibility with existent 2.0 scores
1066 1207 : else if (tag == "Tablature" || tag == "StringData") {
1067 61 : StringData sd;
1068 61 : read(&sd, e);
1069 61 : item->setStringData(sd);
1070 1207 : } else if (tag == "MidiAction") {
1071 0 : NamedEventList a;
1072 0 : read(&a, e);
1073 0 : item->addMidiAction(a);
1074 1146 : } else if (tag == "Articulation") {
1075 732 : MidiArticulation a;
1076 732 : read(&a, e);
1077 732 : item->addMidiArticulation(a);
1078 1146 : } else if (tag == "Channel" || tag == "channel") {
1079 321 : InstrChannel* a = new InstrChannel;
1080 321 : read(a, e, ctx, part, trackId);
1081 321 : item->appendChannel(a);
1082 93 : } else if (tag == "clef") { // sets both transposing and concert clef
1083 93 : int idx = e.intAttribute("staff", 1) - 1;
1084 93 : ClefType ct = TConv::fromXml(e.readAsciiText(), ClefType::G);
1085 93 : item->setClefType(idx, ClefTypeList(ct, ct));
1086 0 : } else if (tag == "concertClef") {
1087 0 : int idx = e.intAttribute("staff", 1) - 1;
1088 0 : item->setClefType(idx, ClefTypeList(TConv::fromXml(e.readAsciiText(), ClefType::G), item->clefType(idx).transposingClef));
1089 0 : } else if (tag == "transposingClef") {
1090 0 : int idx = e.intAttribute("staff", 1) - 1;
1091 0 : item->setClefType(idx, ClefTypeList(item->clefType(idx).concertClef, TConv::fromXml(e.readAsciiText(), ClefType::G)));
1092 : } else {
1093 0 : return false;
1094 : }
1095 :
1096 3084 : return true;
1097 9252 : }
1098 :
1099 321 : void TRead::read(InstrChannel* item, XmlReader& e, ReadContext& ctx, Part* part, const InstrumentTrackId& instrId)
1100 : {
1101 321 : item->setNotifyAboutChangedEnabled(false);
1102 :
1103 : // synti = 0;
1104 321 : item->setName(e.attribute("name"));
1105 321 : if (item->name() == "") {
1106 209 : item->setName(String::fromUtf8(InstrChannel::DEFAULT_NAME));
1107 : }
1108 :
1109 321 : int midiPort = -1;
1110 321 : int midiChannel = -1;
1111 321 : PartAudioSettingsCompat partAudioSetting;
1112 321 : partAudioSetting.instrumentId = instrId;
1113 :
1114 1087 : while (e.readNextStartElement()) {
1115 766 : const AsciiStringView tag(e.name());
1116 766 : if (tag == "program") {
1117 321 : item->setProgram(e.intAttribute("value", -1));
1118 321 : if (item->program() == -1) {
1119 0 : item->setProgram(e.readInt());
1120 : } else {
1121 321 : e.readNext();
1122 : }
1123 445 : } else if (tag == "controller") {
1124 69 : int value = e.intAttribute("value", 0);
1125 69 : int ctrl = e.intAttribute("ctrl", 0);
1126 69 : switch (ctrl) {
1127 10 : case CTRL_HBANK:
1128 10 : item->setBank((value << 7) + (item->bank() & 0x7f));
1129 10 : item->setUserBankController(true);
1130 10 : break;
1131 10 : case CTRL_LBANK:
1132 10 : item->setBank((item->bank() & ~0x7f) + (value & 0x7f));
1133 10 : item->setUserBankController(true);
1134 10 : break;
1135 45 : case CTRL_VOLUME:
1136 45 : item->setVolume(value);
1137 45 : break;
1138 4 : case CTRL_PANPOT:
1139 4 : item->setPan(value);
1140 4 : break;
1141 0 : case CTRL_CHORUS_SEND:
1142 0 : item->setChorus(value);
1143 0 : break;
1144 0 : case CTRL_REVERB_SEND:
1145 0 : item->setReverb(value);
1146 0 : break;
1147 0 : default:
1148 : {
1149 0 : Event ev(ME_CONTROLLER);
1150 0 : ev.setOntime(-1);
1151 0 : ev.setChannel(0);
1152 0 : ev.setDataA(ctrl);
1153 0 : ev.setDataB(value);
1154 0 : item->addToInit(ev);
1155 0 : }
1156 0 : break;
1157 : }
1158 69 : e.readNext();
1159 376 : } else if (tag == "Articulation") {
1160 0 : MidiArticulation a;
1161 0 : read(&a, e);
1162 0 : item->articulation.push_back(a);
1163 376 : } else if (tag == "MidiAction") {
1164 0 : NamedEventList a;
1165 0 : read(&a, e);
1166 0 : item->midiActions.push_back(a);
1167 376 : } else if (tag == "synti") {
1168 306 : item->setSynti(e.readText());
1169 70 : } else if (tag == "color") {
1170 0 : item->setColor(e.readInt());
1171 70 : } else if (tag == "mute") {
1172 0 : partAudioSetting.mute = e.readInt();
1173 70 : } else if (tag == "solo") {
1174 0 : partAudioSetting.solo = e.readInt();
1175 70 : } else if (tag == "midiPort") {
1176 35 : midiPort = e.readInt();
1177 35 : } else if (tag == "midiChannel") {
1178 35 : midiChannel = e.readInt();
1179 : } else {
1180 0 : e.unknown();
1181 : }
1182 : }
1183 :
1184 321 : item->setMustUpdateInit(true);
1185 :
1186 321 : ctx.addPartAudioSettingCompat(partAudioSetting);
1187 :
1188 321 : item->setNotifyAboutChangedEnabled(true);
1189 :
1190 321 : if ((midiPort != -1 || midiChannel != -1) && part && part->score()->isMaster()) {
1191 35 : part->masterScore()->addMidiMapping(item, part, midiPort, midiChannel);
1192 : }
1193 321 : }
1194 :
1195 732 : void TRead::read(MidiArticulation* item, XmlReader& e)
1196 : {
1197 732 : item->name = e.attribute("name");
1198 2196 : while (e.readNextStartElement()) {
1199 1464 : const AsciiStringView tag(e.name());
1200 1464 : if (tag == "velocity") {
1201 732 : String text(e.readText());
1202 732 : if (text.endsWith(u"%")) {
1203 0 : text = text.left(text.size() - 1);
1204 : }
1205 732 : item->velocity = text.toInt();
1206 1464 : } else if (tag == "gateTime") {
1207 732 : String text(e.readText());
1208 732 : if (text.endsWith(u"%")) {
1209 0 : text = text.left(text.size() - 1);
1210 : }
1211 732 : item->gateTime = text.toInt();
1212 732 : } else if (tag == "descr") {
1213 0 : item->descr = e.readText();
1214 : } else {
1215 0 : e.unknown();
1216 : }
1217 : }
1218 732 : }
1219 :
1220 0 : void TRead::read(NamedEventList* item, XmlReader& e)
1221 : {
1222 0 : item->name = e.attribute("name");
1223 0 : while (e.readNextStartElement()) {
1224 0 : const AsciiStringView tag(e.name());
1225 0 : if (tag == "program") {
1226 0 : MidiCoreEvent ev(ME_CONTROLLER, 0, CTRL_PROGRAM, e.intAttribute("value", 0));
1227 0 : item->events.push_back(ev);
1228 0 : e.skipCurrentElement();
1229 0 : } else if (tag == "controller") {
1230 0 : MidiCoreEvent ev;
1231 0 : ev.setType(ME_CONTROLLER);
1232 0 : ev.setDataA(e.intAttribute("ctrl", 0));
1233 0 : ev.setDataB(e.intAttribute("value", 0));
1234 0 : item->events.push_back(ev);
1235 0 : e.skipCurrentElement();
1236 0 : } else if (tag == "descr") {
1237 0 : item->descr = e.readText();
1238 : } else {
1239 0 : e.unknown();
1240 : }
1241 : }
1242 0 : }
1243 :
1244 0 : void TRead::read(InstrumentChange* c, XmlReader& e, ReadContext& ctx)
1245 : {
1246 0 : Instrument inst;
1247 0 : while (e.readNextStartElement()) {
1248 0 : const AsciiStringView tag(e.name());
1249 0 : if (tag == "Instrument") {
1250 0 : read(&inst, e, ctx, c->part());
1251 0 : } else if (tag == "init") {
1252 0 : c->setInit(e.readBool());
1253 0 : } else if (!readProperties(toTextBase(c), e, ctx)) {
1254 0 : e.unknown();
1255 : }
1256 : }
1257 :
1258 0 : c->setInstrument(inst);
1259 0 : }
1260 :
1261 0 : void TRead::read(KeyList* item, XmlReader& e, ReadContext& ctx)
1262 : {
1263 0 : while (e.readNextStartElement()) {
1264 0 : if (e.name() == "key") {
1265 : Key k;
1266 0 : int tick = e.intAttribute("tick", 0);
1267 0 : if (e.hasAttribute("custom")) {
1268 0 : k = Key::C; // ke.setCustomType(e.intAttribute("custom"));
1269 : } else {
1270 0 : k = Key(e.intAttribute("idx"));
1271 : }
1272 0 : KeySigEvent ke;
1273 0 : ke.setConcertKey(k);
1274 0 : (*item)[ctx.fileDivision(tick)] = ke;
1275 0 : e.readNext();
1276 0 : } else {
1277 0 : e.unknown();
1278 : }
1279 : }
1280 0 : }
1281 :
1282 262 : void TRead::read(KeySig* s, XmlReader& e, ReadContext& ctx)
1283 : {
1284 262 : KeySigEvent sig;
1285 262 : int subtype = 0;
1286 262 : Part* p = s->part();
1287 :
1288 705 : while (e.readNextStartElement()) {
1289 443 : const AsciiStringView tag(e.name());
1290 443 : if (tag == "CustDef" || tag == "KeySym") {
1291 0 : CustDef cd;
1292 0 : while (e.readNextStartElement()) {
1293 0 : const AsciiStringView t(e.name());
1294 0 : if (t == "sym") {
1295 0 : AsciiStringView val(e.readAsciiText());
1296 : bool valid;
1297 0 : SymId id = SymId(val.toInt(&valid));
1298 0 : if (!valid) {
1299 0 : id = SymNames::symIdByName(val);
1300 : }
1301 0 : cd.sym = id;
1302 0 : } else if (t == "def") {
1303 0 : cd.degree = e.intAttribute("degree", 0);
1304 0 : cd.octAlt = e.intAttribute("octAlt", 0);
1305 0 : cd.xAlt = Spatium(e.doubleAttribute("xAlt", 0.0));
1306 0 : e.readNext();
1307 0 : } else if (t == "pos") { // for older files
1308 0 : Spatium prevx = 0_sp;
1309 0 : Spatium accidentalGap = ctx.score()->style().styleS(Sid::keysigAccidentalDistance);
1310 0 : double _spatium = s->spatium();
1311 : // count default x position
1312 0 : for (CustDef& cd2 : sig.customKeyDefs()) {
1313 0 : prevx += Spatium::fromAbsolute(s->symWidth(cd2.sym), _spatium) + accidentalGap + cd2.xAlt;
1314 : }
1315 0 : bool flat = std::string(SymNames::nameForSymId(cd.sym).ascii()).find("Flat") != std::string::npos;
1316 : // if x not there, use default step
1317 0 : cd.xAlt = Spatium(e.doubleAttribute("x", prevx.val())) - prevx;
1318 : // if y not there, use middle line
1319 0 : int line = static_cast<int>(e.doubleAttribute("y", 2) * 2);
1320 0 : cd.degree = (3 - line) % 7;
1321 0 : cd.degree += (cd.degree < 0) ? 7 : 0;
1322 0 : line += flat ? -1 : 1; // top point in treble for # is -1 (gis), and for b is 1 (es)
1323 0 : cd.octAlt = static_cast<int>((line - (line >= 0 ? 0 : 6)) / 7);
1324 0 : e.readNext();
1325 : } else {
1326 0 : e.unknown();
1327 : }
1328 : }
1329 0 : sig.customKeyDefs().push_back(cd);
1330 443 : } else if (TRead::readProperty(s, tag, e, ctx, Pid::SHOW_COURTESY)) {
1331 443 : } else if (tag == "accidental") { // older files; we need to guess proper concert key
1332 1 : Key key = Key(e.readInt());
1333 1 : Key cKey = key;
1334 1 : if (p && !s->concertPitch()) {
1335 1 : Interval v = p->instrument(s->tick())->transpose();
1336 1 : if (!v.isZero()) {
1337 0 : cKey = Transpose::transposeKey(key, v);
1338 : }
1339 : }
1340 1 : sig.setConcertKey(cKey);
1341 1 : sig.setKey(key);
1342 442 : } else if (tag == "concertKey") {
1343 258 : sig.setConcertKey(Key(e.readInt()));
1344 184 : } else if (tag == "actualKey") {
1345 15 : sig.setKey(Key(e.readInt()));
1346 169 : } else if (tag == "custom") {
1347 3 : e.readInt();
1348 3 : sig.setCustom(true);
1349 166 : } else if (tag == "mode") {
1350 3 : sig.setMode(TConv::fromXml(e.readAsciiText(), KeyMode::UNKNOWN));
1351 163 : } else if (tag == "subtype") {
1352 0 : subtype = e.readInt();
1353 163 : } else if (tag == "forInstrumentChange") {
1354 0 : sig.setForInstrumentChange(e.readBool());
1355 163 : } else if (TRead::readProperty(s, tag, e, ctx, Pid::IS_COURTESY)) {
1356 163 : } else if (!readItemProperties(s, e, ctx)) {
1357 0 : e.unknown();
1358 : }
1359 : }
1360 : // for backward compatibility
1361 262 : if (!sig.isValid()) {
1362 0 : sig.initFromSubtype(subtype);
1363 : }
1364 262 : if (sig.custom() && sig.customKeyDefs().empty()) {
1365 3 : sig.setMode(KeyMode::NONE);
1366 : }
1367 : // if there are more than 6 accidentals in transposing key, it cannot be PreferSharpFlat::AUTO
1368 262 : if (p && !s->concertPitch() && (sig.key() > 6 || sig.key() < -6)
1369 524 : && p->preferSharpFlat() == PreferSharpFlat::AUTO && !p->instrument(s->tick())->transpose().isZero()) {
1370 0 : p->setPreferSharpFlat(PreferSharpFlat::NONE);
1371 : }
1372 :
1373 262 : s->setKeySigEvent(sig);
1374 262 : }
1375 :
1376 0 : void TRead::read(LaissezVib* lv, XmlReader& xml, ReadContext& ctx)
1377 : {
1378 0 : while (xml.readNextStartElement()) {
1379 0 : const AsciiStringView tag(xml.name());
1380 0 : if (TRead::readProperty(lv, tag, xml, ctx, Pid::TIE_PLACEMENT)) {
1381 0 : } else if (TRead::readProperty(lv, tag, xml, ctx, Pid::MIN_LENGTH)) {
1382 0 : } else if (!readProperties(toSlurTie(lv), xml, ctx)) {
1383 0 : xml.unknown();
1384 : }
1385 : }
1386 0 : }
1387 :
1388 0 : void TRead::read(StaffState* s, XmlReader& e, ReadContext& ctx)
1389 : {
1390 0 : while (e.readNextStartElement()) {
1391 0 : const AsciiStringView tag(e.name());
1392 0 : if (tag == "subtype") {
1393 0 : s->setStaffStateType(StaffStateType(e.readInt()));
1394 0 : } else if (tag == "Instrument") {
1395 0 : Instrument i;
1396 0 : read(&i, e, ctx, nullptr);
1397 0 : s->setInstrument(std::move(i));
1398 0 : } else if (!readItemProperties(s, e, ctx)) {
1399 0 : e.unknown();
1400 : }
1401 : }
1402 0 : }
1403 :
1404 5 : void TRead::read(FiguredBass* b, XmlReader& e, ReadContext& ctx)
1405 : {
1406 5 : String normalizedText;
1407 5 : int idx = 0;
1408 15 : while (e.readNextStartElement()) {
1409 10 : const AsciiStringView tag(e.name());
1410 10 : if (tag == "ticks") {
1411 5 : b->setTicks(e.readFraction());
1412 5 : } else if (tag == "onNote") {
1413 0 : b->setOnNote(e.readInt() != 0l);
1414 5 : } else if (tag == "FiguredBassItem") {
1415 5 : FiguredBassItem* pItem = b->createItem(idx++);
1416 5 : pItem->setTrack(b->track());
1417 5 : pItem->setOwnershipParent(b);
1418 5 : TRead::read(pItem, e, ctx);
1419 5 : b->appendItem(pItem);
1420 : // add item normalized text
1421 5 : if (!normalizedText.isEmpty()) {
1422 0 : normalizedText.append('\n');
1423 : }
1424 5 : normalizedText.append(pItem->normalizedText());
1425 : }
1426 : // else if (tag == "style")
1427 : // setStyledPropertyListIdx(e.readElementText());
1428 0 : else if (!readProperties(toTextBase(b), e, ctx)) {
1429 0 : e.unknown();
1430 : }
1431 : }
1432 : // if items could be parsed set normalized text
1433 5 : if (b->items().size() > 0) {
1434 5 : b->setXmlText(normalizedText); // this is the text to show while editing
1435 : }
1436 5 : }
1437 :
1438 5 : void TRead::read(FiguredBassItem* i, XmlReader& e, ReadContext& ctx)
1439 : {
1440 15 : while (e.readNextStartElement()) {
1441 10 : const AsciiStringView tag(e.name());
1442 :
1443 10 : if (tag == "brackets") {
1444 5 : i->setParenth1((FiguredBassItem::Parenthesis)e.intAttribute("b0"));
1445 5 : i->setParenth2((FiguredBassItem::Parenthesis)e.intAttribute("b1"));
1446 5 : i->setParenth3((FiguredBassItem::Parenthesis)e.intAttribute("b2"));
1447 5 : i->setParenth4((FiguredBassItem::Parenthesis)e.intAttribute("b3"));
1448 5 : i->setParenth5((FiguredBassItem::Parenthesis)e.intAttribute("b4"));
1449 5 : e.readNext();
1450 5 : } else if (tag == "prefix") {
1451 0 : i->setPrefix((FiguredBassItem::Modifier)(e.readInt()));
1452 5 : } else if (tag == "digit") {
1453 5 : i->setDigit(e.readInt());
1454 0 : } else if (tag == "suffix") {
1455 0 : i->setSuffix((FiguredBassItem::Modifier)(e.readInt()));
1456 0 : } else if (tag == "continuationLine") {
1457 0 : i->setContLine((FiguredBassItem::ContLine)(e.readInt()));
1458 0 : } else if (!readItemProperties(i, e, ctx)) {
1459 0 : e.unknown();
1460 : }
1461 : }
1462 5 : }
1463 :
1464 0 : void TRead::read(Excerpt* item, XmlReader& e, ReadContext&)
1465 : {
1466 0 : const std::vector<Part*>& pl = item->masterScore()->parts();
1467 0 : std::vector<Part*> parts;
1468 0 : while (e.readNextStartElement()) {
1469 0 : const AsciiStringView tag = e.name();
1470 0 : if (tag == "name" || tag == "title") {
1471 0 : item->setName(e.readText().trimmed(), /*saveAndNotify=*/ false);
1472 0 : } else if (tag == "part") {
1473 0 : size_t partIdx = static_cast<size_t>(e.readInt());
1474 0 : if (partIdx >= pl.size()) {
1475 0 : LOGD("Excerpt::read: bad part index");
1476 : } else {
1477 0 : parts.push_back(pl.at(partIdx));
1478 : }
1479 : }
1480 : }
1481 0 : item->setParts(parts);
1482 0 : }
1483 :
1484 2 : void TRead::read(Fermata* f, XmlReader& e, ReadContext& ctx)
1485 : {
1486 7 : while (e.readNextStartElement()) {
1487 3 : if (!readProperties(f, e, ctx)) {
1488 0 : e.unknown();
1489 : }
1490 : }
1491 2 : }
1492 :
1493 3 : bool TRead::readProperties(Fermata* f, XmlReader& xml, ReadContext& ctx)
1494 : {
1495 3 : const AsciiStringView tag(xml.name());
1496 :
1497 3 : if (tag == "subtype") {
1498 2 : AsciiStringView s = xml.readAsciiText();
1499 2 : SymId id = SymNames::symIdByName(s);
1500 2 : f->setSymIdAndTimeStretch(id);
1501 1 : } else if (tag == "play") {
1502 0 : f->setPlay(xml.readBool());
1503 1 : } else if (tag == "timeStretch") {
1504 0 : f->setTimeStretch(xml.readDouble());
1505 1 : } else if (readItemProperties(f, xml, ctx)) {
1506 : } else {
1507 0 : return false;
1508 : }
1509 3 : return true;
1510 : }
1511 :
1512 0 : void TRead::read(Image* img, XmlReader& e, ReadContext& ctx)
1513 : {
1514 0 : bool loaded = false;
1515 :
1516 0 : while (e.readNextStartElement()) {
1517 0 : const AsciiStringView tag(e.name());
1518 0 : if (tag == "autoScale") {
1519 0 : TRead::readProperty(img, e, ctx, Pid::AUTOSCALE);
1520 0 : } else if (tag == "size") {
1521 0 : TRead::readProperty(img, e, ctx, Pid::SIZE);
1522 0 : } else if (tag == "lockAspectRatio") {
1523 0 : TRead::readProperty(img, e, ctx, Pid::LOCK_ASPECT_RATIO);
1524 0 : } else if (tag == "sizeIsSpatium") {
1525 : // setting this using the property Pid::SIZE_IS_SPATIUM breaks, because the
1526 : // property setter attempts to maintain a constant size. If we're reading, we
1527 : // don't want to do that, because the stored size will be in:
1528 : // absolute if size isn't spatium
1529 : // sp if size is spatium
1530 0 : img->setSizeIsSpatium(e.readBool());
1531 0 : } else if (tag == "path") {
1532 0 : loaded = img->loadFromStore(e.readText().toStdString());
1533 0 : } else if (tag == "linkPath") {
1534 0 : if (img->configuration()->allowReadingImagesFromOutsideMscz() && !loaded) {
1535 0 : loaded = img->loadFromFile(e.readText());
1536 : } else {
1537 0 : e.skipCurrentElement();
1538 : }
1539 0 : } else if (!TRead::readProperties(img, e, ctx)) {
1540 0 : e.unknown();
1541 : }
1542 : }
1543 :
1544 0 : compat::CompatUtils::convertPre470ImageSize(img);
1545 0 : }
1546 :
1547 108 : void TRead::read(Tuplet* t, XmlReader& e, ReadContext& ctx)
1548 : {
1549 108 : Text* number = nullptr;
1550 108 : Fraction ratio;
1551 108 : TDuration baseLen;
1552 :
1553 564 : while (e.readNextStartElement()) {
1554 456 : const AsciiStringView tag(e.name());
1555 :
1556 456 : if (TRead::readStyledProperty(t, tag, e, ctx)) {
1557 450 : } else if (tag == "bold") { //important that these properties are read after number is created
1558 0 : bool val = e.readInt();
1559 0 : if (number) {
1560 0 : number->setBold(val);
1561 : }
1562 0 : if (t->isStyled(Pid::FONT_STYLE)) {
1563 0 : t->setPropertyFlags(Pid::FONT_STYLE, PropertyFlags::UNSTYLED);
1564 : }
1565 450 : } else if (tag == "italic") {
1566 0 : bool val = e.readInt();
1567 0 : if (number) {
1568 0 : number->setItalic(val);
1569 : }
1570 0 : if (t->isStyled(Pid::FONT_STYLE)) {
1571 0 : t->setPropertyFlags(Pid::FONT_STYLE, PropertyFlags::UNSTYLED);
1572 : }
1573 450 : } else if (tag == "underline") {
1574 0 : bool val = e.readInt();
1575 0 : if (number) {
1576 0 : number->setUnderline(val);
1577 : }
1578 0 : if (t->isStyled(Pid::FONT_STYLE)) {
1579 0 : t->setPropertyFlags(Pid::FONT_STYLE, PropertyFlags::UNSTYLED);
1580 : }
1581 450 : } else if (tag == "strike") {
1582 0 : bool val = e.readInt();
1583 0 : if (number) {
1584 0 : number->setStrike(val);
1585 : }
1586 0 : if (t->isStyled(Pid::FONT_STYLE)) {
1587 0 : t->setPropertyFlags(Pid::FONT_STYLE, PropertyFlags::UNSTYLED);
1588 : }
1589 450 : } else if (tag == "normalNotes") {
1590 108 : ratio.setDenominator(e.readInt());
1591 342 : } else if (tag == "actualNotes") {
1592 108 : ratio.setNumerator(e.readInt());
1593 234 : } else if (tag == "p1") {
1594 0 : t->setUserPoint1(e.readPoint() * t->style().spatium());
1595 234 : } else if (tag == "p2") {
1596 0 : t->setUserPoint2(e.readPoint() * t->style().spatium());
1597 234 : } else if (tag == "baseNote") {
1598 108 : baseLen = TDuration(TConv::fromXml(e.readAsciiText(), DurationType::V_INVALID));
1599 126 : } else if (tag == "baseDots") {
1600 0 : baseLen.setDots(e.readInt());
1601 126 : } else if (tag == "Number") {
1602 108 : number = Factory::createText(t, TextStyleType::TUPLET);
1603 108 : number->setComposition(true);
1604 108 : Tuplet::resetNumberProperty(number);
1605 108 : TRead::read(number, e, ctx);
1606 108 : number->setVisible(t->visible()); //?? override saved property
1607 108 : number->setColor(t->color());
1608 108 : number->setTrack(t->track());
1609 : // move property flags from _number back to tuplet
1610 648 : for (auto p : { Pid::FONT_FACE, Pid::FONT_SIZE, Pid::FONT_STYLE, Pid::ALIGN, Pid::POSITION }) {
1611 540 : t->setPropertyFlags(p, number->propertyFlags(p));
1612 : }
1613 18 : } else if (!readItemProperties(t, e, ctx)) {
1614 0 : e.unknown();
1615 : }
1616 : }
1617 :
1618 108 : t->setNumber(number);
1619 108 : t->setBaseLen(baseLen);
1620 108 : t->setRatio(ratio);
1621 :
1622 108 : Fraction f = t->baseLen().fraction() * t->ratio().denominator();
1623 108 : t->setTicks(f.reduced());
1624 108 : }
1625 :
1626 54 : void TRead::read(Beam* b, XmlReader& e, ReadContext& ctx)
1627 : {
1628 132 : while (e.readNextStartElement()) {
1629 78 : const AsciiStringView tag(e.name());
1630 78 : if (tag == "StemDirection") {
1631 3 : TRead::readProperty(b, e, ctx, Pid::STEM_DIRECTION);
1632 75 : } else if (TRead::readStyledProperty(b, tag, e, ctx)) {
1633 75 : } else if (tag == "growLeft") {
1634 0 : b->setGrowLeft(e.readDouble());
1635 75 : } else if (tag == "growRight") {
1636 0 : b->setGrowRight(e.readDouble());
1637 75 : } else if (tag == "Fragment") {
1638 0 : BeamFragment* f = new BeamFragment;
1639 0 : int idx = b->directionIdx();
1640 0 : b->setUserModified(true);
1641 0 : double _spatium = b->spatium();
1642 0 : while (e.readNextStartElement()) {
1643 0 : const AsciiStringView tag1(e.name());
1644 0 : if (tag1 == "y1") {
1645 0 : f->py1[idx] = e.readDouble() * _spatium;
1646 0 : } else if (tag1 == "y2") {
1647 0 : f->py2[idx] = e.readDouble() * _spatium;
1648 : } else {
1649 0 : e.unknown();
1650 : }
1651 : }
1652 0 : b->addBeamFragment(f);
1653 75 : } else if (tag == "l1" || tag == "l2") { // ignore
1654 50 : e.skipCurrentElement();
1655 25 : } else if (readProperty(b, tag, e, ctx, Pid::BEAM_CROSS_STAFF_MOVE)) {
1656 25 : } else if (!readItemProperties(b, e, ctx)) {
1657 0 : e.unknown();
1658 : }
1659 : }
1660 54 : }
1661 :
1662 0 : void TRead::read(Ambitus* a, XmlReader& e, ReadContext& ctx)
1663 : {
1664 0 : while (e.readNextStartElement()) {
1665 0 : if (!readProperties(a, e, ctx)) {
1666 0 : e.unknown();
1667 : }
1668 : }
1669 0 : }
1670 :
1671 0 : bool TRead::readProperties(Ambitus* a, XmlReader& e, ReadContext& ctx)
1672 : {
1673 0 : const AsciiStringView tag(e.name());
1674 0 : if (tag == "head") {
1675 0 : TRead::readProperty(a, e, ctx, Pid::HEAD_GROUP);
1676 0 : } else if (tag == "headType") {
1677 0 : TRead::readProperty(a, e, ctx, Pid::HEAD_TYPE);
1678 0 : } else if (tag == "mirror") {
1679 0 : TRead::readProperty(a, e, ctx, Pid::MIRROR_HEAD);
1680 0 : } else if (tag == "hasLine") {
1681 0 : a->setHasLine(e.readInt());
1682 0 : } else if (tag == "lineWidth") {
1683 0 : TRead::readProperty(a, e, ctx, Pid::LINE_WIDTH);
1684 0 : } else if (tag == "topPitch") {
1685 0 : a->setTopPitch(e.readInt(), false);
1686 0 : } else if (tag == "bottomPitch") {
1687 0 : a->setBottomPitch(e.readInt(), false);
1688 0 : } else if (tag == "topTpc") {
1689 0 : a->setTopTpc(e.readInt(), false);
1690 0 : } else if (tag == "bottomTpc") {
1691 0 : a->setBottomTpc(e.readInt(), false);
1692 0 : } else if (tag == "topAccidental") {
1693 0 : while (e.readNextStartElement()) {
1694 0 : if (e.name() == "Accidental") {
1695 0 : TRead::read(a->topAccidental(), e, ctx);
1696 : } else {
1697 0 : e.skipCurrentElement();
1698 : }
1699 : }
1700 0 : } else if (tag == "bottomAccidental") {
1701 0 : while (e.readNextStartElement()) {
1702 0 : if (e.name() == "Accidental") {
1703 0 : TRead::read(a->bottomAccidental(), e, ctx);
1704 : } else {
1705 0 : e.skipCurrentElement();
1706 : }
1707 : }
1708 0 : } else if (readItemProperties(a, e, ctx)) {
1709 : } else {
1710 0 : return false;
1711 : }
1712 0 : return true;
1713 : }
1714 :
1715 139 : void TRead::read(Accidental* a, XmlReader& e, ReadContext& ctx)
1716 : {
1717 409 : while (e.readNextStartElement()) {
1718 270 : const AsciiStringView tag(e.name());
1719 270 : if (tag == "bracket") {
1720 0 : int i = e.readInt();
1721 0 : if (i == 0 || i == 1 || i == 2) {
1722 0 : a->setBracket(AccidentalBracket(i));
1723 : }
1724 270 : } else if (tag == "subtype") {
1725 139 : a->setSubtype(e.readAsciiText());
1726 131 : } else if (tag == "role") {
1727 14 : a->setRole(TConv::fromXml(e.readAsciiText(), AccidentalRole::AUTO));
1728 117 : } else if (tag == "small") {
1729 0 : a->setSmall(e.readInt());
1730 117 : } else if (readProperty(a, tag, e, ctx, Pid::ACCIDENTAL_STACKING_ORDER_OFFSET)) {
1731 117 : } else if (readItemProperties(a, e, ctx)) {
1732 : } else {
1733 0 : e.unknown();
1734 : }
1735 : }
1736 139 : }
1737 :
1738 17 : void TRead::read(Marker* m, XmlReader& e, ReadContext& ctx)
1739 : {
1740 17 : MarkerType mt = MarkerType::SEGNO;
1741 :
1742 72 : while (e.readNextStartElement()) {
1743 55 : const AsciiStringView tag(e.name());
1744 55 : if (tag == "label") {
1745 17 : AsciiStringView s(e.readAsciiText());
1746 17 : m->setLabel(String::fromAscii(s.ascii()));
1747 17 : mt = TConv::fromXml(s, MarkerType::USER);
1748 38 : } else if (!readProperties(toTextBase(m), e, ctx)) {
1749 0 : e.unknown();
1750 : }
1751 : }
1752 17 : m->setMarkerType(mt);
1753 17 : }
1754 :
1755 12 : void TRead::read(Jump* j, XmlReader& e, ReadContext& ctx)
1756 : {
1757 83 : while (e.readNextStartElement()) {
1758 71 : const AsciiStringView tag(e.name());
1759 71 : if (tag == "jumpTo") {
1760 12 : j->setJumpTo(e.readText());
1761 59 : } else if (tag == "playUntil") {
1762 12 : j->setPlayUntil(e.readText());
1763 47 : } else if (tag == "continueAt") {
1764 12 : j->setContinueAt(e.readText());
1765 35 : } else if (tag == "playRepeats") {
1766 0 : j->setPlayRepeats(e.readBool());
1767 35 : } else if (!readProperties(toTextBase(j), e, ctx)) {
1768 0 : e.unknown();
1769 : }
1770 : }
1771 12 : }
1772 :
1773 0 : void TRead::read(MeasureNumber* n, XmlReader& xml, ReadContext& ctx)
1774 : {
1775 0 : read(static_cast<MeasureNumberBase*>(n), xml, ctx);
1776 0 : }
1777 :
1778 0 : void TRead::read(MeasureNumberBase* b, XmlReader& xml, ReadContext& ctx)
1779 : {
1780 0 : while (xml.readNextStartElement()) {
1781 0 : if (!readProperties(b, xml, ctx)) {
1782 0 : xml.unknown();
1783 : }
1784 : }
1785 0 : }
1786 :
1787 0 : bool TRead::readProperties(MeasureNumberBase* n, XmlReader& xml, ReadContext& ctx)
1788 : {
1789 0 : if (TRead::readProperty(n, xml.name(), xml, ctx, Pid::HPLACEMENT)) {
1790 0 : return true;
1791 : } else {
1792 0 : return readProperties(toTextBase(n), xml, ctx);
1793 : }
1794 : }
1795 :
1796 0 : void TRead::read(MMRestRange* r, XmlReader& xml, ReadContext& ctx)
1797 : {
1798 0 : read(static_cast<MeasureNumberBase*>(r), xml, ctx);
1799 0 : }
1800 :
1801 0 : void TRead::read(SystemDivider* d, XmlReader& e, ReadContext& ctx)
1802 : {
1803 0 : if (e.attribute("type") == "left") {
1804 0 : d->setDividerType(SystemDividerType::LEFT);
1805 : } else {
1806 0 : d->setDividerType(SystemDividerType::RIGHT);
1807 : }
1808 0 : TRead::read(static_cast<Symbol*>(d), e, ctx);
1809 0 : }
1810 :
1811 0 : void TRead::read(ActionIcon* i, XmlReader& e, ReadContext&)
1812 : {
1813 0 : while (e.readNextStartElement()) {
1814 0 : const AsciiStringView tag(e.name());
1815 0 : if (tag == "subtype") {
1816 : // This is fragile, see https://github.com/musescore/MuseScore/issues/24060#issuecomment-2299665318.
1817 : // Keeping it here for compatbility in case an ActionIcon from some old version doesn't have an <action> tag.
1818 : // If the <action> tag is present, it will override this value, see below.
1819 0 : i->setActionType(static_cast<ActionIconType>(e.readInt()));
1820 0 : } else if (tag == "action") {
1821 0 : i->setActionType(TConv::fromXml(e.readAsciiText(), ActionIconType::UNDEFINED));
1822 : } else {
1823 0 : e.unknown();
1824 : }
1825 : }
1826 0 : }
1827 :
1828 7 : void TRead::read(Arpeggio* a, XmlReader& e, ReadContext& ctx)
1829 : {
1830 19 : while (e.readNextStartElement()) {
1831 12 : const AsciiStringView tag(e.name());
1832 12 : if (tag == "subtype") {
1833 7 : a->setArpeggioType(TConv::fromXml(e.readAsciiText(), ArpeggioType::NORMAL));
1834 5 : } else if (tag == "userLen1") {
1835 0 : a->setUserLen1(e.readDouble() * a->spatium());
1836 5 : } else if (tag == "userLen2") {
1837 0 : a->setUserLen2(e.readDouble() * a->spatium());
1838 5 : } else if (tag == "span") {
1839 0 : int span = e.readInt();
1840 0 : if (ctx.mscVersion() < 420) {
1841 : // Span now refers to number of voices spanned, not staves
1842 0 : span = (span - 1) * VOICES + 1;
1843 : }
1844 0 : a->setSpan(span);
1845 5 : } else if (tag == "play") {
1846 0 : a->setPlayArpeggio(e.readBool());
1847 5 : } else if (tag == "timeStretch") {
1848 0 : a->setStretch(e.readDouble());
1849 5 : } else if (!readItemProperties(a, e, ctx)) {
1850 0 : e.unknown();
1851 : }
1852 : }
1853 7 : }
1854 :
1855 22 : void TRead::read(Ornament* o, XmlReader& xml, ReadContext& ctx)
1856 : {
1857 95 : while (xml.readNextStartElement()) {
1858 51 : if (!readProperties(o, xml, ctx)) {
1859 0 : xml.unknown();
1860 : }
1861 : }
1862 22 : }
1863 :
1864 51 : bool TRead::readProperties(Ornament* o, XmlReader& xml, ReadContext& ctx)
1865 : {
1866 51 : const AsciiStringView tag(xml.name());
1867 51 : if (readProperty(o, tag, xml, ctx, Pid::INTERVAL_ABOVE)) {
1868 47 : } else if (readProperty(o, tag, xml, ctx, Pid::INTERVAL_BELOW)) {
1869 46 : } else if (readProperty(o, tag, xml, ctx, Pid::ORNAMENT_SHOW_ACCIDENTAL)) {
1870 46 : } else if (readProperty(o, tag, xml, ctx, Pid::ORNAMENT_SHOW_CUE_NOTE)) {
1871 46 : } else if (readProperty(o, tag, xml, ctx, Pid::START_ON_UPPER_NOTE)) {
1872 46 : } else if (readProperties(toArticulation(o), xml, ctx)) {
1873 5 : } else if (tag == "Accidental") {
1874 4 : Accidental* accidental = Factory::createAccidental(o);
1875 4 : TRead::read(accidental, xml, ctx);
1876 4 : accidental->setTrack(ctx.track());
1877 4 : accidental->placement() == PlacementV::ABOVE ? o->setAccidentalAbove(accidental) : o->setAccidentalBelow(accidental);
1878 1 : } else if (tag == "Chord") {
1879 1 : Chord* chord = Factory::createChord(ctx.score()->dummy());
1880 1 : TRead::read(chord, xml, ctx);
1881 1 : chord->setTrack(ctx.track());
1882 1 : chord->setIsTrillCueNote(true);
1883 1 : o->setCueNoteChord(chord);
1884 1 : o->setNoteAbove(chord->notes().front());
1885 2 : for (Note* note : chord->notes()) {
1886 1 : compat::CompatUtils::doMigrateNoteParens(note);
1887 : }
1888 : } else {
1889 0 : return false;
1890 : }
1891 51 : return true;
1892 : }
1893 :
1894 137 : void TRead::read(Articulation* a, XmlReader& xml, ReadContext& ctx)
1895 : {
1896 528 : while (xml.readNextStartElement()) {
1897 254 : if (!readProperties(a, xml, ctx)) {
1898 0 : xml.unknown();
1899 : }
1900 : }
1901 137 : }
1902 :
1903 300 : bool TRead::readProperties(Articulation* a, XmlReader& xml, ReadContext& ctx)
1904 : {
1905 300 : const AsciiStringView tag(xml.name());
1906 :
1907 300 : if (tag == "subtype") {
1908 159 : AsciiStringView s = xml.readAsciiText();
1909 159 : ArticulationTextType textType = TConv::fromXml(s, ArticulationTextType::NO_TEXT);
1910 159 : if (textType != ArticulationTextType::NO_TEXT) {
1911 0 : a->setTextType(textType);
1912 : } else {
1913 159 : SymId id = SymNames::symIdByName(s);
1914 159 : if (id == SymId::noSym) {
1915 0 : id = read206::Read206::articulationNames2SymId206(s); // compatibility hack for "old" 3.0 scores
1916 : }
1917 159 : if (id == SymId::noSym || s == "ornamentMordentInverted") { // SMuFL < 1.30
1918 0 : id = SymId::ornamentMordent;
1919 : }
1920 159 : a->setSymId(id);
1921 : }
1922 141 : } else if (tag == "channel") {
1923 0 : a->setChannelName(xml.attribute("name"));
1924 0 : xml.readNext();
1925 141 : } else if (tag == "anchor") {
1926 1 : TRead::readProperty(a, tag, xml, ctx, Pid::ARTICULATION_ANCHOR);
1927 140 : } else if (tag == "direction") {
1928 0 : TRead::readProperty(a, xml, ctx, Pid::DIRECTION);
1929 140 : } else if (tag == "ornamentStyle") {
1930 0 : TRead::readProperty(a, xml, ctx, Pid::ORNAMENT_STYLE);
1931 140 : } else if (tag == "play") {
1932 0 : a->setPlayArticulation(xml.readBool());
1933 0 : readItemProperties(a, xml, ctx);
1934 140 : } else if (readItemProperties(a, xml, ctx)) {
1935 : } else {
1936 5 : return false;
1937 : }
1938 295 : return true;
1939 : }
1940 :
1941 0 : void TRead::read(BagpipeEmbellishment* b, XmlReader& e, ReadContext&)
1942 : {
1943 0 : while (e.readNextStartElement()) {
1944 0 : const AsciiStringView tag(e.name());
1945 0 : if (tag == "subtype") {
1946 0 : b->setEmbelType(TConv::fromXml(e.readAsciiText(), EmbellishmentType(0)));
1947 : } else {
1948 0 : e.unknown();
1949 : }
1950 : }
1951 0 : }
1952 :
1953 89 : void TRead::read(BarLine* b, XmlReader& e, ReadContext& ctx)
1954 : {
1955 : // initialize span properties with staff values
1956 89 : b->resetProperty(Pid::BARLINE_SPAN);
1957 89 : b->resetProperty(Pid::BARLINE_SPAN_FROM);
1958 89 : b->resetProperty(Pid::BARLINE_SPAN_TO);
1959 :
1960 217 : while (e.readNextStartElement()) {
1961 128 : const AsciiStringView tag(e.name());
1962 128 : if (tag == "subtype") {
1963 56 : b->setBarLineType(TConv::fromXml(e.readAsciiText(), BarLineType::NORMAL));
1964 72 : } else if (tag == "span") {
1965 11 : b->setSpanStaff(e.readBool());
1966 61 : } else if (tag == "spanFromOffset") {
1967 0 : b->setSpanFrom(e.readInt());
1968 61 : } else if (tag == "spanToOffset") {
1969 0 : b->setSpanTo(e.readInt());
1970 61 : } else if (tag == "Articulation") {
1971 0 : Articulation* a = Factory::createArticulation(b->score()->dummy());
1972 0 : TRead::read(a, e, ctx);
1973 0 : b->add(a);
1974 61 : } else if (tag == "Symbol") {
1975 0 : Symbol* s = Factory::createSymbol(b);
1976 0 : s->setTrack(b->track());
1977 0 : TRead::read(s, e, ctx);
1978 0 : b->add(s);
1979 61 : } else if (tag == "Image") {
1980 0 : if (MScore::noImages) {
1981 0 : e.skipCurrentElement();
1982 : } else {
1983 0 : Image* image = Factory::createImage(b);
1984 0 : image->setTrack(b->track());
1985 0 : TRead::read(image, e, ctx);
1986 0 : b->add(image);
1987 : }
1988 61 : } else if (!readItemProperties(b, e, ctx)) {
1989 0 : e.unknown();
1990 : }
1991 : }
1992 89 : }
1993 :
1994 0 : void TRead::read(Bend* b, XmlReader& e, ReadContext& ctx)
1995 : {
1996 0 : while (e.readNextStartElement()) {
1997 0 : const AsciiStringView tag(e.name());
1998 :
1999 0 : if (TRead::readStyledProperty(b, tag, e, ctx)) {
2000 0 : } else if (tag == "point") {
2001 0 : PitchValue pv;
2002 0 : pv.time = e.intAttribute("time");
2003 0 : pv.pitch = e.intAttribute("pitch");
2004 0 : pv.vibrato = e.intAttribute("vibrato");
2005 0 : b->addPoint(pv);
2006 0 : e.readNext();
2007 0 : } else if (tag == "play") {
2008 0 : b->setPlayBend(e.readBool());
2009 0 : } else if (!readItemProperties(b, e, ctx)) {
2010 0 : e.unknown();
2011 : }
2012 : }
2013 0 : }
2014 :
2015 57 : void TRead::read(Box* b, XmlReader& e, ReadContext& ctx)
2016 : {
2017 316 : while (e.readNextStartElement()) {
2018 202 : if (!readProperties(b, e, ctx)) {
2019 0 : e.unknown();
2020 : }
2021 : }
2022 :
2023 57 : if (b->score()->mscVersion() < 440) {
2024 35 : b->setSizeIsSpatiumDependent(true);
2025 : }
2026 57 : }
2027 :
2028 2 : void TRead::read(HBox* b, XmlReader& e, ReadContext& ctx)
2029 : {
2030 6 : while (e.readNextStartElement()) {
2031 2 : if (!readProperties(b, e, ctx)) {
2032 0 : e.unknown();
2033 : }
2034 : }
2035 2 : if (b->score()->mscVersion() < 440) {
2036 1 : b->setSizeIsSpatiumDependent(true);
2037 : }
2038 2 : }
2039 :
2040 2 : bool TRead::readProperties(HBox* b, XmlReader& e, ReadContext& ctx)
2041 : {
2042 2 : const AsciiStringView tag(e.name());
2043 2 : if (readProperty(b, tag, e, ctx, Pid::CREATE_SYSTEM_HEADER)) {
2044 2 : } else if (readProperties(static_cast<Box*>(b), e, ctx)) {
2045 : } else {
2046 0 : return false;
2047 : }
2048 2 : return true;
2049 : }
2050 :
2051 57 : void TRead::read(VBox* b, XmlReader& xml, ReadContext& ctx)
2052 : {
2053 57 : TRead::read(static_cast<Box*>(b), xml, ctx);
2054 57 : }
2055 :
2056 0 : void TRead::read(FBox* b, XmlReader& xml, ReadContext& ctx)
2057 : {
2058 0 : while (xml.readNextStartElement()) {
2059 0 : const AsciiStringView tag(xml.name());
2060 0 : if (readProperty(b, tag, xml, ctx, Pid::FRET_FRAME_TEXT_SCALE)) {
2061 0 : } else if (readProperty(b, tag, xml, ctx, Pid::FRET_FRAME_DIAGRAM_SCALE)) {
2062 0 : } else if (readProperty(b, tag, xml, ctx, Pid::FRET_FRAME_COLUMN_GAP)) {
2063 0 : } else if (readProperty(b, tag, xml, ctx, Pid::FRET_FRAME_ROW_GAP)) {
2064 0 : } else if (readProperty(b, tag, xml, ctx, Pid::FRET_FRAME_CHORDS_PER_ROW)) {
2065 0 : } else if (readProperty(b, tag, xml, ctx, Pid::FRET_FRAME_H_ALIGN)) {
2066 0 : } else if (TRead::readProperties(static_cast<Box*>(b), xml, ctx)) {
2067 : } else {
2068 0 : xml.unknown();
2069 : }
2070 : }
2071 0 : }
2072 :
2073 1 : void TRead::read(TBox* b, XmlReader& e, ReadContext& ctx)
2074 : {
2075 3 : while (e.readNextStartElement()) {
2076 2 : const AsciiStringView tag(e.name());
2077 2 : if (tag == "Text") {
2078 1 : TRead::read(b->text(), e, ctx);
2079 1 : } else if (TRead::readProperties(static_cast<Box*>(b), e, ctx)) {
2080 : } else {
2081 0 : e.unknown();
2082 : }
2083 : }
2084 1 : }
2085 :
2086 0 : bool TRead::readBoxProperties(Box* b, XmlReader& e, ReadContext& ctx)
2087 : {
2088 0 : if (b->isHBox()) {
2089 0 : return readProperties(dynamic_cast<HBox*>(b), e, ctx);
2090 : }
2091 0 : return readProperties(b, e, ctx);
2092 : }
2093 :
2094 205 : bool TRead::readProperties(Box* b, XmlReader& e, ReadContext& ctx)
2095 : {
2096 205 : const AsciiStringView tag(e.name());
2097 205 : if (tag == "height") {
2098 57 : b->setBoxHeight(Spatium(e.readDouble()));
2099 148 : } else if (tag == "width") {
2100 2 : b->setBoxWidth(Spatium(e.readDouble()));
2101 146 : } else if (tag == "topGap") {
2102 0 : double gap = e.readDouble();
2103 0 : b->setTopGap(Spatium(gap));
2104 0 : b->setPropertyFlags(Pid::TOP_GAP, PropertyFlags::UNSTYLED);
2105 146 : } else if (tag == "bottomGap") {
2106 0 : double gap = e.readDouble();
2107 0 : b->setBottomGap(Spatium(gap));
2108 0 : b->setPropertyFlags(Pid::BOTTOM_GAP, PropertyFlags::UNSTYLED);
2109 146 : } else if (tag == "leftMargin") {
2110 0 : b->setLeftMargin(e.readDouble());
2111 146 : } else if (tag == "rightMargin") {
2112 0 : b->setRightMargin(e.readDouble());
2113 146 : } else if (tag == "topMargin") {
2114 0 : b->setTopMargin(e.readDouble());
2115 146 : } else if (tag == "bottomMargin") {
2116 0 : b->setBottomMargin(e.readDouble());
2117 146 : } else if (tag == "boxAutoSize") {
2118 4 : b->setAutoSizeEnabled(e.readBool());
2119 142 : } else if (tag == "Text") {
2120 : Text* t;
2121 117 : if (b->isTBox()) {
2122 0 : t = toTBox(b)->text();
2123 0 : TRead::read(t, e, ctx);
2124 : } else {
2125 117 : t = Factory::createText(b);
2126 117 : TRead::read(t, e, ctx);
2127 117 : if (t->empty()) {
2128 0 : LOGD("read empty text");
2129 : } else {
2130 117 : b->add(t);
2131 : }
2132 : }
2133 25 : } else if (tag == "Symbol") {
2134 0 : Symbol* s = new Symbol(b);
2135 0 : TRead::read(s, e, ctx);
2136 0 : b->add(s);
2137 25 : } else if (tag == "Image") {
2138 0 : if (MScore::noImages) {
2139 0 : e.skipCurrentElement();
2140 : } else {
2141 0 : Image* image = new Image(b);
2142 0 : image->setTrack(ctx.track());
2143 0 : TRead::read(image, e, ctx);
2144 0 : b->add(image);
2145 : }
2146 25 : } else if (tag == "FretDiagram") {
2147 0 : FretDiagram* f = Factory::createFretDiagram(b->score()->dummy());
2148 0 : TRead::read(f, e, ctx);
2149 : //! TODO Looks like a bug.
2150 : //! The FretDiagram parent must be Segment
2151 : //! there is a method: `Segment* segment() const { return toSegment(parent()); }`,
2152 : //! but when we add it to Box, the parent will be rewritten.
2153 0 : b->add(f);
2154 25 : } else if (tag == "HBox") {
2155 : // m_parent is used here (rather than system()) because explicit parent isn't set for this object
2156 : // until it is fully read. m_parent is nonetheless valid and using it here matches MU3 behavior.
2157 : // If we do not set the parent of this new box correctly, it will cause a crash on read()
2158 : // because it needs access to the system it is being added to. (c.r. issue #14643)
2159 0 : if (b->parent() && b->parent()->isSystem()) {
2160 0 : HBox* hb = new HBox(b->score());
2161 0 : TRead::read(hb, e, ctx);
2162 : //! TODO Looks like a bug.
2163 : //! The HBox parent must be System
2164 : //! there is a method: `System* system() const { return (System*)parent(); }`,
2165 : //! but when we add it to Box, the parent will be rewritten.
2166 0 : b->add(hb);
2167 : }
2168 25 : } else if (tag == "VBox") {
2169 0 : if (b->parent() && b->parent()->isSystem()) {
2170 0 : VBox* vb = new VBox(b->score());
2171 0 : TRead::read(vb, e, ctx);
2172 : //! TODO Looks like a bug.
2173 : //! The VBox parent must be System
2174 : //! there is a method: `System* system() const { return (System*)parent(); }`,
2175 : //! but when we add it to Box, the parent will be rewritten.
2176 0 : b->add(vb);
2177 : }
2178 25 : } else if (TRead::readProperties(static_cast<MeasureBase*>(b), e, ctx)) {
2179 : } else {
2180 0 : return false;
2181 : }
2182 205 : return true;
2183 : }
2184 :
2185 543 : bool TRead::readProperties(MeasureBase* b, XmlReader& e, ReadContext& ctx)
2186 : {
2187 543 : const AsciiStringView tag(e.name());
2188 543 : if (tag == "LayoutBreak") {
2189 24 : LayoutBreak* lb = Factory::createLayoutBreak(b);
2190 24 : TRead::read(lb, e, ctx);
2191 24 : lb->setTrack(0);
2192 24 : bool doAdd = true;
2193 24 : switch (lb->layoutBreakType()) {
2194 19 : case LayoutBreakType::LINE:
2195 19 : if (b->lineBreak()) {
2196 0 : doAdd = false;
2197 : }
2198 19 : break;
2199 0 : case LayoutBreakType::PAGE:
2200 0 : if (b->pageBreak()) {
2201 0 : doAdd = false;
2202 : }
2203 0 : break;
2204 2 : case LayoutBreakType::SECTION:
2205 2 : if (b->sectionBreak()) {
2206 0 : doAdd = false;
2207 : }
2208 2 : break;
2209 3 : case LayoutBreakType::NOBREAK:
2210 3 : if (b->noBreak()) {
2211 0 : doAdd = false;
2212 : }
2213 3 : break;
2214 : }
2215 24 : if (doAdd) {
2216 24 : b->add(lb);
2217 24 : b->cleanupLayoutBreaks(false);
2218 : }
2219 519 : } else if (tag == "StaffTypeChange") {
2220 0 : StaffTypeChange* stc = Factory::createStaffTypeChange(b);
2221 0 : stc->setTrack(ctx.track());
2222 0 : TRead::read(stc, e, ctx);
2223 0 : b->add(stc);
2224 519 : } else if (readItemProperties(b, e, ctx)) {
2225 : } else {
2226 0 : return false;
2227 : }
2228 543 : return true;
2229 : }
2230 :
2231 0 : void TRead::read(Bracket* b, XmlReader& e, ReadContext& ctx)
2232 : {
2233 0 : BracketItem* bi = Factory::createBracketItem(b->score()->dummy());
2234 0 : bi->setBracketType(TConv::fromXml(e.asciiAttribute("type"), BracketType::NORMAL));
2235 :
2236 0 : while (e.readNextStartElement()) {
2237 0 : if (e.name() == "level") {
2238 0 : bi->setColumn(e.readInt());
2239 0 : } else if (!readItemProperties(b, e, ctx)) {
2240 0 : e.unknown();
2241 : }
2242 : }
2243 :
2244 0 : b->setBracketItem(bi);
2245 0 : }
2246 :
2247 4 : void TRead::read(Breath* b, XmlReader& e, ReadContext& ctx)
2248 : {
2249 14 : while (e.readNextStartElement()) {
2250 10 : const AsciiStringView tag(e.name());
2251 10 : if (tag == "symbol") {
2252 4 : b->setSymId(SymNames::symIdByName(e.readAsciiText()));
2253 6 : } else if (tag == "pause") {
2254 4 : b->setPause(e.readDouble());
2255 2 : } else if (!readItemProperties(b, e, ctx)) {
2256 0 : e.unknown();
2257 : }
2258 : }
2259 4 : }
2260 :
2261 12 : bool TRead::readProperties(BSymbol* sym, XmlReader& e, ReadContext& ctx)
2262 : {
2263 12 : const AsciiStringView tag = e.name();
2264 :
2265 12 : if (readItemProperties(sym, e, ctx)) {
2266 12 : return true;
2267 0 : } else if (tag == "systemFlag") {
2268 0 : sym->setSystemFlag(e.readInt());
2269 0 : } else if (tag == "Symbol") {
2270 0 : Symbol* s = Factory::createSymbol(sym);
2271 0 : TRead::read(s, e, ctx);
2272 0 : sym->add(s);
2273 0 : } else if (tag == "FSymbol") {
2274 0 : FSymbol* s = Factory::createFSymbol(sym);
2275 0 : TRead::read(s, e, ctx);
2276 0 : sym->add(s);
2277 0 : } else if (tag == "Image") {
2278 0 : if (MScore::noImages) {
2279 0 : e.skipCurrentElement();
2280 : } else {
2281 0 : Image* image = new Image(sym);
2282 0 : TRead::read(image, e, ctx);
2283 0 : sym->add(image);
2284 : }
2285 : } else {
2286 0 : return false;
2287 : }
2288 0 : return true;
2289 : }
2290 :
2291 14 : void TRead::read(Symbol* sym, XmlReader& e, ReadContext& ctx)
2292 : {
2293 14 : SymId symId = SymId::noSym;
2294 14 : String fontName;
2295 40 : while (e.readNextStartElement()) {
2296 26 : const AsciiStringView tag(e.name());
2297 26 : if (tag == "name") {
2298 14 : String val(e.readText());
2299 14 : symId = SymNames::symIdByName(val);
2300 14 : if (val != "noSym" && symId == SymId::noSym) {
2301 : // if symbol name not found, fall back to user names
2302 : // TODO: does it make sense? user names are probably localized
2303 0 : symId = SymNames::symIdByUserName(val);
2304 0 : if (symId == SymId::noSym) {
2305 0 : LOGD("unknown symbol <%s>, falling back to no symbol", muPrintable(val));
2306 : // set a default symbol, or layout() will crash
2307 0 : symId = SymId::noSym;
2308 : }
2309 : }
2310 14 : sym->setSym(symId);
2311 26 : } else if (tag == "font") {
2312 0 : fontName = e.readText();
2313 12 : } else if (readProperty(sym, tag, e, ctx, Pid::SYMBOLS_SIZE)) {
2314 12 : } else if (readProperty(sym, tag, e, ctx, Pid::SYMBOL_ANGLE)) {
2315 12 : } else if (tag == "Symbol") {
2316 0 : Symbol* s = new Symbol(sym);
2317 0 : TRead::read(s, e, ctx);
2318 0 : sym->add(s);
2319 12 : } else if (tag == "Image") {
2320 0 : if (MScore::noImages) {
2321 0 : e.skipCurrentElement();
2322 : } else {
2323 0 : Image* image = new Image(sym);
2324 0 : TRead::read(image, e, ctx);
2325 0 : sym->add(image);
2326 : }
2327 12 : } else if (!TRead::readProperties(static_cast<BSymbol*>(sym), e, ctx)) {
2328 0 : e.unknown();
2329 : }
2330 : }
2331 :
2332 14 : std::shared_ptr<IEngravingFont> scoreFont = nullptr;
2333 14 : if (!fontName.empty()) {
2334 0 : scoreFont = ctx.engravingFonts()->fontByName(fontName.toStdString());
2335 : }
2336 :
2337 14 : sym->setPos(PointF());
2338 14 : sym->setSym(symId, scoreFont);
2339 14 : }
2340 :
2341 9 : void TRead::read(SoundFlag* item, XmlReader& xml, ReadContext&)
2342 : {
2343 21 : while (xml.readNextStartElement()) {
2344 12 : const AsciiStringView tag(xml.name());
2345 :
2346 12 : if (tag == "play") {
2347 0 : item->setPlay(xml.readBool());
2348 12 : } else if (tag == "presets") {
2349 0 : item->setSoundPresets(xml.readText().split(u","));
2350 12 : } else if (tag == "playingTechnique") {
2351 9 : item->setPlayingTechnique(xml.readText());
2352 3 : } else if (tag == "applyToAllStaves") {
2353 3 : item->setApplyToAllStaves(xml.readBool());
2354 : } else {
2355 0 : xml.unknown();
2356 : }
2357 : }
2358 9 : }
2359 :
2360 0 : void TRead::read(FSymbol* sym, XmlReader& e, ReadContext& ctx)
2361 : {
2362 0 : Font font = sym->font();
2363 0 : while (e.readNextStartElement()) {
2364 0 : const AsciiStringView tag(e.name());
2365 0 : if (tag == "font") {
2366 0 : font.setFamily(e.readText(), Font::Type::Unknown);
2367 0 : } else if (tag == "fontsize") {
2368 0 : font.setPointSizeF(e.readDouble());
2369 0 : } else if (tag == "code") {
2370 0 : sym->setCode(e.readInt());
2371 0 : } else if (!TRead::readProperties(static_cast<BSymbol*>(sym), e, ctx)) {
2372 0 : e.unknown();
2373 : }
2374 : }
2375 :
2376 0 : sym->setPos(PointF());
2377 0 : sym->setFont(font);
2378 0 : }
2379 :
2380 2056 : void TRead::read(Chord* ch, XmlReader& e, ReadContext& ctx)
2381 : {
2382 9972 : while (e.readNextStartElement()) {
2383 5860 : if (TRead::readProperties(ch, e, ctx)) {
2384 : } else {
2385 0 : e.unknown();
2386 : }
2387 : }
2388 2056 : }
2389 :
2390 5860 : bool TRead::readProperties(Chord* ch, XmlReader& e, ReadContext& ctx)
2391 : {
2392 5860 : const AsciiStringView tag(e.name());
2393 :
2394 5860 : if (tag == "Note") {
2395 2138 : Note* note = Factory::createNote(ch);
2396 : // the note needs to know the properties of the track it belongs to
2397 2138 : note->setTrack(ch->track());
2398 2138 : TRead::read(note, e, ctx);
2399 2138 : ch->add(note);
2400 3722 : } else if (TRead::readProperties(toChordRest(ch), e, ctx)) {
2401 149 : } else if (tag == "Stem") {
2402 2 : Stem* s = Factory::createStem(ch);
2403 2 : TRead::read(s, e, ctx);
2404 2 : ch->add(s);
2405 147 : } else if (tag == "Hook") {
2406 0 : Hook* hook = new Hook(ch);
2407 0 : TRead::read(hook, e, ctx);
2408 0 : ch->setHook(hook);
2409 0 : ch->add(hook);
2410 147 : } else if (tag == "appoggiatura") {
2411 18 : ch->setNoteType(NoteType::APPOGGIATURA);
2412 18 : e.readNext();
2413 129 : } else if (tag == "acciaccatura") {
2414 8 : ch->setNoteType(NoteType::ACCIACCATURA);
2415 8 : e.readNext();
2416 121 : } else if (tag == "grace4") {
2417 1 : ch->setNoteType(NoteType::GRACE4);
2418 1 : e.readNext();
2419 120 : } else if (tag == "grace16") {
2420 0 : ch->setNoteType(NoteType::GRACE16);
2421 0 : e.readNext();
2422 120 : } else if (tag == "grace32") {
2423 1 : ch->setNoteType(NoteType::GRACE32);
2424 1 : e.readNext();
2425 119 : } else if (tag == "grace8after") {
2426 2 : ch->setNoteType(NoteType::GRACE8_AFTER);
2427 2 : e.readNext();
2428 117 : } else if (tag == "grace16after") {
2429 0 : ch->setNoteType(NoteType::GRACE16_AFTER);
2430 0 : e.readNext();
2431 117 : } else if (tag == "grace32after") {
2432 0 : ch->setNoteType(NoteType::GRACE32_AFTER);
2433 0 : e.readNext();
2434 117 : } else if (tag == "StemSlash") {
2435 0 : StemSlash* ss = Factory::createStemSlash(ch);
2436 0 : TRead::read(ss, e, ctx);
2437 0 : ch->add(ss);
2438 117 : } else if (TRead::readProperty(ch, tag, e, ctx, Pid::STEM_DIRECTION)) {
2439 68 : } else if (tag == "noStem") {
2440 9 : ch->setNoStem(e.readInt());
2441 59 : } else if (tag == "showStemSlash") {
2442 0 : ch->setShowStemSlash(e.readBool());
2443 59 : } else if (tag == "Arpeggio") {
2444 7 : Arpeggio* arpeggio = Factory::createArpeggio(ch);
2445 7 : arpeggio->setTrack(ch->track());
2446 7 : TRead::read(arpeggio, e, ctx);
2447 7 : ch->setArpeggio(arpeggio);
2448 52 : } else if (tag == "Tremolo") { // compat
2449 23 : compat::TremoloCompat tcompat { ch };
2450 23 : TRead::read(&tcompat, e, ctx);
2451 23 : if (tcompat.two) {
2452 2 : tcompat.two->setOwnershipParent(ch);
2453 2 : tcompat.two->setDurationType(ch->durationType());
2454 2 : ch->setTremoloTwoChord(tcompat.two, false);
2455 21 : } else if (tcompat.single) {
2456 21 : tcompat.single->setOwnershipParent(ch);
2457 21 : tcompat.single->setDurationType(ch->durationType());
2458 21 : ch->setTremoloSingleChord(tcompat.single);
2459 : } else {
2460 0 : UNREACHABLE;
2461 : }
2462 29 : } else if (tag == "TremoloSingleChord") {
2463 28 : TremoloSingleChord* trem = Factory::createTremoloSingleChord(ch);
2464 28 : trem->setTrack(ch->track());
2465 28 : TRead::read(trem, e, ctx);
2466 28 : trem->setDurationType(ch->durationType());
2467 28 : ch->setTremoloSingleChord(trem);
2468 1 : } else if (tag == "TremoloTwoChord") {
2469 1 : TremoloTwoChord* trem = Factory::createTremoloTwoChord(ch);
2470 1 : trem->setTrack(ch->track());
2471 1 : TRead::read(trem, e, ctx);
2472 1 : trem->setDurationType(ch->durationType());
2473 1 : ch->setTremoloTwoChord(trem, false);
2474 0 : } else if (tag == "ChordLine") {
2475 0 : ChordLine* cl = Factory::createChordLine(ch);
2476 0 : TRead::read(cl, e, ctx);
2477 0 : ch->add(cl);
2478 0 : } else if (tag == "combineVoice") {
2479 : // Handle mistake in 4.4 & convert from bool
2480 0 : if (ch->score()->mscoreVersion() == u"4.4.0") {
2481 0 : bool val = e.readBool();
2482 0 : ch->setCombineVoice(val ? AutoOnOff::ON : AutoOnOff::OFF);
2483 : } else {
2484 0 : readProperty(ch, tag, e, ctx, Pid::COMBINE_VOICE);
2485 : }
2486 : } else {
2487 0 : return false;
2488 : }
2489 5860 : return true;
2490 : }
2491 :
2492 7440 : bool TRead::readProperties(ChordRest* ch, XmlReader& e, ReadContext& ctx)
2493 : {
2494 7440 : const AsciiStringView tag(e.name());
2495 :
2496 7440 : if (tag == "durationType") {
2497 3446 : ch->setDurationType(TConv::fromXml(e.readAsciiText(), DurationType::V_QUARTER));
2498 3446 : if (ch->actualDurationType().type() != DurationType::V_MEASURE) {
2499 2425 : ch->setTicks(ch->actualDurationType().fraction());
2500 : }
2501 3994 : } else if (tag == "BeamMode") {
2502 9 : ch->setBeamMode(TConv::fromXml(e.readAsciiText(), BeamMode::AUTO));
2503 3985 : } else if (tag == "Articulation") {
2504 137 : Articulation* atr = Factory::createArticulation(ch);
2505 137 : atr->setTrack(ch->track());
2506 137 : TRead::read(atr, e, ctx);
2507 137 : ch->add(atr);
2508 3848 : } else if (tag == "Ornament") {
2509 10 : Ornament* ornament = Factory::createOrnament(ch);
2510 10 : ornament->setTrack(ch->track());
2511 10 : TRead::read(ornament, e, ctx);
2512 10 : ch->add(ornament);
2513 3838 : } else if (tag == "small") {
2514 1 : ch->setSmall(e.readInt());
2515 3837 : } else if (tag == "duration") {
2516 1029 : ch->setTicks(e.readFraction());
2517 2808 : } else if (tag == "dots") {
2518 52 : ch->setDots(e.readInt());
2519 2756 : } else if (tag == "staffMove") {
2520 0 : ch->setStaffMove(e.readInt());
2521 0 : ch->checkStaffMoveValidity();
2522 2756 : } else if (tag == "Spanner") {
2523 52 : readSpanner(e, ctx, ch, ch->track());
2524 2704 : } else if (tag == "Lyrics") {
2525 20 : Lyrics* lyr = Factory::createLyrics(ch);
2526 20 : lyr->setTrack(ctx.track());
2527 20 : TRead::read(lyr, e, ctx);
2528 20 : ch->add(lyr);
2529 2684 : } else if (tag == "pos") {
2530 0 : PointF pt = e.readPoint();
2531 0 : ch->setOffset(pt * ch->spatium());
2532 : }
2533 : // else if (tag == "offset")
2534 : // DurationElement::readProperties(e);
2535 2684 : else if (!readItemProperties(ch, e, ctx)) {
2536 149 : return false;
2537 : }
2538 7291 : return true;
2539 : }
2540 :
2541 47 : void TRead::read(ChordLine* l, XmlReader& e, ReadContext& ctx)
2542 : {
2543 169 : while (e.readNextStartElement()) {
2544 122 : const AsciiStringView tag(e.name());
2545 122 : if (tag == "Path") {
2546 0 : compat::CompatUtils::readChordLinePath(l, e);
2547 122 : } else if (tag == "subtype") {
2548 47 : l->setChordLineType(TConv::fromXml(e.readAsciiText(), ChordLineType::NOTYPE));
2549 75 : } else if (tag == "straight") {
2550 42 : l->setStraight(e.readInt());
2551 33 : } else if (tag == "wavy") {
2552 0 : l->setWavy(e.readInt());
2553 33 : } else if (tag == "lengthX" || tag == "lengthY") { // obsolete
2554 0 : e.skipCurrentElement();
2555 33 : } else if (tag == "play") {
2556 0 : l->setPlayChordLine(e.readBool());
2557 33 : } else if (!readItemProperties(l, e, ctx)) {
2558 0 : e.unknown();
2559 : }
2560 : }
2561 47 : }
2562 :
2563 26 : void TRead::read(Clef* c, XmlReader& e, ReadContext& ctx, bool* isHeader)
2564 : {
2565 110 : while (e.readNextStartElement()) {
2566 84 : const AsciiStringView tag(e.name());
2567 84 : if (tag == "concertClefType") {
2568 26 : c->setConcertClef(TConv::fromXml(e.readAsciiText(), ClefType::G));
2569 58 : } else if (tag == "transposingClefType") {
2570 26 : c->setTransposingClef(TConv::fromXml(e.readAsciiText(), ClefType::G));
2571 32 : } else if (tag == "showCourtesyClef") {
2572 0 : c->setShowCourtesy(e.readInt());
2573 32 : } else if (tag == "forInstrumentChange") {
2574 0 : c->setForInstrumentChange(e.readBool());
2575 32 : } else if (tag == "clefToBarlinePos") {
2576 0 : c->setClefToBarlinePosition(ClefToBarlinePosition(e.readInt()));
2577 32 : } else if (tag == "isHeader") {
2578 15 : const bool header = e.readBool();
2579 15 : if (isHeader) {
2580 15 : *isHeader = header;
2581 : }
2582 17 : } else if (!readItemProperties(c, e, ctx)) {
2583 0 : e.unknown();
2584 : }
2585 : }
2586 :
2587 26 : if (c->clefType() == ClefType::INVALID) {
2588 0 : c->setClefType(ClefType::G);
2589 : }
2590 26 : }
2591 :
2592 0 : void TRead::read(Capo* c, XmlReader& xml, ReadContext& ctx)
2593 : {
2594 0 : CapoParams params = c->params();
2595 :
2596 0 : while (xml.readNextStartElement()) {
2597 0 : const AsciiStringView tag(xml.name());
2598 :
2599 0 : if (tag == "active") {
2600 0 : params.active = xml.readBool();
2601 0 : } else if (tag == "fretPosition") {
2602 0 : params.fretPosition = xml.readInt();
2603 0 : } else if (tag == "string") {
2604 0 : string_idx_t idx = static_cast<string_idx_t>(xml.intAttribute("no"));
2605 :
2606 0 : while (xml.readNextStartElement()) {
2607 0 : const AsciiStringView stringTag(xml.name());
2608 :
2609 0 : if (stringTag == "apply") {
2610 0 : bool apply = xml.readBool();
2611 0 : if (!apply) {
2612 0 : params.ignoredStrings.insert(idx);
2613 : }
2614 : } else {
2615 0 : xml.unknown();
2616 : }
2617 : }
2618 0 : } else if (tag == "generateText") {
2619 0 : c->setProperty(Pid::CAPO_GENERATE_TEXT, xml.readBool());
2620 0 : } else if (!readProperties(static_cast<StaffTextBase*>(c), xml, ctx)) {
2621 0 : xml.unknown();
2622 : }
2623 : }
2624 :
2625 0 : c->setParams(params);
2626 0 : }
2627 :
2628 0 : bool TRead::readProperties(Clef* c, XmlReader& xml, ReadContext& ctx)
2629 : {
2630 0 : return readItemProperties(c, xml, ctx);
2631 : }
2632 :
2633 0 : void TRead::read(Fingering* f, XmlReader& e, ReadContext& ctx)
2634 : {
2635 0 : while (e.readNextStartElement()) {
2636 0 : if (!readProperties(toTextBase(f), e, ctx)) {
2637 0 : e.unknown();
2638 : }
2639 : }
2640 0 : }
2641 :
2642 18 : void TRead::read(Glissando* g, XmlReader& e, ReadContext& ctx)
2643 : {
2644 18 : g->eraseSpannerSegments();
2645 :
2646 18 : staff_idx_t staffIdx = track2staff(ctx.track());
2647 18 : Staff* staff = ctx.score()->staff(staffIdx);
2648 18 : if (staff) {
2649 18 : String instrId = staff->part()->instrumentId(g->tick());
2650 18 : g->setIsHarpGliss(instrId == "harp");
2651 18 : }
2652 18 : g->resetProperty(Pid::GLISS_STYLE);
2653 :
2654 18 : bool textRead = false;
2655 :
2656 83 : while (e.readNextStartElement()) {
2657 65 : const AsciiStringView tag = e.name();
2658 65 : if (tag == "text") {
2659 7 : textRead = true;
2660 7 : TRead::readProperty(g, e, ctx, Pid::GLISS_TEXT);
2661 58 : } else if (tag == "isHarpGliss" && ctx.pasteMode()) {
2662 0 : g->setIsHarpGliss(e.readBool());
2663 0 : g->resetProperty(Pid::GLISS_STYLE);
2664 58 : } else if (tag == "easeInSpin") {
2665 0 : g->setEaseIn(e.readInt());
2666 58 : } else if (tag == "easeOutSpin") {
2667 0 : g->setEaseOut(e.readInt());
2668 58 : } else if (tag == "glissandoShift") {
2669 1 : g->setGlissandoShift(e.readBool());
2670 57 : } else if (TRead::readStyledProperty(g, tag, e, ctx)) {
2671 51 : } else if (!TRead::readProperties(static_cast<SLine*>(g), e, ctx)) {
2672 17 : e.unknown();
2673 : }
2674 : }
2675 :
2676 18 : if (g->score()->mscVersion() < 450 && !textRead) {
2677 10 : g->setShowText(false);
2678 : }
2679 18 : }
2680 :
2681 3 : void TRead::read(GradualTempoChange* c, XmlReader& xml, ReadContext& ctx)
2682 : {
2683 29 : while (xml.readNextStartElement()) {
2684 26 : const AsciiStringView tag(xml.name());
2685 :
2686 26 : if (TRead::readProperty(c, tag, xml, ctx, Pid::LINE_WIDTH)) {
2687 0 : c->setPropertyFlags(Pid::LINE_WIDTH, PropertyFlags::UNSTYLED);
2688 6 : continue;
2689 : }
2690 :
2691 26 : if (TRead::readProperty(c, tag, xml, ctx, Pid::TEMPO_CHANGE_TYPE)) {
2692 3 : continue;
2693 : }
2694 :
2695 23 : if (TRead::readProperty(c, tag, xml, ctx, Pid::TEMPO_EASING_METHOD)) {
2696 0 : continue;
2697 : }
2698 :
2699 23 : if (TRead::readProperty(c, tag, xml, ctx, Pid::TEMPO_CHANGE_FACTOR)) {
2700 3 : continue;
2701 : }
2702 :
2703 20 : if (TRead::readProperty(c, tag, xml, ctx, Pid::SNAP_AFTER)) {
2704 0 : continue;
2705 : }
2706 :
2707 20 : if (!readProperties(toTextLineBase(c), xml, ctx)) {
2708 0 : xml.unknown();
2709 : }
2710 : }
2711 :
2712 3 : compat::CompatUtils::resetHookHeightSign(c);
2713 3 : compat::CompatUtils::setTextLineTextPositionFromAlign(c);
2714 3 : }
2715 :
2716 2 : void TRead::read(Groups* g, XmlReader& e, ReadContext&)
2717 : {
2718 8 : while (e.readNextStartElement()) {
2719 6 : const AsciiStringView tag(e.name());
2720 6 : if (tag == "Node") {
2721 6 : GroupNode n;
2722 6 : n.pos = e.intAttribute("pos");
2723 6 : n.action = e.intAttribute("action");
2724 6 : g->addNode(n);
2725 6 : e.skipCurrentElement();
2726 : } else {
2727 0 : e.unknown();
2728 : }
2729 : }
2730 2 : }
2731 :
2732 28 : void TRead::read(GuitarBend* g, XmlReader& e, ReadContext& ctx)
2733 : {
2734 28 : g->eraseSpannerSegments();
2735 :
2736 165 : while (e.readNextStartElement()) {
2737 137 : const AsciiStringView tag = e.name();
2738 137 : if (tag == "guitarBendType") {
2739 28 : g->setBendType(static_cast<GuitarBendType>(e.readInt()));
2740 109 : } else if (tag == "GuitarBendHold") {
2741 1 : GuitarBendHold* hold = new GuitarBendHold(g);
2742 1 : TRead::read(hold, e, ctx);
2743 1 : g->setHoldLine(hold);
2744 108 : } else if (TRead::readProperty(g, tag, e, ctx, Pid::DIRECTION)) {
2745 108 : } else if (TRead::readProperty(g, tag, e, ctx, Pid::BEND_SHOW_HOLD_LINE)) {
2746 108 : } else if (TRead::readProperty(g, tag, e, ctx, Pid::BEND_START_TIME_FACTOR)) {
2747 80 : } else if (TRead::readProperty(g, tag, e, ctx, Pid::BEND_END_TIME_FACTOR)) {
2748 52 : } else if (TRead::readStyledProperty(g, tag, e, ctx)) {
2749 52 : } else if (!TRead::readProperties(static_cast<SLine*>(g), e, ctx)) {
2750 28 : e.unknown();
2751 : }
2752 : }
2753 28 : }
2754 :
2755 1 : void TRead::read(GuitarBendHold* h, XmlReader& xml, ReadContext& ctx)
2756 : {
2757 1 : h->eraseSpannerSegments();
2758 :
2759 4 : while (xml.readNextStartElement()) {
2760 2 : if (!TRead::readProperties(static_cast<SLine*>(h), xml, ctx)) {
2761 1 : xml.unknown();
2762 : }
2763 : }
2764 1 : }
2765 :
2766 0 : bool TRead::readProperties(GuitarBendSegment* g, const AsciiStringView& tag, XmlReader& xml, ReadContext& ctx)
2767 : {
2768 0 : if (tag == "bendVertexOffset") {
2769 0 : g->setVertexPointOff(xml.readPoint() * g->style().spatium());
2770 0 : } else if (tag == "GuitarBendText") {
2771 0 : GuitarBendText* bendText = new GuitarBendText(g);
2772 0 : read(toTextBase(bendText), xml, ctx);
2773 0 : g->setBendText(bendText);
2774 : } else {
2775 0 : return false;
2776 : }
2777 :
2778 0 : return true;
2779 : }
2780 :
2781 41 : void TRead::read(Hairpin* h, XmlReader& e, ReadContext& ctx)
2782 : {
2783 41 : h->eraseSpannerSegments();
2784 :
2785 41 : int mscVersion = ctx.score()->mscVersion();
2786 :
2787 112 : while (e.readNextStartElement()) {
2788 71 : const AsciiStringView tag(e.name());
2789 71 : if (tag == "subtype") {
2790 41 : h->setHairpinType(HairpinType(e.readInt()));
2791 30 : } else if (TRead::readStyledProperty(h, tag, e, ctx)) {
2792 30 : } else if (tag == "hairpinCircledTip") {
2793 2 : h->setHairpinCircledTip(e.readInt());
2794 28 : } else if (tag == "veloChange") {
2795 0 : h->setVeloChange(e.readInt());
2796 28 : } else if (tag == "dynType") { // obsolete
2797 0 : if (mscVersion < 440) {
2798 0 : h->setVoiceAssignment(read206::Read206::readDynamicRange(e.readInt()));
2799 : } else {
2800 0 : e.skipCurrentElement();
2801 : }
2802 28 : } else if (tag == "singleNoteDynamics") {
2803 0 : h->setSingleNoteDynamics(e.readBool());
2804 28 : } else if (tag == "veloChangeMethod") {
2805 0 : h->setVeloChangeMethod(TConv::fromXml(e.readAsciiText(), ChangeMethod::NORMAL));
2806 28 : } else if (readProperty(h, tag, e, ctx, Pid::VOICE_ASSIGNMENT)) {
2807 28 : } else if (readProperty(h, tag, e, ctx, Pid::DIRECTION)) {
2808 24 : } else if (readProperty(h, tag, e, ctx, Pid::CENTER_BETWEEN_STAVES)) {
2809 24 : } else if (readProperty(h, tag, e, ctx, Pid::SNAP_BEFORE)) {
2810 24 : } else if (readProperty(h, tag, e, ctx, Pid::SNAP_AFTER)) {
2811 24 : } else if (!readProperties(toTextLineBase(h), e, ctx)) {
2812 0 : e.unknown();
2813 : }
2814 : }
2815 :
2816 41 : compat::CompatUtils::resetHookHeightSign(h);
2817 41 : compat::CompatUtils::setTextLineTextPositionFromAlign(h);
2818 :
2819 41 : h->styleChanged();
2820 41 : }
2821 :
2822 30 : void TRead::read(Harmony* h, XmlReader& e, ReadContext& ctx)
2823 : {
2824 30 : HarmonyInfo* info = new HarmonyInfo(ctx.score());
2825 99 : while (e.readNextStartElement()) {
2826 69 : const AsciiStringView tag(e.name());
2827 69 : if (tag == "base") {
2828 0 : info->setBassTpc(e.readInt());
2829 69 : } else if (tag == "baseCase") {
2830 0 : h->setBassCase(static_cast<NoteCaseType>(e.readInt()));
2831 69 : } else if (tag == "extension") {
2832 0 : info->setId(e.readInt());
2833 69 : } else if (tag == "name") {
2834 9 : info->setTextName(e.readText());
2835 60 : } else if (tag == "root") {
2836 30 : info->setRootTpc(e.readInt());
2837 30 : } else if (tag == "rootCase") {
2838 0 : h->setRootCase(static_cast<NoteCaseType>(e.readInt()));
2839 30 : } else if (tag == "function") {
2840 0 : compat::CompatUtils::setHarmonyRootTpcFromFunction(info, h, e.readText());
2841 30 : } else if (tag == "degree") {
2842 0 : int degreeValue = 0;
2843 0 : int degreeAlter = 0;
2844 0 : String degreeType;
2845 0 : while (e.readNextStartElement()) {
2846 0 : const AsciiStringView t(e.name());
2847 0 : if (t == "degree-value") {
2848 0 : degreeValue = e.readInt();
2849 0 : } else if (t == "degree-alter") {
2850 0 : degreeAlter = e.readInt();
2851 0 : } else if (t == "degree-type") {
2852 0 : degreeType = e.readText();
2853 : } else {
2854 0 : e.unknown();
2855 : }
2856 : }
2857 0 : if (degreeValue <= 0 || degreeValue > 13
2858 0 : || degreeAlter < -2 || degreeAlter > 2
2859 0 : || (degreeType != "add" && degreeType != "alter" && degreeType != "subtract")) {
2860 0 : LOGD("incorrect degree: degreeValue=%d degreeAlter=%d degreeType=%s",
2861 0 : degreeValue, degreeAlter, muPrintable(degreeType));
2862 : } else {
2863 0 : if (degreeType == "add") {
2864 0 : h->addDegree(HDegree(degreeValue, degreeAlter, HDegreeType::ADD));
2865 0 : } else if (degreeType == "alter") {
2866 0 : h->addDegree(HDegree(degreeValue, degreeAlter, HDegreeType::ALTER));
2867 0 : } else if (degreeType == "subtract") {
2868 0 : h->addDegree(HDegree(degreeValue, degreeAlter, HDegreeType::SUBTRACT));
2869 : }
2870 : }
2871 30 : } else if (tag == "leftParen") {
2872 0 : h->setParenthesesMode(h->rightParen() ? ParenthesesMode::BOTH : ParenthesesMode::LEFT, true, false);
2873 0 : e.readNext();
2874 30 : } else if (tag == "rightParen") {
2875 0 : h->setParenthesesMode(h->leftParen() ? ParenthesesMode::BOTH : ParenthesesMode::RIGHT, true, false);
2876 0 : e.readNext();
2877 30 : } else if (TRead::readProperty(h, tag, e, ctx, Pid::POS_ABOVE)) {
2878 30 : } else if (TRead::readProperty(h, tag, e, ctx, Pid::HARMONY_TYPE)) {
2879 30 : } else if (TRead::readProperty(h, tag, e, ctx, Pid::PLAY)) {
2880 30 : } else if (TRead::readProperty(h, tag, e, ctx, Pid::HARMONY_VOICE_LITERAL)) {
2881 30 : } else if (TRead::readProperty(h, tag, e, ctx, Pid::HARMONY_VOICING)) {
2882 30 : } else if (TRead::readProperty(h, tag, e, ctx, Pid::HARMONY_DURATION)) {
2883 30 : } else if (!readProperties(toTextBase(h), e, ctx)) {
2884 0 : e.unknown();
2885 : }
2886 : }
2887 :
2888 30 : h->addChord(info);
2889 :
2890 30 : h->afterRead();
2891 30 : }
2892 :
2893 0 : void TRead::read(HarmonicMark* h, XmlReader& xml, ReadContext& ctx)
2894 : {
2895 0 : TRead::read(toTextLineBase(h), xml, ctx);
2896 0 : }
2897 :
2898 6 : void TRead::read(HarpPedalDiagram* h, XmlReader& xml, ReadContext& ctx)
2899 : {
2900 26 : while (xml.readNextStartElement()) {
2901 20 : const AsciiStringView tag = xml.name();
2902 20 : if (tag == "isDiagram") {
2903 3 : h->setIsDiagram(xml.readBool());
2904 17 : } else if (tag == "pedalState") {
2905 48 : while (xml.readNextStartElement()) {
2906 42 : const AsciiStringView stringTag = xml.name();
2907 42 : if (stringTag == "string") {
2908 42 : HarpStringType str = HarpStringType(xml.intAttribute("name"));
2909 42 : PedalPosition pos = PedalPosition(xml.readInt());
2910 42 : h->setPedal(str, pos);
2911 : } else {
2912 0 : xml.unknown();
2913 : }
2914 : }
2915 6 : h->setPlayableTpcs();
2916 11 : } else if (!readProperties(h, xml, ctx)) {
2917 0 : xml.unknown();
2918 : }
2919 : }
2920 6 : }
2921 :
2922 0 : void TRead::read(Hook* h, XmlReader& xml, ReadContext& ctx)
2923 : {
2924 0 : TRead::read(static_cast<Symbol*>(h), xml, ctx);
2925 0 : }
2926 :
2927 24 : void TRead::read(LayoutBreak* b, XmlReader& e, ReadContext& ctx)
2928 : {
2929 70 : while (e.readNextStartElement()) {
2930 46 : const AsciiStringView tag(e.name());
2931 46 : if (tag == "subtype") {
2932 24 : TRead::readProperty(b, e, ctx, Pid::LAYOUT_BREAK);
2933 22 : } else if (tag == "pause") {
2934 2 : TRead::readProperty(b, e, ctx, Pid::PAUSE);
2935 20 : } else if (tag == "startWithLongNames") {
2936 0 : TRead::readProperty(b, e, ctx, Pid::START_WITH_LONG_NAMES);
2937 20 : } else if (tag == "startWithMeasureOne") {
2938 0 : TRead::readProperty(b, e, ctx, Pid::START_WITH_MEASURE_ONE);
2939 20 : } else if (tag == "firstSystemIndentation") {
2940 0 : TRead::readProperty(b, e, ctx, Pid::FIRST_SYSTEM_INDENTATION);
2941 20 : } else if (tag == "showCourtesySig") {
2942 0 : TRead::readProperty(b, e, ctx, Pid::SHOW_COURTESY);
2943 20 : } else if (!readItemProperties(b, e, ctx)) {
2944 0 : e.unknown();
2945 : }
2946 : }
2947 24 : }
2948 :
2949 0 : void TRead::read(LedgerLine* l, XmlReader& e, ReadContext& ctx)
2950 : {
2951 0 : while (e.readNextStartElement()) {
2952 0 : if (!readProperties(l, e, ctx)) {
2953 0 : e.unknown();
2954 : }
2955 : }
2956 0 : }
2957 :
2958 0 : bool TRead::readProperties(LedgerLine* l, XmlReader& e, ReadContext&)
2959 : {
2960 0 : const AsciiStringView tag(e.name());
2961 :
2962 0 : if (tag == "lineWidth") {
2963 : //! NOTE Probably need to be removed, because it is calculated in Layout
2964 0 : LedgerLine::LayoutData* ldata = l->mutldata();
2965 0 : ldata->lineWidth = (e.readDouble() * l->spatium());
2966 0 : } else if (tag == "lineLen") {
2967 0 : l->setLen(e.readDouble() * l->spatium());
2968 0 : } else if (tag == "vertical") {
2969 0 : l->setVertical(e.readInt());
2970 : } else {
2971 0 : return false;
2972 : }
2973 0 : return true;
2974 : }
2975 :
2976 10 : void TRead::read(LetRing* r, XmlReader& e, ReadContext& ctx)
2977 : {
2978 20 : while (e.readNextStartElement()) {
2979 10 : if (readProperty(r, e.name(), e, ctx, Pid::LINE_WIDTH)) {
2980 0 : r->setPropertyFlags(Pid::LINE_WIDTH, PropertyFlags::UNSTYLED);
2981 10 : } else if (!readProperties(toTextLineBase(r), e, ctx)) {
2982 0 : e.unknown();
2983 : }
2984 : }
2985 10 : compat::CompatUtils::resetHookHeightSign(r);
2986 10 : compat::CompatUtils::setTextLineTextPositionFromAlign(r);
2987 10 : }
2988 :
2989 543 : void TRead::read(Location* l, XmlReader& e, ReadContext&)
2990 : {
2991 1174 : while (e.readNextStartElement()) {
2992 631 : const AsciiStringView tag(e.name());
2993 :
2994 631 : if (tag == "staves") {
2995 5 : l->setStaff(e.readInt());
2996 626 : } else if (tag == "voices") {
2997 0 : l->setVoice(e.readInt());
2998 626 : } else if (tag == "measures") {
2999 254 : l->setMeasure(e.readInt());
3000 372 : } else if (tag == "fractions") {
3001 342 : l->setFrac(e.readFraction());
3002 30 : } else if (tag == "grace") {
3003 11 : l->setGraceIndex(e.readInt());
3004 19 : } else if (tag == "notes") {
3005 0 : l->setNote(e.readInt());
3006 19 : } else if (tag == "timeTick") {
3007 19 : l->setIsTimeTick(e.readBool());
3008 : } else {
3009 0 : e.unknown();
3010 : }
3011 : }
3012 543 : }
3013 :
3014 20 : void TRead::read(Lyrics* l, XmlReader& e, ReadContext& ctx)
3015 : {
3016 81 : while (e.readNextStartElement()) {
3017 41 : if (!TRead::readProperties(l, e, ctx)) {
3018 0 : e.unknown();
3019 : }
3020 : }
3021 20 : }
3022 :
3023 4 : void TRead::read(LineSegment* l, XmlReader& e, ReadContext& ctx)
3024 : {
3025 24 : while (e.readNextStartElement()) {
3026 16 : if (!readProperties(l, e, ctx)) {
3027 0 : e.unknown();
3028 : }
3029 : }
3030 4 : }
3031 :
3032 16 : bool TRead::readProperties(LineSegment* l, XmlReader& e, ReadContext& ctx)
3033 : {
3034 16 : const AsciiStringView tag(e.name());
3035 16 : if (tag == "subtype") {
3036 4 : l->setSpannerSegmentType(SpannerSegmentType(e.readInt()));
3037 12 : } else if (tag == "off2") {
3038 4 : l->setUserOff2(e.readPoint() * l->style().spatium());
3039 8 : } else if (l->isGuitarBendSegment() && readProperties(static_cast<GuitarBendSegment*>(l), tag, e, ctx)) {
3040 8 : } else if (!readItemProperties(l, e, ctx)) {
3041 0 : return false;
3042 : }
3043 16 : return true;
3044 : }
3045 :
3046 41 : bool TRead::readProperties(Lyrics* l, XmlReader& e, ReadContext& ctx)
3047 : {
3048 41 : const AsciiStringView tag(e.name());
3049 :
3050 41 : if (tag == "no") {
3051 0 : l->setVerse(e.readInt());
3052 0 : if (l->isEven()) {
3053 0 : l->initTextStyleType(TextStyleType::LYRICS_EVEN);
3054 : }
3055 41 : } else if (tag == "syllabic") {
3056 8 : l->setSyllabic(TConv::fromXml(e.readAsciiText(), LyricsSyllabic::SINGLE));
3057 33 : } else if (tag == "ticks_f") {
3058 1 : l->setTicks(e.readFraction());
3059 32 : } else if (TRead::readProperty(l, tag, e, ctx, Pid::PLACEMENT)) {
3060 32 : } else if (!readProperties(toTextBase(l), e, ctx)) {
3061 0 : return false;
3062 : }
3063 41 : return true;
3064 : }
3065 :
3066 7 : void TRead::read(MeasureRepeat* r, XmlReader& e, ReadContext& ctx)
3067 : {
3068 31 : while (e.readNextStartElement()) {
3069 24 : const AsciiStringView tag(e.name());
3070 24 : if (tag == "subtype") {
3071 7 : r->setNumMeasures(e.readInt());
3072 17 : } else if (!readProperties(toRest(r), e, ctx)) {
3073 0 : e.unknown();
3074 : }
3075 : }
3076 7 : }
3077 :
3078 5 : void TRead::read(MMRest* r, XmlReader& e, ReadContext& ctx)
3079 : {
3080 21 : while (e.readNextStartElement()) {
3081 16 : const AsciiStringView tag(e.name());
3082 16 : if (tag == "Symbol") {
3083 0 : Symbol* s = new Symbol(r);
3084 0 : s->setTrack(r->track());
3085 0 : TRead::read(s, e, ctx);
3086 0 : r->add(s);
3087 16 : } else if (tag == "Image") {
3088 0 : if (MScore::noImages) {
3089 0 : e.skipCurrentElement();
3090 : } else {
3091 0 : Image* image = new Image(r);
3092 0 : image->setTrack(r->track());
3093 0 : TRead::read(image, e, ctx);
3094 0 : r->add(image);
3095 : }
3096 16 : } else if (tag == "NoteDot") {
3097 0 : NoteDot* dot = Factory::createNoteDot(r);
3098 0 : TRead::read(dot, e, ctx);
3099 0 : r->add(dot);
3100 16 : } else if (tag == "mmRestNumberPos") {
3101 : // Old property, deprecated in 4.5
3102 0 : r->setNumberOffset(Spatium(e.readDouble()) - ctx.style().styleS(Sid::mmRestNumberPos));
3103 16 : } else if (TRead::readProperty(r, tag, e, ctx, Pid::MMREST_NUMBER_OFFSET)) {
3104 16 : } else if (TRead::readStyledProperty(r, tag, e, ctx)) {
3105 16 : } else if (readProperties(r, e, ctx)) {
3106 : } else {
3107 0 : e.unknown();
3108 : }
3109 : }
3110 5 : }
3111 :
3112 16 : bool TRead::readProperties(MMRest* r, XmlReader& xml, ReadContext& ctx)
3113 : {
3114 16 : const AsciiStringView tag(xml.name());
3115 16 : if (tag == "mmRestNumberVisible") {
3116 0 : r->setProperty(Pid::MMREST_NUMBER_VISIBLE, xml.readBool());
3117 16 : } else if (TRead::readProperties(toRest(r), xml, ctx)) {
3118 : } else {
3119 0 : return false;
3120 : }
3121 16 : return true;
3122 : }
3123 :
3124 2138 : void TRead::read(Note* n, XmlReader& e, ReadContext& ctx)
3125 : {
3126 2138 : n->setTpc1(Tpc::TPC_INVALID);
3127 2138 : n->setTpc2(Tpc::TPC_INVALID);
3128 :
3129 11227 : while (e.readNextStartElement()) {
3130 6951 : if (TRead::readProperties(n, e, ctx)) {
3131 : } else {
3132 0 : e.unknown();
3133 : }
3134 : }
3135 :
3136 2138 : n->setupAfterRead(ctx.tick(), ctx.pasteMode());
3137 2138 : }
3138 :
3139 6951 : bool TRead::readProperties(Note* n, XmlReader& e, ReadContext& ctx)
3140 : {
3141 6951 : const AsciiStringView tag(e.name());
3142 :
3143 6951 : if (tag == "pitch") {
3144 2138 : n->setPitch(clampPitch(e.readInt()), false);
3145 4813 : } else if (tag == "tpc") {
3146 2138 : int tcp = e.readInt();
3147 2138 : n->setTpc1(tcp);
3148 2138 : n->setTpc2(tcp);
3149 2675 : } else if (tag == "track") { // for performance
3150 0 : n->setTrack(e.readInt());
3151 2675 : } else if (tag == "Accidental") {
3152 135 : Accidental* a = Factory::createAccidental(n);
3153 135 : a->setTrack(n->track());
3154 135 : TRead::read(a, e, ctx);
3155 135 : n->add(a);
3156 2540 : } else if (tag == "Spanner") {
3157 256 : readSpanner(e, ctx, n, n->track());
3158 2284 : } else if (tag == "tpc2") {
3159 77 : n->setTpc2(e.readInt());
3160 2207 : } else if (tag == "small") {
3161 0 : n->setSmall(e.readInt());
3162 2207 : } else if (tag == "mirror") {
3163 0 : TRead::readProperty(n, e, ctx, Pid::MIRROR_HEAD);
3164 2207 : } else if (tag == "dotPosition") {
3165 0 : TRead::readProperty(n, e, ctx, Pid::DOT_POSITION);
3166 2207 : } else if (tag == "fixed") {
3167 0 : n->setFixed(e.readBool());
3168 2207 : } else if (tag == "fixedLine") {
3169 0 : n->setFixedLine(e.readInt());
3170 2207 : } else if (tag == "headScheme") {
3171 0 : TRead::readProperty(n, e, ctx, Pid::HEAD_SCHEME);
3172 2207 : } else if (tag == "head") {
3173 166 : TRead::readProperty(n, e, ctx, Pid::HEAD_GROUP);
3174 2041 : } else if (tag == "velocity") {
3175 0 : n->setUserVelocity(e.readInt());
3176 2041 : } else if (tag == "play") {
3177 0 : n->setPlay(e.readInt());
3178 2041 : } else if (tag == "tuning") {
3179 0 : n->setTuning(e.readDouble());
3180 2041 : } else if (tag == "fret") {
3181 255 : n->setFret(e.readInt());
3182 1786 : } else if (tag == "string") {
3183 257 : n->setString(e.readInt());
3184 1529 : } else if (tag == "ghost") {
3185 2 : n->setGhost(e.readInt());
3186 1527 : } else if (tag == "dead") {
3187 132 : n->setDeadNote(e.readInt());
3188 1395 : } else if (tag == "headType") {
3189 1 : TRead::readProperty(n, e, ctx, Pid::HEAD_TYPE);
3190 1394 : } else if (tag == "veloType") {
3191 0 : TRead::readProperty(n, e, ctx, Pid::VELO_TYPE);
3192 1394 : } else if (tag == "line") {
3193 0 : n->setLine(e.readInt());
3194 1394 : } else if (tag == "Fingering") {
3195 0 : Fingering* f = Factory::createFingering(n);
3196 0 : f->setTrack(n->track());
3197 0 : TRead::read(f, e, ctx);
3198 0 : n->add(f);
3199 1394 : } else if (tag == "Symbol") {
3200 14 : Symbol* s = new Symbol(n);
3201 14 : s->setTrack(n->track());
3202 14 : TRead::read(s, e, ctx);
3203 14 : if (s->sym() == SymId::noteheadParenthesisLeft) {
3204 7 : n->setParenthesesMode(ParenthesesMode::BOTH);
3205 7 : s->deleteLater();
3206 7 : } else if (s->sym() == SymId::noteheadParenthesisRight) {
3207 7 : n->setParenthesesMode(ParenthesesMode::BOTH);
3208 7 : s->deleteLater();
3209 : } else {
3210 0 : n->add(s);
3211 : }
3212 1380 : } else if (tag == "Image") {
3213 0 : if (MScore::noImages) {
3214 0 : e.skipCurrentElement();
3215 : } else {
3216 0 : Image* image = new Image(n);
3217 0 : image->setTrack(n->track());
3218 0 : TRead::read(image, e, ctx);
3219 0 : n->add(image);
3220 : }
3221 1380 : } else if (tag == "Bend") {
3222 0 : Bend* b = Factory::createBend(n);
3223 0 : b->setTrack(n->track());
3224 0 : TRead::read(b, e, ctx);
3225 0 : n->add(b);
3226 1380 : } else if (tag == "NoteDot") {
3227 2 : NoteDot* dot = Factory::createNoteDot(n);
3228 2 : TRead::read(dot, e, ctx);
3229 2 : n->add(dot);
3230 1378 : } else if (tag == "Events") {
3231 0 : NoteEventList playEvents;
3232 0 : while (e.readNextStartElement()) {
3233 0 : const AsciiStringView t(e.name());
3234 0 : if (t == "Event") {
3235 0 : NoteEvent ne;
3236 0 : TRead::read(&ne, e, ctx);
3237 0 : playEvents.push_back(ne);
3238 : } else {
3239 0 : e.unknown();
3240 : }
3241 : }
3242 0 : n->setPlayEvents(playEvents);
3243 0 : if (n->chord()) {
3244 0 : n->chord()->setPlayEventType(PlayEventType::User);
3245 : }
3246 1378 : } else if (tag == "offset") {
3247 0 : readItemProperties(n, e, ctx);
3248 1378 : } else if (tag == "ChordLine" && n->chord()) {
3249 47 : ChordLine* cl = Factory::createChordLine(n->chord());
3250 47 : TRead::read(cl, e, ctx);
3251 47 : cl->setNote(n);
3252 47 : n->chord()->add(cl);
3253 1331 : } else if (tag == "LaissezVib") {
3254 0 : LaissezVib* lv = Factory::createLaissezVib(n);
3255 0 : TRead::read(lv, e, ctx);
3256 0 : n->add(lv);
3257 1331 : } else if (tag == "PartialTie") {
3258 21 : PartialTie* pt = Factory::createPartialTie(n);
3259 21 : TRead::read(pt, e, ctx);
3260 21 : if (pt->isOutgoing()) {
3261 10 : pt->setStartNote(n);
3262 : } else {
3263 11 : pt->setEndNote(n);
3264 : }
3265 21 : n->add(pt);
3266 1310 : } else if (readItemProperties(n, e, ctx)) {
3267 : } else {
3268 0 : return false;
3269 : }
3270 6951 : return true;
3271 : }
3272 :
3273 0 : void TRead::read(NoteEvent* item, XmlReader& e, ReadContext&)
3274 : {
3275 0 : while (e.readNextStartElement()) {
3276 0 : const AsciiStringView tag(e.name());
3277 0 : if (tag == "pitch") {
3278 0 : item->setPitch(e.readInt());
3279 0 : } else if (tag == "ontime") {
3280 0 : item->setOntime(e.readInt());
3281 0 : } else if (tag == "len") {
3282 0 : item->setLen(e.readInt());
3283 : } else {
3284 0 : e.unknown();
3285 : }
3286 : }
3287 0 : }
3288 :
3289 2 : void TRead::read(NoteDot* d, XmlReader& e, ReadContext& ctx)
3290 : {
3291 8 : while (e.readNextStartElement()) {
3292 4 : if (!readItemProperties(d, e, ctx)) {
3293 0 : e.unknown();
3294 : }
3295 : }
3296 2 : }
3297 :
3298 0 : void TRead::read(NoteHead* h, XmlReader& xml, ReadContext& ctx)
3299 : {
3300 0 : read(static_cast<Symbol*>(h), xml, ctx);
3301 0 : }
3302 :
3303 0 : void TRead::read(NoteLine* nl, XmlReader& xml, ReadContext& ctx)
3304 : {
3305 0 : TRead::read(toTextLineBase(nl), xml, ctx);
3306 0 : }
3307 :
3308 4 : void TRead::read(Ottava* o, XmlReader& e, ReadContext& ctx)
3309 : {
3310 4 : o->eraseSpannerSegments();
3311 10 : while (e.readNextStartElement()) {
3312 6 : readProperties(o, e, ctx);
3313 : }
3314 4 : compat::CompatUtils::resetHookHeightSign(o);
3315 4 : compat::CompatUtils::setTextLineTextPositionFromAlign(o);
3316 4 : if (o->ottavaType() != OttavaType::OTTAVA_8VA || o->numbersOnly() != o->propertyDefault(Pid::NUMBERS_ONLY).toBool()) {
3317 1 : o->styleChanged();
3318 : }
3319 4 : }
3320 :
3321 6 : bool TRead::readProperties(Ottava* o, XmlReader& e, ReadContext& ctx)
3322 : {
3323 6 : const AsciiStringView tag(e.name());
3324 6 : if (tag == "subtype") {
3325 4 : String s = e.readText();
3326 : bool ok;
3327 4 : int idx = s.toInt(&ok);
3328 4 : if (!ok) {
3329 4 : o->setOttavaType(OttavaType::OTTAVA_8VA);
3330 5 : for (OttavaDefault d : ottavaDefault) {
3331 5 : if (s == d.name) {
3332 4 : o->setOttavaType(d.type);
3333 4 : break;
3334 : }
3335 5 : }
3336 : } else {
3337 0 : o->setOttavaType(OttavaType(idx));
3338 : }
3339 6 : } else if (readStyledProperty(o, tag, e, ctx)) {
3340 0 : return true;
3341 2 : } else if (!readProperties(toTextLineBase(o), e, ctx)) {
3342 0 : e.unknown();
3343 0 : return false;
3344 : }
3345 6 : return true;
3346 : }
3347 :
3348 0 : void TRead::read(Page* p, XmlReader& e, ReadContext& ctx)
3349 : {
3350 0 : while (e.readNextStartElement()) {
3351 0 : if (e.name() == "System") {
3352 0 : System* system = Factory::createSystem(p->score());
3353 0 : p->score()->systems().push_back(system);
3354 0 : read(system, e, ctx);
3355 : } else {
3356 0 : e.unknown();
3357 : }
3358 : }
3359 0 : }
3360 :
3361 8 : void TRead::read(PalmMute* p, XmlReader& e, ReadContext& ctx)
3362 : {
3363 16 : while (e.readNextStartElement()) {
3364 8 : if (readProperty(p, e.name(), e, ctx, Pid::LINE_WIDTH)) {
3365 0 : p->setPropertyFlags(Pid::LINE_WIDTH, PropertyFlags::UNSTYLED);
3366 8 : } else if (!readProperties(toTextLineBase(p), e, ctx)) {
3367 0 : e.unknown();
3368 : }
3369 : }
3370 8 : compat::CompatUtils::resetHookHeightSign(p);
3371 8 : compat::CompatUtils::setTextLineTextPositionFromAlign(p);
3372 8 : }
3373 :
3374 0 : void TRead::read(Parenthesis* p, XmlReader& xml, ReadContext& ctx)
3375 : {
3376 0 : while (xml.readNextStartElement()) {
3377 0 : const AsciiStringView tag(xml.name());
3378 0 : if (TRead::readProperty(p, tag, xml, ctx, Pid::HORIZONTAL_DIRECTION)) {
3379 0 : } else if (!readItemProperties(p, xml, ctx)) {
3380 0 : xml.unknown();
3381 : }
3382 : }
3383 0 : }
3384 :
3385 237 : void TRead::read(Part* p, XmlReader& e, ReadContext& ctx)
3386 : {
3387 237 : p->setId(e.intAttribute("id", 0));
3388 :
3389 237 : StaffHideModes staffHideModes;
3390 :
3391 1262 : while (e.readNextStartElement()) {
3392 788 : if (!readProperties(p, e, ctx, staffHideModes)) {
3393 236 : e.unknown();
3394 : }
3395 : }
3396 :
3397 237 : read400::TRead::read(p, staffHideModes, ctx.style().styleB(Sid::hideEmptyStaves));
3398 237 : }
3399 :
3400 0 : void TRead::read(PartialLyricsLine* p, XmlReader& xml, ReadContext& ctx)
3401 : {
3402 0 : while (xml.readNextStartElement()) {
3403 0 : const AsciiStringView tag(xml.name());
3404 0 : if (tag == "isEndMelisma") {
3405 0 : p->setIsEndMelisma(xml.readBool());
3406 0 : } else if (TRead::readProperty(p, tag, xml, ctx, Pid::VERSE)) {
3407 0 : } else if (!readItemProperties(p, xml, ctx)) {
3408 0 : xml.unknown();
3409 : }
3410 : }
3411 0 : }
3412 :
3413 21 : void TRead::read(PartialTie* p, XmlReader& xml, ReadContext& ctx)
3414 : {
3415 43 : while (xml.readNextStartElement()) {
3416 22 : const AsciiStringView tag(xml.name());
3417 22 : if (TRead::readProperty(p, tag, xml, ctx, Pid::TIE_PLACEMENT)) {
3418 22 : } else if (TRead::readProperty(p, tag, xml, ctx, Pid::PARTIAL_SPANNER_DIRECTION)) {
3419 11 : } else if (!readProperties(toSlurTie(p), xml, ctx)) {
3420 0 : xml.unknown();
3421 : }
3422 : }
3423 21 : }
3424 :
3425 788 : bool TRead::readProperties(Part* p, XmlReader& e, ReadContext& ctx, StaffHideModes& staffHideModes)
3426 : {
3427 788 : const AsciiStringView tag(e.name());
3428 788 : if (tag == "id") {
3429 0 : p->setId(e.readInt());
3430 788 : } else if (tag == "Staff") {
3431 300 : Staff* staff = Factory::createStaff(p);
3432 300 : p->score()->appendStaff(staff);
3433 300 : TRead::read(staff, e, ctx, staffHideModes);
3434 488 : } else if (tag == "Instrument") {
3435 237 : Instrument* instr = new Instrument;
3436 237 : read(instr, e, ctx, p);
3437 237 : p->setInstrument(instr, Fraction(-1, 1));
3438 251 : } else if (tag == "name") {
3439 0 : p->instrument()->setLongName(e.readText());
3440 251 : } else if (tag == "color") {
3441 0 : e.skipCurrentElement(); // Unused
3442 251 : } else if (tag == "shortName") {
3443 0 : p->instrument()->setShortName(e.readText());
3444 251 : } else if (tag == "show") {
3445 1 : p->setShow(e.readInt());
3446 250 : } else if (tag == "soloist") {
3447 1 : p->setSoloist(e.readInt());
3448 249 : } else if (tag == "preferSharpFlat") {
3449 13 : String val = e.readText();
3450 13 : if (val == "sharps") {
3451 0 : p->setPreferSharpFlat(PreferSharpFlat::SHARPS);
3452 13 : } else if (val == "flats") {
3453 0 : p->setPreferSharpFlat(PreferSharpFlat::FLATS);
3454 13 : } else if (val == "none") {
3455 13 : p->setPreferSharpFlat(PreferSharpFlat::NONE);
3456 : } else {
3457 0 : p->setPreferSharpFlat(PreferSharpFlat::AUTO);
3458 : }
3459 13 : } else {
3460 236 : return false;
3461 : }
3462 552 : return true;
3463 : }
3464 :
3465 7 : void TRead::read(Pedal* p, XmlReader& e, ReadContext& ctx)
3466 : {
3467 7 : bool beginTextTag = false;
3468 7 : bool continueTextTag = false;
3469 7 : bool endTextTag = false;
3470 :
3471 26 : while (e.readNextStartElement()) {
3472 19 : const AsciiStringView tag(e.name());
3473 19 : beginTextTag = beginTextTag || tag == "beginText";
3474 19 : continueTextTag = continueTextTag || tag == "continueText";
3475 19 : endTextTag = endTextTag || tag == "endText";
3476 :
3477 19 : if (readStyledProperty(p, tag, e, ctx)) {
3478 14 : } else if (TRead::readProperty(p, tag, e, ctx, Pid::LINE_VISIBLE)) {
3479 3 : p->resetProperty(Pid::END_TEXT);
3480 11 : } else if (TRead::readProperty(p, tag, e, ctx, Pid::BEGIN_HOOK_TYPE)) {
3481 1 : if (p->beginHookType() != HookType::NONE) {
3482 1 : p->setBeginText(String());
3483 1 : p->setContinueText(String());
3484 : }
3485 10 : } else if (!readProperties(toTextLineBase(p), e, ctx)) {
3486 0 : e.unknown();
3487 : }
3488 : }
3489 :
3490 7 : if (p->score()->mscVersion() < 420 && !ctx.pasteMode()) {
3491 : // Set to the pre-420 defaults if no value was specified;
3492 : // or follow the new style setting if the specified value matches it
3493 2 : if (!beginTextTag) {
3494 1 : p->setBeginText(String());
3495 1 : p->setPropertyFlags(Pid::BEGIN_TEXT, PropertyFlags::UNSTYLED);
3496 1 : } else if (p->beginText() == p->propertyDefault(Pid::BEGIN_TEXT).value<String>()) {
3497 1 : p->setPropertyFlags(Pid::BEGIN_TEXT, PropertyFlags::STYLED);
3498 : }
3499 2 : if (!continueTextTag) {
3500 1 : p->setContinueText(String());
3501 1 : p->setPropertyFlags(Pid::CONTINUE_TEXT, PropertyFlags::UNSTYLED);
3502 1 : } else if (p->continueText() == p->propertyDefault(Pid::CONTINUE_TEXT).value<String>()) {
3503 0 : p->setPropertyFlags(Pid::CONTINUE_TEXT, PropertyFlags::STYLED);
3504 : }
3505 2 : if (!endTextTag) {
3506 2 : p->setEndText(String());
3507 2 : p->setPropertyFlags(Pid::END_TEXT, PropertyFlags::UNSTYLED);
3508 0 : } else if (p->endText() == p->propertyDefault(Pid::END_TEXT).value<String>()) {
3509 0 : p->setPropertyFlags(Pid::END_TEXT, PropertyFlags::STYLED);
3510 : }
3511 : }
3512 7 : compat::CompatUtils::resetHookHeightSign(p);
3513 7 : compat::CompatUtils::setTextLineTextPositionFromAlign(p);
3514 7 : }
3515 :
3516 0 : void TRead::read(Rasgueado* r, XmlReader& xml, ReadContext& ctx)
3517 : {
3518 0 : TRead::read(toTextLineBase(r), xml, ctx);
3519 0 : }
3520 :
3521 1378 : void TRead::read(Rest* r, XmlReader& e, ReadContext& ctx)
3522 : {
3523 5063 : while (e.readNextStartElement()) {
3524 3685 : const AsciiStringView tag(e.name());
3525 3685 : if (tag == "Symbol" && r->score()->mscVersion() < 420) {
3526 0 : Segment* seg = toSegment(r->parent());
3527 0 : Symbol* s = new Symbol(seg);
3528 0 : s->setTrack(r->track());
3529 0 : TRead::read(s, e, ctx);
3530 0 : seg->add(s);
3531 3685 : } else if (tag == "Image" && r->score()->mscVersion() < 420) {
3532 0 : if (MScore::noImages) {
3533 0 : e.skipCurrentElement();
3534 : } else {
3535 0 : Segment* seg = toSegment(r->parent());
3536 0 : Image* image = new Image(seg);
3537 0 : image->setTrack(r->track());
3538 0 : TRead::read(image, e, ctx);
3539 0 : seg->add(image);
3540 : }
3541 3685 : } else if (tag == "NoteDot") {
3542 0 : NoteDot* dot = Factory::createNoteDot(r);
3543 0 : TRead::read(dot, e, ctx);
3544 0 : r->add(dot);
3545 3685 : } else if (TRead::readStyledProperty(r, tag, e, ctx)) {
3546 3685 : } else if (TRead::readProperties(r, e, ctx)) {
3547 : } else {
3548 0 : e.unknown();
3549 : }
3550 : }
3551 1378 : }
3552 :
3553 0 : void TRead::read(Segment* s, XmlReader& e, ReadContext& ctx)
3554 : {
3555 : UNUSED(ctx);
3556 0 : while (e.readNextStartElement()) {
3557 0 : const AsciiStringView tag(e.name());
3558 :
3559 0 : if (tag == "subtype") {
3560 0 : e.skipCurrentElement();
3561 0 : } else if (tag == "leadingSpace") {
3562 0 : s->setExtraLeadingSpace(Spatium(e.readDouble()));
3563 : } else {
3564 0 : e.unknown();
3565 : }
3566 : }
3567 0 : }
3568 :
3569 0 : void TRead::read(SLine* l, XmlReader& e, ReadContext& ctx)
3570 : {
3571 0 : l->eraseSpannerSegments();
3572 :
3573 0 : while (e.readNextStartElement()) {
3574 0 : if (!readProperties(l, e, ctx)) {
3575 0 : e.unknown();
3576 : }
3577 : }
3578 0 : }
3579 :
3580 171 : bool TRead::readProperties(SLine* l, XmlReader& e, ReadContext& ctx)
3581 : {
3582 171 : const AsciiStringView tag(e.name());
3583 :
3584 171 : if (tag == "ticks") {
3585 0 : l->setTicks(Fraction::fromTicks(e.readInt()));
3586 171 : } else if (tag == "Segment") {
3587 4 : LineSegment* ls = l->createLineSegment();
3588 4 : ls->setTrack(l->track()); // needed in read to get the right staff mag
3589 4 : l->add(ls);
3590 4 : TRead::read(ls, e, ctx);
3591 4 : ls->setVisible(l->visible());
3592 167 : } else if (TRead::readProperty(l, tag, e, ctx, Pid::DIAGONAL)) {
3593 149 : } else if (TRead::readProperty(l, tag, e, ctx, Pid::LINE_WIDTH)) {
3594 148 : } else if (TRead::readProperty(l, tag, e, ctx, Pid::LINE_STYLE)) {
3595 148 : } else if (TRead::readProperty(l, tag, e, ctx, Pid::DASH_LINE_LEN)) {
3596 148 : } else if (TRead::readProperty(l, tag, e, ctx, Pid::DASH_GAP_LEN)) {
3597 148 : } else if (tag == "lineColor" || tag == "color") {
3598 18 : l->setLineColor(e.readColor());
3599 130 : } else if (!readProperties(toSpanner(l), e, ctx)) {
3600 46 : return false;
3601 : }
3602 125 : return true;
3603 : }
3604 :
3605 26 : void TRead::read(Slur* s, XmlReader& e, ReadContext& ctx)
3606 : {
3607 69 : while (e.readNextStartElement()) {
3608 17 : if (!readProperties(s, e, ctx)) {
3609 0 : e.unknown();
3610 : }
3611 : }
3612 26 : }
3613 :
3614 17 : bool TRead::readProperties(Slur* s, XmlReader& e, ReadContext& ctx)
3615 : {
3616 17 : const AsciiStringView tag(e.name());
3617 17 : if (TRead::readProperty(s, tag, e, ctx, Pid::PARTIAL_SPANNER_DIRECTION)) {
3618 2 : return true;
3619 : }
3620 :
3621 15 : return readProperties(toSlurTie(s), e, ctx);
3622 : }
3623 :
3624 0 : void TRead::read(SlurTie* s, XmlReader& e, ReadContext& ctx)
3625 : {
3626 0 : while (e.readNextStartElement()) {
3627 0 : if (!readProperties(s, e, ctx)) {
3628 0 : e.unknown();
3629 : }
3630 : }
3631 0 : }
3632 :
3633 94 : bool TRead::readProperties(SlurTie* s, XmlReader& e, ReadContext& ctx)
3634 : {
3635 94 : const AsciiStringView tag(e.name());
3636 :
3637 94 : if (TRead::readProperty(s, tag, e, ctx, Pid::SLUR_DIRECTION)) {
3638 94 : } else if (tag == "lineType") {
3639 0 : s->setStyleType(static_cast<SlurStyleType>(e.readInt()));
3640 94 : } else if (tag == "SlurSegment" || tag == "TieSegment" || tag == "LaissezVibSegment" || tag == "PartialTieSegment") {
3641 2 : const int idx = e.intAttribute("no", 0);
3642 2 : const int n = int(s->spannerSegments().size());
3643 2 : for (int i = n; i < idx; ++i) {
3644 0 : s->add(s->newSlurTieSegment());
3645 : }
3646 2 : SlurTieSegment* sts = s->newSlurTieSegment();
3647 2 : s->add(sts);
3648 2 : TRead::read(sts, e, ctx);
3649 92 : } else if (!readProperties(toSpanner(s), e, ctx)) {
3650 0 : return false;
3651 : }
3652 94 : return true;
3653 : }
3654 :
3655 2 : void TRead::read(SlurTieSegment* s, XmlReader& e, ReadContext& ctx)
3656 : {
3657 4 : while (e.readNextStartElement()) {
3658 2 : const AsciiStringView tag(e.name());
3659 2 : if (readProperty(s, tag, e, ctx, Pid::BEZIER_OFFSET1)) {
3660 2 : } else if (readProperty(s, tag, e, ctx, Pid::BEZIER_OFFSET2)) {
3661 2 : } else if (readProperty(s, tag, e, ctx, Pid::BEZIER_OFFSET3)) {
3662 2 : } else if (readProperty(s, tag, e, ctx, Pid::BEZIER_OFFSET4)) {
3663 1 : } else if (!readItemProperties(s, e, ctx)) {
3664 0 : e.unknown();
3665 : }
3666 : }
3667 2 : }
3668 :
3669 222 : bool TRead::readProperties(Spanner* s, XmlReader& e, ReadContext& ctx)
3670 : {
3671 222 : const AsciiStringView tag(e.name());
3672 222 : if (ctx.pasteMode() && (tag == "ticks_f")) {
3673 0 : s->setTicks(e.readFraction());
3674 0 : return true;
3675 222 : } else if (tag == "play") {
3676 0 : s->setPlaySpanner(e.readBool());
3677 0 : return true;
3678 222 : } else if (!readItemProperties(s, e, ctx)) {
3679 46 : return false;
3680 : }
3681 176 : return true;
3682 : }
3683 :
3684 0 : void TRead::read(Spacer* s, XmlReader& e, ReadContext& ctx)
3685 : {
3686 0 : while (e.readNextStartElement()) {
3687 0 : const AsciiStringView tag(e.name());
3688 0 : if (tag == "subtype") {
3689 0 : s->setSpacerType(SpacerType(e.readInt()));
3690 0 : } else if (tag == "space") {
3691 0 : s->setGap(Spatium(e.readDouble()));
3692 0 : } else if (!readItemProperties(s, e, ctx)) {
3693 0 : e.unknown();
3694 : }
3695 : }
3696 0 : }
3697 :
3698 300 : void TRead::read(StaffType* t, XmlReader& e, ReadContext&)
3699 : {
3700 300 : t->setGroup(TConv::fromXml(e.asciiAttribute("group"), StaffGroup::STANDARD));
3701 :
3702 300 : if (t->group() == StaffGroup::TAB) {
3703 28 : t->setGenKeysig(false);
3704 : }
3705 :
3706 300 : t->setFretUseTextStyle(false);
3707 :
3708 1138 : while (e.readNextStartElement()) {
3709 838 : const AsciiStringView tag(e.name());
3710 838 : if (tag == "name") {
3711 300 : t->setType(TConv::fromXml(e.readAsciiText(), StaffTypes::STANDARD));
3712 538 : } else if (tag == "lines") {
3713 30 : t->setLines(e.readInt());
3714 508 : } else if (tag == "lineDistance") {
3715 28 : t->setLineDistance(Spatium(e.readDouble()));
3716 480 : } else if (tag == "yoffset") {
3717 0 : t->setYoffset(Spatium(e.readDouble()));
3718 480 : } else if (tag == "mag") {
3719 0 : t->setUserMag(e.readDouble());
3720 480 : } else if (tag == "small") {
3721 0 : t->setSmall(e.readBool());
3722 480 : } else if (tag == "stepOffset") {
3723 0 : t->setStepOffset(e.readInt());
3724 480 : } else if (tag == "clef") {
3725 0 : t->setGenClef(e.readInt());
3726 480 : } else if ((tag == "slashStyle") || (tag == "stemless")) {
3727 28 : bool val = e.readInt() != 0;
3728 28 : t->setStemless(val);
3729 28 : t->setShowBackTied(!val); // for compatibility with 2.0.2 scores where this prop
3730 : } // was lacking and controlled by "slashStyle" instead
3731 452 : else if (tag == "barlines") {
3732 0 : t->setShowBarlines(e.readInt());
3733 452 : } else if (tag == "timesig") {
3734 28 : t->setGenTimesig(e.readInt());
3735 424 : } else if (tag == "noteheadScheme") {
3736 0 : t->setNoteHeadScheme(TConv::fromXml(e.readAsciiText(), NoteHeadScheme::HEAD_NORMAL));
3737 424 : } else if (tag == "keysig") {
3738 4 : t->setGenKeysig(e.readInt());
3739 420 : } else if (tag == "ledgerlines") {
3740 0 : t->setShowLedgerLines(e.readInt());
3741 420 : } else if (tag == "invisible") {
3742 0 : t->setInvisible(e.readInt());
3743 420 : } else if (tag == "color") {
3744 0 : t->setColor(e.readColor());
3745 420 : } else if (tag == "durations") {
3746 28 : t->setGenDurations(e.readBool());
3747 392 : } else if (tag == "durationFontName") {
3748 28 : t->setDurationFontName(e.readText());
3749 364 : } else if (tag == "durationFontSize") {
3750 28 : t->setDurationFontSize(e.readDouble());
3751 336 : } else if (tag == "durationFontY") {
3752 28 : t->setDurationFontUserY(e.readDouble());
3753 308 : } else if (tag == "fretFontName") {
3754 28 : t->setFretPreset(e.readText());
3755 280 : } else if (tag == "fretFontSize") {
3756 28 : t->setFretFontSize(e.readDouble());
3757 252 : } else if (tag == "fretFontY") {
3758 28 : t->setFretFontUserY(e.readDouble());
3759 224 : } else if (tag == "symbolRepeat") {
3760 0 : t->setSymbolRepeat((TablatureSymbolRepeat)e.readInt());
3761 224 : } else if (tag == "linesThrough") {
3762 28 : t->setLinesThrough(e.readBool());
3763 196 : } else if (tag == "minimStyle") {
3764 28 : t->setMinimStyle((TablatureMinimStyle)e.readInt());
3765 168 : } else if (tag == "onLines") {
3766 28 : t->setOnLines(e.readBool());
3767 140 : } else if (tag == "showRests") {
3768 28 : t->setShowRests(e.readBool());
3769 112 : } else if (tag == "stemsDown") {
3770 28 : t->setStemsDown(e.readBool());
3771 84 : } else if (tag == "stemsThrough") {
3772 28 : t->setStemsThrough(e.readBool());
3773 56 : } else if (tag == "upsideDown") {
3774 28 : t->setUpsideDown(e.readBool());
3775 28 : } else if (tag == "showTabFingering") {
3776 0 : t->setShowTabFingering(e.readBool());
3777 28 : } else if (tag == "useNumbers") {
3778 28 : t->setUseNumbers(e.readBool());
3779 0 : } else if (tag == "showBackTied") { // must be after reading "slashStyle"/"stemless" prop, as in older
3780 0 : t->setShowBackTied(e.readBool()); // scores, this prop was lacking and controlled by "slashStyle"
3781 : } else {
3782 0 : e.unknown();
3783 : }
3784 : }
3785 300 : }
3786 :
3787 0 : void TRead::read(StaffTypeChange* c, XmlReader& e, ReadContext& ctx)
3788 : {
3789 0 : while (e.readNextStartElement()) {
3790 0 : const AsciiStringView tag(e.name());
3791 0 : if (tag == "StaffType") {
3792 0 : StaffType* st = new StaffType();
3793 0 : TRead::read(st, e, ctx);
3794 : // Measure::add() will replace this with a pointer to a copy in the staff
3795 0 : c->setStaffType(st, true);
3796 0 : } else if (!readItemProperties(c, e, ctx)) {
3797 0 : e.unknown();
3798 : }
3799 : }
3800 0 : }
3801 :
3802 300 : void TRead::read(Staff* s, XmlReader& e, ReadContext& ctx, StaffHideModes& staffHideModes)
3803 : {
3804 1185 : while (e.readNextStartElement()) {
3805 585 : if (!readProperties(s, e, ctx, staffHideModes)) {
3806 0 : e.unknown();
3807 : }
3808 : }
3809 300 : }
3810 :
3811 585 : bool TRead::readProperties(Staff* s, XmlReader& e, ReadContext& ctx, StaffHideModes& staffHideModes)
3812 : {
3813 585 : const AsciiStringView tag(e.name());
3814 585 : if (tag == "StaffType") {
3815 300 : StaffType st;
3816 300 : TRead::read(&st, e, ctx);
3817 300 : s->setStaffType(Fraction(0, 1), st);
3818 585 : } else if (tag == "defaultClef") { // sets both default transposing and concert clef
3819 57 : ClefType ct = TConv::fromXml(e.readAsciiText(), ClefType::G);
3820 57 : s->setDefaultClefType(ClefTypeList(ct, ct));
3821 228 : } else if (tag == "defaultConcertClef") {
3822 0 : s->setDefaultClefType(ClefTypeList(TConv::fromXml(e.readAsciiText(), ClefType::G), s->defaultClefType().transposingClef));
3823 228 : } else if (tag == "defaultTransposingClef") {
3824 0 : s->setDefaultClefType(ClefTypeList(s->defaultClefType().concertClef, TConv::fromXml(e.readAsciiText(), ClefType::G)));
3825 228 : } else if (tag == "invisible") {
3826 0 : s->staffType(Fraction(0, 1))->setInvisible(e.readInt()); // same as: setInvisible(Fraction(0,1)), e.readInt())
3827 228 : } else if (tag == "hideWhenEmpty") {
3828 18 : staffHideModes[s] = static_cast<StaffHideMode>(e.readInt());
3829 210 : } else if (tag == "cutaway") {
3830 0 : s->setCutaway(e.readInt());
3831 210 : } else if (tag == "showIfSystemEmpty") {
3832 0 : s->setShowIfEntireSystemEmpty(e.readInt());
3833 210 : } else if (tag == "hideSystemBarLine") {
3834 0 : s->setHideSystemBarLine(e.readInt());
3835 210 : } else if (tag == "mergeMatchingRests") {
3836 0 : if (ctx.score()->mscVersion() < 450) {
3837 0 : s->setMergeMatchingRests(e.readInt() ? AutoOnOff::ON : AutoOnOff::AUTO);
3838 : } else {
3839 0 : s->setMergeMatchingRests(TConv::fromXml(e.readAsciiText(), AutoOnOff::AUTO));
3840 : }
3841 210 : } else if (tag == "isStaffVisible") {
3842 2 : s->setVisible(e.readBool());
3843 208 : } else if (tag == "keylist") {
3844 0 : TRead::read(s->keyList(), e, ctx);
3845 208 : } else if (tag == "bracket") {
3846 68 : int col = e.intAttribute("col", -1);
3847 68 : if (col == -1) {
3848 0 : col = static_cast<int>(ctx.score()->brackets(s->idx()).size());
3849 : }
3850 68 : EditStaffBrackets::setBracketType(ctx.score(), s->idx(), col, BracketType(e.intAttribute("type", -1)));
3851 68 : EditStaffBrackets::setBracketSpan(ctx.score(), s->idx(), col, e.intAttribute("span", 0));
3852 68 : EditStaffBrackets::setBracketVisible(ctx.score(), s->idx(), col, static_cast<bool>(e.intAttribute("visible", 1)));
3853 68 : e.readNext();
3854 140 : } else if (tag == "barLineSpan") {
3855 73 : const int barLineSpan = e.readInt();
3856 73 : if (barLineSpan < 0) {
3857 0 : LOGW() << "barLineSpan is negative: " << barLineSpan;
3858 0 : s->setBarLineSpan(false);
3859 73 : } else if (barLineSpan > 1) {
3860 0 : LOGW() << "barLineSpan is > 1: " << barLineSpan;
3861 0 : s->setBarLineSpan(true);
3862 : } else {
3863 73 : s->setBarLineSpan(static_cast<bool>(barLineSpan));
3864 : }
3865 67 : } else if (tag == "barLineSpanFrom") {
3866 0 : s->setBarLineFrom(e.readInt());
3867 67 : } else if (tag == "barLineSpanTo") {
3868 0 : s->setBarLineTo(e.readInt());
3869 67 : } else if (tag == "distOffset") {
3870 0 : s->setUserDist(Spatium(e.readDouble()));
3871 67 : } else if (tag == "mag") {
3872 : /*_userMag =*/
3873 0 : e.readDouble(0.1, 10.0);
3874 67 : } else if (tag == "linkedTo") {
3875 67 : int v = e.readInt() - 1;
3876 67 : Staff* st = s->score()->masterScore()->staff(v);
3877 67 : if (s->links()) {
3878 2 : LOGD("Staff::readProperties: multiple <linkedTo> tags");
3879 2 : if (!st || s->isLinked(st)) { // maybe we don't need actually to relink...
3880 2 : return true;
3881 : }
3882 : // not using unlink() here as it may delete _links
3883 : // a pointer to which is stored also in XmlReader.
3884 0 : s->links()->remove(s);
3885 0 : s->setLinks(nullptr);
3886 : }
3887 65 : if (st && st != s) {
3888 38 : s->linkTo(st);
3889 27 : } else if (!s->score()->isMaster() && !st) {
3890 : // if it is a master score it is OK not to find
3891 : // a staff which is going after the current one.
3892 0 : LOGD("staff %d not found in parent", v);
3893 : }
3894 0 : } else if (tag == "color") {
3895 0 : s->staffType(Fraction(0, 1))->setColor(e.readColor());
3896 0 : } else if (tag == "transposeDiatonic") {
3897 0 : ctx.setTransposeDiatonic(static_cast<int8_t>(e.readInt()));
3898 0 : } else if (tag == "transposeChromatic") {
3899 0 : ctx.setTransposeChromatic(static_cast<int8_t>(e.readInt()));
3900 0 : } else if (tag == "playbackVoice1") {
3901 0 : s->setPlaybackVoice(0, e.readInt());
3902 0 : } else if (tag == "playbackVoice2") {
3903 0 : s->setPlaybackVoice(1, e.readInt());
3904 0 : } else if (tag == "playbackVoice3") {
3905 0 : s->setPlaybackVoice(2, e.readInt());
3906 0 : } else if (tag == "playbackVoice4") {
3907 0 : s->setPlaybackVoice(3, e.readInt());
3908 : } else {
3909 0 : return false;
3910 : }
3911 583 : return true;
3912 : }
3913 :
3914 2 : void TRead::read(Stem* s, XmlReader& e, ReadContext& ctx)
3915 : {
3916 7 : while (e.readNextStartElement()) {
3917 3 : if (!TRead::readProperties(s, e, ctx)) {
3918 0 : e.unknown();
3919 : }
3920 : }
3921 2 : }
3922 :
3923 3 : bool TRead::readProperties(Stem* s, XmlReader& e, ReadContext& ctx)
3924 : {
3925 3 : const AsciiStringView tag(e.name());
3926 :
3927 3 : if (TRead::readProperty(s, tag, e, ctx, Pid::USER_LEN)) {
3928 3 : } else if (TRead::readStyledProperty(s, tag, e, ctx)) {
3929 3 : } else if (readItemProperties(s, e, ctx)) {
3930 : } else {
3931 0 : return false;
3932 : }
3933 3 : return true;
3934 : }
3935 :
3936 0 : void TRead::read(StemSlash* s, XmlReader& e, ReadContext& ctx)
3937 : {
3938 0 : while (e.readNextStartElement()) {
3939 0 : if (!readItemProperties(s, e, ctx)) {
3940 0 : e.unknown();
3941 : }
3942 : }
3943 0 : }
3944 :
3945 61 : void TRead::read(StringData* item, XmlReader& e)
3946 : {
3947 61 : item->stringList().clear();
3948 478 : while (e.readNextStartElement()) {
3949 417 : const AsciiStringView tag(e.name());
3950 417 : if (tag == "frets") {
3951 61 : item->setFrets(e.readInt());
3952 356 : } else if (tag == "string") {
3953 356 : instrString strg;
3954 356 : strg.open = e.intAttribute("open", 0);
3955 356 : strg.useFlat = e.intAttribute("useFlat", 0);
3956 356 : strg.pitch = e.readInt();
3957 356 : item->stringList().push_back(strg);
3958 : } else {
3959 0 : e.unknown();
3960 : }
3961 : }
3962 61 : if (item->isFiveStringBanjo()) {
3963 0 : item->configBanjo5thString();
3964 : }
3965 61 : }
3966 :
3967 0 : void TRead::read(StringTunings* s, XmlReader& xml, ReadContext& ctx)
3968 : {
3969 0 : while (xml.readNextStartElement()) {
3970 0 : const AsciiStringView tag(xml.name());
3971 :
3972 0 : if (tag == "preset") {
3973 0 : s->setPreset(xml.readText());
3974 0 : } else if (tag == "StringData") {
3975 0 : StringData sd;
3976 0 : read(&sd, xml);
3977 0 : s->setStringData(sd);
3978 0 : } else if (tag == "visibleStrings") {
3979 0 : s->setVisibleStrings(TConv::fromXml(xml.readText(), std::vector<string_idx_t>()));
3980 0 : } else if (!readProperties(static_cast<StaffTextBase*>(s), xml, ctx)) {
3981 0 : xml.unknown();
3982 : }
3983 : }
3984 0 : }
3985 :
3986 0 : void TRead::read(System* s, XmlReader& e, ReadContext& ctx)
3987 : {
3988 0 : while (e.readNextStartElement()) {
3989 0 : const AsciiStringView tag(e.name());
3990 0 : if (tag == "SystemDivider") {
3991 0 : SystemDivider* sd = new SystemDivider(s);
3992 0 : TRead::read(sd, e, ctx);
3993 0 : s->add(sd);
3994 : } else {
3995 0 : e.unknown();
3996 : }
3997 : }
3998 0 : }
3999 :
4000 226 : void TRead::read(Text* t, XmlReader& e, ReadContext& ctx)
4001 : {
4002 734 : while (e.readNextStartElement()) {
4003 508 : const AsciiStringView tag(e.name());
4004 508 : if (tag == "style") {
4005 226 : TextStyleType s = TConv::fromXml(e.readAsciiText(), TextStyleType::DEFAULT);
4006 226 : if (TextStyleType::TUPLET == s) { // ugly hack for compatibility
4007 108 : continue;
4008 : }
4009 118 : t->initTextStyleType(s);
4010 282 : } else if (!readProperties(toTextBase(t), e, ctx)) {
4011 0 : e.unknown();
4012 : }
4013 : }
4014 226 : }
4015 :
4016 4 : void TRead::read(TextLine* l, XmlReader& e, ReadContext& ctx)
4017 : {
4018 4 : bool system = e.intAttribute("system", 0) == 1;
4019 4 : l->setSystemFlag(system);
4020 4 : l->initStyle();
4021 4 : TRead::read(toTextLineBase(l), e, ctx);
4022 4 : }
4023 :
4024 4 : void TRead::read(TextLineBase* b, XmlReader& e, ReadContext& ctx)
4025 : {
4026 4 : b->eraseSpannerSegments();
4027 :
4028 17 : while (e.readNextStartElement()) {
4029 9 : if (!readProperties(b, e, ctx)) {
4030 0 : e.unknown();
4031 : }
4032 : }
4033 :
4034 4 : compat::CompatUtils::resetHookHeightSign(b);
4035 4 : compat::CompatUtils::setTextLineTextPositionFromAlign(b);
4036 4 : }
4037 :
4038 82 : void TRead::read(Tie* t, XmlReader& xml, ReadContext& ctx)
4039 : {
4040 150 : while (xml.readNextStartElement()) {
4041 68 : AsciiStringView tag = xml.name();
4042 68 : if (TRead::readProperty(t, tag, xml, ctx, Pid::TIE_PLACEMENT)) {
4043 68 : } else if (!readProperties(toSlurTie(t), xml, ctx)) {
4044 0 : xml.unknown();
4045 : }
4046 : }
4047 82 : }
4048 :
4049 296 : void TRead::read(TimeSig* s, XmlReader& e, ReadContext& ctx)
4050 : {
4051 296 : int n=0, z1=0, z2=0, z3=0, z4=0;
4052 296 : bool old = false;
4053 :
4054 296 : TimeSigType timeSigType = TimeSigType::NORMAL;
4055 296 : Fraction sig;
4056 296 : Fraction stretch(1, 1);
4057 296 : String numeratorString;
4058 296 : String denominatorString;
4059 :
4060 1088 : while (e.readNextStartElement()) {
4061 792 : const AsciiStringView tag(e.name());
4062 :
4063 792 : if (tag == "den") {
4064 0 : old = true;
4065 0 : n = e.readInt();
4066 792 : } else if (tag == "nom1") {
4067 0 : old = true;
4068 0 : z1 = e.readInt();
4069 792 : } else if (tag == "nom2") {
4070 0 : old = true;
4071 0 : z2 = e.readInt();
4072 792 : } else if (tag == "nom3") {
4073 0 : old = true;
4074 0 : z3 = e.readInt();
4075 792 : } else if (tag == "nom4") {
4076 0 : old = true;
4077 0 : z4 = e.readInt();
4078 792 : } else if (tag == "subtype") {
4079 0 : timeSigType = TimeSigType(e.readInt());
4080 792 : } else if (tag == "showCourtesySig") {
4081 0 : s->setShowCourtesySig(e.readInt());
4082 792 : } else if (tag == "sigN") {
4083 296 : sig.setNumerator(e.readInt());
4084 496 : } else if (tag == "sigD") {
4085 296 : sig.setDenominator(e.readInt());
4086 200 : } else if (tag == "stretchN") {
4087 13 : stretch.setNumerator(e.readInt());
4088 187 : } else if (tag == "stretchD") {
4089 13 : stretch.setDenominator(e.readInt());
4090 174 : } else if (tag == "textN") {
4091 2 : numeratorString = e.readText();
4092 172 : } else if (tag == "textD") {
4093 2 : denominatorString = e.readText();
4094 170 : } else if (tag == "Groups") {
4095 2 : Groups groups;
4096 2 : TRead::read(&groups, e, ctx);
4097 2 : s->setGroups(groups);
4098 170 : } else if (tag == "isCourtesy") {
4099 0 : s->setIsCourtesy(e.readBool());
4100 168 : } else if (TRead::readStyledProperty(s, tag, e, ctx)) {
4101 168 : } else if (!readItemProperties(s, e, ctx)) {
4102 0 : e.unknown();
4103 : }
4104 : }
4105 296 : if (old) {
4106 0 : sig.set(z1 + z2 + z3 + z4, n);
4107 : }
4108 296 : stretch.reduce();
4109 :
4110 296 : s->setSig(sig, timeSigType);
4111 296 : s->setStretch(stretch);
4112 296 : s->setNumeratorString(numeratorString);
4113 296 : s->setDenominatorString(denominatorString);
4114 296 : }
4115 :
4116 1 : void TRead::read(TremoloTwoChord* t, XmlReader& xml, ReadContext& ctx)
4117 : {
4118 1 : compat::TremoloCompat tc { parentOrDummy(t->chord(), ctx.dummy()) };
4119 1 : tc.two = t;
4120 1 : read(&tc, xml, ctx);
4121 1 : }
4122 :
4123 28 : void TRead::read(TremoloSingleChord* t, XmlReader& xml, ReadContext& ctx)
4124 : {
4125 28 : compat::TremoloCompat tc { parentOrDummy(t->chord(), ctx.dummy()) };
4126 28 : tc.single = t;
4127 28 : read(&tc, xml, ctx);
4128 28 : }
4129 :
4130 52 : void TRead::read(compat::TremoloCompat* tc, XmlReader& e, ReadContext& ctx)
4131 : {
4132 92 : auto item = [](compat::TremoloCompat* tc) -> EngravingItem* {
4133 92 : if (tc->two) {
4134 0 : return tc->two;
4135 : }
4136 92 : return tc->single;
4137 : };
4138 :
4139 52 : const Chord* chord = tc->parent.as<Chord>();
4140 52 : const track_idx_t track = chord ? chord->track() : 0;
4141 :
4142 150 : while (e.readNextStartElement()) {
4143 98 : const AsciiStringView tag(e.name());
4144 98 : if (tag == "subtype") {
4145 52 : TremoloType type = TConv::fromXml(e.readAsciiText(), TremoloType::INVALID_TREMOLO);
4146 52 : if (isTremoloTwoChord(type)) {
4147 3 : if (!tc->two) {
4148 2 : tc->two = Factory::createTremoloTwoChord(tc->parent);
4149 2 : tc->two->setTrack(track);
4150 : }
4151 3 : tc->two->setTremoloType(type);
4152 : } else {
4153 49 : if (!tc->single) {
4154 21 : tc->single = Factory::createTremoloSingleChord(tc->parent);
4155 21 : tc->single->setTrack(track);
4156 : }
4157 49 : tc->single->setTremoloType(type);
4158 : }
4159 : }
4160 : // Style needs special handling other than readStyledProperty()
4161 : // to avoid calling customStyleApplicable() in setProperty(),
4162 : // which cannot be called now because durationType() isn't defined yet.
4163 46 : else if (tag == "strokeStyle") {
4164 0 : if (tc->two) {
4165 0 : tc->two->setTremoloStyle(TremoloStyle(e.readInt()));
4166 0 : tc->two->setPropertyFlags(Pid::TREMOLO_STYLE, PropertyFlags::UNSTYLED);
4167 : } else {
4168 0 : UNREACHABLE;
4169 : e.skipCurrentElement();
4170 : }
4171 46 : } else if (tag == "Fragment") {
4172 0 : if (tc->two) {
4173 0 : BeamFragment f = BeamFragment();
4174 0 : int idx = tc->two->directionIdx();
4175 0 : tc->two->setUserModified(true);
4176 0 : double _spatium = tc->two->spatium();
4177 0 : while (e.readNextStartElement()) {
4178 0 : const AsciiStringView tag1(e.name());
4179 0 : if (tag1 == "y1") {
4180 0 : f.py1[idx] = e.readDouble() * _spatium;
4181 0 : } else if (tag1 == "y2") {
4182 0 : f.py2[idx] = e.readDouble() * _spatium;
4183 : } else {
4184 0 : e.unknown();
4185 : }
4186 : }
4187 0 : tc->two->setBeamFragment(f);
4188 : } else {
4189 0 : UNREACHABLE;
4190 : e.skipCurrentElement();
4191 : }
4192 46 : } else if (tag == "play") {
4193 0 : if (tc->two) {
4194 0 : tc->two->setPlayTremolo(e.readBool());
4195 0 : } else if (tc->single) {
4196 0 : tc->single->setPlayTremolo(e.readBool());
4197 : } else {
4198 0 : UNREACHABLE;
4199 : }
4200 46 : } else if (TRead::readStyledProperty(item(tc), tag, e, ctx)) {
4201 46 : } else if (!readItemProperties(item(tc), e, ctx)) {
4202 0 : e.unknown();
4203 : }
4204 : }
4205 52 : }
4206 :
4207 : static constexpr std::array<Pid, 18> TextBasePropertyId { {
4208 : Pid::TEXT_STYLE,
4209 : Pid::FONT_FACE,
4210 : Pid::FONT_SIZE,
4211 : Pid::TEXT_LINE_SPACING,
4212 : Pid::FONT_STYLE,
4213 : Pid::COLOR,
4214 : Pid::FRAME_TYPE,
4215 : Pid::FRAME_WIDTH,
4216 : Pid::FRAME_PADDING,
4217 : Pid::FRAME_ROUND,
4218 : Pid::FRAME_FG_COLOR,
4219 : Pid::FRAME_BG_COLOR,
4220 : Pid::ALIGN,
4221 : } };
4222 :
4223 0 : bool TRead::readTextProperties(TextBase* t, XmlReader& xml, ReadContext& ctx)
4224 : {
4225 0 : if (t->isStaffTextBase()) {
4226 0 : return readProperties(dynamic_cast<StaffTextBase*>(t), xml, ctx);
4227 : }
4228 0 : return readProperties(t, xml, ctx);
4229 : }
4230 :
4231 769 : bool TRead::readProperties(TextBase* t, XmlReader& e, ReadContext& ctx)
4232 : {
4233 769 : const AsciiStringView tag(e.name());
4234 13744 : for (Pid i : TextBasePropertyId) {
4235 13026 : if (TRead::readProperty(t, tag, e, ctx, i)) {
4236 51 : if (tag != "align") {
4237 51 : return true;
4238 : }
4239 :
4240 0 : t->setPosition(t->align().horizontal);
4241 0 : if (t->position() != t->propertyDefault(Pid::POSITION).value<AlignH>()) {
4242 0 : t->setPropertyFlags(Pid::POSITION, PropertyFlags::UNSTYLED);
4243 : }
4244 0 : return true;
4245 : }
4246 : }
4247 :
4248 718 : if (tag == "text") {
4249 441 : String str = e.readXml();
4250 441 : t->setXmlText(str);
4251 441 : t->checkCustomFormatting(str);
4252 718 : } else if (tag == "bold") {
4253 0 : bool val = e.readInt();
4254 0 : if (val) {
4255 0 : t->setFontStyle(t->fontStyle() + FontStyle::Bold);
4256 : } else {
4257 0 : t->setFontStyle(t->fontStyle() - FontStyle::Bold);
4258 : }
4259 0 : if (t->isStyled(Pid::FONT_STYLE)) {
4260 0 : t->setPropertyFlags(Pid::FONT_STYLE, PropertyFlags::UNSTYLED);
4261 : }
4262 277 : } else if (tag == "italic") {
4263 1 : bool val = e.readInt();
4264 1 : if (val) {
4265 1 : t->setFontStyle(t->fontStyle() + FontStyle::Italic);
4266 : } else {
4267 0 : t->setFontStyle(t->fontStyle() - FontStyle::Italic);
4268 : }
4269 1 : if (t->isStyled(Pid::FONT_STYLE)) {
4270 1 : t->setPropertyFlags(Pid::FONT_STYLE, PropertyFlags::UNSTYLED);
4271 : }
4272 276 : } else if (tag == "underline") {
4273 0 : bool val = e.readInt();
4274 0 : if (val) {
4275 0 : t->setFontStyle(t->fontStyle() + FontStyle::Underline);
4276 : } else {
4277 0 : t->setFontStyle(t->fontStyle() - FontStyle::Underline);
4278 : }
4279 0 : if (t->isStyled(Pid::FONT_STYLE)) {
4280 0 : t->setPropertyFlags(Pid::FONT_STYLE, PropertyFlags::UNSTYLED);
4281 : }
4282 276 : } else if (tag == "strike") {
4283 0 : bool val = e.readInt();
4284 0 : if (val) {
4285 0 : t->setFontStyle(t->fontStyle() + FontStyle::Strike);
4286 : } else {
4287 0 : t->setFontStyle(t->fontStyle() - FontStyle::Strike);
4288 : }
4289 0 : if (t->isStyled(Pid::FONT_STYLE)) {
4290 0 : t->setPropertyFlags(Pid::FONT_STYLE, PropertyFlags::UNSTYLED);
4291 : }
4292 276 : } else if (TRead::readProperty(t, tag, e, ctx, Pid::TEXT_LINKED_TO_MASTER)) {
4293 276 : } else if (readProperty(t, tag, e, ctx, Pid::VOICE_ASSIGNMENT)) {
4294 266 : } else if (readProperty(t, tag, e, ctx, Pid::DIRECTION)) {
4295 266 : } else if (readProperty(t, tag, e, ctx, Pid::CENTER_BETWEEN_STAVES)) {
4296 266 : } else if (!readItemProperties(t, e, ctx)) {
4297 0 : return false;
4298 : }
4299 718 : return true;
4300 : }
4301 :
4302 103 : bool TRead::readProperties(TextLineBase* b, XmlReader& e, ReadContext& ctx)
4303 : {
4304 103 : const AsciiStringView tag(e.name());
4305 3109 : for (Pid i : TextLineBase::textLineBasePropertyIds()) {
4306 3054 : if (TRead::readProperty(b, tag, e, ctx, i)) {
4307 48 : b->setPropertyFlags(i, PropertyFlags::UNSTYLED);
4308 48 : return true;
4309 : }
4310 : }
4311 55 : return readProperties(static_cast<SLine*>(b), e, ctx);
4312 : }
4313 :
4314 12 : void TRead::read(Trill* t, XmlReader& e, ReadContext& ctx)
4315 : {
4316 12 : t->eraseSpannerSegments();
4317 :
4318 47 : while (e.readNextStartElement()) {
4319 35 : const AsciiStringView tag(e.name());
4320 35 : if (tag == "subtype") {
4321 12 : t->setTrillType(TConv::fromXml(e.readAsciiText(), TrillType::TRILL_LINE));
4322 23 : } else if (tag == "Ornament") {
4323 12 : Ornament* ornament = t->ornament();
4324 12 : if (!ornament) {
4325 0 : ornament = Factory::createOrnament(toChordRest(t->ownershipParent()));
4326 0 : t->setOrnament(ornament);
4327 : }
4328 12 : ornament->setSymId(Ornament::fromTrillType(t->trillType()));
4329 12 : TRead::read(ornament, e, ctx);
4330 12 : ornament->setTrack(t->track());
4331 11 : } else if (tag == "Accidental") {
4332 0 : Accidental* accidental = Factory::createAccidental(t);
4333 0 : TRead::read(accidental, e, ctx);
4334 0 : t->setAccidental(accidental);
4335 0 : if (t->ornament()) {
4336 0 : t->ornament()->setTrillOldCompatAccidental(accidental);
4337 : }
4338 11 : } else if (tag == "ornamentStyle") {
4339 0 : readProperty(t, e, ctx, Pid::ORNAMENT_STYLE);
4340 11 : } else if (!readProperties(static_cast<SLine*>(t), e, ctx)) {
4341 0 : e.unknown();
4342 : }
4343 : }
4344 12 : }
4345 :
4346 0 : void TRead::read(Vibrato* v, XmlReader& e, ReadContext& ctx)
4347 : {
4348 0 : v->eraseSpannerSegments();
4349 :
4350 0 : while (e.readNextStartElement()) {
4351 0 : const AsciiStringView tag(e.name());
4352 0 : if (tag == "subtype") {
4353 0 : v->setVibratoType(TConv::fromXml(e.readAsciiText(), VibratoType::GUITAR_VIBRATO));
4354 0 : } else if (!readProperties(static_cast<SLine*>(v), e, ctx)) {
4355 0 : e.unknown();
4356 : }
4357 : }
4358 0 : }
4359 :
4360 11 : void TRead::read(Volta* v, XmlReader& e, ReadContext& ctx)
4361 : {
4362 11 : v->eraseSpannerSegments();
4363 :
4364 42 : while (e.readNextStartElement()) {
4365 31 : const AsciiStringView tag(e.name());
4366 31 : if (tag == "endings") {
4367 11 : v->setEndings(TConv::fromXml(e.readText(), std::vector<int>()));
4368 20 : } else if (TRead::readStyledProperty(v, tag, e, ctx)) {
4369 20 : } else if (!readProperties(v, e, ctx)) {
4370 0 : e.unknown();
4371 : }
4372 : }
4373 11 : compat::CompatUtils::resetHookHeightSign(v);
4374 11 : compat::CompatUtils::setTextLineTextPositionFromAlign(v);
4375 11 : }
4376 :
4377 20 : bool TRead::readProperties(Volta* v, XmlReader& e, ReadContext& ctx)
4378 : {
4379 20 : if (!readProperties(toTextLineBase(v), e, ctx)) {
4380 0 : return false;
4381 : }
4382 :
4383 20 : return true;
4384 : }
4385 :
4386 509 : void TRead::readSpanner(XmlReader& e, ReadContext& ctx, EngravingItem* current, track_idx_t track)
4387 : {
4388 509 : std::shared_ptr<ConnectorInfoReader> info(new ConnectorInfoReader(e, &ctx, current, static_cast<int>(track)));
4389 509 : ConnectorInfoReader::readConnector(info, e, ctx);
4390 509 : }
4391 :
4392 0 : void TRead::readSpanner(XmlReader& e, ReadContext& ctx, Score* current, track_idx_t track)
4393 : {
4394 0 : std::shared_ptr<ConnectorInfoReader> info(new ConnectorInfoReader(e, &ctx, current, static_cast<int>(track)));
4395 0 : ConnectorInfoReader::readConnector(info, e, ctx);
4396 0 : }
4397 :
4398 5 : void TRead::readSystemLocks(Score* score, XmlReader& e)
4399 : {
4400 45 : while (e.readNextStartElement()) {
4401 40 : if (e.name() == "systemLock") {
4402 40 : readSystemLock(score, e);
4403 : } else {
4404 0 : e.unknown();
4405 : }
4406 : }
4407 5 : }
4408 :
4409 40 : void TRead::readSystemLock(Score* score, XmlReader& e)
4410 : {
4411 40 : MeasureBase* startMeas = nullptr;
4412 40 : MeasureBase* endMeas = nullptr;
4413 40 : EIDRegister* eidRegister = score->masterScore()->eidRegister();
4414 :
4415 120 : while (e.readNextStartElement()) {
4416 80 : AsciiStringView tag(e.name());
4417 80 : if (tag == "startMeasure") {
4418 40 : EID startMeasId = EID::fromStdString(e.readAsciiText());
4419 40 : startMeas = toMeasureBase(eidRegister->itemFromEID(startMeasId));
4420 40 : } else if (tag == "endMeasure") {
4421 40 : EID endMeasId = EID::fromStdString(e.readAsciiText());
4422 40 : endMeas = toMeasureBase(eidRegister->itemFromEID(endMeasId));
4423 : } else {
4424 0 : e.unknown();
4425 : }
4426 : }
4427 :
4428 40 : IF_ASSERT_FAILED(startMeas && endMeas) {
4429 0 : return;
4430 : }
4431 :
4432 40 : score->addSystemLock(new RangeLock(startMeas, endMeas));
4433 : }
|