From b3e61cbc803d2d263e324073023c1a9381ef3c6d Mon Sep 17 00:00:00 2001 From: Shmuel H Date: Sun, 9 Jun 2019 09:47:28 +0300 Subject: [PATCH 01/10] Song: isSavingProject. --- include/Song.h | 19 +++++++++++++++++++ src/core/Song.cpp | 7 +++++++ 2 files changed, 26 insertions(+) diff --git a/include/Song.h b/include/Song.h index d88a59e2b40..32ead7181f5 100644 --- a/include/Song.h +++ b/include/Song.h @@ -65,6 +65,17 @@ class LMMS_EXPORT Song : public TrackContainer Mode_Count } ; + struct SaveOptions { + /** + * Should we discard MIDI ControllerConnections from project files? + */ + BoolModel discardMIDIConnections{false}; + + void setDefaultOptions() { + discardMIDIConnections.setValue(false); + } + }; + void clearErrors(); void collectError( const QString error ); bool hasErrors(); @@ -322,6 +333,11 @@ class LMMS_EXPORT Song : public TrackContainer void exportProjectMidi(QString const & exportFileName) const; inline void setLoadOnLauch(bool value) { m_loadOnLaunch = value; } + SaveOptions &getSaveOptions() { + return m_saveOptions; + } + + bool isSavingProject() const; public slots: void playSong(); @@ -419,9 +435,12 @@ private slots: volatile bool m_playing; volatile bool m_paused; + bool m_savingProject; bool m_loadingProject; bool m_isCancelled; + SaveOptions m_saveOptions; + QStringList m_errors; PlayModes m_playMode; diff --git a/src/core/Song.cpp b/src/core/Song.cpp index 2809c61adb1..274fff2b677 100644 --- a/src/core/Song.cpp +++ b/src/core/Song.cpp @@ -1212,6 +1212,7 @@ void Song::loadProject( const QString & fileName ) bool Song::saveProjectFile( const QString & filename ) { DataFile dataFile( DataFile::SongProject ); + m_savingProject = true; m_tempoModel.saveSettings( dataFile, dataFile.head(), "bpm" ); m_timeSigModel.saveSettings( dataFile, dataFile.head(), "timesig" ); @@ -1233,6 +1234,8 @@ bool Song::saveProjectFile( const QString & filename ) saveControllerStates( dataFile, dataFile.content() ); + m_savingProject = false; + return dataFile.writeFile( filename ); } @@ -1434,3 +1437,7 @@ QString Song::errorSummary() return errors; } + +bool Song::isSavingProject() const { + return m_savingProject; +} From 64e0e65ab64c6dff4bf745a0355f67d478d701d7 Mon Sep 17 00:00:00 2001 From: Shmuel H Date: Sun, 9 Jun 2019 09:30:35 +0300 Subject: [PATCH 02/10] VersionedSaveDialog: Add support for a custom option dialog. --- include/VersionedSaveDialog.h | 10 +++++++++ src/gui/dialogs/VersionedSaveDialog.cpp | 28 +++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/include/VersionedSaveDialog.h b/include/VersionedSaveDialog.h index 781c6b71cb6..2e30e9f095c 100644 --- a/include/VersionedSaveDialog.h +++ b/include/VersionedSaveDialog.h @@ -29,15 +29,25 @@ #define VERSIONEDSAVEDIALOG_H #include "FileDialog.h" +#include "Song.h" class QLineEdit; +class LedCheckBox; +class SaveOptionsWidget : public QWidget { +public: + SaveOptionsWidget(Song::SaveOptions &saveOptions); + +private: + LedCheckBox *m_discardMIDIConnectionsCheckbox; +}; class VersionedSaveDialog : public FileDialog { Q_OBJECT public: explicit VersionedSaveDialog( QWidget *parent = 0, + QWidget *saveOptionsWidget = nullptr, const QString &caption = QString(), const QString &directory = QString(), const QString &filter = QString() ); diff --git a/src/gui/dialogs/VersionedSaveDialog.cpp b/src/gui/dialogs/VersionedSaveDialog.cpp index e2acff590c4..157d48fbbe6 100644 --- a/src/gui/dialogs/VersionedSaveDialog.cpp +++ b/src/gui/dialogs/VersionedSaveDialog.cpp @@ -28,13 +28,15 @@ #include #include #include +#include +#include #include "VersionedSaveDialog.h" - - +#include "LedCheckbox.h" VersionedSaveDialog::VersionedSaveDialog( QWidget *parent, + QWidget *saveOptionsWidget, const QString &caption, const QString &directory, const QString &filter ) : @@ -63,6 +65,17 @@ VersionedSaveDialog::VersionedSaveDialog( QWidget *parent, hLayout->addWidget( minusButton ); layout->addLayout( hLayout, 2, 1 ); + if (saveOptionsWidget) { + auto *groupBox = new QGroupBox(tr("Save Options")); + auto optionsLayout = new QGridLayout; + + optionsLayout->addWidget(saveOptionsWidget, 0, 0, Qt::AlignLeft); + + groupBox->setLayout(optionsLayout); + + layout->addWidget(groupBox, layout->rowCount()+1, 0, 1, -1); + } + // Connect + and - buttons connect( plusButton, SIGNAL( clicked() ), this, SLOT( incrementVersion() )); connect( minusButton, SIGNAL( clicked() ), this, SLOT( decrementVersion() )); @@ -160,3 +173,14 @@ bool VersionedSaveDialog::fileExistsQuery( QString FileName, QString WindowTitle } return fileExists; } + +SaveOptionsWidget::SaveOptionsWidget(Song::SaveOptions &saveOptions) { + auto *layout = new QVBoxLayout(); + + m_discardMIDIConnectionsCheckbox = new LedCheckBox( nullptr ); + m_discardMIDIConnectionsCheckbox->setText(tr( "Discard MIDI connections")); + m_discardMIDIConnectionsCheckbox->setModel(&saveOptions.discardMIDIConnections); + layout->addWidget( m_discardMIDIConnectionsCheckbox ); + + setLayout(layout); +} From dbef39fbbbb3c6cede0ea6cca77df790e312038d Mon Sep 17 00:00:00 2001 From: Shmuel H Date: Sun, 9 Jun 2019 09:11:15 +0300 Subject: [PATCH 03/10] AutomatableModel: Support the discardMIDIConnections save option. --- src/core/AutomatableModel.cpp | 50 ++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/src/core/AutomatableModel.cpp b/src/core/AutomatableModel.cpp index 1780da5e186..1c5c9716325 100644 --- a/src/core/AutomatableModel.cpp +++ b/src/core/AutomatableModel.cpp @@ -31,6 +31,7 @@ #include "LocaleHelper.h" #include "Mixer.h" #include "ProjectJournal.h" +#include "Song.h" long AutomatableModel::s_periodCounter = 0; @@ -132,32 +133,37 @@ void AutomatableModel::saveSettings( QDomDocument& doc, QDomElement& element, co } if( m_controllerConnection && m_controllerConnection->getController()->type() - != Controller::DummyController ) - { - QDomElement controllerElement; - - // get "connection" element (and create it if needed) - QDomNode node = element.namedItem( "connection" ); - if( node.isElement() ) - { - controllerElement = node.toElement(); - } - else - { - controllerElement = doc.createElement( "connection" ); - element.appendChild( controllerElement ); - } + != Controller::DummyController) { + // Skip saving MIDI connections if we're saving project and + // the discardMIDIConnections option is true. + if (!Engine::getSong()->isSavingProject() + || !Engine::getSong()->getSaveOptions().discardMIDIConnections.value() + || m_controllerConnection->getController()->type() != Controller::MidiController) { + QDomElement controllerElement; + + // get "connection" element (and create it if needed) + QDomNode node = element.namedItem( "connection" ); + if (node.isElement()) + { + controllerElement = node.toElement(); + } + else + { + controllerElement = doc.createElement( "connection" ); + element.appendChild( controllerElement ); + } - bool mustQuote = mustQuoteName(name); - QString elementName = mustQuote ? "controllerconnection" + bool mustQuote = mustQuoteName( name ); + QString elementName = mustQuote ? "controllerconnection" : name; - QDomElement element = doc.createElement( elementName ); - if(mustQuote) - element.setAttribute( "nodename", name ); - m_controllerConnection->saveSettings( doc, element ); + QDomElement element = doc.createElement( elementName ); + if (mustQuote) + element.setAttribute( "nodename", name ); + m_controllerConnection->saveSettings( doc, element ); - controllerElement.appendChild( element ); + controllerElement.appendChild( element ); + } } } From c68859dec6c382409ef5169301ac9e8648298480 Mon Sep 17 00:00:00 2001 From: Shmuel H Date: Sun, 9 Jun 2019 09:11:47 +0300 Subject: [PATCH 04/10] InstrumentTrack: Support the discardMIDIConnections save option. --- src/tracks/InstrumentTrack.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/tracks/InstrumentTrack.cpp b/src/tracks/InstrumentTrack.cpp index 6c95f3c9a23..cd60dae0e9b 100644 --- a/src/tracks/InstrumentTrack.cpp +++ b/src/tracks/InstrumentTrack.cpp @@ -749,7 +749,12 @@ void InstrumentTrack::saveTrackSpecificSettings( QDomDocument& doc, QDomElement m_soundShaping.saveState( doc, thisElement ); m_noteStacking.saveState( doc, thisElement ); m_arpeggio.saveState( doc, thisElement ); - m_midiPort.saveState( doc, thisElement ); + + // Don't save midi port info if the user chose to. + if (Engine::getSong()->isSavingProject() + && !Engine::getSong()->getSaveOptions().discardMIDIConnections.value()) + m_midiPort.saveState( doc, thisElement ); + m_audioPort.effects()->saveState( doc, thisElement ); } From ea09e95f60bed72405b1f52b0cfe59df1d76957a Mon Sep 17 00:00:00 2001 From: Shmuel H Date: Sun, 9 Jun 2019 09:12:35 +0300 Subject: [PATCH 05/10] SaveOptions: Show the save option dialog on "save as". --- src/core/Song.cpp | 6 +++++- src/gui/MainWindow.cpp | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/core/Song.cpp b/src/core/Song.cpp index 274fff2b677..0cf7af8a507 100644 --- a/src/core/Song.cpp +++ b/src/core/Song.cpp @@ -1268,7 +1268,11 @@ bool Song::guiSaveProjectAs( const QString & _file_name ) m_oldFileName = m_fileName; setProjectFileName(_file_name); - if(!guiSaveProject()) + bool saveResult = guiSaveProject(); + // After saving as, restore default save options. + m_saveOptions.setDefaultOptions(); + + if(saveResult) { // Saving failed. Restore old filenames. setProjectFileName(m_oldFileName); diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 424c23d26e6..5d1dbf66673 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -922,7 +922,8 @@ bool MainWindow::saveProject() bool MainWindow::saveProjectAs() { - VersionedSaveDialog sfd( this, tr( "Save Project" ), "", + auto optionsWidget = new SaveOptionsWidget(Engine::getSong()->getSaveOptions()); + VersionedSaveDialog sfd( this, optionsWidget, tr( "Save Project" ), "", tr( "LMMS Project" ) + " (*.mmpz *.mmp);;" + tr( "LMMS Project Template" ) + " (*.mpt)" ); QString f = Engine::getSong()->projectFileName(); From b94ab2bc156cbb171cb5bba9b6f3de2ca179cd58 Mon Sep 17 00:00:00 2001 From: Shmuel H Date: Sun, 9 Jun 2019 13:55:57 +0300 Subject: [PATCH 06/10] Codestyle fixup --- src/core/AutomatableModel.cpp | 54 ++++++++++++------------- src/gui/dialogs/VersionedSaveDialog.cpp | 10 ++--- 2 files changed, 30 insertions(+), 34 deletions(-) diff --git a/src/core/AutomatableModel.cpp b/src/core/AutomatableModel.cpp index 1c5c9716325..c33777c75b5 100644 --- a/src/core/AutomatableModel.cpp +++ b/src/core/AutomatableModel.cpp @@ -132,38 +132,34 @@ void AutomatableModel::saveSettings( QDomDocument& doc, QDomElement& element, co } } - if( m_controllerConnection && m_controllerConnection->getController()->type() - != Controller::DummyController) { - // Skip saving MIDI connections if we're saving project and - // the discardMIDIConnections option is true. - if (!Engine::getSong()->isSavingProject() - || !Engine::getSong()->getSaveOptions().discardMIDIConnections.value() - || m_controllerConnection->getController()->type() != Controller::MidiController) { - QDomElement controllerElement; - - // get "connection" element (and create it if needed) - QDomNode node = element.namedItem( "connection" ); - if (node.isElement()) - { - controllerElement = node.toElement(); - } - else - { - controllerElement = doc.createElement( "connection" ); - element.appendChild( controllerElement ); - } + // Skip saving MIDI connections if we're saving project and + // the discardMIDIConnections option is true. + auto controllerType = m_controllerConnection->getController()->type(); + bool skipMidiController = Engine::getSong()->isSavingProject() + && Engine::getSong()->getSaveOptions().discardMIDIConnections.value(); + if (m_controllerConnection && controllerType != Controller::DummyController + && !(skipMidiController && controllerType == Controller::MidiController)) { + QDomElement controllerElement; + + // get "connection" element (and create it if needed) + QDomNode node = element.namedItem( "connection" ); + if (node.isElement()) { + controllerElement = node.toElement(); + } else { + controllerElement = doc.createElement( "connection" ); + element.appendChild( controllerElement ); + } - bool mustQuote = mustQuoteName( name ); - QString elementName = mustQuote ? "controllerconnection" - : name; + bool mustQuote = mustQuoteName( name ); + QString elementName = mustQuote ? "controllerconnection" + : name; - QDomElement element = doc.createElement( elementName ); - if (mustQuote) - element.setAttribute( "nodename", name ); - m_controllerConnection->saveSettings( doc, element ); + QDomElement element = doc.createElement( elementName ); + if (mustQuote) + element.setAttribute( "nodename", name ); + m_controllerConnection->saveSettings( doc, element ); - controllerElement.appendChild( element ); - } + controllerElement.appendChild( element ); } } diff --git a/src/gui/dialogs/VersionedSaveDialog.cpp b/src/gui/dialogs/VersionedSaveDialog.cpp index 157d48fbbe6..18993c23bf4 100644 --- a/src/gui/dialogs/VersionedSaveDialog.cpp +++ b/src/gui/dialogs/VersionedSaveDialog.cpp @@ -66,14 +66,14 @@ VersionedSaveDialog::VersionedSaveDialog( QWidget *parent, layout->addLayout( hLayout, 2, 1 ); if (saveOptionsWidget) { - auto *groupBox = new QGroupBox(tr("Save Options")); + auto groupBox = new QGroupBox(tr("Save Options")); auto optionsLayout = new QGridLayout; optionsLayout->addWidget(saveOptionsWidget, 0, 0, Qt::AlignLeft); groupBox->setLayout(optionsLayout); - layout->addWidget(groupBox, layout->rowCount()+1, 0, 1, -1); + layout->addWidget(groupBox, layout->rowCount() + 1, 0, 1, -1); } // Connect + and - buttons @@ -177,10 +177,10 @@ bool VersionedSaveDialog::fileExistsQuery( QString FileName, QString WindowTitle SaveOptionsWidget::SaveOptionsWidget(Song::SaveOptions &saveOptions) { auto *layout = new QVBoxLayout(); - m_discardMIDIConnectionsCheckbox = new LedCheckBox( nullptr ); - m_discardMIDIConnectionsCheckbox->setText(tr( "Discard MIDI connections")); + m_discardMIDIConnectionsCheckbox = new LedCheckBox(nullptr); + m_discardMIDIConnectionsCheckbox->setText(tr("Discard MIDI connections")); m_discardMIDIConnectionsCheckbox->setModel(&saveOptions.discardMIDIConnections); - layout->addWidget( m_discardMIDIConnectionsCheckbox ); + layout->addWidget(m_discardMIDIConnectionsCheckbox); setLayout(layout); } From 316fab8a4528806dfc99805347250411c8b7d00d Mon Sep 17 00:00:00 2001 From: Shmuel H Date: Sun, 9 Jun 2019 13:58:05 +0300 Subject: [PATCH 07/10] another codestyle fixup --- src/tracks/InstrumentTrack.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tracks/InstrumentTrack.cpp b/src/tracks/InstrumentTrack.cpp index cd60dae0e9b..a7809a077ef 100644 --- a/src/tracks/InstrumentTrack.cpp +++ b/src/tracks/InstrumentTrack.cpp @@ -753,7 +753,9 @@ void InstrumentTrack::saveTrackSpecificSettings( QDomDocument& doc, QDomElement // Don't save midi port info if the user chose to. if (Engine::getSong()->isSavingProject() && !Engine::getSong()->getSaveOptions().discardMIDIConnections.value()) + { m_midiPort.saveState( doc, thisElement ); + } m_audioPort.effects()->saveState( doc, thisElement ); } From 786169f5c2bcd2304be4dd856c75b5d4fd32f388 Mon Sep 17 00:00:00 2001 From: Shmuel H Date: Sun, 9 Jun 2019 14:04:17 +0300 Subject: [PATCH 08/10] aand another codestyle fixup --- src/core/AutomatableModel.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/core/AutomatableModel.cpp b/src/core/AutomatableModel.cpp index c33777c75b5..4e1a181ab95 100644 --- a/src/core/AutomatableModel.cpp +++ b/src/core/AutomatableModel.cpp @@ -138,24 +138,27 @@ void AutomatableModel::saveSettings( QDomDocument& doc, QDomElement& element, co bool skipMidiController = Engine::getSong()->isSavingProject() && Engine::getSong()->getSaveOptions().discardMIDIConnections.value(); if (m_controllerConnection && controllerType != Controller::DummyController - && !(skipMidiController && controllerType == Controller::MidiController)) { + && !(skipMidiController && controllerType == Controller::MidiController)) + { QDomElement controllerElement; // get "connection" element (and create it if needed) QDomNode node = element.namedItem( "connection" ); - if (node.isElement()) { + if(node.isElement()) + { controllerElement = node.toElement(); - } else { + } + else + { controllerElement = doc.createElement( "connection" ); element.appendChild( controllerElement ); } - bool mustQuote = mustQuoteName( name ); - QString elementName = mustQuote ? "controllerconnection" - : name; + bool mustQuote = mustQuoteName(name); + QString elementName = mustQuote ? "controllerconnection" : name; QDomElement element = doc.createElement( elementName ); - if (mustQuote) + if(mustQuote) element.setAttribute( "nodename", name ); m_controllerConnection->saveSettings( doc, element ); From ed44b6c4accaebc1cc120c765cae36ca7acb9b22 Mon Sep 17 00:00:00 2001 From: Shmuel H Date: Sun, 9 Jun 2019 14:06:21 +0300 Subject: [PATCH 09/10] another fixup --- src/core/AutomatableModel.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/core/AutomatableModel.cpp b/src/core/AutomatableModel.cpp index 4e1a181ab95..7ba2876e6eb 100644 --- a/src/core/AutomatableModel.cpp +++ b/src/core/AutomatableModel.cpp @@ -144,7 +144,7 @@ void AutomatableModel::saveSettings( QDomDocument& doc, QDomElement& element, co // get "connection" element (and create it if needed) QDomNode node = element.namedItem( "connection" ); - if(node.isElement()) + if( node.isElement() ) { controllerElement = node.toElement(); } @@ -155,7 +155,8 @@ void AutomatableModel::saveSettings( QDomDocument& doc, QDomElement& element, co } bool mustQuote = mustQuoteName(name); - QString elementName = mustQuote ? "controllerconnection" : name; + QString elementName = mustQuote ? "controllerconnection" + : name; QDomElement element = doc.createElement( elementName ); if(mustQuote) From 59f4f885529a3c5279255167b66e9ceddac02483 Mon Sep 17 00:00:00 2001 From: Shmuel H Date: Sun, 9 Jun 2019 14:14:31 +0300 Subject: [PATCH 10/10] Few more fixups and done --- src/core/AutomatableModel.cpp | 6 ++++-- src/core/Song.cpp | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/core/AutomatableModel.cpp b/src/core/AutomatableModel.cpp index 7ba2876e6eb..9b52ce8fe61 100644 --- a/src/core/AutomatableModel.cpp +++ b/src/core/AutomatableModel.cpp @@ -134,7 +134,9 @@ void AutomatableModel::saveSettings( QDomDocument& doc, QDomElement& element, co // Skip saving MIDI connections if we're saving project and // the discardMIDIConnections option is true. - auto controllerType = m_controllerConnection->getController()->type(); + auto controllerType = m_controllerConnection + ? m_controllerConnection->getController()->type() + : Controller::DummyController; bool skipMidiController = Engine::getSong()->isSavingProject() && Engine::getSong()->getSaveOptions().discardMIDIConnections.value(); if (m_controllerConnection && controllerType != Controller::DummyController @@ -156,7 +158,7 @@ void AutomatableModel::saveSettings( QDomDocument& doc, QDomElement& element, co bool mustQuote = mustQuoteName(name); QString elementName = mustQuote ? "controllerconnection" - : name; + : name; QDomElement element = doc.createElement( elementName ); if(mustQuote) diff --git a/src/core/Song.cpp b/src/core/Song.cpp index 0cf7af8a507..336aa3df273 100644 --- a/src/core/Song.cpp +++ b/src/core/Song.cpp @@ -1272,7 +1272,7 @@ bool Song::guiSaveProjectAs( const QString & _file_name ) // After saving as, restore default save options. m_saveOptions.setDefaultOptions(); - if(saveResult) + if(!saveResult) { // Saving failed. Restore old filenames. setProjectFileName(m_oldFileName);