1 #include "importmidi_model.h"
2 #include "importmidi_inner.h"
3 #include "importmidi_clef.h"
4 #include "mscore/preferences.h"
5 #include "libmscore/instrtemplate.h"
6
7
8 namespace Ms {
9
10 class TracksModel::Column
11 {
12 public:
Column(MidiOperations::Opers & opers)13 explicit Column(MidiOperations::Opers &opers) : _opers(opers) {}
~Column()14 virtual ~Column() {}
15
16 virtual QVariant value(int trackIndex) const = 0;
17 virtual void setValue(const QVariant &value, int trackIndex) = 0;
18 virtual QString headerName() const = 0;
isVisible(int) const19 virtual bool isVisible(int /*trackIndex*/) const { return true; }
valueList(int) const20 virtual QStringList valueList(int /*trackIndex*/) const { return _values; }
width() const21 virtual int width() const { return -1; }
isEditable(int) const22 virtual bool isEditable(int /*trackIndex*/) const { return true; }
isForAllTracksOnly() const23 virtual bool isForAllTracksOnly() const { return false; }
24
25 protected:
26 MidiOperations::Opers &_opers;
27 QStringList _values;
28 };
29
30
TracksModel()31 TracksModel::TracksModel()
32 : _trackCount(0)
33 , _frozenColCount(0)
34 , _isAllApplied(true)
35 {
36 }
37
~TracksModel()38 TracksModel::~TracksModel()
39 {
40 }
41
reset(const MidiOperations::Opers & opers,const QList<std::string> & lyricsList,int trackCount,const QString & midiFile,bool hasHumanBeats,bool hasTempoText,bool hasChordNames)42 void TracksModel::reset(const MidiOperations::Opers &opers,
43 const QList<std::string> &lyricsList,
44 int trackCount,
45 const QString &midiFile,
46 bool hasHumanBeats,
47 bool hasTempoText,
48 bool hasChordNames)
49 {
50 beginResetModel();
51 _trackOpers = opers;
52 _columns.clear();
53 _trackCount = trackCount;
54 _frozenColCount = 0;
55 _midiFile = midiFile;
56 _isAllApplied = true;
57 if (trackCount == 0)
58 return;
59
60 //-----------------------------------------------------------------------
61 struct Import : Column {
62 Import(MidiOperations::Opers &opers) : Column(opers) {}
63
64 QString headerName() const override { return QCoreApplication::translate(
65 "MIDI import operations", "Import"); }
66 QVariant value(int trackIndex) const override
67 {
68 return _opers.doImport.value(trackIndex);
69 }
70 void setValue(const QVariant &value, int trackIndex) override
71 {
72 _opers.doImport.setValue(trackIndex, value.toBool());
73 }
74 };
75 ++_frozenColCount;
76 _columns.push_back(std::unique_ptr<Column>(new Import(_trackOpers)));
77
78 //-----------------------------------------------------------------------
79 struct Channel : Column {
80 Channel(MidiOperations::Opers &opers) : Column(opers) {}
81 QString headerName() const override { return QCoreApplication::translate(
82 "MIDI import operations", "Channel"); }
83 bool isEditable(int /*trackIndex*/) const override { return false; }
84 QVariant value(int trackIndex) const override
85 {
86 return QString::number(_opers.channel.value(trackIndex));
87 }
88 void setValue(const QVariant &/*value*/, int /*trackIndex*/) override {}
89 };
90 ++_frozenColCount;
91 _columns.push_back(std::unique_ptr<Column>(new Channel(_trackOpers)));
92
93 //-----------------------------------------------------------------------
94 bool hasStaffName = false;
95 for (int i = 0; i != _trackCount; ++i) {
96 if (_trackOpers.staffName.value(i) != "") {
97 hasStaffName = true;
98 break;
99 }
100 }
101 if (hasStaffName) {
102 struct StaffName : Column {
103 StaffName(MidiOperations::Opers &opers, const QString &midiFile)
104 : Column(opers), _midiFile(midiFile)
105 {
106 }
107 int width() const override { return 180; }
108 QString headerName() const override { return QCoreApplication::translate(
109 "MIDI import operations", "Staff name"); }
110 bool isEditable(int /*trackIndex*/) const override { return false; }
111 QVariant value(int trackIndex) const override
112 {
113 MidiOperations::Data &opers = midiImportOperations;
114 MidiOperations::CurrentMidiFileSetter setCurrentMidiFile(opers, _midiFile);
115
116 return MidiCharset::convertToCharset(_opers.staffName.value(trackIndex));
117 }
118 void setValue(const QVariant &/*value*/, int /*trackIndex*/) override {}
119
120 private:
121 QString _midiFile;
122 };
123 ++_frozenColCount;
124 _columns.push_back(std::unique_ptr<Column>(new StaffName(_trackOpers, _midiFile)));
125 }
126
127 //-----------------------------------------------------------------------
128 struct MidiInstrumentName : Column {
129 MidiInstrumentName(MidiOperations::Opers &opers) : Column(opers)
130 {
131 }
132 int width() const override { return 130; }
133 QString headerName() const override { return QCoreApplication::translate(
134 "MIDI import operations", "Sound"); }
135 bool isEditable(int /*trackIndex*/) const override { return false; }
136 QVariant value(int trackIndex) const override
137 {
138 return _opers.midiInstrName.value(trackIndex);
139 }
140 void setValue(const QVariant &/*value*/, int /*trackIndex*/) override {}
141 };
142 ++_frozenColCount;
143 _columns.push_back(std::unique_ptr<Column>(new MidiInstrumentName(_trackOpers)));
144
145 //-----------------------------------------------------------------------
146 bool hasMsInstrument = false;
147 for (int i = 0; i != _trackCount; ++i) {
148 if (!_trackOpers.msInstrList.value(i).empty()) {
149 hasMsInstrument = true;
150 break;
151 }
152 }
153 if (hasMsInstrument) {
154 struct MsInstrument : Column {
155 MsInstrument(MidiOperations::Opers &opers) : Column(opers)
156 {
157 }
158 int width() const override { return 220; }
159 QString headerName() const override { return QCoreApplication::translate(
160 "MIDI import operations", "MuseScore instrument"); }
161 bool isEditable(int trackIndex) const override
162 {
163 return _opers.msInstrList.value(trackIndex).size() > 1;
164 }
165 QVariant value(int trackIndex) const override
166 {
167 const int instrIndex = _opers.msInstrIndex.value(trackIndex);
168 const auto &trackInstrList = _opers.msInstrList.value(trackIndex);
169 const InstrumentTemplate *instr = (trackInstrList.empty())
170 ? nullptr : trackInstrList[instrIndex];
171 return instrName(instr);
172 }
173 void setValue(const QVariant &value, int trackIndex) override
174 {
175 _opers.msInstrIndex.setValue(trackIndex, value.toInt());
176 }
177 QStringList valueList(int trackIndex) const override
178 {
179 auto list = QStringList();
180 const auto &trackInstrList = _opers.msInstrList.value(trackIndex);
181 for (const InstrumentTemplate *instr: trackInstrList)
182 list.append(instrName(instr));
183 return list;
184 }
185
186 private:
187 static QString instrName(const InstrumentTemplate *instr)
188 {
189 if (!instr)
190 return "-";
191 if (!instr->trackName.isEmpty())
192 return instr->trackName;
193 if (instr->longNames.isEmpty())
194 return instr->id;
195 return instr->longNames.front().name();
196 }
197 };
198 _columns.push_back(std::unique_ptr<Column>(new MsInstrument(_trackOpers)));
199 }
200
201 //-----------------------------------------------------------------------
202 if (!lyricsList.isEmpty()) {
203 struct Lyrics : Column {
204 Lyrics(MidiOperations::Opers &opers,
205 const QList<std::string> &lyricsList,
206 const QString &midiFile)
207 : Column(opers), _lyricsList(lyricsList), _midiFile(midiFile)
208 {
209 }
210 int width() const override { return 185; }
211 QString headerName() const override { return QCoreApplication::translate(
212 "MIDI import operations", "Lyrics"); }
213 QVariant value(int trackIndex) const override
214 {
215 int index = _opers.lyricTrackIndex.value(trackIndex);
216 if (index >= 0) {
217 MidiOperations::Data &opers = midiImportOperations;
218 MidiOperations::CurrentMidiFileSetter setCurrentMidiFile(opers, _midiFile);
219
220 return MidiCharset::convertToCharset(_lyricsList[index]);
221 }
222 return "";
223 }
224 void setValue(const QVariant &value, int trackIndex) override
225 {
226 // GUI lyrics list always have "" row, so: (index - 1)
227 _opers.lyricTrackIndex.setValue(trackIndex, value.toInt() - 1);
228 }
229 QStringList valueList(int /*trackIndex*/) const override
230 {
231 MidiOperations::Data &opers = midiImportOperations;
232 MidiOperations::CurrentMidiFileSetter setCurrentMidiFile(opers, _midiFile);
233
234 auto list = QStringList("");
235 for (const auto &lyric: _lyricsList)
236 list.append(MidiCharset::convertToCharset(lyric));
237 return list;
238 }
239 private:
240 QList<std::string> _lyricsList;
241 QString _midiFile;
242 };
243 _columns.push_back(std::unique_ptr<Column>(new Lyrics(_trackOpers, lyricsList, _midiFile)));
244 }
245
246 //-----------------------------------------------------------------------
247 struct QuantValue : Column {
248 QuantValue(MidiOperations::Opers &opers) : Column(opers)
249 {
250 _values.push_back(QCoreApplication::translate("MIDI import operations", "Quarter"));
251 _values.push_back(QCoreApplication::translate("MIDI import operations", "Eighth"));
252 _values.push_back(QCoreApplication::translate("MIDI import operations", "16th"));
253 _values.push_back(QCoreApplication::translate("MIDI import operations", "32nd"));
254 _values.push_back(QCoreApplication::translate("MIDI import operations", "64th"));
255 _values.push_back(QCoreApplication::translate("MIDI import operations", "128th"));
256 }
257 QString headerName() const override { return QCoreApplication::translate(
258 "MIDI import operations", "Max. quantization"); }
259 QVariant value(int trackIndex) const override
260 {
261 return _values[(int)_opers.quantValue.value(trackIndex)];
262 }
263 void setValue(const QVariant &value, int trackIndex) override
264 {
265 _opers.quantValue.setValue(trackIndex, (MidiOperations::QuantValue)value.toInt());
266 }
267 };
268 _columns.push_back(std::unique_ptr<Column>(new QuantValue(_trackOpers)));
269
270 //-----------------------------------------------------------------------
271 struct VoiceCount : Column {
272 VoiceCount(MidiOperations::Opers &opers) : Column(opers)
273 {
274 _values.push_back("1");
275 _values.push_back("2");
276 _values.push_back("3");
277 _values.push_back("4");
278 }
279 QString headerName() const override { return QCoreApplication::translate(
280 "MIDI import operations", "Max. voices"); }
281 QVariant value(int trackIndex) const override
282 {
283 return _values[(int)_opers.maxVoiceCount.value(trackIndex)];
284 }
285 void setValue(const QVariant &value, int trackIndex) override
286 {
287 _opers.maxVoiceCount.setValue(trackIndex, (MidiOperations::VoiceCount)value.toInt());
288 }
289 bool isVisible(int trackIndex) const override
290 {
291 if (_opers.isDrumTrack.value(trackIndex))
292 return false;
293 return true;
294 }
295 };
296 _columns.push_back(std::unique_ptr<Column>(new VoiceCount(_trackOpers)));
297
298 //-----------------------------------------------------------------------
299 struct Tuplets : Column {
300 Tuplets(MidiOperations::Opers &opers, int trackCount)
301 : Column(opers), _trackCount(trackCount)
302 {
303 _values.push_back(QCoreApplication::translate("MIDI import operations", "2-plets"));
304 _values.push_back(QCoreApplication::translate("MIDI import operations", "3-plets"));
305 _values.push_back(QCoreApplication::translate("MIDI import operations", "4-plets"));
306 _values.push_back(QCoreApplication::translate("MIDI import operations", "5-plets"));
307 _values.push_back(QCoreApplication::translate("MIDI import operations", "7-plets"));
308 _values.push_back(QCoreApplication::translate("MIDI import operations", "9-plets"));
309 }
310 int width() const override { return 140; }
311 QString headerName() const override { return QCoreApplication::translate(
312 "MIDI import operations", "Tuplets"); }
313 QVariant value(int trackIndex) const override
314 {
315 QString val;
316 if (_opers.search2plets.value(trackIndex)) {
317 if (val != "")
318 val += ", ";
319 val += "2";
320 }
321 if (_opers.search3plets.value(trackIndex)) {
322 if (val != "")
323 val += ", ";
324 val += "3";
325 }
326 if (_opers.search4plets.value(trackIndex)) {
327 if (val != "")
328 val += ", ";
329 val += "4";
330 }
331 if (_opers.search5plets.value(trackIndex)) {
332 if (val != "")
333 val += ", ";
334 val += "5";
335 }
336 if (_opers.search7plets.value(trackIndex)) {
337 if (val != "")
338 val += ", ";
339 val += "7";
340 }
341 if (_opers.search9plets.value(trackIndex)) {
342 if (val != "")
343 val += ", ";
344 val += "9";
345 }
346 return val;
347 }
348 void setValue(const QVariant &value, int trackIndex) override
349 {
350 const QStringList list = value.toStringList();
351
352 Q_ASSERT_X(list.size() > 5, "Midi import operations",
353 "Invalid size of the tuplets value list");
354
355 bool searchTuplets = false;
356 if (list[0] != "undefined") {
357 const bool doSearch = (list[0] == "true");
358 _opers.search2plets.setValue(trackIndex, doSearch);
359 if (!searchTuplets && doSearch)
360 searchTuplets = true;
361 }
362 if (list[1] != "undefined") {
363 const bool doSearch = (list[1] == "true");
364 _opers.search3plets.setValue(trackIndex, doSearch);
365 if (!searchTuplets && doSearch)
366 searchTuplets = true;
367 }
368 if (list[2] != "undefined") {
369 const bool doSearch = (list[2] == "true");
370 _opers.search4plets.setValue(trackIndex, doSearch);
371 if (!searchTuplets && doSearch)
372 searchTuplets = true;
373 }
374 if (list[3] != "undefined") {
375 const bool doSearch = (list[3] == "true");
376 _opers.search5plets.setValue(trackIndex, doSearch);
377 if (!searchTuplets && doSearch)
378 searchTuplets = true;
379 }
380 if (list[4] != "undefined") {
381 const bool doSearch = (list[4] == "true");
382 _opers.search7plets.setValue(trackIndex, doSearch);
383 if (!searchTuplets && doSearch)
384 searchTuplets = true;
385 }
386 if (list[5] != "undefined") {
387 const bool doSearch = (list[5] == "true");
388 _opers.search9plets.setValue(trackIndex, doSearch);
389 if (!searchTuplets && doSearch)
390 searchTuplets = true;
391 }
392 _opers.searchTuplets.setValue(trackIndex, searchTuplets);
393 }
394 QStringList valueList(int trackIndex) const override
395 {
396 auto list = QStringList("__MultiValue__");
397
398 list.append(_values[0]);
399 list.append(checkBoxValue(trackIndex, _opers.search2plets));
400 list.append(_values[1]);
401 list.append(checkBoxValue(trackIndex, _opers.search3plets));
402 list.append(_values[2]);
403 list.append(checkBoxValue(trackIndex, _opers.search4plets));
404 list.append(_values[3]);
405 list.append(checkBoxValue(trackIndex, _opers.search5plets));
406 list.append(_values[4]);
407 list.append(checkBoxValue(trackIndex, _opers.search7plets));
408 list.append(_values[5]);
409 list.append(checkBoxValue(trackIndex, _opers.search9plets));
410
411 return list;
412 }
413
414 private:
415 QString checkBoxValue(int trackIndex,
416 const MidiOperations::TrackOp<bool> &operation) const
417 {
418 if (trackIndex == -1) { // symbolizes all tracks
419 const bool firstValue = operation.value(0);
420 for (int i = 1; i < _trackCount; ++i) {
421 if (operation.value(i) != firstValue)
422 return "undefined";
423 }
424 trackIndex = 0; // to pick the first track value on return
425 }
426 return operation.value(trackIndex) ? "true" : "false";
427 }
428
429 int _trackCount;
430 };
431 _columns.push_back(std::unique_ptr<Column>(new Tuplets(_trackOpers, _trackCount)));
432
433 //-----------------------------------------------------------------------
434 if (hasHumanBeats) {
435 struct TimeSig : Column {
436 TimeSig(MidiOperations::Opers &opers) : Column(opers)
437 {
438 _values.push_back(QCoreApplication::translate("MIDI import operations", "2"));
439 _values.push_back(QCoreApplication::translate("MIDI import operations", "3"));
440 _values.push_back(QCoreApplication::translate("MIDI import operations", "4"));
441 _values.push_back(QCoreApplication::translate("MIDI import operations", "5"));
442 _values.push_back(QCoreApplication::translate("MIDI import operations", "6"));
443 _values.push_back(QCoreApplication::translate("MIDI import operations", "7"));
444 _values.push_back(QCoreApplication::translate("MIDI import operations", "9"));
445 _values.push_back(QCoreApplication::translate("MIDI import operations", "12"));
446 _values.push_back(QCoreApplication::translate("MIDI import operations", "15"));
447 _values.push_back(QCoreApplication::translate("MIDI import operations", "21"));
448 _numeratorCount = _values.size();
449
450 _values.push_back(QCoreApplication::translate("MIDI import operations", "2"));
451 _values.push_back(QCoreApplication::translate("MIDI import operations", "4"));
452 _values.push_back(QCoreApplication::translate("MIDI import operations", "8"));
453 _values.push_back(QCoreApplication::translate("MIDI import operations", "16"));
454 _values.push_back(QCoreApplication::translate("MIDI import operations", "32"));
455 }
456 QString headerName() const override { return QCoreApplication::translate(
457 "MIDI import operations", "Time signature"); }
458 bool isForAllTracksOnly() const override { return true; }
459 QVariant value(int /*trackIndex*/) const override
460 {
461 const int numeratorIndex = (int)_opers.timeSigNumerator.value();
462 const int denominatorIndex = (int)_opers.timeSigDenominator.value();
463
464 return _values[numeratorIndex] + " / " + _values[_numeratorCount + denominatorIndex];
465 }
466 void setValue(const QVariant &value, int /*trackIndex*/) override
467 {
468 const QStringList list = value.toStringList();
469
470 Q_ASSERT_X(list.size() == 2, "Midi import operations",
471 "Invalid size of the time signature value list");
472
473 bool ok = false;
474 _opers.timeSigNumerator.setValue((MidiOperations::TimeSigNumerator)list[0].toInt(&ok));
475
476 Q_ASSERT_X(ok, "Midi import operations", "Invalid numerator value");
477
478 ok = false;
479 _opers.timeSigDenominator.setValue((MidiOperations::TimeSigDenominator)list[1].toInt(&ok));
480
481 Q_ASSERT_X(ok, "Midi import operations", "Invalid denominator value");
482
483 }
484 QStringList valueList(int /*trackIndex*/) const override
485 {
486 auto list = QStringList("__TimeSig__");
487 list.append("__Numerator__");
488 list.append(QString::number((int)_opers.timeSigNumerator.value()));
489 for (int i = 0; i != _numeratorCount; ++i)
490 list.append(_values[i]);
491 list.append("__Denominator__");
492 list.append(QString::number((int)_opers.timeSigDenominator.value()));
493 for (int i = _numeratorCount; i != _values.size(); ++i)
494 list.append(_values[i]);
495 return list;
496 }
497 private:
498 int _numeratorCount;
499 };
500 _columns.push_back(std::unique_ptr<Column>(new TimeSig(_trackOpers)));
501
502 //-----------------------------------------------------------------------
503 struct MeasureCount2xLess : Column {
504 MeasureCount2xLess(MidiOperations::Opers &opers) : Column(opers)
505 {
506 }
507 QString headerName() const override { return QCoreApplication::translate(
508 "MIDI import operations", "Halving the\nmeasure count"); }
509 bool isForAllTracksOnly() const override { return true; }
510 QVariant value(int /*trackIndex*/) const override
511 {
512 return _opers.measureCount2xLess.value();
513 }
514 void setValue(const QVariant &value, int /*trackIndex*/) override
515 {
516 _opers.measureCount2xLess.setValue(value.toBool());
517 }
518 };
519 _columns.push_back(std::unique_ptr<Column>(new MeasureCount2xLess(_trackOpers)));
520 }
521
522 //-----------------------------------------------------------------------
523 struct Human : Column {
524 Human(MidiOperations::Opers &opers) : Column(opers)
525 {
526 }
527 QString headerName() const override { return QCoreApplication::translate(
528 "MIDI import operations", "Is human\nperformance"); }
529 bool isForAllTracksOnly() const override { return true; }
530 QVariant value(int /*trackIndex*/) const override
531 {
532 return _opers.isHumanPerformance.value();
533 }
534 void setValue(const QVariant &value, int /*trackIndex*/) override
535 {
536 _opers.isHumanPerformance.setValue(value.toBool());
537 }
538 };
539 _columns.push_back(std::unique_ptr<Column>(new Human(_trackOpers)));
540
541 //-----------------------------------------------------------------------
542 struct StaffSplit : Column {
543 StaffSplit(MidiOperations::Opers &opers) : Column(opers)
544 {
545 }
546 QString headerName() const override { return QCoreApplication::translate(
547 "MIDI import operations", "Split staff"); }
548 QVariant value(int trackIndex) const override
549 {
550 return _opers.doStaffSplit.value(trackIndex);
551 }
552 void setValue(const QVariant &value, int trackIndex) override
553 {
554 _opers.doStaffSplit.setValue(trackIndex, value.toBool());
555 }
556 };
557 _columns.push_back(std::unique_ptr<Column>(new StaffSplit(_trackOpers)));
558
559 //-----------------------------------------------------------------------
560 struct ClefChanges : Column {
561 ClefChanges(MidiOperations::Opers &opers) : Column(opers)
562 {
563 }
564 QString headerName() const override { return QCoreApplication::translate(
565 "MIDI import operations", "Clef\nchanges"); }
566 bool isEditable(int trackIndex) const override
567 {
568 if (_opers.isDrumTrack.value(trackIndex))
569 return false;
570 const int instrIndex = _opers.msInstrIndex.value(trackIndex);
571 const auto &trackInstrList = _opers.msInstrList.value(trackIndex);
572 const InstrumentTemplate *instr = (trackInstrList.empty())
573 ? nullptr : trackInstrList[instrIndex];
574 if (instr && !MidiClef::hasGFclefs(instr))
575 return false;
576 return true;
577 }
578 QVariant value(int trackIndex) const override
579 {
580 return _opers.changeClef.value(trackIndex);
581 }
582 void setValue(const QVariant &value, int trackIndex) override
583 {
584 _opers.changeClef.setValue(trackIndex, value.toBool());
585 }
586 bool isVisible(int trackIndex) const override
587 {
588 return isEditable(trackIndex);
589 }
590 };
591 _columns.push_back(std::unique_ptr<Column>(new ClefChanges(_trackOpers)));
592
593 //-----------------------------------------------------------------------
594 struct Simplify : Column {
595 Simplify(MidiOperations::Opers &opers) : Column(opers)
596 {
597 }
598 QString headerName() const override { return QCoreApplication::translate(
599 "MIDI import operations", "Simplify\ndurations"); }
600 QVariant value(int trackIndex) const override
601 {
602 return _opers.simplifyDurations.value(trackIndex);
603 }
604 void setValue(const QVariant &value, int trackIndex) override
605 {
606 _opers.simplifyDurations.setValue(trackIndex, value.toBool());
607 }
608 };
609 _columns.push_back(std::unique_ptr<Column>(new Simplify(_trackOpers)));
610
611 //-----------------------------------------------------------------------
612 struct ShowStaccato : Column {
613 ShowStaccato(MidiOperations::Opers &opers) : Column(opers)
614 {
615 }
616 QString headerName() const override { return QCoreApplication::translate(
617 "MIDI import operations", "Show\nstaccato"); }
618 QVariant value(int trackIndex) const override
619 {
620 return _opers.showStaccato.value(trackIndex);
621 }
622 void setValue(const QVariant &value, int trackIndex) override
623 {
624 _opers.showStaccato.setValue(trackIndex, value.toBool());
625 }
626 };
627 _columns.push_back(std::unique_ptr<Column>(new ShowStaccato(_trackOpers)));
628
629 //-----------------------------------------------------------------------
630 struct DottedNotes : Column {
631 DottedNotes(MidiOperations::Opers &opers) : Column(opers)
632 {
633 }
634 QString headerName() const override { return QCoreApplication::translate(
635 "MIDI import operations", "Dotted\nnotes"); }
636 QVariant value(int trackIndex) const override
637 {
638 return _opers.useDots.value(trackIndex);
639 }
640 void setValue(const QVariant &value, int trackIndex) override
641 {
642 _opers.useDots.setValue(trackIndex, value.toBool());
643 }
644 };
645 _columns.push_back(std::unique_ptr<Column>(new DottedNotes(_trackOpers)));
646
647 //-----------------------------------------------------------------------
648 if (hasTempoText) {
649 struct ShowTempoText : Column {
650 ShowTempoText(MidiOperations::Opers &opers) : Column(opers)
651 {
652 }
653 QString headerName() const override { return QCoreApplication::translate(
654 "MIDI import operations", "Show\ntempo text"); }
655 bool isForAllTracksOnly() const override { return true; }
656 QVariant value(int /*trackIndex*/) const override
657 {
658 return _opers.showTempoText.value();
659 }
660 void setValue(const QVariant &value, int /*trackIndex*/) override
661 {
662 _opers.showTempoText.setValue(value.toBool());
663 }
664 };
665 _columns.push_back(std::unique_ptr<Column>(new ShowTempoText(_trackOpers)));
666 }
667
668 //-----------------------------------------------------------------------
669 if (hasChordNames) {
670 struct ShowChordNames : Column {
671 ShowChordNames(MidiOperations::Opers &opers) : Column(opers)
672 {
673 }
674 QString headerName() const override { return QCoreApplication::translate(
675 "MIDI import operations", "Show\nchord symbols"); }
676 bool isForAllTracksOnly() const override { return true; }
677 QVariant value(int /*trackIndex*/) const override
678 {
679 return _opers.showChordNames.value();
680 }
681 void setValue(const QVariant &value, int /*trackIndex*/) override
682 {
683 _opers.showChordNames.setValue(value.toBool());
684 }
685 };
686 _columns.push_back(std::unique_ptr<Column>(new ShowChordNames(_trackOpers)));
687 }
688
689 //-----------------------------------------------------------------------
690 struct PickupBar : Column {
691 PickupBar(MidiOperations::Opers &opers) : Column(opers)
692 {
693 }
694 QString headerName() const override { return QCoreApplication::translate(
695 "MIDI import operations", "Recognize\npickup measure"); }
696 bool isForAllTracksOnly() const override { return true; }
697 QVariant value(int /*trackIndex*/) const override
698 {
699 return _opers.searchPickupMeasure.value();
700 }
701 void setValue(const QVariant &value, int /*trackIndex*/) override
702 {
703 _opers.searchPickupMeasure.setValue(value.toBool());
704 }
705 };
706 _columns.push_back(std::unique_ptr<Column>(new PickupBar(_trackOpers)));
707
708 //-----------------------------------------------------------------------
709 struct Swing : Column {
710 Swing(MidiOperations::Opers &opers) : Column(opers)
711 {
712 _values.push_back(QCoreApplication::translate("MIDI import operations", "None (1:1)"));
713 _values.push_back(QCoreApplication::translate("MIDI import operations", "Swing (2:1)"));
714 _values.push_back(QCoreApplication::translate("MIDI import operations", "Shuffle (3:1)"));
715 }
716 QString headerName() const override { return QCoreApplication::translate(
717 "MIDI import operations", "Detect swing"); }
718 int width() const override { return 130; }
719 QVariant value(int trackIndex) const override
720 {
721 return _values[(int)_opers.swing.value(trackIndex)];
722 }
723 void setValue(const QVariant &value, int trackIndex) override
724 {
725 _opers.swing.setValue(trackIndex, (MidiOperations::Swing)value.toInt());
726 }
727 };
728 _columns.push_back(std::unique_ptr<Column>(new Swing(_trackOpers)));
729
730 endResetModel();
731 }
732
clear()733 void TracksModel::clear()
734 {
735 beginResetModel();
736 _trackCount = 0;
737 _frozenColCount = 0;
738 _trackOpers = MidiOperations::Opers();
739 _columns.clear();
740 _isAllApplied = true;
741 endResetModel();
742 }
743
trackOpers() const744 const MidiOperations::Opers& TracksModel::trackOpers() const
745 {
746 return _trackOpers;
747 }
748
updateCharset()749 void TracksModel::updateCharset()
750 {
751 _isAllApplied = false;
752 forceAllChanged();
753 }
754
notifyAllApplied()755 void TracksModel::notifyAllApplied()
756 {
757 _isAllApplied = true;
758 }
759
rowFromTrackIndex(int trackIndex) const760 int TracksModel::rowFromTrackIndex(int trackIndex) const
761 {
762 // first row reserved for all tracks if track count > 1
763 return (_trackCount > 1) ? trackIndex + 1 : trackIndex;
764 }
765
trackIndexFromRow(int row) const766 int TracksModel::trackIndexFromRow(int row) const
767 {
768 // first row reserved for all tracks if track count > 1
769 // return -1 if row is all tracks row
770 return (_trackCount > 1) ? row - 1 : row;
771 }
772
trackCountForImport() const773 int TracksModel::trackCountForImport() const
774 {
775 int count = 0;
776 for (int i = 0; i != _trackCount; ++i) {
777 if (_trackOpers.doImport.value(i))
778 ++count;
779 }
780 return count;
781 }
782
frozenRowCount() const783 int TracksModel::frozenRowCount() const
784 {
785 if (_trackCount > 1)
786 return 1;
787 return 0;
788 }
789
frozenColCount() const790 int TracksModel::frozenColCount() const
791 {
792 return _frozenColCount;
793 }
794
rowCount(const QModelIndex &) const795 int TracksModel::rowCount(const QModelIndex &/*parent*/) const
796 {
797 return (_trackCount > 1) ? _trackCount + 1 : _trackCount;
798 }
799
columnCount(const QModelIndex &) const800 int TracksModel::columnCount(const QModelIndex &/*parent*/) const
801 {
802 return int(_columns.size());
803 }
804
editableSingleTrack(int trackIndex,int column) const805 bool TracksModel::editableSingleTrack(int trackIndex, int column) const
806 {
807 return !(trackIndex >= 0 && _trackCount != 1 && _columns[column]->isForAllTracksOnly());
808 }
809
data(const QModelIndex & index,int role) const810 QVariant TracksModel::data(const QModelIndex &index, int role) const
811 {
812 if (!index.isValid())
813 return QVariant();
814 const int trackIndex = trackIndexFromRow(index.row());
815 if (!isTrackIndexValid(trackIndex) || !isColumnValid(index.column()))
816 return QVariant();
817
818 switch (role) {
819 case Qt::DisplayRole:
820 if (trackIndex == -1) { // all tracks
821 if (_columns[index.column()]->isEditable(-1)) {
822 QVariant value = _columns[index.column()]->value(0);
823 if (value.type() == QVariant::String) {
824 value = QVariant();
825 if (!_columns[index.column()]->isForAllTracksOnly()) {
826 for (int i = 0; i < _trackCount; ++i) {
827 if (!_columns[index.column()]->isVisible(i))
828 continue;
829 const auto newValue
830 = _columns[index.column()]->value(i);
831 if (!value.isValid()) { // value to compare with
832 value = newValue;
833 continue;
834 }
835 if (newValue.toString() != value.toString())
836 return "…";
837 }
838 }
839 else {
840 value = _columns[index.column()]->value(0);
841 }
842 if (value.isValid())
843 return value.toString();
844 }
845 }
846 }
847 else if (editableSingleTrack(trackIndex, index.column())
848 && _columns[index.column()]->isVisible(trackIndex)) {
849 QVariant value = _columns[index.column()]->value(trackIndex);
850 if (value.type() == QVariant::String)
851 return value.toString();
852 }
853 break;
854 case Qt::EditRole:
855 if (_columns[index.column()]->isEditable(trackIndex)
856 && editableSingleTrack(trackIndex, index.column())
857 && _columns[index.column()]->isVisible(trackIndex)) {
858 const auto list = _columns[index.column()]->valueList(trackIndex);
859 if (!list.isEmpty())
860 return list;
861 }
862 break;
863 case Qt::CheckStateRole:
864 if (trackIndex == -1) {
865 QVariant value = _columns[index.column()]->value(0);
866 if (value.type() == QVariant::Bool) {
867 value = QVariant();
868 if (!_columns[index.column()]->isForAllTracksOnly()) {
869 for (int i = 0; i < _trackCount; ++i) {
870 if (!_columns[index.column()]->isVisible(i))
871 continue;
872 const auto newValue
873 = _columns[index.column()]->value(i);
874 if (!value.isValid()) { // value to compare with
875 value = newValue;
876 continue;
877 }
878 if (newValue.toBool() != value.toBool()) {
879 return Qt::PartiallyChecked;
880 }
881 }
882 }
883 else {
884 value = _columns[index.column()]->value(0);
885 }
886 if (value.isValid())
887 return (value.toBool()) ? Qt::Checked : Qt::Unchecked;
888 }
889 }
890 else if (editableSingleTrack(trackIndex, index.column())
891 && _columns[index.column()]->isVisible(trackIndex)) {
892 QVariant value = _columns[index.column()]->value(trackIndex);
893 if (value.type() == QVariant::Bool)
894 return (value.toBool()) ? Qt::Checked : Qt::Unchecked;
895 }
896 break;
897 case Qt::TextAlignmentRole:
898 return Qt::AlignCenter;
899 break;
900 case Qt::ToolTipRole:
901 if (trackIndex != -1 && _columns[index.column()]->isVisible(trackIndex)) {
902 QVariant value = _columns[index.column()]->value(trackIndex);
903 if (value.type() == QVariant::String
904 && _columns[index.column()]->valueList(trackIndex).empty()) {
905 MidiOperations::Data &opers = midiImportOperations;
906 MidiOperations::CurrentMidiFileSetter setCurrentMidiFile(opers, _midiFile);
907
908 return MidiCharset::convertToCharset(value.toString().toUtf8().constData());
909 }
910 }
911 break;
912 case Qt::SizeHintRole:
913 return QSize(_columns[index.column()]->width(), -1);
914 break;
915 default:
916 break;
917 }
918 return QVariant();
919 }
920
editableFlags(int row,int col) const921 Qt::ItemFlags TracksModel::editableFlags(int row, int col) const
922 {
923 Qt::ItemFlags flags;
924 const int trackIndex = trackIndexFromRow(row);
925
926 if (_columns[col]->isVisible(trackIndex)) {
927 if (_columns[col]->value(0).type() == QVariant::Bool) {
928 flags |= Qt::ItemIsUserCheckable;
929 }
930 else if (_columns[col]->isEditable(trackIndex)) {
931 if (trackIndex == -1) {
932 flags |= Qt::ItemIsEditable;
933 }
934 else if (editableSingleTrack(trackIndex, col)) {
935 QVariant value = _columns[col]->value(0);
936 if (value.type() != QVariant::Bool) // not checkboxes
937 flags |= Qt::ItemIsEditable;
938 }
939 }
940 }
941 return flags;
942 }
943
flags(const QModelIndex & index) const944 Qt::ItemFlags TracksModel::flags(const QModelIndex &index) const
945 {
946 if (!index.isValid())
947 return {};
948
949 Qt::ItemFlags flags = Qt::ItemFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
950 const int trackIndex = trackIndexFromRow(index.row());
951
952 if (trackIndex == -1) { // all tracks row
953 if (!_columns[index.column()]->isForAllTracksOnly()
954 && _columns[index.column()]->isEditable(-1)) {
955 for (int i = 0; i < _trackCount; ++i) {
956 const auto newFlags = editableFlags(rowFromTrackIndex(i), index.column());
957 if (newFlags) {
958 flags |= newFlags;
959 break;
960 }
961 }
962 }
963 else {
964 flags |= editableFlags(index.row(), index.column());
965 }
966 }
967 else {
968 flags |= editableFlags(index.row(), index.column());
969 }
970
971 return flags;
972 }
973
forceRowDataChanged(int row)974 void TracksModel::forceRowDataChanged(int row)
975 {
976 const auto begIndex = this->index(row, 0);
977 const auto endIndex = this->index(row, columnCount(QModelIndex()));
978 emit dataChanged(begIndex, endIndex);
979 }
980
forceColumnDataChanged(int col)981 void TracksModel::forceColumnDataChanged(int col)
982 {
983 const auto begIndex = this->index(0, col);
984 const auto endIndex = this->index(rowCount(QModelIndex()), col);
985 emit dataChanged(begIndex, endIndex);
986 }
987
forceAllChanged()988 void TracksModel::forceAllChanged()
989 {
990 const auto begIndex = this->index(0, 0);
991 const auto endIndex = this->index(rowCount(QModelIndex()), columnCount(QModelIndex()));
992 emit dataChanged(begIndex, endIndex);
993 }
994
setData(const QModelIndex & index,const QVariant & value,int)995 bool TracksModel::setData(const QModelIndex &index, const QVariant &value, int /*role*/)
996 {
997 const int trackIndex = trackIndexFromRow(index.row());
998 if (!isTrackIndexValid(trackIndex) || !isColumnValid(index.column()))
999 return false;
1000
1001 if (trackIndex == -1) { // all tracks row
1002 if (!_columns[index.column()]->isForAllTracksOnly()) {
1003 for (int i = 0; i != _trackCount; ++i) {
1004 if (_columns[index.column()]->isVisible(i))
1005 _columns[index.column()]->setValue(value, i);
1006 }
1007 forceColumnDataChanged(index.column());
1008 }
1009 else {
1010 _columns[index.column()]->setValue(value, 0);
1011 }
1012 }
1013 else if (editableSingleTrack(trackIndex, index.column())
1014 && _columns[index.column()]->isVisible(trackIndex)) {
1015 _columns[index.column()]->setValue(value, trackIndex);
1016 emit dataChanged(index, index);
1017 if (_trackCount > 1) // update 'all tracks' row
1018 forceRowDataChanged(0);
1019 }
1020
1021 _isAllApplied = false;
1022 return true;
1023 }
1024
headerData(int section,Qt::Orientation orientation,int role) const1025 QVariant TracksModel::headerData(int section, Qt::Orientation orientation, int role) const
1026 {
1027 if ((orientation == Qt::Vertical && !isRowValid(section))
1028 || (orientation == Qt::Horizontal && !isColumnValid(section))) {
1029 return QVariant();
1030 }
1031
1032 if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
1033 if (!_columns.empty()) {
1034 return QCoreApplication::translate("MIDI import: tracks model",
1035 _columns[section]->headerName().toUtf8().constData());
1036 }
1037 }
1038 else if (orientation == Qt::Vertical && role == Qt::DisplayRole) {
1039 if (_trackCount > 1) {
1040 if (section == 0)
1041 return QCoreApplication::translate("MIDI import: tracks model", "All");
1042 return section;
1043 }
1044 return section + 1;
1045 }
1046 return QVariant();
1047 }
1048
isTrackIndexValid(int trackIndex) const1049 bool TracksModel::isTrackIndexValid(int trackIndex) const
1050 {
1051 return trackIndex >= -1 && trackIndex < _trackCount;
1052 }
1053
isRowValid(int row) const1054 bool TracksModel::isRowValid(int row) const
1055 {
1056 return row >= 0 && ((_trackCount == 1) ? row < _trackCount : row <= _trackCount);
1057 }
1058
isColumnValid(int column) const1059 bool TracksModel::isColumnValid(int column) const
1060 {
1061 return column >= 0 && column < (int)_columns.size();
1062 }
1063
1064 } // namespace Ms
1065