Created
January 25, 2024 16:53
-
-
Save antiufo/136038b69e3341de8a965b13b24df105 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/Edit.c b/src/Edit.c | |
index d605e24..172b322 100644 | |
--- a/src/Edit.c | |
+++ b/src/Edit.c | |
@@ -1187,7 +1187,8 @@ BOOL EditLoadFile( | |
int* iEncoding, | |
int* iEOLMode, | |
BOOL *pbUnicodeErr, | |
- BOOL *pbFileTooBig) | |
+ BOOL *pbFileTooBig, | |
+ BOOL bRecovery) | |
{ | |
HANDLE hFile; | |
@@ -1242,6 +1243,18 @@ BOOL EditLoadFile( | |
} | |
lpData = GlobalAlloc(GPTR,dwBufSize); | |
+ | |
+ if (bRecovery) | |
+ { | |
+ WCHAR dummy[MAX_PATH + 40]; | |
+ DWORD magic; | |
+ DWORD nameLength; | |
+ ReadFile(hFile, &magic, 4, NULL, NULL); | |
+ if (magic != RECOVERY_FILE_MAGIC_NUMBER) return FALSE; | |
+ ReadFile(hFile, &nameLength, 4, NULL, NULL); | |
+ ReadFile(hFile, &dummy, nameLength * 2 + 2, NULL, NULL); | |
+ } | |
+ | |
bReadSuccess = ReadFile(hFile,lpData,(DWORD)GlobalSize(lpData)-2,&cbData,NULL); | |
dwLastIOError = GetLastError(); | |
CloseHandle(hFile); | |
@@ -1435,7 +1448,10 @@ BOOL EditSaveFile( | |
LPCWSTR pszFile, | |
int iEncoding, | |
BOOL *pbCancelDataLoss, | |
- BOOL bSaveCopy) | |
+ BOOL bSaveCopy, | |
+ BOOL bRecovery, | |
+ LPCWSTR pszPrefix | |
+ ) | |
{ | |
HANDLE hFile; | |
@@ -1477,14 +1493,23 @@ BOOL EditSaveFile( | |
if (hFile == INVALID_HANDLE_VALUE) | |
return FALSE; | |
+ if (pszPrefix != NULL) { | |
+ DWORD magic = RECOVERY_FILE_MAGIC_NUMBER; | |
+ DWORD prefixLength = wcslen(pszPrefix); | |
+ WriteFile(hFile, &magic, 4, &dwBytesWritten, NULL); | |
+ WriteFile(hFile, &prefixLength, 4, &dwBytesWritten, NULL); | |
+ WriteFile(hFile, (byte*)pszPrefix, (prefixLength + 1) * 2, &dwBytesWritten, NULL); | |
+ } | |
+ | |
+ | |
// ensure consistent line endings | |
- if (bFixLineEndings) { | |
+ if (bFixLineEndings && !bRecovery) { | |
SendMessage(hwnd,SCI_CONVERTEOLS,SendMessage(hwnd,SCI_GETEOLMODE,0,0),0); | |
EditFixPositions(hwnd); | |
} | |
// strip trailing blanks | |
- if (bAutoStripBlanks) | |
+ if (bAutoStripBlanks && !bRecovery) | |
EditStripTrailingBlanks(hwnd,TRUE); | |
// get text | |
@@ -1616,8 +1641,9 @@ BOOL EditSaveFile( | |
if (bWriteSuccess) | |
{ | |
if (!bSaveCopy) | |
+ { | |
SendMessage(hwnd,SCI_SETSAVEPOINT,0,0); | |
- | |
+ } | |
return TRUE; | |
} | |
diff --git a/src/Edit.h b/src/Edit.h | |
index bc3f59b..94586e3 100644 | |
--- a/src/Edit.h | |
+++ b/src/Edit.h | |
@@ -77,7 +77,7 @@ char* EditGetClipboardText(HWND); | |
BOOL EditCopyAppend(HWND); | |
int EditDetectEOLMode(HWND,char*,DWORD); | |
BOOL EditLoadFile(HWND,LPCWSTR,BOOL,int*,int*,BOOL*,BOOL*); | |
-BOOL EditSaveFile(HWND,LPCWSTR,int,BOOL*,BOOL); | |
+BOOL EditSaveFile(HWND,LPCWSTR,int,BOOL*,BOOL,BOOL,LPCWSTR); | |
void EditInvertCase(HWND); | |
void EditTitleCase(HWND); | |
diff --git a/src/Helpers.c b/src/Helpers.c | |
index 8138467..d876210 100644 | |
--- a/src/Helpers.c | |
+++ b/src/Helpers.c | |
@@ -353,7 +353,7 @@ BOOL bFreezeAppTitle = FALSE; | |
BOOL SetWindowTitle(HWND hwnd,UINT uIDAppName,BOOL bIsElevated,UINT uIDUntitled, | |
LPCWSTR lpszFile,int iFormat,BOOL bModified, | |
- UINT uIDReadOnly,BOOL bReadOnly,LPCWSTR lpszExcerpt) | |
+ UINT uIDReadOnly,BOOL bReadOnly,LPCWSTR lpszExcerpt,BOOL bIsRecovered) | |
{ | |
WCHAR szUntitled[128]; | |
@@ -423,6 +423,11 @@ BOOL SetWindowTitle(HWND hwnd,UINT uIDAppName,BOOL bIsElevated,UINT uIDUntitled, | |
lstrcat(szTitle,szUntitled); | |
} | |
+ if (bIsRecovered) | |
+ { | |
+ lstrcat(szTitle, L" [RECOVERED]"); | |
+ } | |
+ | |
if (bReadOnly && GetString(uIDReadOnly,szReadOnly,COUNTOF(szReadOnly))) | |
{ | |
lstrcat(szTitle,L" "); | |
@@ -1656,6 +1661,7 @@ BOOL MRU_AddFile(LPMRULIST pmru,LPCWSTR pszFile,BOOL bRelativePath,BOOL bUnexpan | |
int i; | |
for (i = 0; i < pmru->iSize; i++) { | |
+ if (pmru->pszItems[i] == NULL) continue; | |
if (lstrcmpi(pmru->pszItems[i],pszFile) == 0) { | |
LocalFree(pmru->pszItems[i]); | |
break; | |
diff --git a/src/Helpers.h b/src/Helpers.h | |
index 490fac2..279207e 100644 | |
--- a/src/Helpers.h | |
+++ b/src/Helpers.h | |
@@ -85,7 +85,7 @@ BOOL VerifyContrast(COLORREF,COLORREF); | |
BOOL IsFontAvailable(LPCWSTR); | |
-BOOL SetWindowTitle(HWND,UINT,BOOL,UINT,LPCWSTR,int,BOOL,UINT,BOOL,LPCWSTR); | |
+BOOL SetWindowTitle(HWND,UINT,BOOL,UINT,LPCWSTR,int,BOOL,UINT,BOOL,LPCWSTR,BOOL); | |
void SetWindowTransparentMode(HWND,BOOL); | |
diff --git a/src/Notepad2.c b/src/Notepad2.c | |
index 4f26aa8..4d4d025 100644 | |
--- a/src/Notepad2.c | |
+++ b/src/Notepad2.c | |
@@ -214,8 +214,16 @@ LPMRULIST mruReplace; | |
DWORD dwLastIOError; | |
WCHAR szCurFile[MAX_PATH+40]; | |
+WCHAR szRecoveryFile[MAX_PATH+50]; | |
+WCHAR szRecoveryDirectory[MAX_PATH]; | |
+DWORD iRecoveryInterval; | |
+BOOL bIsRecovered = FALSE; | |
+BOOL bNotARealSavePoint = FALSE; | |
FILEVARS fvCurFile; | |
BOOL bModified; | |
+BOOL bModifiedSinceLastRecoverySave; | |
+BOOL bIgnoreNextChangeNotificationForRecovery; | |
+UINT_PTR pFileRecoveryTimer = NULL; | |
BOOL bReadOnly = FALSE; | |
int iEncoding; | |
int iOriginalEncoding; | |
@@ -988,7 +996,7 @@ HWND InitInstance(HINSTANCE hInstance,LPSTR pszCmdLine,int nCmdShow) | |
uidsAppTitle = IDS_APPTITLE_PASTEBOARD; | |
SetWindowTitle(hwndMain,uidsAppTitle,fIsElevated,IDS_UNTITLED,szCurFile, | |
iPathNameFormat,bModified || iEncoding != iOriginalEncoding, | |
- IDS_READONLY,bReadOnly,szTitleExcerpt); | |
+ IDS_READONLY,bReadOnly,szTitleExcerpt,bIsRecovered); | |
bLastCopyFromMe = FALSE; | |
dwLastCopyTime = 0; | |
@@ -1121,13 +1129,13 @@ LRESULT CALLBACK MainWndProc(HWND hwnd,UINT umsg,WPARAM wParam,LPARAM lParam) | |
case WM_CLOSE: | |
- if (FileSave(FALSE,TRUE,FALSE,FALSE)) | |
+ if (FileSaveEx(FALSE,TRUE,FALSE,FALSE,TRUE)) | |
DestroyWindow(hwnd); | |
break; | |
case WM_QUERYENDSESSION: | |
- if (FileSave(FALSE,TRUE,FALSE,FALSE)) | |
+ if (FileSaveEx(FALSE,TRUE,FALSE,FALSE,TRUE)) | |
return TRUE; | |
else | |
return FALSE; | |
@@ -1280,7 +1288,7 @@ LRESULT CALLBACK MainWndProc(HWND hwnd,UINT umsg,WPARAM wParam,LPARAM lParam) | |
lstrcpyn(szTitleExcerpt,StrEnd(¶ms->wchData)+1,COUNTOF(szTitleExcerpt)); | |
SetWindowTitle(hwnd,uidsAppTitle,fIsElevated,IDS_UNTITLED,szCurFile, | |
iPathNameFormat,bModified || iEncoding != iOriginalEncoding, | |
- IDS_READONLY,bReadOnly,szTitleExcerpt); | |
+ IDS_READONLY,bReadOnly,szTitleExcerpt,bIsRecovered); | |
} | |
} | |
// reset | |
@@ -1370,6 +1378,11 @@ LRESULT CALLBACK MainWndProc(HWND hwnd,UINT umsg,WPARAM wParam,LPARAM lParam) | |
MsgInitMenu(hwnd,wParam,lParam); | |
break; | |
+ case WM_INITMENUPOPUP: | |
+ if (GetMenuItemID(wParam, 0) == IDM_FILE_RECOVERED) { | |
+ PopulateRecoveredFilesMenu((HMENU)wParam); | |
+ } | |
+ break; | |
case WM_NOTIFY: | |
return MsgNotify(hwnd,wParam,lParam); | |
@@ -2040,6 +2053,89 @@ void MsgSize(HWND hwnd,WPARAM wParam,LPARAM lParam) | |
} | |
+#define MAX_RECOVERY_MENU_ITEMS 50 | |
+ | |
+ | |
+BOOL GetDisplayNameForRecoveryFile(PWCHAR destination, PWCHAR name) | |
+{ | |
+ if (isdigit(name[0])) | |
+ { | |
+ // Eg. 36275755171385521050--example.txt.dat | |
+ PWCHAR idx = wcschr(name, '-'); | |
+ if (idx == NULL || *(idx + 1) != '-') return FALSE; | |
+ wcscpy(destination, idx + 2); | |
+ destination[wcslen(destination) - 4] = 0; | |
+ return TRUE; | |
+ } | |
+ else | |
+ { | |
+ // Eg. Untitled--2017-03-07--05-44-26--10452.txt.dat | |
+ if (wcslen(name) <= 32) return FALSE; | |
+ | |
+ wcscpy(destination, L"Untitled ("); | |
+ wcscat(destination, name + 10); | |
+ wcscpy(destination + 21, name + 22); | |
+ destination[20] = ' '; | |
+ destination[23] = ':'; | |
+ destination[26] = ')'; | |
+ destination[27] = 0; | |
+ return TRUE; | |
+ } | |
+ | |
+ | |
+ | |
+ return TRUE; | |
+} | |
+ | |
+PWCHAR pRecoveryMenuItems[MAX_RECOVERY_MENU_ITEMS]; | |
+int iRecoveryMenuItemsCount = 0; | |
+ | |
+void PopulateRecoveredFilesMenu(HMENU menu) | |
+{ | |
+ if (wcslen(szCurFile) == 0 && wcslen(szRecoveryFile) != 0 && (int)SendMessage(hwndEdit, SCI_GETLENGTH, 0, 0) == 0) | |
+ { | |
+ // If the current untitled, recovered file has been emptied, remove it immediately from the list. | |
+ SaveRecoveryFile(); | |
+ } | |
+ for (size_t i = 0; i < iRecoveryMenuItemsCount; i++) | |
+ { | |
+ free(pRecoveryMenuItems[i]); | |
+ RemoveMenu(menu, 0, MF_BYPOSITION); | |
+ } | |
+ | |
+ RemoveMenu(menu, 0, MF_BYPOSITION); // Delete dummy entry | |
+ | |
+ WIN32_FIND_DATA findData; | |
+ iRecoveryMenuItemsCount = 0; | |
+ WCHAR szSearchPath[MAX_PATH]; | |
+ wcscpy(szSearchPath, szRecoveryDirectory); | |
+ PathAppend(szSearchPath, L"*.dat"); | |
+ HANDLE hFind = FindFirstFile(szSearchPath, &findData); | |
+ if (hFind != -1) | |
+ { | |
+ WCHAR szDisplayName[MAX_PATH]; | |
+ while (TRUE) | |
+ { | |
+ | |
+ | |
+ if (GetDisplayNameForRecoveryFile(szDisplayName, findData.cFileName)) | |
+ { | |
+ PWCHAR szCopiedName = (PWCHAR)malloc(MAX_PATH * 2); | |
+ wcscpy(szCopiedName, findData.cFileName); | |
+ pRecoveryMenuItems[iRecoveryMenuItemsCount] = szCopiedName; | |
+ | |
+ AppendMenu(menu, MF_STRING | MF_ENABLED, IDM_FILE_RECOVERED + iRecoveryMenuItemsCount, szDisplayName); | |
+ iRecoveryMenuItemsCount++; | |
+ if (iRecoveryMenuItemsCount == MAX_RECOVERY_MENU_ITEMS) return; | |
+ } | |
+ if (!FindNextFile(hFind, &findData)) break; | |
+ } | |
+ } | |
+ | |
+ if(iRecoveryMenuItemsCount == 0) | |
+ AppendMenu(menu, MF_STRING | MF_DISABLED, IDM_FILE_RECOVERED, L"(Empty)"); | |
+ | |
+} | |
//============================================================================= | |
// | |
@@ -2246,6 +2342,8 @@ void MsgInitMenu(HWND hwnd,WPARAM wParam,LPARAM lParam) | |
CheckCmd(hmenu,IDM_VIEW_REUSEWINDOW,i); | |
i = IniGetInt(L"Settings2",L"SingleFileInstance",0); | |
CheckCmd(hmenu,IDM_VIEW_SINGLEFILEINSTANCE,i); | |
+ i = IniGetInt(L"Settings2",L"AutomaticFileRecovery",1); | |
+ CheckCmd(hmenu, IDM_VIEW_FILERECOVERY, i); | |
bStickyWinPos = IniGetInt(L"Settings2",L"StickyWindowPosition",0); | |
CheckCmd(hmenu,IDM_VIEW_STICKYWINPOS,bStickyWinPos); | |
CheckCmd(hmenu,IDM_VIEW_ALWAYSONTOP,((bAlwaysOnTop || flagAlwaysOnTop == 2) && flagAlwaysOnTop != 1)); | |
@@ -2283,6 +2381,7 @@ void MsgInitMenu(HWND hwnd,WPARAM wParam,LPARAM lParam) | |
EnableCmd(hmenu,IDM_VIEW_REUSEWINDOW,i); | |
EnableCmd(hmenu,IDM_VIEW_STICKYWINPOS,i); | |
EnableCmd(hmenu,IDM_VIEW_SINGLEFILEINSTANCE,i); | |
+ EnableCmd(hmenu,IDM_VIEW_FILERECOVERY,i); | |
EnableCmd(hmenu,IDM_VIEW_NOSAVERECENT,i); | |
EnableCmd(hmenu,IDM_VIEW_NOSAVEFINDREPL,i); | |
EnableCmd(hmenu,IDM_VIEW_SAVESETTINGS,i); | |
@@ -2392,7 +2491,7 @@ LRESULT MsgCommand(HWND hwnd,WPARAM wParam,LPARAM lParam) | |
SetWindowTitle(hwnd,uidsAppTitle,fIsElevated,IDS_UNTITLED,szCurFile, | |
iPathNameFormat,bModified || iEncoding != iOriginalEncoding, | |
- IDS_READONLY,bReadOnly,szTitleExcerpt); | |
+ IDS_READONLY,bReadOnly,szTitleExcerpt,bIsRecovered); | |
} | |
break; | |
@@ -2756,7 +2855,7 @@ LRESULT MsgCommand(HWND hwnd,WPARAM wParam,LPARAM lParam) | |
SetWindowTitle(hwnd,uidsAppTitle,fIsElevated,IDS_UNTITLED,szCurFile, | |
iPathNameFormat,bModified || iEncoding != iOriginalEncoding, | |
- IDS_READONLY,bReadOnly,szTitleExcerpt); | |
+ IDS_READONLY,bReadOnly,szTitleExcerpt,bIsRecovered); | |
} | |
} | |
break; | |
@@ -2810,7 +2909,7 @@ LRESULT MsgCommand(HWND hwnd,WPARAM wParam,LPARAM lParam) | |
UpdateStatusbar(); | |
SetWindowTitle(hwnd,uidsAppTitle,fIsElevated,IDS_UNTITLED,szCurFile, | |
iPathNameFormat,bModified || iEncoding != iOriginalEncoding, | |
- IDS_READONLY,bReadOnly,szTitleExcerpt); | |
+ IDS_READONLY,bReadOnly,szTitleExcerpt,bIsRecovered); | |
} | |
break; | |
@@ -3661,9 +3760,9 @@ LRESULT MsgCommand(HWND hwnd,WPARAM wParam,LPARAM lParam) | |
} | |
else | |
{ | |
- // define (beh�ver bara g�ra detta en g�ng egentligen) | |
- //SendMessage( hwndEdit , SCI_MARKERSETBACK , 0 , 74 | (203 << 8) | (0 << 16) ); //beh�ver bara g�ra detta en g�ng egentligen | |
- //SendMessage( hwndEdit , SCI_MARKERDEFINE , 0 , SC_MARK_ARROWS ); //beh�ver bara g�ra detta en g�ng egentligen | |
+ // define (beh�ver bara g�ra detta en g�ng egentligen) | |
+ //SendMessage( hwndEdit , SCI_MARKERSETBACK , 0 , 74 | (203 << 8) | (0 << 16) ); //beh�ver bara g�ra detta en g�ng egentligen | |
+ //SendMessage( hwndEdit , SCI_MARKERDEFINE , 0 , SC_MARK_ARROWS ); //beh�ver bara g�ra detta en g�ng egentligen | |
if( bShowSelectionMargin ) | |
{ | |
@@ -4199,6 +4298,22 @@ LRESULT MsgCommand(HWND hwnd,WPARAM wParam,LPARAM lParam) | |
IniSetInt(L"Settings2",L"SingleFileInstance",1); | |
break; | |
+ case IDM_VIEW_FILERECOVERY: | |
+ if (IniGetInt(L"Settings2", L"AutomaticFileRecovery", 0)) | |
+ { | |
+ IniSetInt(L"Settings2", L"AutomaticFileRecovery", 0); | |
+ StopFileRecoveryTimer(TRUE); | |
+ wcscpy(szRecoveryFile, L""); | |
+ } | |
+ else | |
+ { | |
+ IniSetInt(L"Settings2", L"AutomaticFileRecovery", 1); | |
+ InitRecoveryFilePath(szCurFile,szRecoveryFile); | |
+ if (bModified) StartFileRecoveryTimer(); | |
+ } | |
+ break; | |
+ | |
+ | |
case IDM_VIEW_ALWAYSONTOP: | |
if ((bAlwaysOnTop || flagAlwaysOnTop == 2) && flagAlwaysOnTop != 1) { | |
@@ -4230,7 +4345,7 @@ LRESULT MsgCommand(HWND hwnd,WPARAM wParam,LPARAM lParam) | |
lstrcpy(szTitleExcerpt,L""); | |
SetWindowTitle(hwnd,uidsAppTitle,fIsElevated,IDS_UNTITLED,szCurFile, | |
iPathNameFormat,bModified || iEncoding != iOriginalEncoding, | |
- IDS_READONLY,bReadOnly,szTitleExcerpt); | |
+ IDS_READONLY,bReadOnly,szTitleExcerpt,bIsRecovered); | |
break; | |
@@ -4239,7 +4354,7 @@ LRESULT MsgCommand(HWND hwnd,WPARAM wParam,LPARAM lParam) | |
lstrcpy(szTitleExcerpt,L""); | |
SetWindowTitle(hwnd,uidsAppTitle,fIsElevated,IDS_UNTITLED,szCurFile, | |
iPathNameFormat,bModified || iEncoding != iOriginalEncoding, | |
- IDS_READONLY,bReadOnly,szTitleExcerpt); | |
+ IDS_READONLY,bReadOnly,szTitleExcerpt,bIsRecovered); | |
break; | |
@@ -4248,7 +4363,7 @@ LRESULT MsgCommand(HWND hwnd,WPARAM wParam,LPARAM lParam) | |
lstrcpy(szTitleExcerpt,L""); | |
SetWindowTitle(hwnd,uidsAppTitle,fIsElevated,IDS_UNTITLED,szCurFile, | |
iPathNameFormat,bModified || iEncoding != iOriginalEncoding, | |
- IDS_READONLY,bReadOnly,szTitleExcerpt); | |
+ IDS_READONLY,bReadOnly,szTitleExcerpt,bIsRecovered); | |
break; | |
@@ -4256,7 +4371,7 @@ LRESULT MsgCommand(HWND hwnd,WPARAM wParam,LPARAM lParam) | |
EditGetExcerpt(hwndEdit,szTitleExcerpt,COUNTOF(szTitleExcerpt)); | |
SetWindowTitle(hwnd,uidsAppTitle,fIsElevated,IDS_UNTITLED,szCurFile, | |
iPathNameFormat,bModified || iEncoding != iOriginalEncoding, | |
- IDS_READONLY,bReadOnly,szTitleExcerpt); | |
+ IDS_READONLY,bReadOnly,szTitleExcerpt,bIsRecovered); | |
break; | |
@@ -4775,7 +4890,7 @@ LRESULT MsgCommand(HWND hwnd,WPARAM wParam,LPARAM lParam) | |
EditGetExcerpt(hwndEdit,szTitleExcerpt,COUNTOF(szTitleExcerpt)); | |
SetWindowTitle(hwnd,uidsAppTitle,fIsElevated,IDS_UNTITLED,szCurFile, | |
iPathNameFormat,bModified || iEncoding != iOriginalEncoding, | |
- IDS_READONLY,bReadOnly,szTitleExcerpt); | |
+ IDS_READONLY,bReadOnly,szTitleExcerpt,bIsRecovered); | |
break; | |
@@ -5071,6 +5186,11 @@ LRESULT MsgCommand(HWND hwnd,WPARAM wParam,LPARAM lParam) | |
MessageBeep(0); | |
break; | |
+ default: | |
+ if (LOWORD(wParam) >= IDM_FILE_RECOVERED && LOWORD(wParam) <= IDM_FILE_RECOVERED_MAX) | |
+ { | |
+ LoadRecoveryFile(pRecoveryMenuItems[LOWORD(wParam) - IDM_FILE_RECOVERED]); | |
+ } | |
} | |
return(0); | |
@@ -5310,15 +5430,24 @@ LRESULT MsgNotify(HWND hwnd,WPARAM wParam,LPARAM lParam) | |
break; | |
case SCN_MODIFIED: | |
+ if (bIgnoreNextChangeNotificationForRecovery) { | |
+ bIgnoreNextChangeNotificationForRecovery = FALSE; | |
+ }else{ | |
+ bModifiedSinceLastRecoverySave = TRUE; | |
+ StartFileRecoveryTimer(); | |
+ } | |
+ // Fall throuh | |
case SCN_ZOOM: | |
UpdateLineNumberWidth(); | |
break; | |
case SCN_SAVEPOINTREACHED: | |
+ if (bNotARealSavePoint) break; | |
bModified = FALSE; | |
+ StopFileRecoveryTimer(TRUE); | |
SetWindowTitle(hwnd,uidsAppTitle,fIsElevated,IDS_UNTITLED,szCurFile, | |
iPathNameFormat,bModified || iEncoding != iOriginalEncoding, | |
- IDS_READONLY,bReadOnly,szTitleExcerpt); | |
+ IDS_READONLY,bReadOnly,szTitleExcerpt,bIsRecovered); | |
break; | |
case SCN_MARGINCLICK: | |
@@ -5333,9 +5462,11 @@ LRESULT MsgNotify(HWND hwnd,WPARAM wParam,LPARAM lParam) | |
case SCN_SAVEPOINTLEFT: | |
bModified = TRUE; | |
+ bModifiedSinceLastRecoverySave = TRUE; | |
+ StartFileRecoveryTimer(); | |
SetWindowTitle(hwnd,uidsAppTitle,fIsElevated,IDS_UNTITLED,szCurFile, | |
iPathNameFormat,bModified || iEncoding != iOriginalEncoding, | |
- IDS_READONLY,bReadOnly,szTitleExcerpt); | |
+ IDS_READONLY,bReadOnly,szTitleExcerpt,bIsRecovered); | |
break; | |
} | |
break; | |
@@ -5734,6 +5865,19 @@ void LoadSettings() | |
IniSectionGetString(pIniSection,L"DefaultDirectory",L"", | |
tchDefaultDir,COUNTOF(tchDefaultDir)); | |
+ iRecoveryInterval = IniGetInt(pIniSection, L"AutomaticRecoveryInterval", 30000); | |
+ | |
+ if (!IniSectionGetString(pIniSection, L"RecoveryFileDirectory", L"", szRecoveryDirectory, COUNTOF(szRecoveryDirectory))) | |
+ { | |
+ SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, szRecoveryDirectory); | |
+ PathAppend(szRecoveryDirectory, L"Notepad2\\Recovered Files"); | |
+ } | |
+ else | |
+ { | |
+ PathAbsoluteFromApp(szRecoveryDirectory, NULL, COUNTOF(szRecoveryDirectory), TRUE); | |
+ } | |
+ | |
+ | |
ZeroMemory(tchFileDlgFilters,sizeof(WCHAR)*COUNTOF(tchFileDlgFilters)); | |
IniSectionGetString(pIniSection,L"FileDlgFilters",L"", | |
tchFileDlgFilters,COUNTOF(tchFileDlgFilters)-2); | |
@@ -6790,7 +6934,7 @@ void UpdateLineNumberWidth() | |
// | |
BOOL FileIO(BOOL fLoad,LPCWSTR psz,BOOL bNoEncDetect,int *ienc,int *ieol, | |
BOOL *pbUnicodeErr,BOOL *pbFileTooBig, | |
- BOOL *pbCancelDataLoss,BOOL bSaveCopy) | |
+ BOOL *pbCancelDataLoss,BOOL bSaveCopy,BOOL bRecovery) | |
{ | |
WCHAR tch[MAX_PATH+40]; | |
BOOL fSuccess; | |
@@ -6807,13 +6951,21 @@ BOOL FileIO(BOOL fLoad,LPCWSTR psz,BOOL bNoEncDetect,int *ienc,int *ieol, | |
UpdateWindow(hwndStatus); | |
if (fLoad) | |
- fSuccess = EditLoadFile(hwndEdit,psz,bNoEncDetect,ienc,ieol,pbUnicodeErr,pbFileTooBig); | |
+ fSuccess = EditLoadFile(hwndEdit,psz,bNoEncDetect,ienc,ieol,pbUnicodeErr,pbFileTooBig,bRecovery); | |
else | |
- fSuccess = EditSaveFile(hwndEdit,psz,*ienc,pbCancelDataLoss,bSaveCopy); | |
+ fSuccess = EditSaveFile(hwndEdit,psz,*ienc,pbCancelDataLoss,bSaveCopy,bRecovery,bRecovery ? szCurFile : NULL); | |
- dwFileAttributes = GetFileAttributes(psz); | |
- bReadOnly = (dwFileAttributes != INVALID_FILE_ATTRIBUTES && dwFileAttributes & FILE_ATTRIBUTE_READONLY); | |
+ if (!bRecovery) { | |
+ dwFileAttributes = GetFileAttributes(psz); | |
+ bReadOnly = (dwFileAttributes != INVALID_FILE_ATTRIBUTES && dwFileAttributes & FILE_ATTRIBUTE_READONLY); | |
+ if (fSuccess && !fLoad) | |
+ { | |
+ bNotARealSavePoint = FALSE; | |
+ } | |
+ } | |
+ if (fSuccess && fLoad) | |
+ bIsRecovered = bRecovery; | |
StatusSetSimple(hwndStatus,FALSE); | |
EndWaitCursor(); | |
@@ -6821,28 +6973,188 @@ BOOL FileIO(BOOL fLoad,LPCWSTR psz,BOOL bNoEncDetect,int *ienc,int *ieol, | |
return(fSuccess); | |
} | |
+unsigned long HashBytes(BYTE *data, int length) | |
+{ | |
+ unsigned long hash = 5381; | |
+ | |
+ for (size_t i = 0; i < length; i++) | |
+ { | |
+ int c = data[i]; | |
+ hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ | |
+ } | |
+ | |
+ return hash; | |
+} | |
+ | |
+void InitRecoveryFilePath(PWCHAR originalFile, PWCHAR dest) | |
+{ | |
+ if (IniGetInt(L"Settings2", L"AutomaticFileRecovery", 1) == 0) | |
+ { | |
+ wcscpy(dest, L""); | |
+ return; | |
+ } | |
+ wcscpy(dest, szRecoveryDirectory); | |
+ if(dest[wcslen(dest) - 1] != '\\') wcscat(dest, L"\\"); | |
+ | |
+ | |
+ if (wcslen(originalFile) == 0) | |
+ { | |
+ wcscat(dest, L"Untitled--"); | |
+ SYSTEMTIME time; | |
+ GetSystemTime(&time); | |
+ GetDateFormat(LOCALE_INVARIANT, 0, &time, L"yyyy-MM-dd--", dest + wcslen(dest), 256); | |
+ GetTimeFormat(LOCALE_INVARIANT, 0, &time, L"hh-mm-ss--", dest + wcslen(dest), 256); | |
+ srand((UINT)GetTickCount()); | |
+ int r = abs(rand()); | |
+ wsprintf(dest + wcslen(dest), L"%d", r); | |
+ wcscat(dest, L".txt.dat"); | |
+ } | |
+ else | |
+ { | |
+ PWCHAR lastBackslash = wcsrchr(originalFile, '\\'); | |
+ if (lastBackslash != NULL) | |
+ { | |
+ WCHAR buffer[MAX_PATH + 40]; | |
+ wcscpy(buffer, originalFile); | |
+ wcsupr(buffer); | |
+ | |
+ unsigned long hash1 = HashBytes(((byte*)buffer) + 0, wcslen(buffer) * 2 + 0); | |
+ unsigned long hash2 = HashBytes(((byte*)buffer) + 1, wcslen(buffer) * 2 - 1); | |
+ | |
+ wsprintf(dest + wcslen(dest), L"%hu%hu--", hash1, hash2);; | |
+ wcscat(dest, lastBackslash + 1); | |
+ wcscat(dest, L".dat"); | |
+ } | |
+ else | |
+ { | |
+ wcscat(dest, L"wat"); | |
+ } | |
+ } | |
+ | |
+ | |
+ | |
+ | |
+} | |
+ | |
+ | |
+BOOL LoadRecoveryFile(PWCHAR pszRecoveryFileName) | |
+{ | |
+ WCHAR szRecoveryFilePath[MAX_PATH]; | |
+ wcscpy(szRecoveryFilePath, szRecoveryDirectory); | |
+ PathAppend(szRecoveryFilePath, pszRecoveryFileName); | |
+ BOOL bResult = FALSE; | |
+ HANDLE hFile = CreateFile(szRecoveryFilePath, | |
+ GENERIC_READ, | |
+ FILE_SHARE_READ | FILE_SHARE_WRITE, | |
+ NULL, | |
+ OPEN_EXISTING, | |
+ FILE_ATTRIBUTE_NORMAL, | |
+ NULL); | |
+ if (hFile == INVALID_HANDLE_VALUE) return bResult; | |
+ DWORD magic; | |
+ DWORD pathLength; | |
+ if (!ReadFile(hFile, &magic, 4, NULL, NULL)) goto cleanup; | |
+ if (magic != RECOVERY_FILE_MAGIC_NUMBER) goto cleanup; | |
+ if (!ReadFile(hFile, &pathLength, 4, NULL, NULL)) goto cleanup; | |
+ WCHAR szOriginalPath[MAX_PATH]; | |
+ if (!ReadFile(hFile, &szOriginalPath, (pathLength + 1) * 2, NULL, NULL)) goto cleanup; | |
+ | |
+ if (wcslen(szOriginalPath) != 0) | |
+ { | |
+ if (wcsicmp(szOriginalPath, szCurFile) == 0) goto cleanup; | |
+ } | |
+ else | |
+ { | |
+ if (wcsicmp(szRecoveryFilePath, szRecoveryFile) == 0) goto cleanup; | |
+ } | |
+ | |
+ if (!FileLoadEx(FALSE, FALSE, FALSE, FALSE, szOriginalPath, szRecoveryFilePath, TRUE)) goto cleanup; | |
+ bResult = TRUE; | |
+cleanup: | |
+ CloseHandle(hFile); | |
+ return bResult; | |
+} | |
+ | |
+BOOL SaveRecoveryFile() | |
+{ | |
+ bModifiedSinceLastRecoverySave = FALSE; | |
+ | |
+ int encoding = iEncoding; | |
+ int eol = iEOLMode; | |
+ BOOL cancelDataLoss = FALSE; | |
+ | |
+ if (!bModified || wcslen(szCurFile) == 0 && (int)SendMessage(hwndEdit,SCI_GETLENGTH,0,0) == 0) | |
+ { | |
+ StopFileRecoveryTimer(TRUE); | |
+ return TRUE; | |
+ } | |
+ else | |
+ { | |
+ SHCreateDirectoryEx(NULL, szRecoveryDirectory, NULL); | |
+ return FileIO(FALSE, szRecoveryFile, FALSE, &encoding, &eol, NULL, NULL, &cancelDataLoss, TRUE, TRUE); | |
+ } | |
+ | |
+} | |
+ | |
+ | |
+ | |
+void CALLBACK FileRecoveryTimerCallback(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) | |
+{ | |
+ StopFileRecoveryTimer(FALSE); | |
+ SaveRecoveryFile(); | |
+ pFileRecoveryTimer = NULL; | |
+} | |
+ | |
+void StartFileRecoveryTimer() { | |
+ if (pFileRecoveryTimer != NULL) return; | |
+ pFileRecoveryTimer = SetTimer(hwndMain, ID_FILERECOVERYTIMER, iRecoveryInterval, FileRecoveryTimerCallback); | |
+} | |
+ | |
+ | |
+void StopFileRecoveryTimer(BOOL deleteRecoveryFile) { | |
+ bModifiedSinceLastRecoverySave = FALSE; | |
+ if (deleteRecoveryFile && wcslen(szRecoveryFile) != 0) { | |
+ DeleteFile(szRecoveryFile); | |
+ } | |
+ if (pFileRecoveryTimer != NULL) | |
+ { | |
+ KillTimer(hwndMain, pFileRecoveryTimer); | |
+ pFileRecoveryTimer = NULL; | |
+ } | |
+} | |
+ | |
//============================================================================= | |
// | |
// FileLoad() | |
// | |
// | |
-BOOL FileLoad(BOOL bDontSave,BOOL bNew,BOOL bReload,BOOL bNoEncDetect,LPCWSTR lpszFile) | |
+BOOL FileLoad(BOOL bDontSave, BOOL bNew, BOOL bReload, BOOL bNoEncDetect, LPCWSTR lpszFile) | |
+{ | |
+ return FileLoadEx(bDontSave,bNew,bReload,bNoEncDetect,lpszFile,NULL,FALSE); | |
+} | |
+BOOL FileLoadEx(BOOL bDontSave,BOOL bNew,BOOL bReload,BOOL bNoEncDetect,LPCWSTR lpszFile,LPCWSTR lpszRecoveryPath,BOOL bAllowSaveToRecovery) | |
{ | |
WCHAR tch[MAX_PATH] = L""; | |
WCHAR szFileName[MAX_PATH] = L""; | |
BOOL fSuccess; | |
BOOL bUnicodeErr = FALSE; | |
BOOL bFileTooBig = FALSE; | |
+ BOOL bIsRecoveredUntitledFile = wcslen(lpszFile) == 0 && lpszRecoveryPath != NULL; | |
if (!bDontSave) | |
{ | |
- if (!FileSave(FALSE,TRUE,FALSE,FALSE)) | |
+ if (!FileSaveEx(FALSE,TRUE,FALSE,FALSE,bAllowSaveToRecovery)) | |
return FALSE; | |
+ wcscpy(szRecoveryFile, L""); | |
} | |
+ StopFileRecoveryTimer(TRUE); | |
+ bIsRecovered = FALSE; | |
if (bNew) { | |
lstrcpy(szCurFile,L""); | |
+ InitRecoveryFilePath(szCurFile, szRecoveryFile); | |
+ bNotARealSavePoint = FALSE; | |
SetDlgItemText(hwndMain,IDC_FILENAME,szCurFile); | |
SetDlgItemInt(hwndMain,IDC_REUSELOCK,GetTickCount(),FALSE); | |
if (!fKeepTitleExcerpt) | |
@@ -6861,7 +7173,7 @@ BOOL FileLoad(BOOL bDontSave,BOOL bNew,BOOL bReload,BOOL bNoEncDetect,LPCWSTR lp | |
EditSetNewText(hwndEdit,"",0); | |
SetWindowTitle(hwndMain,uidsAppTitle,fIsElevated,IDS_UNTITLED,szCurFile, | |
iPathNameFormat,bModified || iEncoding != iOriginalEncoding, | |
- IDS_READONLY,bReadOnly,szTitleExcerpt); | |
+ IDS_READONLY,bReadOnly,szTitleExcerpt,bIsRecovered); | |
// Terminate file watching | |
if (bResetFileWatching) | |
@@ -6871,7 +7183,7 @@ BOOL FileLoad(BOOL bDontSave,BOOL bNew,BOOL bReload,BOOL bNoEncDetect,LPCWSTR lp | |
return TRUE; | |
} | |
- if (!lpszFile || lstrlen(lpszFile) == 0) { | |
+ if ((!lpszFile || lstrlen(lpszFile) == 0) && lpszRecoveryPath == NULL) { | |
if (!OpenFileDlg(hwndMain,tch,COUNTOF(tch),NULL)) | |
return FALSE; | |
} | |
@@ -6881,7 +7193,7 @@ BOOL FileLoad(BOOL bDontSave,BOOL bNew,BOOL bReload,BOOL bNoEncDetect,LPCWSTR lp | |
ExpandEnvironmentStringsEx(tch,COUNTOF(tch)); | |
- if (PathIsRelative(tch)) { | |
+ if (PathIsRelative(tch) && !bIsRecoveredUntitledFile) { | |
StrCpyN(szFileName,g_wchWorkingDirectory,COUNTOF(szFileName)); | |
PathAppend(szFileName,tch); | |
if (!PathFileExists(szFileName)) { | |
@@ -6894,14 +7206,18 @@ BOOL FileLoad(BOOL bDontSave,BOOL bNew,BOOL bReload,BOOL bNoEncDetect,LPCWSTR lp | |
else | |
lstrcpy(szFileName,tch); | |
- PathCanonicalizeEx(szFileName); | |
- GetLongPathNameEx(szFileName,COUNTOF(szFileName)); | |
+ if (!bIsRecoveredUntitledFile) { | |
+ PathCanonicalizeEx(szFileName); | |
+ GetLongPathNameEx(szFileName, COUNTOF(szFileName)); | |
- if (PathIsLnkFile(szFileName)) | |
- PathGetLnkPath(szFileName,szFileName,COUNTOF(szFileName)); | |
+ if (PathIsLnkFile(szFileName)) | |
+ PathGetLnkPath(szFileName, szFileName, COUNTOF(szFileName)); | |
+ } | |
+ | |
+ BOOL usedRecoveryInfo = FALSE; | |
// Ask to create a new file... | |
- if (!bReload && !PathFileExists(szFileName)) | |
+ if (!bReload && !PathFileExists(szFileName) && lpszRecoveryPath == NULL) | |
{ | |
if (flagQuietCreate || MsgBox(MBYESNO,IDS_ASK_CREATE,szFileName) == IDYES) { | |
HANDLE hFile = CreateFile(szFileName, | |
@@ -6933,10 +7249,44 @@ BOOL FileLoad(BOOL bDontSave,BOOL bNew,BOOL bReload,BOOL bNoEncDetect,LPCWSTR lp | |
} | |
else | |
- fSuccess = FileIO(TRUE,szFileName,bNoEncDetect,&iEncoding,&iEOLMode,&bUnicodeErr,&bFileTooBig,NULL,FALSE); | |
+ { | |
+ WCHAR szRecoveryFileToReadFrom[MAX_PATH + 40] = L""; | |
+ if (bIsRecoveredUntitledFile) | |
+ { | |
+ wcscpy(szRecoveryFileToReadFrom, lpszRecoveryPath); | |
+ usedRecoveryInfo = TRUE; | |
+ } | |
+ else | |
+ { | |
+ InitRecoveryFilePath(szFileName, szRecoveryFileToReadFrom); | |
+ usedRecoveryInfo = wcslen(szRecoveryFileToReadFrom) && GetFileAttributes(szRecoveryFileToReadFrom) != INVALID_FILE_ATTRIBUTES; | |
+ } | |
+ fSuccess = FileIO(TRUE, usedRecoveryInfo ? szRecoveryFileToReadFrom : szFileName, bNoEncDetect, &iEncoding, &iEOLMode, &bUnicodeErr, &bFileTooBig, NULL, FALSE, usedRecoveryInfo); | |
+ if (fSuccess) | |
+ { | |
+ if (usedRecoveryInfo) { | |
+ bNotARealSavePoint = TRUE; | |
+ if (bIsRecoveredUntitledFile) | |
+ { | |
+ bReadOnly = FALSE; | |
+ } | |
+ else | |
+ { | |
+ DWORD dwFileAttributes = GetFileAttributes(szFileName); | |
+ bReadOnly = (dwFileAttributes != INVALID_FILE_ATTRIBUTES && dwFileAttributes & FILE_ATTRIBUTE_READONLY); | |
+ } | |
+ } | |
+ else | |
+ { | |
+ bNotARealSavePoint = FALSE; | |
+ } | |
+ } | |
+ } | |
if (fSuccess) { | |
lstrcpy(szCurFile,szFileName); | |
+ if (lpszRecoveryPath != NULL) wcscpy(szRecoveryFile, lpszRecoveryPath); | |
+ else InitRecoveryFilePath(szCurFile,szRecoveryFile); | |
SetDlgItemText(hwndMain,IDC_FILENAME,szCurFile); | |
SetDlgItemInt(hwndMain,IDC_REUSELOCK,GetTickCount(),FALSE); | |
if (!fKeepTitleExcerpt) | |
@@ -6945,7 +7295,7 @@ BOOL FileLoad(BOOL bDontSave,BOOL bNew,BOOL bReload,BOOL bNoEncDetect,LPCWSTR lp | |
Style_SetLexerFromFile(hwndEdit,szCurFile); | |
UpdateLineNumberWidth(); | |
iOriginalEncoding = iEncoding; | |
- bModified = FALSE; | |
+ bModified = usedRecoveryInfo; | |
//bReadOnly = FALSE; | |
SendMessage(hwndEdit,SCI_SETEOLMODE,iEOLMode,0); | |
MRU_AddFile(pFileMRU,szFileName,flagRelativeFileMRU,flagPortableMyDocs); | |
@@ -6953,7 +7303,7 @@ BOOL FileLoad(BOOL bDontSave,BOOL bNew,BOOL bReload,BOOL bNoEncDetect,LPCWSTR lp | |
SHAddToRecentDocs(SHARD_PATHW,szFileName); | |
SetWindowTitle(hwndMain,uidsAppTitle,fIsElevated,IDS_UNTITLED,szFileName, | |
iPathNameFormat,bModified || iEncoding != iOriginalEncoding, | |
- IDS_READONLY,bReadOnly,szTitleExcerpt); | |
+ IDS_READONLY,bReadOnly,szTitleExcerpt,bIsRecovered); | |
// Install watching of the current file | |
if (!bReload && bResetFileWatching) | |
@@ -6985,6 +7335,8 @@ BOOL FileLoad(BOOL bDontSave,BOOL bNew,BOOL bReload,BOOL bNoEncDetect,LPCWSTR lp | |
else if (!bFileTooBig) | |
MsgBox(MBWARN,IDS_ERR_LOADFILE,szFileName); | |
+ if (fSuccess && bReload) bIgnoreNextChangeNotificationForRecovery = TRUE; | |
+ | |
return(fSuccess); | |
} | |
@@ -6994,12 +7346,21 @@ BOOL FileLoad(BOOL bDontSave,BOOL bNew,BOOL bReload,BOOL bNoEncDetect,LPCWSTR lp | |
// FileSave() | |
// | |
// | |
-BOOL FileSave(BOOL bSaveAlways,BOOL bAsk,BOOL bSaveAs,BOOL bSaveCopy) | |
+ | |
+BOOL FileSave(BOOL bSaveAlways, BOOL bAsk, BOOL bSaveAs, BOOL bSaveCopy) | |
+{ | |
+ return FileSaveEx(bSaveAlways, bAsk, bSaveAs, bSaveCopy, FALSE); | |
+} | |
+BOOL FileSaveEx(BOOL bSaveAlways,BOOL bAsk,BOOL bSaveAs,BOOL bSaveCopy,BOOL bAllowSaveToRecovery) | |
{ | |
WCHAR tchFile[MAX_PATH]; | |
BOOL fSuccess = FALSE; | |
BOOL bCancelDataLoss = FALSE; | |
+ if (bIsRecovered) bAllowSaveToRecovery = TRUE; | |
+ | |
+ if (wcslen(szRecoveryFile) == 0 || !IniGetInt(L"Settings2", L"AutomaticFileRecovery", 1)) bAllowSaveToRecovery = FALSE; | |
+ | |
BOOL bIsEmptyNewFile = FALSE; | |
if (lstrlen(szCurFile) == 0) { | |
int cchText = (int)SendMessage(hwndEdit,SCI_GETLENGTH,0,0); | |
@@ -7014,11 +7375,23 @@ BOOL FileSave(BOOL bSaveAlways,BOOL bAsk,BOOL bSaveAs,BOOL bSaveCopy) | |
} | |
} | |
- if (!bSaveAlways && (!bModified && iEncoding == iOriginalEncoding || bIsEmptyNewFile) && !bSaveAs) | |
+ if (!bSaveAlways && (!bModified && iEncoding == iOriginalEncoding || bIsEmptyNewFile) && !bSaveAs) { | |
return TRUE; | |
+ } | |
+ | |
+ if (!bModifiedSinceLastRecoverySave && bIsEmptyNewFile && !bSaveAs && !bSaveAlways) | |
+ { | |
+ SaveRecoveryFile(); // Deletes the current empty recovery file | |
+ return TRUE; | |
+ } | |
+ | |
if (bAsk) | |
{ | |
+ if (bAllowSaveToRecovery) | |
+ { | |
+ return SaveRecoveryFile(); | |
+ } | |
// File or "Untitled" ... | |
WCHAR tch[MAX_PATH]; | |
if (lstrlen(szCurFile)) | |
@@ -7043,7 +7416,7 @@ BOOL FileSave(BOOL bSaveAlways,BOOL bAsk,BOOL bSaveAs,BOOL bSaveCopy) | |
if (bReadOnly) { | |
SetWindowTitle(hwndMain,uidsAppTitle,fIsElevated,IDS_UNTITLED,szCurFile, | |
iPathNameFormat,bModified || iEncoding != iOriginalEncoding, | |
- IDS_READONLY,bReadOnly,szTitleExcerpt); | |
+ IDS_READONLY,bReadOnly,szTitleExcerpt,bIsRecovered); | |
if (MsgBox(MBYESNOWARN,IDS_READONLY_SAVE,szCurFile) == IDYES) | |
bSaveAs = TRUE; | |
else | |
@@ -7065,11 +7438,13 @@ BOOL FileSave(BOOL bSaveAlways,BOOL bAsk,BOOL bSaveAs,BOOL bSaveCopy) | |
if (SaveFileDlg(hwndMain,tchFile,COUNTOF(tchFile),tchInitialDir)) | |
{ | |
- if (fSuccess = FileIO(FALSE,tchFile,FALSE,&iEncoding,&iEOLMode,NULL,NULL,&bCancelDataLoss,bSaveCopy)) | |
+ if (fSuccess = FileIO(FALSE,tchFile,FALSE,&iEncoding,&iEOLMode,NULL,NULL,&bCancelDataLoss,bSaveCopy,FALSE)) | |
{ | |
if (!bSaveCopy) | |
{ | |
lstrcpy(szCurFile,tchFile); | |
+ StopFileRecoveryTimer(TRUE); | |
+ InitRecoveryFilePath(szCurFile, szRecoveryFile); | |
SetDlgItemText(hwndMain,IDC_FILENAME,szCurFile); | |
SetDlgItemInt(hwndMain,IDC_REUSELOCK,GetTickCount(),FALSE); | |
if (!fKeepTitleExcerpt) | |
@@ -7089,12 +7464,13 @@ BOOL FileSave(BOOL bSaveAlways,BOOL bAsk,BOOL bSaveAs,BOOL bSaveCopy) | |
} | |
else | |
- fSuccess = FileIO(FALSE,szCurFile,FALSE,&iEncoding,&iEOLMode,NULL,NULL,&bCancelDataLoss,FALSE); | |
+ fSuccess = FileIO(FALSE,szCurFile,FALSE,&iEncoding,&iEOLMode,NULL,NULL,&bCancelDataLoss,FALSE,FALSE); | |
if (fSuccess) | |
{ | |
if (!bSaveCopy) | |
{ | |
+ bIsRecovered = FALSE; | |
bModified = FALSE; | |
iOriginalEncoding = iEncoding; | |
MRU_AddFile(pFileMRU,szCurFile,flagRelativeFileMRU,flagPortableMyDocs); | |
@@ -7102,7 +7478,8 @@ BOOL FileSave(BOOL bSaveAlways,BOOL bAsk,BOOL bSaveAs,BOOL bSaveCopy) | |
SHAddToRecentDocs(SHARD_PATHW,szCurFile); | |
SetWindowTitle(hwndMain,uidsAppTitle,fIsElevated,IDS_UNTITLED,szCurFile, | |
iPathNameFormat,bModified || iEncoding != iOriginalEncoding, | |
- IDS_READONLY,bReadOnly,szTitleExcerpt); | |
+ IDS_READONLY,bReadOnly,szTitleExcerpt,bIsRecovered); | |
+ StopFileRecoveryTimer(TRUE); | |
// Install watching of the current file | |
if (bSaveAs && bResetFileWatching) | |
@@ -7118,7 +7495,7 @@ BOOL FileSave(BOOL bSaveAlways,BOOL bAsk,BOOL bSaveAs,BOOL bSaveCopy) | |
SetWindowTitle(hwndMain,uidsAppTitle,fIsElevated,IDS_UNTITLED,szCurFile, | |
iPathNameFormat,bModified || iEncoding != iOriginalEncoding, | |
- IDS_READONLY,bReadOnly,szTitleExcerpt); | |
+ IDS_READONLY,bReadOnly,szTitleExcerpt,bIsRecovered); | |
MsgBox(MBWARN,IDS_ERR_SAVEFILE,tchFile); | |
} | |
diff --git a/src/Notepad2.h b/src/Notepad2.h | |
index a4c71df..a1391ba 100644 | |
--- a/src/Notepad2.h | |
+++ b/src/Notepad2.h | |
@@ -90,11 +90,17 @@ typedef struct np2params { | |
//==== Paste Board Timer ====================================================== | |
#define ID_PASTEBOARDTIMER 0xA001 | |
+//==== File Recovery Timer ====================================================== | |
+#define ID_FILERECOVERYTIMER 0xA002 | |
//==== Reuse Window Lock Timeout ============================================== | |
#define REUSEWINDOWLOCKTIMEOUT 1000 | |
+ | |
+ | |
+#define RECOVERY_FILE_MAGIC_NUMBER 0x54832144 | |
+ | |
//==== Function Declarations ================================================== | |
BOOL InitApplication(HINSTANCE); | |
HWND InitInstance(HINSTANCE,LPSTR,int); | |
@@ -126,9 +132,10 @@ void UpdateToolbar(); | |
void UpdateLineNumberWidth(); | |
-BOOL FileIO(BOOL,LPCWSTR,BOOL,int*,int*,BOOL*,BOOL*,BOOL*,BOOL); | |
+BOOL FileIO(BOOL,LPCWSTR,BOOL,int*,int*,BOOL*,BOOL*,BOOL*,BOOL,BOOL); | |
BOOL FileLoad(BOOL,BOOL,BOOL,BOOL,LPCWSTR); | |
BOOL FileSave(BOOL,BOOL,BOOL,BOOL); | |
+BOOL FileSaveEx(BOOL,BOOL,BOOL,BOOL,BOOL); | |
BOOL OpenFileDlg(HWND,LPWSTR,int,LPCWSTR); | |
BOOL SaveFileDlg(HWND,LPWSTR,int,LPCWSTR); | |
@@ -138,10 +145,16 @@ LRESULT MsgCreate(HWND,WPARAM,LPARAM); | |
void CreateBars(HWND,HINSTANCE); | |
void MsgThemeChanged(HWND,WPARAM,LPARAM); | |
void MsgSize(HWND,WPARAM,LPARAM); | |
+void PopulateRecoveredFilesMenu(HMENU); | |
void MsgInitMenu(HWND,WPARAM,LPARAM); | |
LRESULT MsgCommand(HWND,WPARAM,LPARAM); | |
LRESULT MsgNotify(HWND,WPARAM,LPARAM); | |
+BOOL SaveRecoveryFile(); | |
+void InitRecoveryFilePath(PWCHAR originalFile, PWCHAR dest); | |
+void CALLBACK FileRecoveryTimerCallback(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime); | |
+void StartFileRecoveryTimer(); | |
+void StopFileRecoveryTimer(BOOL deleteRecoveryFile); | |
/// End of Notepad2.h \\\ | |
diff --git a/src/Notepad2.rc b/src/Notepad2.rc | |
index 7803b2a..652ad0c 100644 | |
--- a/src/Notepad2.rc | |
+++ b/src/Notepad2.rc | |
@@ -119,6 +119,10 @@ BEGIN | |
MENUITEM "&Manage...\tAlt+F9", IDM_FILE_MANAGEFAV | |
END | |
MENUITEM "Recent (&History)...\tAlt+H", IDM_FILE_RECENT | |
+ POPUP "&Recovered" | |
+ BEGIN | |
+ MENUITEM "(Dummy)", IDM_FILE_RECOVERED | |
+ END | |
MENUITEM SEPARATOR | |
MENUITEM "E&xit\tAlt+F4", IDM_FILE_EXIT | |
END | |
@@ -321,7 +325,8 @@ BEGIN | |
MENUITEM "Minimi&ze To Tray", IDM_VIEW_MINTOTRAY | |
MENUITEM "Transparent &Mode\tCtrl+0", IDM_VIEW_TRANSPARENT | |
MENUITEM SEPARATOR | |
- MENUITEM "Single &File Instance", IDM_VIEW_SINGLEFILEINSTANCE | |
+ MENUITEM "Single &File Instance", IDM_VIEW_SINGLEFILEINSTANCE | |
+ MENUITEM "&Automatic File Recovery", IDM_VIEW_FILERECOVERY | |
MENUITEM "File &Change Notification...\tAlt+F5", | |
IDM_VIEW_CHANGENOTIFY | |
POPUP "Window Title Displa&y" | |
diff --git a/src/resource.h b/src/resource.h | |
index 734421a..5a935db 100644 | |
--- a/src/resource.h | |
+++ b/src/resource.h | |
@@ -352,6 +352,7 @@ | |
#define IDM_VIEW_MARKOCCURRENCES_CASE 40451 | |
#define IDM_VIEW_MARKOCCURRENCES_WORD 40452 | |
#define IDM_VIEW_AUTOCOMPLETEWORDS 40453 | |
+#define IDM_VIEW_FILERECOVERY 40454 | |
#define IDM_HELP_ABOUT 40500 | |
#define IDM_TRAY_RESTORE 40600 | |
#define IDM_TRAY_EXIT 40601 | |
@@ -425,6 +426,9 @@ | |
#define IDS_EXPORT_FAIL 50040 | |
#define IDS_CMDLINEHELP 60000 | |
+#define IDM_FILE_RECOVERED 60001 | |
+#define IDM_FILE_RECOVERED_MAX (IDM_FILE_RECOVERED + MAX_RECOVERY_MENU_ITEMS) | |
+ | |
// Next default values for new objects | |
// | |
#ifdef APSTUDIO_INVOKED |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment