diff --git a/mptrack/AutoSaver.cpp b/mptrack/AutoSaver.cpp index f19c1b669c..4c008ca0c1 100644 --- a/mptrack/AutoSaver.cpp +++ b/mptrack/AutoSaver.cpp @@ -28,7 +28,7 @@ OPENMPT_NAMESPACE_BEGIN CAutoSaver::CAutoSaver() - : m_lastSave(timeGetTime()) + : m_lastSave{timeGetTime()} { } @@ -53,32 +53,38 @@ uint32 CAutoSaver::GetHistoryDepth() const return TrackerSettings::Instance().AutosaveHistoryDepth; } -uint32 CAutoSaver::GetSaveInterval() const +std::chrono::minutes CAutoSaver::GetSaveInterval() const { - return TrackerSettings::Instance().AutosaveIntervalMinutes; + return std::chrono::minutes{TrackerSettings::Instance().AutosaveIntervalMinutes.Get()}; } -bool CAutoSaver::DoSave(DWORD curTime) +std::chrono::days CAutoSaver::GetRetentionTime() const +{ + return std::chrono::days{TrackerSettings::Instance().AutosaveRetentionTimeDays.Get()}; +} + + +bool CAutoSaver::DoSave() { // Do nothing if we are already saving, or if time to save has not been reached yet. - if(m_saveInProgress || !CheckTimer(curTime)) + if(m_saveInProgress || !CheckTimer(timeGetTime())) return true; bool success = true, clearStatus = false; m_saveInProgress = true; - theApp.BeginWaitCursor(); // Display hour glass + theApp.BeginWaitCursor(); // Display hour glass for(auto &modDoc : theApp.GetOpenDocuments()) { if(modDoc->ModifiedSinceLastAutosave()) { clearStatus = true; - static_cast(theApp.GetMainWnd())->SetHelpText(MPT_CFORMAT("Auto-saving {}...")(modDoc->GetPathNameMpt().GetFilename())); + CMainFrame::GetMainFrame()->SetHelpText(MPT_CFORMAT("Auto-saving {}...")(modDoc->GetPathNameMpt().GetFilename())); if(SaveSingleFile(*modDoc)) { - CleanUpBackups(*modDoc); + CleanUpAutosaves(*modDoc); } else { TrackerSettings::Instance().AutosaveEnabled = false; @@ -87,13 +93,14 @@ bool CAutoSaver::DoSave(DWORD curTime) } } } + CleanUpAutosaves(); m_lastSave = timeGetTime(); theApp.EndWaitCursor(); // End display hour glass m_saveInProgress = false; if(clearStatus) - static_cast(theApp.GetMainWnd())->SetHelpText(_T("")); + CMainFrame::GetMainFrame()->SetHelpText(_T("")); return success; } @@ -101,7 +108,7 @@ bool CAutoSaver::DoSave(DWORD curTime) bool CAutoSaver::CheckTimer(DWORD curTime) const { - return (curTime - m_lastSave) >= GetSaveIntervalMilliseconds(); + return std::chrono::milliseconds{curTime - m_lastSave} >= GetSaveInterval(); } @@ -149,41 +156,19 @@ mpt::PathString CAutoSaver::BuildFileName(const CModDoc &modDoc) const bool CAutoSaver::SaveSingleFile(CModDoc &modDoc) { - // We do not call CModDoc::DoSave as this populates the Recent Files - // list with backups... hence we have duplicated code.. :( - CSoundFile &sndFile = modDoc.GetSoundFile(); - mpt::PathString fileName = BuildFileName(modDoc); // We are actually not going to show the log for autosaved files. ScopedLogCapturer logcapturer(modDoc, _T(""), nullptr, false); - - bool success = false; - mpt::ofstream f(fileName, std::ios::binary); - if(f) - { - switch(modDoc.GetSoundFile().GetBestSaveFormat()) - { - case MOD_TYPE_MOD: success = sndFile.SaveMod(f); break; - case MOD_TYPE_S3M: success = sndFile.SaveS3M(f); break; - case MOD_TYPE_XM: success = sndFile.SaveXM(f); break; - case MOD_TYPE_IT: success = sndFile.SaveIT(f, GetUseOriginalPath() ? fileName : mpt::PathString{}); break; - case MOD_TYPE_MPT: success = sndFile.SaveIT(f, GetUseOriginalPath() ? fileName : mpt::PathString{}); break; - default: - // nothing - break; - } - } - - return success; + return modDoc.SaveFile(BuildFileName(modDoc), GetUseOriginalPath()); } -void CAutoSaver::CleanUpBackups(const CModDoc &modDoc) const +void CAutoSaver::CleanUpAutosaves(const CModDoc &modDoc) const { // Find all autosave files for this document, and delete the oldest ones if there are more than the user wants. std::vector foundfiles; - FolderScanner scanner(GetBasePath(modDoc, false), FolderScanner::kOnlyFiles, GetBaseName(modDoc) + P_(".AutoSave.*")); + FolderScanner scanner(GetBasePath(modDoc, false), FolderScanner::kOnlyFiles, GetBaseName(modDoc) + P_(".AutoSave.*.*.*")); mpt::PathString fileName; while(scanner.Next(fileName)) { @@ -191,11 +176,53 @@ void CAutoSaver::CleanUpBackups(const CModDoc &modDoc) const } std::sort(foundfiles.begin(), foundfiles.end()); size_t filesToDelete = std::max(static_cast(GetHistoryDepth()), foundfiles.size()) - GetHistoryDepth(); + const bool deletePermanently = TrackerSettings::Instance().AutosaveDeletePermanently; for(size_t i = 0; i < filesToDelete; i++) { - DeleteFile(foundfiles[i].AsNative().c_str()); + DeleteAutosave(foundfiles[i], deletePermanently); } } +// Find all autosave files in the autosave folder and delete all of those older than X days +void CAutoSaver::CleanUpAutosaves() const +{ + if(GetUseOriginalPath() || !GetRetentionTime().count()) + return; + auto path = GetPath(); + if(!mpt::native_fs{}.is_directory(path)) + return; + const std::chrono::seconds maxAge = GetRetentionTime(); + const bool deletePermanently = TrackerSettings::Instance().AutosaveDeletePermanently; + FILETIME sysFileTime; + GetSystemTimeAsFileTime(&sysFileTime); + const int64 currentTime = static_cast(mpt::bit_cast(sysFileTime).QuadPart); + FolderScanner scanner(std::move(path), FolderScanner::kOnlyFiles, P_("*.AutoSave.*.*.*")); + mpt::PathString fileName; + WIN32_FIND_DATA fileInfo; + while(scanner.Next(fileName, &fileInfo)) + { + const auto fileTime = static_cast(mpt::bit_cast(fileInfo.ftLastWriteTime).QuadPart); + const auto timeDiff = std::chrono::seconds{(currentTime - fileTime) / 10000000}; + if(timeDiff >= maxAge) + DeleteAutosave(fileName, deletePermanently); + } +} + + +void CAutoSaver::DeleteAutosave(const mpt::PathString &fileName, bool deletePermanently) +{ + // Create double-null-terminated path list + // Note: We could supply multiple filenames here. However, if the files in total are too big for the recycling bin, + // this will cause all of them to be deleted permanently. If we supply them one by one, at least some of them + // will go to the recycling bin until it is full. + mpt::winstring path = fileName.AsNative() + _T('\0'); + SHFILEOPSTRUCT fos{}; + fos.hwnd = CMainFrame::GetMainFrame()->m_hWnd; + fos.wFunc = FO_DELETE; + fos.pFrom = path.c_str(); + fos.fFlags = (deletePermanently ? 0 : FOF_ALLOWUNDO) | FOF_NO_UI; + SHFileOperation(&fos); +} + OPENMPT_NAMESPACE_END diff --git a/mptrack/AutoSaver.h b/mptrack/AutoSaver.h index 42f7b74dd5..66d70da331 100644 --- a/mptrack/AutoSaver.h +++ b/mptrack/AutoSaver.h @@ -21,28 +21,27 @@ class CAutoSaver public: CAutoSaver(); - bool DoSave(DWORD curTime); + bool DoSave(); bool IsEnabled() const; bool GetUseOriginalPath() const; mpt::PathString GetPath() const; uint32 GetHistoryDepth() const; - uint32 GetSaveInterval() const; - uint32 GetSaveIntervalMilliseconds() const - { - return Clamp(GetSaveInterval(), 0u, (1u << 30) / 60u / 1000u) * 60 * 1000; - } + std::chrono::minutes GetSaveInterval() const; + std::chrono::days GetRetentionTime() const; private: bool SaveSingleFile(CModDoc &modDoc); mpt::PathString GetBasePath(const CModDoc &modDoc, bool createPath) const; mpt::PathString GetBaseName(const CModDoc &modDoc) const; mpt::PathString BuildFileName(const CModDoc &modDoc) const; - void CleanUpBackups(const CModDoc &modDoc) const; + void CleanUpAutosaves(const CModDoc &modDoc) const; + void CleanUpAutosaves() const; bool CheckTimer(DWORD curTime) const; + static void DeleteAutosave(const mpt::PathString &fileName, bool deletePermanently); DWORD m_lastSave = 0; - //Flag to prevent autosave from starting new saving if previous is still in progress. + // Flag to prevent autosave from starting new saving if previous is still in progress. bool m_saveInProgress = false; }; diff --git a/mptrack/FolderScanner.cpp b/mptrack/FolderScanner.cpp index 7ed7c7e7eb..bdbb50ae20 100644 --- a/mptrack/FolderScanner.cpp +++ b/mptrack/FolderScanner.cpp @@ -14,19 +14,18 @@ OPENMPT_NAMESPACE_BEGIN -FolderScanner::FolderScanner(const mpt::PathString &path, FlagSet type, mpt::PathString filter) - : m_paths(1, path) - , m_filter(std::move(filter)) - , m_hFind(INVALID_HANDLE_VALUE) - , m_type(type) +FolderScanner::FolderScanner(mpt::PathString path, FlagSet type, mpt::PathString filter) + : m_paths{1, std::move(path)} + , m_filter{std::move(filter)} + , m_type{type} { - MemsetZero(m_wfd); } FolderScanner::~FolderScanner() { - FindClose(m_hFind); + if(m_hFind != INVALID_HANDLE_VALUE) + FindClose(m_hFind); } #if MPT_COMPILER_MSVC @@ -34,7 +33,7 @@ FolderScanner::~FolderScanner() #pragma warning(push) #pragma warning(disable:6387) // 'HANDLE' could be '0' #endif // MPT_COMPILER_MSVC -bool FolderScanner::Next(mpt::PathString &file) +bool FolderScanner::Next(mpt::PathString &file, WIN32_FIND_DATA *fileInfo) { bool found = false; do @@ -42,13 +41,10 @@ bool FolderScanner::Next(mpt::PathString &file) if(m_hFind == INVALID_HANDLE_VALUE) { if(m_paths.empty()) - { return false; - } - m_currentPath = m_paths.back(); + m_currentPath = m_paths.back().WithTrailingSlash(); m_paths.pop_back(); - m_currentPath = m_currentPath.WithTrailingSlash(); m_hFind = FindFirstFile(mpt::support_long_path((m_currentPath + m_filter).AsNative()).c_str(), &m_wfd); } @@ -62,29 +58,25 @@ bool FolderScanner::Next(mpt::PathString &file) { if(_tcscmp(m_wfd.cFileName, _T("..")) && _tcscmp(m_wfd.cFileName, _T("."))) { + // Add sub directory if(m_type[kFindInSubDirectories]) - { - // Add sub directory m_paths.push_back(file); - } if(m_type[kOnlyDirectories]) - { found = true; - } } } else if(m_type[kOnlyFiles]) { found = true; } + if(found && fileInfo) + *fileInfo = m_wfd; } while((nextFile = FindNextFile(m_hFind, &m_wfd)) != FALSE && !found); } if(nextFile == FALSE) { // Done with this directory, advance to next if(m_hFind != INVALID_HANDLE_VALUE) - { FindClose(m_hFind); - } m_hFind = INVALID_HANDLE_VALUE; } } while(!found); diff --git a/mptrack/FolderScanner.h b/mptrack/FolderScanner.h index c55fcbfa80..292f7c7ba0 100644 --- a/mptrack/FolderScanner.h +++ b/mptrack/FolderScanner.h @@ -27,20 +27,19 @@ class FolderScanner kFindInSubDirectories = 0x04, }; -protected: - std::vector m_paths; - mpt::PathString m_currentPath; - mpt::PathString m_filter; - HANDLE m_hFind; - WIN32_FIND_DATA m_wfd; - FlagSet m_type; - -public: - FolderScanner(const mpt::PathString &path, FlagSet type, mpt::PathString filter = MPT_PATHSTRING("*.*")); + FolderScanner(mpt::PathString path, FlagSet type, mpt::PathString filter = P_("*.*")); ~FolderScanner(); // Return one file or directory at a time in parameter file. Returns true if a file was found (file parameter is valid), false if no more files can be found (file parameter is not touched). - bool Next(mpt::PathString &file); + bool Next(mpt::PathString &file, WIN32_FIND_DATA *fileInfo = nullptr); + +protected: + std::vector m_paths; + mpt::PathString m_currentPath; + const mpt::PathString m_filter; + HANDLE m_hFind = INVALID_HANDLE_VALUE; + WIN32_FIND_DATA m_wfd{}; + const FlagSet m_type; }; MPT_DECLARE_ENUM(FolderScanner::ScanType) diff --git a/mptrack/MainFrm.cpp b/mptrack/MainFrm.cpp index d235071ba8..516d52ca4f 100644 --- a/mptrack/MainFrm.cpp +++ b/mptrack/MainFrm.cpp @@ -2216,17 +2216,14 @@ void CMainFrame::OnTimerGUI() { m_dwTimeSec = time; m_nAvgMixChn = m_nMixChn; - OnUpdateTime(NULL); + OnUpdateTime(nullptr); } } - // Idle Time Check - DWORD curTime = timeGetTime(); - if(m_AutoSaver.IsEnabled()) { - bool success = m_AutoSaver.DoSave(curTime); - if (!success) // autosave failure; bring up options. + bool success = m_AutoSaver.DoSave(); + if(!success) // autosave failure; bring up options. { CMainFrame::m_nLastOptionsPage = OPTIONS_PAGE_PATHS; OnViewOptions(); diff --git a/mptrack/Moddoc.cpp b/mptrack/Moddoc.cpp index 50cf9f2e66..d1012017cd 100644 --- a/mptrack/Moddoc.cpp +++ b/mptrack/Moddoc.cpp @@ -318,65 +318,41 @@ bool CModDoc::OnSaveDocument(const mpt::PathString &filename, const bool setPath if(filename.empty()) return false; - bool ok = false; BeginWaitCursor(); - m_SndFile.m_dwLastSavedWithVersion = Version::Current(); - try + const bool ok = SaveFile(filename, true); + if(ok && m_SndFile.m_SongFlags[SONG_IMPORTED]) { - mpt::IO::SafeOutputFile sf(filename, std::ios::binary, mpt::IO::FlushModeFromBool(TrackerSettings::Instance().MiscFlushFileBuffersOnSave)); - mpt::IO::ofstream &f = sf; - if(f) + const auto formatName = m_SndFile.GetModSpecifications().GetFileExtensionUpper(); + if(!(GetModType() & (MOD_TYPE_MOD | MOD_TYPE_S3M))) { - if(m_SndFile.m_SongFlags[SONG_IMPORTED]) + // Check if any non-supported playback behaviours are enabled due to being imported from a different format + // File saving code will omit those flags automatically, so it's okay if we check and reset them after a successful save only + const auto supportedBehaviours = m_SndFile.GetSupportedPlaybackBehaviour(GetModType()); + bool showWarning = true; + for(size_t i = 0; i < kMaxPlayBehaviours; i++) { - const auto formatName = m_SndFile.GetModSpecifications().GetFileExtensionUpper(); - if(!(GetModType() & (MOD_TYPE_MOD | MOD_TYPE_S3M))) + if(m_SndFile.m_playBehaviour[i] && !supportedBehaviours[i]) { - // Check if any non-supported playback behaviours are enabled due to being imported from a different format - const auto supportedBehaviours = m_SndFile.GetSupportedPlaybackBehaviour(GetModType()); - bool showWarning = true; - for(size_t i = 0; i < kMaxPlayBehaviours; i++) + if(showWarning) { - if(m_SndFile.m_playBehaviour[i] && !supportedBehaviours[i]) - { - if(showWarning) - { - AddToLog(LogWarning, MPT_UFORMAT("Some imported Compatibility Settings that are not supported by the {} format have been disabled. Verify that the module still sounds as intended.") - (formatName)); - showWarning = false; - } - m_SndFile.m_playBehaviour.reset(i); - } + AddToLog(LogWarning, MPT_UFORMAT("Some imported Compatibility Settings that are not supported by the {} format have been disabled. Verify that the module still sounds as intended.")(formatName)); + showWarning = false; } + m_SndFile.m_playBehaviour.reset(i); } - - for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) - { - if(m_SndFile.Instruments[i] && m_SndFile.Instruments[i]->synth.HasScripts()) - { - AddToLog(LogWarning, MPT_UFORMAT("Scripted instruments are not supported by the {} format and will not be exported.")(formatName)); - break; - } - } - if(!m_SndFile.m_globalScript.empty()) - AddToLog(LogWarning, MPT_UFORMAT("Global instrument scripts are not supported by the {} format and will not be exported.")(formatName)); } + } - f.exceptions(f.exceptions() | std::ios::badbit | std::ios::failbit); - FixNullStrings(); - switch(m_SndFile.GetType()) + for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) + { + if(m_SndFile.Instruments[i] && m_SndFile.Instruments[i]->synth.HasScripts()) { - case MOD_TYPE_MOD: ok = m_SndFile.SaveMod(f); break; - case MOD_TYPE_S3M: ok = m_SndFile.SaveS3M(f); break; - case MOD_TYPE_XM: ok = m_SndFile.SaveXM(f); break; - case MOD_TYPE_IT: ok = m_SndFile.SaveIT(f, filename); break; - case MOD_TYPE_MPT: ok = m_SndFile.SaveIT(f, filename); break; - default: MPT_ASSERT_NOTREACHED(); + AddToLog(LogWarning, MPT_UFORMAT("Scripted instruments are not supported by the {} format and will not be exported.")(formatName)); + break; } } - } catch(const std::exception &) - { - ok = false; + if(!m_SndFile.m_globalScript.empty()) + AddToLog(LogWarning, MPT_UFORMAT("Global instrument scripts are not supported by the {} format and will not be exported.")(formatName)); } EndWaitCursor(); @@ -398,6 +374,33 @@ bool CModDoc::OnSaveDocument(const mpt::PathString &filename, const bool setPath } +bool CModDoc::SaveFile(const mpt::PathString &filename, bool allowRelativeSamplePaths) +{ + try + { + mpt::IO::SafeOutputFile sf(filename, std::ios::binary, mpt::IO::FlushModeFromBool(TrackerSettings::Instance().MiscFlushFileBuffersOnSave)); + mpt::IO::ofstream &f = sf; + if(!f) + return false; + + f.exceptions(f.exceptions() | std::ios::badbit | std::ios::failbit); + FixNullStrings(); + switch(m_SndFile.GetBestSaveFormat()) + { + case MOD_TYPE_MOD: return m_SndFile.SaveMod(f); + case MOD_TYPE_S3M: return m_SndFile.SaveS3M(f); + case MOD_TYPE_XM: return m_SndFile.SaveXM(f); + case MOD_TYPE_IT: return m_SndFile.SaveIT(f, allowRelativeSamplePaths ? filename : mpt::PathString{}); + case MOD_TYPE_MPT: return m_SndFile.SaveIT(f, allowRelativeSamplePaths ? filename : mpt::PathString{}); + default: MPT_ASSERT_NOTREACHED(); + } + } catch(const std::exception &) + { + } + return false; +} + + BOOL CModDoc::SaveModified() { if(m_SndFile.GetType() == MOD_TYPE_MPT && !SaveAllSamples()) diff --git a/mptrack/Moddoc.h b/mptrack/Moddoc.h index 7429d8c867..c7db5aa2ff 100644 --- a/mptrack/Moddoc.h +++ b/mptrack/Moddoc.h @@ -369,6 +369,7 @@ class CModDoc final : public CDocument void OnCloseDocument() override; void SafeFileClose(); bool OnSaveDocument(const mpt::PathString &filename, const bool setPath = true); + bool SaveFile(const mpt::PathString &filename, bool allowRelativeSamplePaths); #if MPT_COMPILER_CLANG #pragma clang diagnostic push diff --git a/mptrack/PathConfigDlg.cpp b/mptrack/PathConfigDlg.cpp index 5029243e33..2ee24e275a 100644 --- a/mptrack/PathConfigDlg.cpp +++ b/mptrack/PathConfigDlg.cpp @@ -74,14 +74,17 @@ BEGIN_MESSAGE_MAP(PathConfigDlg, CPropertyPage) ON_COMMAND(IDC_BUTTON_CHANGE_VSTPRESETSDIR, &PathConfigDlg::OnBrowsePresets) // Autosave - ON_COMMAND(IDC_CHECK1, &PathConfigDlg::OnSettingsChanged) - ON_BN_CLICKED(IDC_AUTOSAVE_BROWSE, &PathConfigDlg::OnBrowseAutosavePath) - ON_BN_CLICKED(IDC_AUTOSAVE_ENABLE, &PathConfigDlg::OnAutosaveEnable) - ON_BN_CLICKED(IDC_AUTOSAVE_USEORIGDIR, &PathConfigDlg::OnAutosaveUseOrigDir) - ON_BN_CLICKED(IDC_AUTOSAVE_USECUSTOMDIR, &PathConfigDlg::OnAutosaveUseOrigDir) - ON_EN_UPDATE(IDC_AUTOSAVE_PATH, &PathConfigDlg::OnSettingsChanged) - ON_EN_UPDATE(IDC_AUTOSAVE_HISTORY, &PathConfigDlg::OnSettingsChanged) - ON_EN_UPDATE(IDC_AUTOSAVE_INTERVAL, &PathConfigDlg::OnSettingsChanged) + ON_COMMAND(IDC_CHECK1, &PathConfigDlg::OnSettingsChanged) + ON_COMMAND(IDC_CHECK2, &PathConfigDlg::OnAutosaveRetention) + ON_COMMAND(IDC_CHECK3, &PathConfigDlg::OnSettingsChanged) + ON_COMMAND(IDC_AUTOSAVE_BROWSE, &PathConfigDlg::OnBrowseAutosavePath) + ON_COMMAND(IDC_AUTOSAVE_ENABLE, &PathConfigDlg::OnAutosaveEnable) + ON_COMMAND(IDC_AUTOSAVE_USEORIGDIR, &PathConfigDlg::OnAutosaveUseOrigDir) + ON_COMMAND(IDC_AUTOSAVE_USECUSTOMDIR, &PathConfigDlg::OnAutosaveUseOrigDir) + ON_EN_UPDATE(IDC_AUTOSAVE_PATH, &PathConfigDlg::OnSettingsChanged) + ON_EN_UPDATE(IDC_AUTOSAVE_HISTORY, &PathConfigDlg::OnSettingsChanged) + ON_EN_UPDATE(IDC_AUTOSAVE_INTERVAL, &PathConfigDlg::OnSettingsChanged) + ON_EN_UPDATE(IDC_EDIT1, &PathConfigDlg::OnSettingsChanged) END_MESSAGE_MAP() @@ -101,14 +104,19 @@ BOOL PathConfigDlg::OnInitDialog() static_cast(GetDlgItem(IDC_SPIN1))->SetRange32(1, int32_max); static_cast(GetDlgItem(IDC_SPIN2))->SetRange32(1, int32_max); + static_cast(GetDlgItem(IDC_SPIN3))->SetRange32(1, int32_max); CheckDlgButton(IDC_AUTOSAVE_ENABLE, settings.AutosaveEnabled ? BST_CHECKED : BST_UNCHECKED); SetDlgItemInt(IDC_AUTOSAVE_HISTORY, settings.AutosaveHistoryDepth); SetDlgItemInt(IDC_AUTOSAVE_INTERVAL, settings.AutosaveIntervalMinutes); + SetDlgItemInt(IDC_EDIT1, settings.AutosaveRetentionTimeDays ? settings.AutosaveRetentionTimeDays : 30); + CheckDlgButton(IDC_CHECK2, settings.AutosaveRetentionTimeDays > 0); CheckDlgButton(IDC_AUTOSAVE_USEORIGDIR, settings.AutosaveUseOriginalPath ? BST_CHECKED : BST_UNCHECKED); CheckDlgButton(IDC_AUTOSAVE_USECUSTOMDIR, settings.AutosaveUseOriginalPath ? BST_UNCHECKED : BST_CHECKED); + CheckDlgButton(IDC_CHECK3, settings.AutosaveDeletePermanently ? BST_CHECKED : BST_UNCHECKED); //enable/disable stuff as appropriate OnAutosaveEnable(); OnAutosaveUseOrigDir(); + OnAutosaveRetention(); return TRUE; } @@ -132,10 +140,15 @@ void PathConfigDlg::OnOK() // Autosave settings.CreateBackupFiles = IsDlgButtonChecked(IDC_CHECK1) != BST_UNCHECKED; - settings.AutosaveEnabled = (IsDlgButtonChecked(IDC_AUTOSAVE_ENABLE) != BST_UNCHECKED); - settings.AutosaveHistoryDepth = (GetDlgItemInt(IDC_AUTOSAVE_HISTORY)); - settings.AutosaveIntervalMinutes = (GetDlgItemInt(IDC_AUTOSAVE_INTERVAL)); - settings.AutosaveUseOriginalPath = (IsDlgButtonChecked(IDC_AUTOSAVE_USEORIGDIR) == BST_CHECKED); + settings.AutosaveEnabled = IsDlgButtonChecked(IDC_AUTOSAVE_ENABLE) != BST_UNCHECKED; + settings.AutosaveHistoryDepth = GetDlgItemInt(IDC_AUTOSAVE_HISTORY); + settings.AutosaveIntervalMinutes = GetDlgItemInt(IDC_AUTOSAVE_INTERVAL); + if(IsDlgButtonChecked(IDC_CHECK2)) + settings.AutosaveRetentionTimeDays = std::max(GetDlgItemInt(IDC_EDIT1), UINT(1)); + else + settings.AutosaveRetentionTimeDays = 0; + settings.AutosaveUseOriginalPath = IsDlgButtonChecked(IDC_AUTOSAVE_USEORIGDIR) != BST_UNCHECKED; + settings.AutosaveDeletePermanently = IsDlgButtonChecked(IDC_CHECK3) != BST_UNCHECKED; CPropertyPage::OnOK(); } @@ -157,15 +170,16 @@ void PathConfigDlg::BrowseFolder(UINT nID) void PathConfigDlg::OnAutosaveEnable() { - BOOL enabled = IsDlgButtonChecked(IDC_AUTOSAVE_ENABLE); - GetDlgItem(IDC_AUTOSAVE_INTERVAL)->EnableWindow(enabled); - GetDlgItem(IDC_SPIN1)->EnableWindow(enabled); - GetDlgItem(IDC_AUTOSAVE_HISTORY)->EnableWindow(enabled); - GetDlgItem(IDC_SPIN2)->EnableWindow(enabled); - GetDlgItem(IDC_AUTOSAVE_USEORIGDIR)->EnableWindow(enabled); - GetDlgItem(IDC_AUTOSAVE_USECUSTOMDIR)->EnableWindow(enabled); - GetDlgItem(IDC_AUTOSAVE_PATH)->EnableWindow(enabled); - GetDlgItem(IDC_AUTOSAVE_BROWSE)->EnableWindow(enabled); + const BOOL enabled = IsDlgButtonChecked(IDC_AUTOSAVE_ENABLE); + static constexpr UINT AutoSaveDlgItems[] = + { + IDC_AUTOSAVE_INTERVAL, IDC_AUTOSAVE_HISTORY, IDC_AUTOSAVE_USEORIGDIR, IDC_AUTOSAVE_USECUSTOMDIR, + IDC_AUTOSAVE_PATH, IDC_AUTOSAVE_BROWSE, IDC_CHECK2, IDC_CHECK3, IDC_EDIT1, IDC_SPIN1, IDC_SPIN2, IDC_SPIN3 + }; + for(UINT id : AutoSaveDlgItems) + { + GetDlgItem(id)->EnableWindow(enabled); + } OnSettingsChanged(); return; } @@ -173,17 +187,28 @@ void PathConfigDlg::OnAutosaveEnable() void PathConfigDlg::OnAutosaveUseOrigDir() { - if (IsDlgButtonChecked(IDC_AUTOSAVE_ENABLE)) + if(IsDlgButtonChecked(IDC_AUTOSAVE_ENABLE)) { - BOOL enabled = IsDlgButtonChecked(IDC_AUTOSAVE_USEORIGDIR); - GetDlgItem(IDC_AUTOSAVE_PATH)->EnableWindow(!enabled); - GetDlgItem(IDC_AUTOSAVE_BROWSE)->EnableWindow(!enabled); + const BOOL enabled = IsDlgButtonChecked(IDC_AUTOSAVE_USEORIGDIR) ? FALSE : TRUE; + static constexpr UINT AutoSaveDirDlgItems[] = {IDC_AUTOSAVE_PATH, IDC_AUTOSAVE_BROWSE, IDC_CHECK2, IDC_EDIT1, IDC_SPIN3}; + for(UINT id : AutoSaveDirDlgItems) + { + GetDlgItem(id)->EnableWindow(enabled); + } OnSettingsChanged(); } return; } +void PathConfigDlg::OnAutosaveRetention() +{ + const BOOL enabled = IsDlgButtonChecked(IDC_CHECK2) ? TRUE : FALSE; + GetDlgItem(IDC_EDIT1)->EnableWindow(enabled); + GetDlgItem(IDC_SPIN3)->EnableWindow(enabled); +} + + void PathConfigDlg::OnSettingsChanged() { SetModified(TRUE); diff --git a/mptrack/PathConfigDlg.h b/mptrack/PathConfigDlg.h index a9674d58b7..ca7e5e2ed7 100644 --- a/mptrack/PathConfigDlg.h +++ b/mptrack/PathConfigDlg.h @@ -31,6 +31,7 @@ class PathConfigDlg : public CPropertyPage afx_msg void OnAutosaveEnable(); afx_msg void OnAutosaveUseOrigDir(); + afx_msg void OnAutosaveRetention(); afx_msg void OnBrowseAutosavePath(); afx_msg void OnBrowseSongs(); afx_msg void OnBrowseSamples(); diff --git a/mptrack/TrackerSettings.cpp b/mptrack/TrackerSettings.cpp index 9f1242b3de..607be0cda6 100644 --- a/mptrack/TrackerSettings.cpp +++ b/mptrack/TrackerSettings.cpp @@ -318,7 +318,9 @@ TrackerSettings::TrackerSettings(SettingsContainer &conf) , AutosaveEnabled(conf, UL_("AutoSave"), UL_("Enabled"), true) , AutosaveIntervalMinutes(conf, UL_("AutoSave"), UL_("IntervalMinutes"), 10) , AutosaveHistoryDepth(conf, UL_("AutoSave"), UL_("BackupHistory"), 3) + , AutosaveRetentionTimeDays(conf, UL_("AutoSave"), UL_("RetentionTimeDays"), 30) , AutosaveUseOriginalPath(conf, UL_("AutoSave"), UL_("UseOriginalPath"), true) + , AutosaveDeletePermanently(conf, UL_("AutoSave"), UL_("DeletePermanently"), false) , AutosavePath(conf, UL_("AutoSave"), UL_("Path"), mpt::common_directories::get_temp_directory()) // Paths , PathSongs(conf, UL_("Paths"), UL_("Songs_Directory"), mpt::PathString()) diff --git a/mptrack/TrackerSettings.h b/mptrack/TrackerSettings.h index 918bc62d84..c88df59ecd 100644 --- a/mptrack/TrackerSettings.h +++ b/mptrack/TrackerSettings.h @@ -886,7 +886,9 @@ class TrackerSettings CachedSetting AutosaveEnabled; CachedSetting AutosaveIntervalMinutes; CachedSetting AutosaveHistoryDepth; + CachedSetting AutosaveRetentionTimeDays; CachedSetting AutosaveUseOriginalPath; + CachedSetting AutosaveDeletePermanently; ConfigurableDirectory AutosavePath; // Paths diff --git a/mptrack/mptrack.rc b/mptrack/mptrack.rc index bbcb0cb8d9..6740e4093f 100644 --- a/mptrack/mptrack.rc +++ b/mptrack/mptrack.rc @@ -2188,21 +2188,23 @@ STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION CAPTION "Paths / Auto Save" FONT 8, "MS Shell Dlg", 0, 0, 0x0 BEGIN + GROUPBOX "Default Directories",IDC_STATIC,6,6,312,102 RTEXT "Songs:",IDC_STATIC_MODDIR,12,18,48,12,SS_CENTERIMAGE EDITTEXT IDC_OPTIONS_DIR_MODS,66,18,192,12,ES_AUTOHSCROLL - PUSHBUTTON "Browse...",IDC_BUTTON_CHANGE_MODDIR,264,18,48,11 + PUSHBUTTON "Browse...",IDC_BUTTON_CHANGE_MODDIR,264,18,48,12 RTEXT "Samples:",IDC_STATIC_SAMPDIR,12,36,48,12,SS_CENTERIMAGE EDITTEXT IDC_OPTIONS_DIR_SAMPS,66,36,192,12,ES_AUTOHSCROLL - PUSHBUTTON "Browse...",IDC_BUTTON_CHANGE_SAMPDIR,264,36,48,11 + PUSHBUTTON "Browse...",IDC_BUTTON_CHANGE_SAMPDIR,264,36,48,12 RTEXT "Instruments:",IDC_STATIC_INSTRDIR,12,54,48,12,SS_CENTERIMAGE EDITTEXT IDC_OPTIONS_DIR_INSTS,66,54,192,12,ES_AUTOHSCROLL - PUSHBUTTON "Browse...",IDC_BUTTON_CHANGE_INSTRDIR,264,54,48,11 + PUSHBUTTON "Browse...",IDC_BUTTON_CHANGE_INSTRDIR,264,54,48,12 RTEXT "VST Plugins:",IDC_STATIC_VSTDIR,12,72,48,12,SS_CENTERIMAGE EDITTEXT IDC_OPTIONS_DIR_VSTS,66,72,192,12,ES_AUTOHSCROLL - PUSHBUTTON "Browse...",IDC_BUTTON_CHANGE_VSTDIR,264,72,48,11 + PUSHBUTTON "Browse...",IDC_BUTTON_CHANGE_VSTDIR,264,72,48,12 RTEXT "VST Presets:",IDC_STATIC_VSTPRESETDIR,12,90,48,12,SS_CENTERIMAGE EDITTEXT IDC_OPTIONS_DIR_VSTPRESETS,66,90,192,12,ES_AUTOHSCROLL - PUSHBUTTON "Browse...",IDC_BUTTON_CHANGE_VSTPRESETSDIR,264,90,48,11 + PUSHBUTTON "Browse...",IDC_BUTTON_CHANGE_VSTPRESETSDIR,264,90,48,12 + GROUPBOX "Backup and Auto Save",IDC_STATIC,6,120,312,186 CONTROL "Create &backup copy (*.bak) when saving module files",IDC_CHECK1, "Button",BS_AUTOCHECKBOX | WS_TABSTOP,18,135,258,12 CONTROL "&Enable Auto Save",IDC_AUTOSAVE_ENABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,18,154,237,10 @@ -2218,12 +2220,16 @@ BEGIN "Button",BS_AUTORADIOBUTTON,18,202,218,10 CONTROL "S&tore in:",IDC_AUTOSAVE_USECUSTOMDIR,"Button",BS_AUTORADIOBUTTON,18,218,43,10 EDITTEXT IDC_AUTOSAVE_PATH,72,216,186,12,ES_AUTOHSCROLL - PUSHBUTTON "Browse...",IDC_AUTOSAVE_BROWSE,264,216,48,11 - LTEXT "Filename:",IDC_STATIC,30,240,36,12,SS_CENTERIMAGE - LTEXT "[filename].AutoSave.[timestamp].[extension]",IDC_STATIC,72,240,240,12,SS_CENTERIMAGE,WS_EX_CLIENTEDGE - LTEXT "(example: mySong.AutoSave.20050327.2343.it)",IDC_STATIC,72,258,240,12,SS_CENTERIMAGE - GROUPBOX "Backup and Auto Save",IDC_STATIC,6,120,312,186 - GROUPBOX "Default Directories",IDC_STATIC,6,6,312,102 + PUSHBUTTON "Browse...",IDC_AUTOSAVE_BROWSE,264,216,48,12 + CONTROL "&Delete auto saves older than",IDC_CHECK2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,72,234,114,12 + EDITTEXT IDC_EDIT1,186,234,40,12,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "",IDC_SPIN3,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS,210,240,11,14 + LTEXT "days",IDC_STATIC,234,236,30,8 + CONTROL "Delete old auto saves &permanently instead of moving them to the recycling bin",IDC_CHECK3, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,18,252,294,10 + LTEXT "Filename:",IDC_STATIC,18,270,36,12,SS_CENTERIMAGE + LTEXT "[filename].AutoSave.[timestamp].[extension]",IDC_STATIC,60,270,252,12,SS_CENTERIMAGE,WS_EX_CLIENTEDGE + LTEXT "(example: mySong.it.AutoSave.20050327.2343.it)",IDC_STATIC,60,288,252,12,SS_CENTERIMAGE END IDD_EDIT_GOTO DIALOGEX 0, 0, 123, 122