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