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