1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4     Rosegarden
5     A MIDI and audio sequencer and musical notation editor.
6     Copyright 2000-2021 the Rosegarden development team.
7 
8     Other copyrights also apply to some parts of this work.  Please
9     see the AUTHORS file and individual file headers for details.
10 
11     This program is free software; you can redistribute it and/or
12     modify it under the terms of the GNU General Public License as
13     published by the Free Software Foundation; either version 2 of the
14     License, or (at your option) any later version.  See the file
15     COPYING included with this distribution for more information.
16 */
17 
18 #define RG_MODULE_STRING "[SimpleEventEditDialog]"
19 
20 #include "SimpleEventEditDialog.h"
21 #include "base/BaseProperties.h"
22 #include "base/Event.h"
23 #include "base/MidiTypes.h"
24 #include "base/NotationTypes.h"
25 #include "document/RosegardenDocument.h"
26 #include "gui/editors/guitar/Chord.h"
27 #include "misc/Strings.h"
28 #include "misc/Debug.h"
29 #include "misc/ConfigGroups.h"  // for LastUsedPathsConfigGroup
30 #include "PitchDialog.h"
31 #include "TimeDialog.h"
32 #include "gui/widgets/LineEdit.h"
33 #include "gui/widgets/FileDialog.h"
34 #include "sound/Midi.h"
35 
36 #include <QComboBox>
37 #include <QDialog>
38 #include <QDialogButtonBox>
39 #include <QCheckBox>
40 #include <QFile>
41 #include <QGroupBox>
42 #include <QGridLayout>
43 #include <QLabel>
44 #include <QMessageBox>
45 #include <QPushButton>
46 #include <QSpinBox>
47 #include <QString>
48 #include <QWidget>
49 #include <QVBoxLayout>
50 #include <QLayout>
51 #include <QSettings>
52 
53 
54 
55 namespace Rosegarden
56 {
57 
SimpleEventEditDialog(QWidget * parent,RosegardenDocument * doc,const Event & event,bool inserting)58 SimpleEventEditDialog::SimpleEventEditDialog(QWidget *parent,
59         RosegardenDocument *doc,
60         const Event &event,
61         bool inserting) :
62         QDialog(parent),
63         m_event(event),
64         m_doc(doc),
65         m_type(event.getType()),
66         m_absoluteTime(event.getAbsoluteTime()),
67         m_duration(event.getDuration()),
68         m_modified(false)
69 {
70     setModal(true);
71     setWindowTitle(tr(inserting ?
72                           tr("Insert Event").toStdString().c_str() :
73                           tr("Edit Event").toStdString().c_str()));
74 
75     QGridLayout *metagrid = new QGridLayout;
76     setLayout(metagrid);
77     QWidget *vbox = new QWidget(this);
78     QVBoxLayout *vboxLayout = new QVBoxLayout;
79     metagrid->addWidget(vbox, 0, 0);
80 
81 
82     QGroupBox *frame = new QGroupBox( tr("Event Properties"), vbox );
83     frame->setContentsMargins(5, 5, 5, 5);
84     QGridLayout *layout = new QGridLayout(frame);
85     layout->setSpacing(5);
86     vboxLayout->addWidget(frame);
87 
88     layout->addWidget(new QLabel(tr("Event type:"), frame), 0, 0);
89 
90     if (inserting) {
91 
92         m_typeLabel = nullptr;
93 
94         m_typeCombo = new QComboBox(frame);
95         layout->addWidget(m_typeCombo, 0, 1);
96 
97         m_typeCombo->addItem(strtoqstr(Note::EventType));
98         m_typeCombo->addItem(strtoqstr(Controller::EventType));
99         m_typeCombo->addItem(strtoqstr(KeyPressure::EventType));
100         m_typeCombo->addItem(strtoqstr(ChannelPressure::EventType));
101         m_typeCombo->addItem(strtoqstr(ProgramChange::EventType));
102         m_typeCombo->addItem(strtoqstr(SystemExclusive::EventType));
103         m_typeCombo->addItem(strtoqstr(PitchBend::EventType));
104         m_typeCombo->addItem(strtoqstr(Indication::EventType));
105         m_typeCombo->addItem(strtoqstr(Text::EventType));
106         m_typeCombo->addItem(strtoqstr(Note::EventRestType));
107         m_typeCombo->addItem(strtoqstr(Clef::EventType));
108         m_typeCombo->addItem(strtoqstr(::Rosegarden::Key::EventType));
109         m_typeCombo->addItem(strtoqstr(Guitar::Chord::EventType));
110 
111         // Connect up the combos
112         //
113         connect(m_typeCombo, SIGNAL(activated(int)),
114                 SLOT(slotEventTypeChanged(int)));
115 
116     } else {
117 
118         m_typeCombo = nullptr;
119 
120         m_typeLabel = new QLabel(frame);
121         layout->addWidget(m_typeLabel, 0, 1);
122     }
123 
124     m_timeLabel = new QLabel(tr("Absolute time:"), frame);
125     layout->addWidget(m_timeLabel, 1, 0);
126     m_timeSpinBox = new QSpinBox(frame);
127     m_timeSpinBox->setMinimum(INT_MIN);
128     m_timeSpinBox->setMaximum(INT_MAX);
129     m_timeSpinBox->setSingleStep(Note(Note::Shortest).getDuration());
130     m_timeEditButton = new QPushButton(tr("edit"), frame);
131     layout->addWidget(m_timeSpinBox, 1, 1);
132     layout->addWidget(m_timeEditButton, 1, 2);
133 
134     connect(m_timeSpinBox, SIGNAL(valueChanged(int)),
135             SLOT(slotAbsoluteTimeChanged(int)));
136     connect(m_timeEditButton, &QAbstractButton::released,
137             this, &SimpleEventEditDialog::slotEditAbsoluteTime);
138 
139     m_durationLabel = new QLabel(tr("Duration:"), frame);
140     layout->addWidget(m_durationLabel, 2, 0);
141     m_durationSpinBox = new QSpinBox(frame);
142     m_durationSpinBox->setMinimum(0);
143     m_durationSpinBox->setMaximum(INT_MAX);
144     m_durationSpinBox->setSingleStep(Note(Note::Shortest).getDuration());
145     m_durationEditButton = new QPushButton(tr("edit"), frame);
146     layout->addWidget(m_durationSpinBox, 2, 1);
147     layout->addWidget(m_durationEditButton, 2, 2);
148 
149     connect(m_durationSpinBox, SIGNAL(valueChanged(int)),
150             SLOT(slotDurationChanged(int)));
151     connect(m_durationEditButton, &QAbstractButton::released,
152             this, &SimpleEventEditDialog::slotEditDuration);
153 
154     m_pitchLabel = new QLabel(tr("Pitch:"), frame);
155     layout->addWidget(m_pitchLabel, 3, 0);
156     m_pitchSpinBox = new QSpinBox(frame);
157     m_pitchEditButton = new QPushButton(tr("edit"), frame);
158     layout->addWidget(m_pitchSpinBox, 3, 1);
159     layout->addWidget(m_pitchEditButton, 3, 2);
160 
161     connect(m_pitchSpinBox, SIGNAL(valueChanged(int)),
162             SLOT(slotPitchChanged(int)));
163     connect(m_pitchEditButton, &QAbstractButton::released,
164             this, &SimpleEventEditDialog::slotEditPitch);
165 
166     m_pitchSpinBox->setMinimum(MidiMinValue);
167     m_pitchSpinBox->setMaximum(MidiMaxValue);
168 
169     m_controllerLabel = new QLabel(tr("Controller name:"), frame);
170     m_controllerLabelValue = new QLabel(tr("<none>"), frame);
171     m_controllerLabelValue->setAlignment( Qt::AlignRight );
172 
173     layout->addWidget(m_controllerLabel, 4, 0);
174     layout->addWidget(m_controllerLabelValue, 4, 1);
175 
176     m_velocityLabel = new QLabel(tr("Velocity:"), frame);
177     layout->addWidget(m_velocityLabel, 5, 0);
178     m_velocitySpinBox = new QSpinBox(frame);
179     layout->addWidget(m_velocitySpinBox, 5, 1);
180 
181     connect(m_velocitySpinBox, SIGNAL(valueChanged(int)),
182             SLOT(slotVelocityChanged(int)));
183 
184     m_velocitySpinBox->setMinimum(MidiMinValue);
185     m_velocitySpinBox->setMaximum(MidiMaxValue);
186 
187     m_metaLabel = new QLabel(tr("Meta string:"), frame);
188     layout->addWidget(m_metaLabel, 6, 0);
189     m_metaEdit = new LineEdit(frame);
190     layout->addWidget(m_metaEdit, 6, 1);
191 
192     m_sysexLoadButton = new QPushButton(tr("Load data"), frame);
193     layout->addWidget(m_sysexLoadButton, 6, 2);
194     m_sysexSaveButton = new QPushButton(tr("Save data"), frame);
195     layout->addWidget(m_sysexSaveButton, 4, 2);
196 
197     frame->setLayout(layout);
198 
199     connect(m_metaEdit, &QLineEdit::textChanged,
200             this, &SimpleEventEditDialog::slotMetaChanged);
201     connect(m_sysexLoadButton, &QAbstractButton::released,
202             this, &SimpleEventEditDialog::slotSysexLoad);
203     connect(m_sysexSaveButton, &QAbstractButton::released,
204             this, &SimpleEventEditDialog::slotSysexSave);
205 
206     m_notationGroupBox = new QGroupBox( tr("Notation Properties"), vbox );
207     m_notationGroupBox->setContentsMargins(5, 5, 5, 5);
208     layout = new QGridLayout(m_notationGroupBox);
209     layout->setSpacing(5);
210     vboxLayout->addWidget(m_notationGroupBox);
211     vbox->setLayout(vboxLayout);
212 
213     m_lockNotationValues = new QCheckBox(tr("Lock to changes in performed values"), m_notationGroupBox);
214     layout->addWidget(m_lockNotationValues, 0, 0, 0- 0+1, 2-0+ 1);
215     m_lockNotationValues->setChecked(true);
216 
217     connect(m_lockNotationValues, &QAbstractButton::released,
218             this, &SimpleEventEditDialog::slotLockNotationChanged);
219 
220     m_notationTimeLabel = new QLabel(tr("Notation time:"), m_notationGroupBox);
221     layout->addWidget(m_notationTimeLabel, 1, 0);
222     m_notationTimeSpinBox = new QSpinBox(m_notationGroupBox);
223     m_notationTimeSpinBox->setMinimum(INT_MIN);
224     m_notationTimeSpinBox->setMaximum(INT_MAX);
225     m_notationTimeSpinBox->setSingleStep(Note(Note::Shortest).getDuration());
226     m_notationTimeEditButton = new QPushButton(tr("edit"), m_notationGroupBox);
227     layout->addWidget(m_notationTimeSpinBox, 1, 1);
228     layout->addWidget(m_notationTimeEditButton, 1, 2);
229 
230     connect(m_notationTimeSpinBox, SIGNAL(valueChanged(int)),
231             SLOT(slotNotationAbsoluteTimeChanged(int)));
232     connect(m_notationTimeEditButton, &QAbstractButton::released,
233             this, &SimpleEventEditDialog::slotEditNotationAbsoluteTime);
234 
235     m_notationDurationLabel = new QLabel(tr("Notation duration:"), m_notationGroupBox);
236     layout->addWidget(m_notationDurationLabel, 2, 0);
237     m_notationDurationSpinBox = new QSpinBox(m_notationGroupBox);
238     m_notationDurationSpinBox->setMinimum(0);
239     m_notationDurationSpinBox->setMaximum(INT_MAX);
240     m_notationDurationSpinBox->setSingleStep(Note(Note::Shortest).getDuration());
241     m_notationDurationEditButton = new QPushButton(tr("edit"), m_notationGroupBox);
242     layout->addWidget(m_notationDurationSpinBox, 2, 1);
243     layout->addWidget(m_notationDurationEditButton, 2, 2);
244 
245     m_notationGroupBox->setLayout(layout);
246 
247     connect(m_notationDurationSpinBox, SIGNAL(valueChanged(int)),
248             SLOT(slotNotationDurationChanged(int)));
249     connect(m_notationDurationEditButton, &QAbstractButton::released,
250             this, &SimpleEventEditDialog::slotEditNotationDuration);
251 
252     setupForEvent();
253     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
254     metagrid->addWidget(buttonBox, 1, 0);
255     metagrid->setRowStretch(0, 10);
256     connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
257     connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
258 }
259 
260 void
setupForEvent()261 SimpleEventEditDialog::setupForEvent()
262 {
263     using BaseProperties::PITCH;
264     using BaseProperties::VELOCITY;
265 
266     if (m_typeCombo) {
267         m_typeCombo->blockSignals(true);
268     }
269     m_timeSpinBox->blockSignals(true);
270     m_notationTimeSpinBox->blockSignals(true);
271     m_durationSpinBox->blockSignals(true);
272     m_notationDurationSpinBox->blockSignals(true);
273     m_pitchSpinBox->blockSignals(true);
274     m_velocitySpinBox->blockSignals(true);
275     m_metaEdit->blockSignals(true);
276 
277     m_pitchSpinBox->setMinimum(MidiMinValue);
278     m_pitchSpinBox->setMaximum(MidiMaxValue);
279 
280     // Some common settings
281     //
282     m_durationLabel->setText(tr("Absolute time:"));
283     m_timeLabel->show();
284     m_timeSpinBox->show();
285     m_timeEditButton->show();
286     m_timeSpinBox->setValue(m_event.getAbsoluteTime());
287 
288     m_durationLabel->setText(tr("Duration:"));
289     m_durationLabel->show();
290     m_durationSpinBox->show();
291     m_durationEditButton->show();
292     m_durationSpinBox->setValue(m_event.getDuration());
293 
294     m_notationGroupBox->hide();
295 
296     // satisfy an ancient feature request:  if the performance and absolute
297     // durations differ or the performance and absolute start times differ, then
298     // this is a notation quantized note, and we set this checkbox off by
299     // default, because "This is ok for ordinary notes but for a
300     // notation-quantised note the note will likely already
301     // have different performance and notation durations (and
302     // probably different start times too) which makes the
303     // lock inappropriate."
304     m_lockNotationValues->setChecked(m_event.getDuration() == m_event.getNotationDuration() &&
305                                      m_event.getAbsoluteTime() == m_event.getNotationAbsoluteTime());
306 
307     if (m_typeLabel)
308         m_typeLabel->setText(strtoqstr(m_event.getType()));
309 
310     m_absoluteTime = m_event.getAbsoluteTime();
311     m_notationAbsoluteTime = m_event.getNotationAbsoluteTime();
312     m_duration = m_event.getDuration();
313     m_notationDuration = m_event.getNotationDuration();
314 
315     m_sysexLoadButton->hide();
316     m_sysexSaveButton->hide();
317 
318     if (m_type == Note::EventType) {
319         m_notationGroupBox->show();
320         m_notationTimeSpinBox->setValue(m_notationAbsoluteTime);
321         m_notationDurationSpinBox->setValue(m_notationDuration);
322 
323         m_pitchLabel->show();
324         m_pitchLabel->setText(tr("Note pitch:"));
325         m_pitchSpinBox->show();
326         m_pitchEditButton->show();
327 
328         m_controllerLabel->hide();
329         m_controllerLabelValue->hide();
330 
331         m_velocityLabel->show();
332         m_velocityLabel->setText(tr("Note velocity:"));
333         m_velocitySpinBox->show();
334 
335         m_metaLabel->hide();
336         m_metaEdit->hide();
337 
338         try {
339             m_pitchSpinBox->setValue(m_event.get<Int>(PITCH));
340         } catch (const Event::NoData &) {
341             m_pitchSpinBox->setValue(60);
342         }
343 
344         try {
345             m_velocitySpinBox->setValue(m_event.get<Int>(VELOCITY));
346         } catch (const Event::NoData &) {
347             m_velocitySpinBox->setValue(100);
348         }
349 
350         if (m_typeCombo)
351             m_typeCombo->setCurrentIndex(0);
352 
353     } else if (m_type == Controller::EventType) {
354 
355         m_durationLabel->hide();
356         m_durationSpinBox->hide();
357         m_durationEditButton->hide();
358 
359         m_pitchLabel->show();
360         m_pitchLabel->setText(tr("Controller number:"));
361         m_pitchSpinBox->show();
362         m_pitchEditButton->hide();
363 
364         m_controllerLabel->show();
365         m_controllerLabelValue->show();
366         m_controllerLabel->setText(tr("Controller name:"));
367 
368         m_velocityLabel->show();
369         m_velocityLabel->setText(tr("Controller value:"));
370         m_velocitySpinBox->show();
371 
372         m_metaLabel->hide();
373         m_metaEdit->hide();
374 
375         try {
376             m_pitchSpinBox->setValue(m_event.get<Int>
377                                      (Controller::NUMBER));
378         } catch (const Event::NoData &) {
379             m_pitchSpinBox->setValue(0);
380         }
381 
382         try {
383             m_velocitySpinBox->setValue(m_event.get<Int>
384                                         (Controller::VALUE));
385         } catch (const Event::NoData &) {
386             m_velocitySpinBox->setValue(0);
387         }
388 
389         if (m_typeCombo)
390             m_typeCombo->setCurrentIndex(1);
391 
392     } else if (m_type == KeyPressure::EventType) {
393 
394         m_durationLabel->hide();
395         m_durationSpinBox->hide();
396         m_durationEditButton->hide();
397 
398         m_pitchLabel->show();
399         m_pitchLabel->setText(tr("Key pitch:"));
400         m_pitchSpinBox->show();
401         m_pitchEditButton->show();
402 
403         m_controllerLabel->hide();
404         m_controllerLabelValue->hide();
405 
406         m_velocityLabel->show();
407         m_velocityLabel->setText(tr("Key pressure:"));
408         m_velocitySpinBox->show();
409 
410         m_metaLabel->hide();
411         m_metaEdit->hide();
412 
413         try {
414             m_pitchSpinBox->setValue(m_event.get<Int>
415                                      (KeyPressure::PITCH));
416         } catch (const Event::NoData &) {
417             m_pitchSpinBox->setValue(0);
418         }
419 
420         try {
421             m_velocitySpinBox->setValue(m_event.get<Int>
422                                         (KeyPressure::PRESSURE));
423         } catch (const Event::NoData &) {
424             m_velocitySpinBox->setValue(0);
425         }
426 
427         if (m_typeCombo)
428             m_typeCombo->setCurrentIndex(2);
429 
430     } else if (m_type == ChannelPressure::EventType) {
431 
432         m_durationLabel->hide();
433         m_durationSpinBox->hide();
434         m_durationEditButton->hide();
435 
436         m_pitchLabel->show();
437         m_pitchLabel->setText(tr("Channel pressure:"));
438         m_pitchSpinBox->show();
439         m_pitchEditButton->hide();
440 
441         m_controllerLabel->hide();
442         m_controllerLabelValue->hide();
443 
444         m_velocityLabel->hide();
445         m_velocitySpinBox->hide();
446 
447         m_metaLabel->hide();
448         m_metaEdit->hide();
449 
450         try {
451             m_pitchSpinBox->setValue(m_event.get<Int>
452                                      (ChannelPressure::PRESSURE));
453         } catch (const Event::NoData &) {
454             m_pitchSpinBox->setValue(0);
455         }
456 
457         if (m_typeCombo)
458             m_typeCombo->setCurrentIndex(3);
459 
460     } else if (m_type == ProgramChange::EventType) {
461 
462         m_durationLabel->hide();
463         m_durationSpinBox->hide();
464         m_durationEditButton->hide();
465 
466         m_pitchSpinBox->setMinimum(MidiMinValue + 1);
467         m_pitchSpinBox->setMaximum(MidiMaxValue + 1);
468 
469         m_pitchLabel->show();
470         m_pitchLabel->setText(tr("Program change:"));
471         m_pitchSpinBox->show();
472         m_pitchEditButton->hide();
473 
474         m_controllerLabel->hide();
475         m_controllerLabelValue->hide();
476 
477         m_velocityLabel->hide();
478         m_velocitySpinBox->hide();
479 
480         m_metaLabel->hide();
481         m_metaEdit->hide();
482 
483         try {
484             m_pitchSpinBox->setValue(m_event.get<Int>
485                                      (ProgramChange::PROGRAM) + 1);
486         } catch (const Event::NoData &) {
487             m_pitchSpinBox->setValue(0);
488         }
489 
490         if (m_typeCombo)
491             m_typeCombo->setCurrentIndex(4);
492 
493     } else if (m_type == SystemExclusive::EventType) {
494 
495         m_durationLabel->hide();
496         m_durationSpinBox->hide();
497         m_durationEditButton->hide();
498 
499         m_pitchLabel->hide();
500         m_pitchSpinBox->hide();
501         m_pitchEditButton->hide();
502 
503         m_controllerLabel->show();
504         m_controllerLabelValue->show();
505 
506         m_velocityLabel->hide();
507         m_velocitySpinBox->hide();
508 
509         m_metaLabel->show();
510         m_metaEdit->show();
511 
512         m_sysexLoadButton->show();
513         m_sysexSaveButton->show();
514 
515         m_controllerLabel->setText(tr("Data length:"));
516         m_metaLabel->setText(tr("Data:"));
517         try {
518             std::string datablock;
519             m_event.get<String>(SystemExclusive::DATABLOCK, datablock);
520             m_controllerLabelValue->setText(QString("%1").
521                     arg(SystemExclusive::toRaw(datablock).length()));
522             m_metaEdit->setText(strtoqstr(datablock));
523         } catch (...) {
524             m_controllerLabelValue->setText("0");
525         }
526 
527         if (m_typeCombo)
528             m_typeCombo->setCurrentIndex(5);
529 
530     } else if (m_type == PitchBend::EventType) {
531 
532         m_durationLabel->hide();
533         m_durationSpinBox->hide();
534         m_durationEditButton->hide();
535 
536         m_pitchLabel->show();
537         m_pitchLabel->setText(tr("Pitchbend MSB:"));
538         m_pitchSpinBox->show();
539         m_pitchEditButton->hide();
540 
541         m_controllerLabel->hide();
542         m_controllerLabelValue->hide();
543 
544         m_velocityLabel->show();
545         m_velocityLabel->setText(tr("Pitchbend LSB:"));
546         m_velocitySpinBox->show();
547 
548         m_metaLabel->hide();
549         m_metaEdit->hide();
550 
551         try {
552             m_pitchSpinBox->setValue(m_event.get<Int>
553                                      (PitchBend::MSB));
554         } catch (const Event::NoData &) {
555             m_pitchSpinBox->setValue(0);
556         }
557 
558         try {
559             m_velocitySpinBox->setValue(m_event.get<Int>
560                                         (PitchBend::LSB));
561         } catch (const Event::NoData &) {
562             m_velocitySpinBox->setValue(0);
563         }
564 
565         if (m_typeCombo)
566             m_typeCombo->setCurrentIndex(6);
567 
568     } else if (m_type == Indication::EventType) {
569 
570         m_pitchLabel->hide();
571         m_pitchSpinBox->hide();
572         m_pitchEditButton->hide();
573 
574         m_controllerLabel->hide();
575         m_controllerLabelValue->hide();
576 
577         m_velocityLabel->hide();
578         m_velocitySpinBox->hide();
579 
580         m_metaLabel->show();
581         m_metaEdit->show();
582         m_metaLabel->setText(tr("Indication:"));
583 
584         try {
585             Indication ind(m_event);
586             m_metaEdit->setText(strtoqstr(ind.getIndicationType()));
587             m_durationSpinBox->setValue(ind.getIndicationDuration());
588         } catch (...) {
589             m_metaEdit->setText(tr("<none>"));
590         }
591 
592         if (m_typeCombo)
593             m_typeCombo->setCurrentIndex(7);
594 
595     } else if (m_type == Text::EventType) {
596 
597         m_durationLabel->hide();
598         m_durationSpinBox->hide();
599         m_durationEditButton->hide();
600 
601         m_pitchLabel->hide();
602         m_pitchSpinBox->hide();
603         m_pitchEditButton->hide();
604 
605         m_controllerLabel->show();
606         m_controllerLabelValue->show();
607 
608         m_velocityLabel->hide();
609         m_velocitySpinBox->hide();
610 
611         m_metaLabel->show();
612         m_metaEdit->show();
613 
614         m_controllerLabel->setText(tr("Text type:"));
615         m_metaLabel->setText(tr("Text:"));
616 
617         // get the text event
618         try {
619             Text text(m_event);
620             m_controllerLabelValue->setText(strtoqstr(text.getTextType()));
621             m_metaEdit->setText(strtoqstr(text.getText()));
622         } catch (...) {
623             m_controllerLabelValue->setText(tr("<none>"));
624             m_metaEdit->setText(tr("<none>"));
625         }
626 
627         if (m_typeCombo)
628             m_typeCombo->setCurrentIndex(8);
629 
630     } else if (m_type == Note::EventRestType) {
631 
632         m_pitchLabel->hide();
633         m_pitchSpinBox->hide();
634         m_pitchEditButton->hide();
635 
636         m_controllerLabel->hide();
637         m_controllerLabelValue->hide();
638 
639         m_velocityLabel->hide();
640         m_velocitySpinBox->hide();
641 
642         m_metaLabel->hide();
643         m_metaEdit->hide();
644 
645         if (m_typeCombo)
646             m_typeCombo->setCurrentIndex(9);
647 
648     } else if (m_type == Clef::EventType) {
649 
650         m_durationLabel->hide();
651         m_durationSpinBox->hide();
652         m_durationEditButton->hide();
653 
654         m_pitchLabel->hide();
655         m_pitchSpinBox->hide();
656         m_pitchEditButton->hide();
657 
658         m_controllerLabel->show();
659         m_controllerLabelValue->show();
660 
661         m_controllerLabel->setText(tr("Clef type:"));
662 
663         try {
664             Clef clef(m_event);
665             m_controllerLabelValue->setText(strtoqstr(clef.getClefType()));
666         } catch (...) {
667             m_controllerLabelValue->setText(tr("<none>"));
668         }
669 
670         m_velocityLabel->hide();
671         m_velocitySpinBox->hide();
672 
673         m_metaLabel->hide();
674         m_metaEdit->hide();
675 
676         if (m_typeCombo)
677             m_typeCombo->setCurrentIndex(10);
678 
679     } else if (m_type == ::Rosegarden::Key::EventType) {
680 
681         m_durationLabel->hide();
682         m_durationSpinBox->hide();
683         m_durationEditButton->hide();
684 
685         m_pitchLabel->hide();
686         m_pitchSpinBox->hide();
687         m_pitchEditButton->hide();
688 
689         m_controllerLabel->show();
690         m_controllerLabelValue->show();
691 
692         m_controllerLabel->setText(tr("Key name:"));
693 
694         try {
695             ::Rosegarden::Key key(m_event);
696             m_controllerLabelValue->setText(strtoqstr(key.getName()));
697         } catch (...) {
698             m_controllerLabelValue->setText(tr("<none>"));
699         }
700 
701         m_velocityLabel->hide();
702         m_velocitySpinBox->hide();
703 
704         m_metaLabel->hide();
705         m_metaEdit->hide();
706 
707         if (m_typeCombo)
708             m_typeCombo->setCurrentIndex(11);
709 
710     } else if (m_type == Guitar::Chord::EventType) {
711 
712         m_durationLabel->hide();
713         m_durationSpinBox->hide();
714         m_durationEditButton->hide();
715 
716         m_pitchLabel->hide();
717         m_pitchSpinBox->hide();
718         m_pitchEditButton->hide();
719 
720         m_controllerLabel->hide();
721         m_controllerLabelValue->hide();
722 
723         m_velocityLabel->hide();
724         m_velocitySpinBox->hide();
725 
726         m_metaLabel->hide();
727         m_metaEdit->hide();
728 
729         // m_controllerLabel->setText(tr("Text type:"));
730         // m_metaLabel->setText(tr("Chord:"));
731 
732         // get the fingering event
733         try {
734             Guitar::Chord chord( m_event );
735         } catch (...) {
736             // m_controllerLabelValue->setText(tr("<none>"));
737             // m_metaEdit->setText(tr("<none>"));
738         }
739 
740         if (m_typeCombo)
741             m_typeCombo->setCurrentIndex(12);
742 
743     } else {
744 
745         m_durationLabel->setText(tr("Unsupported event type:"));
746         m_durationLabel->show();
747         m_durationSpinBox->hide();
748         m_durationEditButton->hide();
749 
750         m_pitchLabel->hide();
751         m_pitchSpinBox->hide();
752         m_pitchEditButton->hide();
753 
754         m_controllerLabel->hide();
755         m_controllerLabelValue->show();
756         m_controllerLabelValue->setText(strtoqstr(m_type));
757 
758         m_velocityLabel->hide();
759         m_velocitySpinBox->hide();
760 
761         m_metaLabel->hide();
762         m_metaEdit->hide();
763 
764         if (m_typeCombo)
765             m_typeCombo->setEnabled(false);
766     }
767 
768     if (m_typeCombo)
769         m_typeCombo->blockSignals(false);
770     m_timeSpinBox->blockSignals(false);
771     m_notationTimeSpinBox->blockSignals(false);
772     m_durationSpinBox->blockSignals(false);
773     m_notationDurationSpinBox->blockSignals(false);
774     m_pitchSpinBox->blockSignals(false);
775     m_velocitySpinBox->blockSignals(false);
776     m_metaEdit->blockSignals(false);
777 
778     slotLockNotationChanged();
779 }
780 
781 Event
getEvent()782 SimpleEventEditDialog::getEvent()
783 {
784     bool useSeparateNotationValues =
785         (m_event.getType() == Note::EventType);
786 
787     if (m_typeCombo) {
788 
789         int subordering = 0;
790         if (m_type == Indication::EventType) {
791             subordering = Indication::EventSubOrdering;
792         } else if (m_type == Clef::EventType) {
793             subordering = Clef::EventSubOrdering;
794         } else if (m_type == ::Rosegarden::Key::EventType) {
795             subordering = ::Rosegarden::Key::EventSubOrdering;
796         } else if (m_type == Text::EventType) {
797             subordering = Text::EventSubOrdering;
798         } else if (m_type == Note::EventRestType) {
799             subordering = Note::EventRestSubOrdering;
800         } else if (m_type == PitchBend::EventType) {
801             subordering = PitchBend::EventSubOrdering;
802         } else if (m_type == Controller::EventType) {
803             subordering = Controller::EventSubOrdering;
804         } else if (m_type == KeyPressure::EventType) {
805             subordering = KeyPressure::EventSubOrdering;
806         } else if (m_type == ChannelPressure::EventType) {
807             subordering = ChannelPressure::EventSubOrdering;
808         } else if (m_type == ProgramChange::EventType) {
809             subordering = ProgramChange::EventSubOrdering;
810         } else if (m_type == SystemExclusive::EventType) {
811             subordering = SystemExclusive::EventSubOrdering;
812         }
813 
814         m_event = Event(m_type,
815                         m_absoluteTime,
816                         m_duration,
817                         subordering,
818                         (useSeparateNotationValues ?
819                          m_notationAbsoluteTime : m_absoluteTime),
820                         (useSeparateNotationValues ?
821                          m_notationDuration : m_duration));
822 
823         // ensure these are set on m_event correctly
824         slotPitchChanged(m_pitchSpinBox->value());
825         slotVelocityChanged(m_velocitySpinBox->value());
826     }
827 
828     Event event(m_event,
829                 m_absoluteTime,
830                 m_duration,
831                 m_event.getSubOrdering(),
832                 (useSeparateNotationValues ?
833                  m_notationAbsoluteTime : m_absoluteTime),
834                 (useSeparateNotationValues ?
835                  m_notationDuration : m_duration));
836 
837     // Values from the pitch and velocity spin boxes should already
838     // have been set on m_event (and thus on event) by slotPitchChanged
839     // and slotVelocityChanged.  Absolute time and duration were set in
840     // the event ctor above; that just leaves the meta values.
841 
842     if (m_type == Indication::EventType) {
843 
844         event.set<String>(Indication::IndicationTypePropertyName,
845                           qstrtostr(m_metaEdit->text()));
846 
847     } else if (m_type == Text::EventType) {
848 
849         event.set<String>(Text::TextTypePropertyName,
850                           qstrtostr(m_controllerLabelValue->text()));
851         event.set<String>(Text::TextPropertyName,
852                           qstrtostr(m_metaEdit->text()));
853 
854     } else if (m_type == Clef::EventType) {
855 
856         event.set<String>(Clef::ClefPropertyName,
857                           qstrtostr(m_controllerLabelValue->text()));
858 
859     } else if (m_type == ::Rosegarden::Key::EventType) {
860 
861         event.set<String>(::Rosegarden::Key::KeyPropertyName,
862                           qstrtostr(m_controllerLabelValue->text()));
863 
864     } else if (m_type == SystemExclusive::EventType) {
865 
866         event.set<String>(SystemExclusive::DATABLOCK,
867                           qstrtostr(m_metaEdit->text()));
868 
869     }
870 
871     return event;
872 }
873 
874 void
slotEventTypeChanged(int value)875 SimpleEventEditDialog::slotEventTypeChanged(int value)
876 {
877     m_type = qstrtostr(m_typeCombo->itemText(value));
878     m_modified = true;
879 
880     if (m_type != m_event.getType())
881         Event m_event(m_type, m_absoluteTime, m_duration);
882 
883     setupForEvent();
884 
885     // update whatever pitch and velocity correspond to
886     if (!m_pitchSpinBox->isHidden())
887         slotPitchChanged(m_pitchSpinBox->value());
888     if (!m_velocitySpinBox->isHidden())
889         slotVelocityChanged(m_velocitySpinBox->value());
890 }
891 
892 void
slotAbsoluteTimeChanged(int value)893 SimpleEventEditDialog::slotAbsoluteTimeChanged(int value)
894 {
895     m_absoluteTime = value;
896 
897     if (m_notationGroupBox->isHidden()) {
898         m_notationAbsoluteTime = value;
899     } else if (m_lockNotationValues->isChecked()) {
900         m_notationAbsoluteTime = value;
901         m_notationTimeSpinBox->setValue(value);
902     }
903 
904     m_modified = true;
905 }
906 
907 void
slotNotationAbsoluteTimeChanged(int value)908 SimpleEventEditDialog::slotNotationAbsoluteTimeChanged(int value)
909 {
910     m_notationAbsoluteTime = value;
911     m_modified = true;
912 }
913 
914 void
slotDurationChanged(int value)915 SimpleEventEditDialog::slotDurationChanged(int value)
916 {
917     m_duration = value;
918 
919     if (m_notationGroupBox->isHidden()) {
920         m_notationDuration = value;
921     } else if (m_lockNotationValues->isChecked()) {
922         m_notationDuration = value;
923         m_notationDurationSpinBox->setValue(value);
924     }
925 
926     m_modified = true;
927 }
928 
929 void
slotNotationDurationChanged(int value)930 SimpleEventEditDialog::slotNotationDurationChanged(int value)
931 {
932     m_notationDuration = value;
933     m_modified = true;
934 }
935 
936 void
slotPitchChanged(int value)937 SimpleEventEditDialog::slotPitchChanged(int value)
938 {
939     m_modified = true;
940 
941     if (m_type == Note::EventType) {
942         m_event.set<Int>(BaseProperties::PITCH, value);
943 
944     } else if (m_type == Controller::EventType) {
945         m_event.set<Int>(Controller::NUMBER, value);
946 
947     } else if (m_type == KeyPressure::EventType) {
948         m_event.set<Int>(KeyPressure::PITCH, value);
949 
950     } else if (m_type == ChannelPressure::EventType) {
951         m_event.set<Int>(ChannelPressure::PRESSURE, value);
952 
953     } else if (m_type == ProgramChange::EventType) {
954         if (value < 1)
955             value = 1;
956         m_event.set<Int>(ProgramChange::PROGRAM, value - 1);
957 
958     } else if (m_type == PitchBend::EventType) {
959         m_event.set<Int>(PitchBend::MSB, value);
960     }
961     //!!!??? sysex?
962 }
963 
964 void
slotVelocityChanged(int value)965 SimpleEventEditDialog::slotVelocityChanged(int value)
966 {
967     m_modified = true;
968 
969     if (m_type == Note::EventType) {
970         m_event.set<Int>(BaseProperties::VELOCITY, value);
971 
972     } else if (m_type == Controller::EventType) {
973         m_event.set<Int>(Controller::VALUE, value);
974 
975     } else if (m_type == KeyPressure::EventType) {
976         m_event.set<Int>(KeyPressure::PRESSURE, value);
977 
978     } else if (m_type == PitchBend::EventType) {
979         m_event.set<Int>(PitchBend::LSB, value);
980     }
981 }
982 
983 void
slotMetaChanged(const QString &)984 SimpleEventEditDialog::slotMetaChanged(const QString &)
985 {
986     m_modified = true;
987 }
988 
989 void
slotLockNotationChanged()990 SimpleEventEditDialog::slotLockNotationChanged()
991 {
992     bool enable = !m_lockNotationValues->isChecked();
993     m_notationTimeSpinBox->setEnabled(enable);
994     m_notationTimeEditButton->setEnabled(enable);
995     m_notationDurationSpinBox->setEnabled(enable);
996     m_notationDurationEditButton->setEnabled(enable);
997 }
998 
999 void
slotEditAbsoluteTime()1000 SimpleEventEditDialog::slotEditAbsoluteTime()
1001 {
1002     TimeDialog dialog(this, tr("Edit Event Time"),
1003                       &m_doc->getComposition(),
1004                       m_timeSpinBox->value(),
1005                       true);
1006     if (dialog.exec() == QDialog::Accepted) {
1007         m_timeSpinBox->setValue(dialog.getTime());
1008     }
1009 }
1010 
1011 void
slotEditNotationAbsoluteTime()1012 SimpleEventEditDialog::slotEditNotationAbsoluteTime()
1013 {
1014     TimeDialog dialog(this, tr("Edit Event Notation Time"),
1015                       &m_doc->getComposition(),
1016                       m_notationTimeSpinBox->value(),
1017                       true);
1018     if (dialog.exec() == QDialog::Accepted) {
1019         m_notationTimeSpinBox->setValue(dialog.getTime());
1020     }
1021 }
1022 
1023 void
slotEditDuration()1024 SimpleEventEditDialog::slotEditDuration()
1025 {
1026     TimeDialog dialog(this, tr("Edit Duration"),
1027                       &m_doc->getComposition(),
1028                       m_timeSpinBox->value(),
1029                       m_durationSpinBox->value(),
1030                       1,
1031                       true);
1032     if (dialog.exec() == QDialog::Accepted) {
1033         m_durationSpinBox->setValue(dialog.getTime());
1034     }
1035 }
1036 
1037 void
slotEditNotationDuration()1038 SimpleEventEditDialog::slotEditNotationDuration()
1039 {
1040     TimeDialog dialog(this, tr("Edit Notation Duration"),
1041                       &m_doc->getComposition(),
1042                       m_notationTimeSpinBox->value(),
1043                       m_notationDurationSpinBox->value(),
1044                       1,
1045                       true);
1046     if (dialog.exec() == QDialog::Accepted) {
1047         m_notationDurationSpinBox->setValue(dialog.getTime());
1048     }
1049 }
1050 
1051 void
slotEditPitch()1052 SimpleEventEditDialog::slotEditPitch()
1053 {
1054     PitchDialog dialog(this, tr("Edit Pitch"), m_pitchSpinBox->value());
1055     if (dialog.exec() == QDialog::Accepted) {
1056         m_pitchSpinBox->setValue(dialog.getPitch());
1057     }
1058 }
1059 
1060 void
slotSysexLoad()1061 SimpleEventEditDialog::slotSysexLoad()
1062 {
1063     QSettings settings;
1064     settings.beginGroup(LastUsedPathsConfigGroup);
1065     const QString pathKey = "load_sysex";
1066     QString directory = settings.value(pathKey, QDir::homePath()).toString();
1067 
1068     QString name = FileDialog::getOpenFileName(
1069             this,  // parent
1070             tr("Load System Exclusive data in File"),  // caption
1071             directory,  // dir
1072             tr("System exclusive files") + " (*.syx *.SYX)" + ";;" +
1073                 tr("All files") + " (*)");  // filter
1074 
1075     if (name.isNull())
1076         return ;
1077 
1078     QFile file(name);
1079     file.open(QIODevice::ReadOnly);
1080     std::string s;
1081     char c;
1082 
1083     // Discard leading bytes up to and including the first SysEx Start (F0).
1084     while (file.getChar(&c)) {
1085         if (c == static_cast<char>(MIDI_SYSTEM_EXCLUSIVE))
1086             break;
1087     }
1088     // Copy up to but not including SysEx End (F7).
1089     while (file.getChar(&c)) {
1090         if (c == static_cast<char>(MIDI_END_OF_EXCLUSIVE))
1091             break;
1092         s += c;
1093     }
1094 
1095     file.close();
1096 
1097     if (s.empty())
1098         QMessageBox::critical(this, tr("Rosegarden"), tr("Could not load SysEx file."));
1099 
1100     m_metaEdit->setText(strtoqstr(SystemExclusive::toHex(s)));
1101 
1102     // Write the directory to the settings
1103     QDir d = QFileInfo(name).dir();
1104     directory = d.canonicalPath();
1105     settings.setValue(pathKey, directory);
1106     settings.endGroup();
1107 }
1108 
1109 void
slotSysexSave()1110 SimpleEventEditDialog::slotSysexSave()
1111 {
1112     QSettings settings;
1113     settings.beginGroup(LastUsedPathsConfigGroup);
1114     const QString pathKey = "save_sysex";
1115     QString directory = settings.value(pathKey, QDir::homePath()).toString();
1116 
1117     QString name = FileDialog::getSaveFileName(
1118             this,  // parent
1119             tr("Save System Exclusive data to..."),  // caption
1120             directory,  // dir
1121             "",  // defaultName
1122             tr("System exclusive files") + " (*.syx *.SYX)" + ";;" +
1123                 tr("All files") + " (*)");  // filter
1124             //tr("*.syx|System exclusive files (*.syx)"));  // filter
1125     if (name.isNull())
1126         return;
1127 
1128     QFile file(name);
1129     file.open(QIODevice::WriteOnly);
1130 
1131     std::string datablock;
1132     m_event.get<String>(SystemExclusive::DATABLOCK, datablock);
1133     // Add SysEx and End SysEx status bytes.
1134     datablock = "F0 " + datablock + " F7";
1135     datablock = SystemExclusive::toRaw(datablock);
1136     file.write(datablock.c_str(),
1137                static_cast<qint64>(datablock.length()));
1138 
1139     file.close();
1140 
1141     // Write the directory to the settings
1142     QDir d = QFileInfo(name).dir();
1143     directory = d.canonicalPath();
1144     settings.setValue(pathKey, directory);
1145     settings.endGroup();
1146 }
1147 
1148 
1149 }
1150