From 9e8020719cf0b0a714e714eb0fa8ebff5e262bc5 Mon Sep 17 00:00:00 2001 From: Oskar Wallgren Date: Thu, 10 Dec 2015 02:53:27 +0100 Subject: [PATCH] Recovery file fixes --- include/MainWindow.h | 30 +++++++++-- src/core/main.cpp | 119 ++++++++++++++++++++++++++++++++++++++--- src/gui/MainWindow.cpp | 90 +++++++++++++++++++++++++++---- 3 files changed, 218 insertions(+), 21 deletions(-) diff --git a/include/MainWindow.h b/include/MainWindow.h index 65fa83ea5..31089f9ed 100644 --- a/include/MainWindow.h +++ b/include/MainWindow.h @@ -81,6 +81,29 @@ public: /// bool mayChangeProject(bool stopPlayback); + void autoSaveTimerStart() + { + m_autoSaveTimer.start( 1000 * 60 ); // 1 minute + } + + enum SessionState + { + Normal, + Recover, + Limited, + }; + + void setSession( SessionState session ) + { + m_session = session; + } + + SessionState getSession() + { + return m_session; + } + + void sessionCleanup(); void clearKeyModifiers(); @@ -131,6 +154,8 @@ public slots: void undo(); void redo(); + void autoSave(); + void runAutoSave(); protected: virtual void closeEvent( QCloseEvent * _ce ); @@ -150,7 +175,6 @@ private: void toggleWindow( QWidget *window, bool forceShow = false ); void refocus(); - QMdiArea * m_workspace; QWidget * m_toolBar; @@ -187,6 +211,8 @@ private: ToolButton * m_metronomeToggle; + SessionState m_session; + private slots: void browseHelp(); void fillTemplatesMenu(); @@ -198,8 +224,6 @@ private slots: void onToggleMetronome(); - void autoSave(); - signals: void periodicUpdate(); void initProgress(const QString &msg); diff --git a/src/core/main.cpp b/src/core/main.cpp index 6351b9062..fb3598c4d 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #ifdef LMMS_BUILD_WIN32 @@ -61,6 +62,7 @@ #include "MemoryManager.h" #include "ConfigManager.h" #include "NotePlayHandle.h" +#include "embed.h" #include "Engine.h" #include "GuiApplication.h" #include "ImportFilter.h" @@ -644,13 +646,102 @@ int main( int argc, char * * argv ) // recover a file? QString recoveryFile = ConfigManager::inst()->recoveryFile(); - if( QFileInfo(recoveryFile).exists() && - QMessageBox::question( gui->mainWindow(), MainWindow::tr( "Project recovery" ), - MainWindow::tr( "It looks like the last session did not end properly. " - "Do you want to recover the project of this session?" ), - QMessageBox::Yes | QMessageBox::No ) == QMessageBox::Yes ) + bool recoveryFilePresent = QFileInfo( recoveryFile ).exists() && + QFileInfo( recoveryFile ).isFile(); + bool autoSaveEnabled = + ConfigManager::inst()->value( "ui", "enableautosave" ).toInt(); + if( recoveryFilePresent ) { - fileToLoad = recoveryFile; + QMessageBox mb; + mb.setWindowTitle( MainWindow::tr( "Project recovery" ) ); + mb.setText( QString( + "" + "

%1

