From 5c7131aa45a92f68ac09c9c9955e12901f833c60 Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Sun, 6 Jul 2025 08:42:54 +0200 Subject: [PATCH] Allow export of only the selected notes (#7991) Users can now choose if they only want to export the selected notes when exporting a MIDI clip as an `xpt` or `xptz` file in the piano roll. The export file dialog now shows a checkbox with the label "Export only selected notes". ## Technical details Add the new public method `exportToXML` to `MidiClip`. Compared to `saveSettings` it has an additional parameter `onlySelectedNotes` which controls which notes are exported. The default is to export all notes. The method `saveSettings` now simply delegates to `exportToXML` using the default. `PianoRollWindow::exportMidiClip` now adds a check box to the export dialog which lets users select if they only want to export the selected notes or all notes. The default is to export all notes. The method now uses the new method `exportToXML` for the export and passes the state of the check box into the method. --- include/MidiClip.h | 1 + src/gui/editors/PianoRoll.cpp | 18 +++++++++++++++- src/tracks/MidiClip.cpp | 39 +++++++++++++++++++++-------------- 3 files changed, 41 insertions(+), 17 deletions(-) diff --git a/include/MidiClip.h b/include/MidiClip.h index 076ec93b0..d8553e87e 100644 --- a/include/MidiClip.h +++ b/include/MidiClip.h @@ -99,6 +99,7 @@ public: MidiClip * nextMidiClip() const; // settings-management + void exportToXML(QDomDocument& doc, QDomElement& midiClipElement, bool onlySelectedNotes = false); void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override; void loadSettings( const QDomElement & _this ) override; inline QString nodeName() const override diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index 3ef056c43..89789937f 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -28,6 +28,8 @@ #include #include +#include +#include #include #include #include @@ -5476,6 +5478,14 @@ void PianoRollWindow::exportMidiClip() FileDialog exportDialog(this, tr("Export clip"), "", tr("XML clip file (*.xpt *.xptz)")); + auto layout = dynamic_cast(exportDialog.layout()); + QCheckBox* onlySelectedNotesCheckBox = nullptr; + if (layout) + { + onlySelectedNotesCheckBox = new QCheckBox(tr("Export only selected notes"), &exportDialog); + layout->addWidget(onlySelectedNotesCheckBox); + } + exportDialog.setAcceptMode(FileDialog::AcceptSave); if (exportDialog.exec() == QDialog::Accepted && @@ -5489,8 +5499,14 @@ void PianoRollWindow::exportMidiClip() exportDialog.setDefaultSuffix(suffix); const QString fullPath = exportDialog.selectedFiles()[0]; + + // Check if only the selected notes should be exported + auto* midiClip = m_editor->m_midiClip; + + const bool onlySelectedNotes = onlySelectedNotesCheckBox && onlySelectedNotesCheckBox->isChecked(); + DataFile dataFile(DataFile::Type::MidiClip); - m_editor->m_midiClip->saveSettings(dataFile, dataFile.content()); + midiClip->exportToXML(dataFile, dataFile.content(), onlySelectedNotes); if (dataFile.writeFile(fullPath)) { diff --git a/src/tracks/MidiClip.cpp b/src/tracks/MidiClip.cpp index b422be824..707cbaf3d 100644 --- a/src/tracks/MidiClip.cpp +++ b/src/tracks/MidiClip.cpp @@ -442,43 +442,50 @@ void MidiClip::checkType() } - - -void MidiClip::saveSettings( QDomDocument & _doc, QDomElement & _this ) +void MidiClip::exportToXML(QDomDocument& doc, QDomElement& midiClipElement, bool onlySelectedNotes) { - _this.setAttribute( "type", static_cast(m_clipType) ); - _this.setAttribute( "name", name() ); - _this.setAttribute("autoresize", QString::number(getAutoResize())); - _this.setAttribute("off", startTimeOffset()); + midiClipElement.setAttribute("type", static_cast(m_clipType)); + midiClipElement.setAttribute("name", name()); + midiClipElement.setAttribute("autoresize", QString::number(getAutoResize())); + midiClipElement.setAttribute("off", startTimeOffset()); if (const auto& c = color()) { - _this.setAttribute("color", c->name()); + midiClipElement.setAttribute("color", c->name()); } // as the target of copied/dragged MIDI clip is always an existing // MIDI clip, we must not store actual position, instead we store -1 // which tells loadSettings() not to mess around with position - if( _this.parentNode().nodeName() == "clipboard" || - _this.parentNode().nodeName() == "dnddata" ) + if (midiClipElement.parentNode().nodeName() == "clipboard" || + midiClipElement.parentNode().nodeName() == "dnddata") { - _this.setAttribute( "pos", -1 ); + midiClipElement.setAttribute("pos", -1); } else { - _this.setAttribute( "pos", startPosition() ); + midiClipElement.setAttribute("pos", startPosition()); } - _this.setAttribute( "muted", isMuted() ); - _this.setAttribute( "steps", m_steps ); - _this.setAttribute( "len", length() ); + midiClipElement.setAttribute("muted", isMuted()); + midiClipElement.setAttribute("steps", m_steps); + midiClipElement.setAttribute("len", length()); // now save settings of all notes for (auto& note : m_notes) { - note->saveState(_doc, _this); + if (!onlySelectedNotes || note->selected()) + { + note->saveState(doc, midiClipElement); + } } } +void MidiClip::saveSettings( QDomDocument & _doc, QDomElement & _this ) +{ + exportToXML(_doc, _this); +} + + void MidiClip::loadSettings( const QDomElement & _this )