From 01265ace66a360185d2581da7c9d27a974050c5f Mon Sep 17 00:00:00 2001 From: Oskar Wallgren Date: Fri, 17 Nov 2017 02:03:49 +0100 Subject: [PATCH] Default project when cancelling project loading (#3941) Default project when cancelling project loading If a user isn't aware that the loading of a project has been cancelled, it may be in an incomplete state. Saving such a project will overwrite the original file and result in data loss. This is solved by loading the default project on cancelling project loading. Add Mixer::clearNewPlayHandles() to prevent crash when cancelling loading of a single streamed instrument. --- include/Mixer.h | 1 + include/Song.h | 13 +++++++++++++ src/core/Mixer.cpp | 14 ++++++++++++++ src/core/Song.cpp | 12 ++++++++++-- src/core/TrackContainer.cpp | 10 ++++++++++ 5 files changed, 48 insertions(+), 2 deletions(-) diff --git a/include/Mixer.h b/include/Mixer.h index 8368e8434..1c3780b1b 100644 --- a/include/Mixer.h +++ b/include/Mixer.h @@ -155,6 +155,7 @@ public: void initDevices(); void clear(); + void clearNewPlayHandles(); // audio-device-stuff diff --git a/include/Song.h b/include/Song.h index b8879ad9b..0ba8a3503 100644 --- a/include/Song.h +++ b/include/Song.h @@ -33,6 +33,7 @@ #include "TrackContainer.h" #include "Controller.h" #include "MeterModel.h" +#include "Mixer.h" #include "VstSyncController.h" @@ -229,6 +230,17 @@ public: return m_loadingProject; } + void loadingCancelled() + { + m_isCancelled = true; + Engine::mixer()->clearNewPlayHandles(); + } + + bool isCancelled() + { + return m_isCancelled; + } + bool isModified() const { return m_modified; @@ -358,6 +370,7 @@ private: volatile bool m_paused; bool m_loadingProject; + bool m_isCancelled; QStringList m_errors; diff --git a/src/core/Mixer.cpp b/src/core/Mixer.cpp index c99d3ab8c..ed8d04a6c 100644 --- a/src/core/Mixer.cpp +++ b/src/core/Mixer.cpp @@ -501,6 +501,20 @@ void Mixer::clear() +void Mixer::clearNewPlayHandles() +{ + requestChangeInModel(); + for( LocklessListElement * e = m_newPlayHandles.popList(); e; ) + { + LocklessListElement * next = e->next; + m_newPlayHandles.free( e ); + e = next; + } + doneChangeInModel(); +} + + + // removes all play-handles. this is necessary, when the song is stopped -> // all remaining notes etc. would be played until their end void Mixer::clearInternal() diff --git a/src/core/Song.cpp b/src/core/Song.cpp index 01071668c..5f8e75320 100644 --- a/src/core/Song.cpp +++ b/src/core/Song.cpp @@ -86,6 +86,7 @@ Song::Song() : m_playing( false ), m_paused( false ), m_loadingProject( false ), + m_isCancelled( false ), m_playMode( Mode_None ), m_length( 0 ), m_patternToPlay( NULL ), @@ -1074,7 +1075,7 @@ void Song::loadProject( const QString & fileName ) } } - while( !node.isNull() ) + while( !node.isNull() && !isCancelled() ) { if( node.isElement() ) { @@ -1133,6 +1134,13 @@ void Song::loadProject( const QString & fileName ) emit projectLoaded(); + if( isCancelled() ) + { + m_isCancelled = false; + createNewProject(); + return; + } + if ( hasErrors()) { if ( gui ) @@ -1278,7 +1286,7 @@ void Song::saveControllerStates( QDomDocument & doc, QDomElement & element ) void Song::restoreControllerStates( const QDomElement & element ) { QDomNode node = element.firstChild(); - while( !node.isNull() ) + while( !node.isNull() && !isCancelled() ) { Controller * c = Controller::create( node.toElement(), this ); Q_ASSERT( c != NULL ); diff --git a/src/core/TrackContainer.cpp b/src/core/TrackContainer.cpp index 6e406b0a9..6877e6b1f 100644 --- a/src/core/TrackContainer.cpp +++ b/src/core/TrackContainer.cpp @@ -33,12 +33,14 @@ #include "AutomationTrack.h" #include "BBTrack.h" #include "BBTrackContainer.h" +#include "embed.h" #include "TrackContainer.h" #include "InstrumentTrack.h" #include "Song.h" #include "GuiApplication.h" #include "MainWindow.h" +#include "TextFloat.h" TrackContainer::TrackContainer() : Model( NULL ), @@ -110,6 +112,14 @@ void TrackContainer::loadSettings( const QDomElement & _this ) QEventLoop::AllEvents, 100 ); if( pd->wasCanceled() ) { + if ( gui ) + { + TextFloat::displayMessage( tr( "Loading cancelled" ), + tr( "Project loading was cancelled." ), + embed::getIconPixmap( "project_file", 24, 24 ), + 2000 ); + } + Engine::getSong()->loadingCancelled(); break; } }