" + "" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + "
%2%3
%4%5
%6%7
%8%9
" + "" ).arg( + MainWindow::tr( "There is a recovery file present. " + "It looks like the last session did not end " + "properly or another instance of LMMS is " + "already running. Do you want to recover the " + "project of this session?" ), + MainWindow::tr( "Recover" ), + MainWindow::tr( "Recover the file. Please don't run " + "multiple instances of LMMS when you do this." ), + MainWindow::tr( "Ignore" ), + MainWindow::tr( "Launch LMMS as usual but with " + "automatic backup disabled to prevent the " + "present recover file from being overwritten." ), + MainWindow::tr( "Discard" ), + MainWindow::tr( "Launch a default session and delete " + "the restored files. This is not reversible." ), + MainWindow::tr( "Quit" ), + MainWindow::tr( "Shut down LMMS with no further action." ) + ) ); + + mb.setIcon( QMessageBox::Warning ); + mb.setWindowIcon( embed::getIconPixmap( "icon" ) ); + + mb.setStandardButtons( QMessageBox::Ok | + QMessageBox::Discard ); + + mb.setButtonText( QMessageBox::Ok, + MainWindow::tr( "Recover" ) ); + + QAbstractButton * recover; + QAbstractButton * discard; + QPushButton * ignore; + QPushButton * exit; + + recover = mb.QMessageBox::button( QMessageBox::Ok ); + discard = mb.QMessageBox::button( QMessageBox::Discard ); + ignore = mb.addButton( MainWindow::tr( "Ignore" ), + QMessageBox::NoRole ); + ignore->setIcon( embed::getIconPixmap( "no_entry" ) ); + exit = mb.addButton( MainWindow::tr( "Exit" ), + QMessageBox::RejectRole ); + exit->setIcon( embed::getIconPixmap( "exit" ) ); + + mb.setDefaultButton( QMessageBox::Ok ); + mb.setEscapeButton( exit ); + + mb.exec(); + if( mb.clickedButton() == discard ) + { + gui->mainWindow()->sessionCleanup(); + } + else if( mb.clickedButton() == recover ) // ::Recover + { + fileToLoad = recoveryFile; + gui->mainWindow()->setSession( MainWindow::SessionState::Recover ); + } + else if( mb.clickedButton() == ignore ) + { + if( autoSaveEnabled ) + { + gui->mainWindow()->setSession( MainWindow::SessionState::Limited ); + } + } + else // Exit + { + return 0; + } } // we try to load given file @@ -689,10 +780,13 @@ int main( int argc, char * * argv ) { // If enabled, open last project if there is one. Else, create - // a new one. + // a new one. Also skip recently opened file if limited session to + // lower the chance of opening an already opened file. if( ConfigManager::inst()-> value( "app", "openlastproject" ).toInt() && - !ConfigManager::inst()->recentlyOpenedProjects().isEmpty() ) + !ConfigManager::inst()->recentlyOpenedProjects().isEmpty() && + gui->mainWindow()->getSession() + != MainWindow::SessionState::Limited ) { QString f = ConfigManager::inst()-> recentlyOpenedProjects().first(); @@ -720,6 +814,15 @@ int main( int argc, char * * argv ) gui->mainWindow()->showMaximized(); } } + // Finally we start the auto save timer and also trigger the + // autosave one time as recover.mmp is a signal to possible other + // instances of LMMS. + if( autoSaveEnabled && + gui->mainWindow()->getSession() != MainWindow::SessionState::Limited ) + { + gui->mainWindow()->runAutoSave(); + gui->mainWindow()->autoSaveTimerStart(); + } } const int ret = app->exec(); diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 97f30a1ad..41cf2112a 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -79,7 +80,8 @@ MainWindow::MainWindow() : m_toolsMenu( NULL ), m_autoSaveTimer( this ), m_viewMenu( NULL ), - m_metronomeToggle( 0 ) + m_metronomeToggle( 0 ), + m_session( Normal ) { setAttribute( Qt::WA_DeleteOnClose ); @@ -201,7 +203,10 @@ MainWindow::MainWindow() : { // connect auto save connect(&m_autoSaveTimer, SIGNAL(timeout()), this, SLOT(autoSave())); - m_autoSaveTimer.start(1000 * 60); // 1 minute + // The auto save function mustn't run until there is a project + // to save or it will run over recover.mmp if you hesitate at the + // recover messagebox for a minute. It is now started in main. + // See autoSaveTimerStart() in MainWindow.h } connect( Engine::getSong(), SIGNAL( playbackStateChanged() ), @@ -650,6 +655,14 @@ void MainWindow::resetWindowTitle() { title += '*'; } + if( getSession() == Recover ) + { + title += " - " + tr( "Recover session. Please save your work!" ); + } + if( getSession() == Limited ) + { + title += " - " + tr( "Automatic backup disabled. Remember to save your work!" ); + } setWindowTitle( title + " - " + tr( "LMMS %1" ).arg( LMMS_VERSION ) ); } @@ -659,17 +672,31 @@ void MainWindow::resetWindowTitle() bool MainWindow::mayChangeProject(bool stopPlayback) { if( stopPlayback ) + { Engine::getSong()->stop(); + } - if( !Engine::getSong()->isModified() ) + if( !Engine::getSong()->isModified() && getSession() != Recover ) { return( true ); } - QMessageBox mb( tr( "Project not saved" ), - tr( "The current project was modified since " + // Separate message strings for modified and recovered files + QString messageTitleRecovered = tr( "Recovered project not saved" ); + QString messageRecovered = tr( "This project was recovered from the " + "previous session. It is currently " + "unsaved and will be lost if you don't " + "save it. Do you want to save it now?" ); + + QString messageTitleUnsaved = tr( "Project not saved" ); + QString messageUnsaved = tr( "The current project was modified since " "last saving. Do you want to save it " - "now?" ), + "now?" ); + + QMessageBox mb( ( getSession() == Recover ? + messageTitleRecovered : messageTitleUnsaved ), + ( getSession() == Recover ? + messageRecovered : messageUnsaved ), QMessageBox::Question, QMessageBox::Save, QMessageBox::Discard, @@ -683,6 +710,10 @@ bool MainWindow::mayChangeProject(bool stopPlayback) } else if( answer == QMessageBox::Discard ) { + if( getSession() == Recover ) + { + sessionCleanup(); + } return( true ); } @@ -789,6 +820,7 @@ void MainWindow::createNewProject() { Engine::getSong()->createNewProject(); } + runAutoSave(); } @@ -807,6 +839,7 @@ void MainWindow::createNewProjectFromTemplate( QAction * _idx ) Engine::getSong()->createNewProjectFromTemplate( dirBase + _idx->text() + ".mpt" ); } + runAutoSave(); } @@ -831,6 +864,7 @@ void MainWindow::openProject() setCursor( Qt::ArrowCursor ); } } + runAutoSave(); } @@ -874,6 +908,7 @@ void MainWindow::openRecentlyOpenedProject( QAction * _action ) ConfigManager::inst()->addRecentlyOpenedProject( f ); setCursor( Qt::ArrowCursor ); } + runAutoSave(); } @@ -888,6 +923,10 @@ bool MainWindow::saveProject() else { Engine::getSong()->guiSaveProject(); + if( getSession() == Recover ) + { + sessionCleanup(); + } } return( true ); } @@ -919,8 +958,11 @@ bool MainWindow::saveProjectAs() { fname += ".mpt"; } - Engine::getSong()->guiSaveProjectAs( - fname ); + Engine::getSong()->guiSaveProjectAs( fname ); + if( getSession() == Recover ) + { + sessionCleanup(); + } return( true ); } return( false ); @@ -1189,6 +1231,8 @@ void MainWindow::updateViewMenu() } + + void MainWindow::updateConfig( QAction * _who ) { QString tag = _who->data().toString(); @@ -1306,8 +1350,12 @@ void MainWindow::closeEvent( QCloseEvent * _ce ) if( mayChangeProject(true) ) { // delete recovery file - QFile::remove(ConfigManager::inst()->recoveryFile()); - _ce->accept(); + if( ConfigManager::inst()->value( "ui", "enableautosave" ).toInt() + && getSession() != Limited ) + { + sessionCleanup(); + _ce->accept(); + } } else { @@ -1318,6 +1366,16 @@ void MainWindow::closeEvent( QCloseEvent * _ce ) +void MainWindow::sessionCleanup() +{ + // delete recover session files + QFile::remove( ConfigManager::inst()->recoveryFile() ); + setSession( Normal ); +} + + + + void MainWindow::focusOutEvent( QFocusEvent * _fe ) { // when loosing focus we do not receive key-(release!)-events anymore, @@ -1459,3 +1517,15 @@ void MainWindow::autoSave() QTimer::singleShot( 10*1000, this, SLOT( autoSave() ) ); } } + + +// For the occasional auto save action that isn't run +// from the timer where we need to do extra tests. +void MainWindow::runAutoSave() +{ + if( ConfigManager::inst()->value( "ui", "enableautosave" ).toInt() && + getSession() != Limited ) + { + autoSave(); + } +}