From 5512a9221cf99cf407b9dce28677ed625429e812 Mon Sep 17 00:00:00 2001 From: Don Ho Date: Sun, 6 Apr 2014 22:22:54 +0000 Subject: [PATCH] [NEW_FEATURE] Automatic Backup System (in progress). git-svn-id: svn://svn.tuxfamily.org/svnroot/notepadplus/repository/trunk@1216 f5eea248-9336-0410-98b8-ebc06183d4e3 --- PowerEditor/src/Notepad_plus.cpp | 17 ++- PowerEditor/src/Notepad_plus.h | 2 +- PowerEditor/src/NppBigSwitch.cpp | 2 + PowerEditor/src/NppIO.cpp | 134 +++++++++++------- PowerEditor/src/ScitillaComponent/Buffer.cpp | 21 ++- PowerEditor/src/ScitillaComponent/Buffer.h | 3 +- .../src/ScitillaComponent/DocTabView.cpp | 19 ++- 7 files changed, 126 insertions(+), 72 deletions(-) diff --git a/PowerEditor/src/Notepad_plus.cpp b/PowerEditor/src/Notepad_plus.cpp index 37623313..306004af 100644 --- a/PowerEditor/src/Notepad_plus.cpp +++ b/PowerEditor/src/Notepad_plus.cpp @@ -2934,7 +2934,8 @@ bool Notepad_plus::canHideView(int whichOne) return canHide; } -void Notepad_plus::loadBufferIntoView(BufferID id, int whichOne, bool dontClose) { +void Notepad_plus::loadBufferIntoView(BufferID id, int whichOne, bool dontClose) +{ DocTabView * tabToOpen = (whichOne == MAIN_VIEW)?&_mainDocTab:&_subDocTab; ScintillaEditView * viewToOpen = (whichOne == MAIN_VIEW)?&_mainEditView:&_subEditView; @@ -2945,23 +2946,29 @@ void Notepad_plus::loadBufferIntoView(BufferID id, int whichOne, bool dontClose) BufferID idToClose = BUFFER_INVALID; //Check if the tab has a single clean buffer. Close it if so - if (!dontClose && tabToOpen->nbItem() == 1) { + if (!dontClose && tabToOpen->nbItem() == 1) + { idToClose = tabToOpen->getBufferByIndex(0); Buffer * buf = MainFileManager->getBufferByID(idToClose); - if (buf->isDirty() || !buf->isUntitled()) { + if (buf->isDirty() || !buf->isUntitled()) + { idToClose = BUFFER_INVALID; } } MainFileManager->addBufferReference(id, viewToOpen); - if (idToClose != BUFFER_INVALID) { //close clean doc. Use special logic to prevent flicker of tab showing then hiding + //close clean doc. Use special logic to prevent flicker of tab showing then hiding + if (idToClose != BUFFER_INVALID) + { tabToOpen->setBuffer(0, id); //index 0 since only one open activateBuffer(id, whichOne); //activate. DocTab already activated but not a problem MainFileManager->closeBuffer(idToClose, viewToOpen); //delete the buffer if (_pFileSwitcherPanel) _pFileSwitcherPanel->closeItem((int)idToClose, whichOne); - } else { + } + else + { tabToOpen->addBuffer(id); } } diff --git a/PowerEditor/src/Notepad_plus.h b/PowerEditor/src/Notepad_plus.h index b744d48b..94d69927 100644 --- a/PowerEditor/src/Notepad_plus.h +++ b/PowerEditor/src/Notepad_plus.h @@ -220,7 +220,7 @@ public: // fileOperations //The doXXX functions apply to a single buffer and dont need to worry about views, with the excpetion of doClose, since closing one view doesnt have to mean the document is gone - BufferID doOpen(const TCHAR *fileName, bool isRecursive = false, bool isReadOnly = false, int encoding = -1); + BufferID doOpen(const TCHAR *fileName, bool isRecursive = false, bool isReadOnly = false, int encoding = -1, const TCHAR *backupFileName = NULL, time_t fileNameTimestamp = 0); bool doReload(BufferID id, bool alert = true); bool doSave(BufferID, const TCHAR * filename, bool isSaveCopy = false); void doClose(BufferID, int whichOne, bool doDeleteBackup = false); diff --git a/PowerEditor/src/NppBigSwitch.cpp b/PowerEditor/src/NppBigSwitch.cpp index fb118f28..e4c5a409 100644 --- a/PowerEditor/src/NppBigSwitch.cpp +++ b/PowerEditor/src/NppBigSwitch.cpp @@ -1398,6 +1398,8 @@ LRESULT Notepad_plus::process(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPa if (_pTrayIco) _pTrayIco->doTrayIcon(REMOVE); + MainFileManager->backupCurrentBuffer(); + const NppGUI & nppgui = pNppParam->getNppGUI(); Session currentSession; if (nppgui._rememberLastSession) diff --git a/PowerEditor/src/NppIO.cpp b/PowerEditor/src/NppIO.cpp index feb2bc40..405fb84e 100644 --- a/PowerEditor/src/NppIO.cpp +++ b/PowerEditor/src/NppIO.cpp @@ -35,7 +35,7 @@ #include -BufferID Notepad_plus::doOpen(const TCHAR *fileName, bool isRecursive, bool isReadOnly, int encoding) +BufferID Notepad_plus::doOpen(const TCHAR *fileName, bool isRecursive, bool isReadOnly, int encoding, const TCHAR *backupFileName, time_t fileNameTimestamp) { NppParameters *pNppParam = NppParameters::getInstance(); TCHAR longFileName[MAX_PATH]; @@ -43,6 +43,13 @@ BufferID Notepad_plus::doOpen(const TCHAR *fileName, bool isRecursive, bool isRe ::GetFullPathName(fileName, MAX_PATH, longFileName, NULL); ::GetLongPathName(longFileName, longFileName, MAX_PATH); + bool isBackupMode = backupFileName != NULL && PathFileExists(backupFileName); + if (isBackupMode && !PathFileExists(longFileName)) // UNTITLED + { + lstrcpy(longFileName, fileName); + } + + _lastRecentFileList.remove(longFileName); const TCHAR * fileName2Find; @@ -90,41 +97,45 @@ BufferID Notepad_plus::doOpen(const TCHAR *fileName, bool isRecursive, bool isRe } bool globbing = wcsrchr(longFileName, TCHAR('*')) || wcsrchr(longFileName, TCHAR('?')); - if (!PathFileExists(longFileName) && !globbing) - { - TCHAR str2display[MAX_PATH*2]; - generic_string longFileDir(longFileName); - PathRemoveFileSpec(longFileDir); - bool isCreateFileSuccessful = false; - if (PathFileExists(longFileDir.c_str())) - { - wsprintf(str2display, TEXT("%s doesn't exist. Create it?"), longFileName); - if (::MessageBox(_pPublicInterface->getHSelf(), str2display, TEXT("Create new file"), MB_YESNO) == IDYES) - { - bool res = MainFileManager->createEmptyFile(longFileName); - if (res) - { - isCreateFileSuccessful = true; - } - else - { - wsprintf(str2display, TEXT("Cannot create the file \"%s\""), longFileName); - ::MessageBox(_pPublicInterface->getHSelf(), str2display, TEXT("Create new file"), MB_OK); - } - } - } + if (!isBackupMode) // if not backup mode, or backupfile path is invalid + { + if (!PathFileExists(longFileName) && !globbing) + { + TCHAR str2display[MAX_PATH*2]; + generic_string longFileDir(longFileName); + PathRemoveFileSpec(longFileDir); - if (!isCreateFileSuccessful) - { - if (isWow64Off) - { - pNppParam->safeWow64EnableWow64FsRedirection(TRUE); - isWow64Off = false; - } - return BUFFER_INVALID; - } - } + bool isCreateFileSuccessful = false; + if (PathFileExists(longFileDir.c_str())) + { + wsprintf(str2display, TEXT("%s doesn't exist. Create it?"), longFileName); + if (::MessageBox(_pPublicInterface->getHSelf(), str2display, TEXT("Create new file"), MB_YESNO) == IDYES) + { + bool res = MainFileManager->createEmptyFile(longFileName); + if (res) + { + isCreateFileSuccessful = true; + } + else + { + wsprintf(str2display, TEXT("Cannot create the file \"%s\""), longFileName); + ::MessageBox(_pPublicInterface->getHSelf(), str2display, TEXT("Create new file"), MB_OK); + } + } + } + + if (!isCreateFileSuccessful) + { + if (isWow64Off) + { + pNppParam->safeWow64EnableWow64FsRedirection(TRUE); + isWow64Off = false; + } + return BUFFER_INVALID; + } + } + } // Notify plugins that current file is about to load // Plugins can should use this notification to filter SCN_MODIFIED @@ -139,7 +150,15 @@ BufferID Notepad_plus::doOpen(const TCHAR *fileName, bool isRecursive, bool isRe encoding = getHtmlXmlEncoding(longFileName); } - BufferID buffer = MainFileManager->loadFile(longFileName, NULL, encoding); + BufferID buffer; + if (isBackupMode) + { + buffer = MainFileManager->loadFile(longFileName, NULL, encoding, backupFileName, fileNameTimestamp); + } + else + { + buffer = MainFileManager->loadFile(longFileName, NULL, encoding); + } if (buffer != BUFFER_INVALID) { @@ -1321,16 +1340,7 @@ bool Notepad_plus::loadSession(Session & session, bool isBackupMode) for ( ; i < session.nbMainFiles() ; ) { - // _fileName - // _backupFilePath - // _originalFileLastModifTimestamp - // if _backupFilePath is not absent, then load _backupFilePath - // otherwise load _fileName - const TCHAR *pFn; - if (isBackupMode && session._mainViewFiles[i]._backupFilePath != TEXT("")) - pFn = session._mainViewFiles[i]._backupFilePath.c_str(); - else - pFn = session._mainViewFiles[i]._fileName.c_str(); + const TCHAR *pFn = session._mainViewFiles[i]._fileName.c_str(); if (isFileSession(pFn)) { @@ -1347,7 +1357,14 @@ bool Notepad_plus::loadSession(Session & session, bool isBackupMode) } if (PathFileExists(pFn)) { - lastOpened = doOpen(pFn, false, false, session._mainViewFiles[i]._encoding); + if (isBackupMode && session._mainViewFiles[i]._backupFilePath != TEXT("")) + lastOpened = doOpen(pFn, false, false, session._mainViewFiles[i]._encoding, session._mainViewFiles[i]._backupFilePath.c_str(), session._mainViewFiles[i]._originalFileLastModifTimestamp); + else + lastOpened = doOpen(pFn, false, false, session._mainViewFiles[i]._encoding); + } + else if (isBackupMode && PathFileExists(session._mainViewFiles[i]._backupFilePath.c_str())) + { + lastOpened = doOpen(pFn, false, false, session._mainViewFiles[i]._encoding, session._mainViewFiles[i]._backupFilePath.c_str(), session._mainViewFiles[i]._originalFileLastModifTimestamp); } else { @@ -1387,8 +1404,11 @@ bool Notepad_plus::loadSession(Session & session, bool isBackupMode) if (session._mainViewFiles[i]._encoding != -1) buf->setEncoding(session._mainViewFiles[i]._encoding); + if (isBackupMode && session._mainViewFiles[i]._backupFilePath != TEXT("")) + buf->setDirty(true); + //Force in the document so we can add the markers - //Dont use default methods because of performance + //Don't use default methods because of performance Document prevDoc = _mainEditView.execute(SCI_GETDOCPOINTER); _mainEditView.execute(SCI_SETDOCPOINTER, 0, buf->getDocument()); for (size_t j = 0, len = session._mainViewFiles[i]._marks.size(); j < len ; ++j) @@ -1415,11 +1435,7 @@ bool Notepad_plus::loadSession(Session & session, bool isBackupMode) for ( ; k < session.nbSubFiles() ; ) { - const TCHAR *pFn; - if (isBackupMode && session._subViewFiles[i]._backupFilePath != TEXT("")) - pFn = session._subViewFiles[i]._backupFilePath.c_str(); - else - pFn = session._subViewFiles[i]._fileName.c_str(); + const TCHAR *pFn = session._subViewFiles[i]._fileName.c_str(); if (isFileSession(pFn)) { vector::iterator posIt = session._subViewFiles.begin() + k; @@ -1435,13 +1451,20 @@ bool Notepad_plus::loadSession(Session & session, bool isBackupMode) } if (PathFileExists(pFn)) { - lastOpened = doOpen(pFn, false, false, session._subViewFiles[k]._encoding); + if (isBackupMode && session._subViewFiles[i]._backupFilePath != TEXT("")) + lastOpened = doOpen(pFn, false, false, session._subViewFiles[i]._encoding, session._subViewFiles[i]._backupFilePath.c_str(), session._subViewFiles[i]._originalFileLastModifTimestamp); + else + lastOpened = doOpen(pFn, false, false, session._subViewFiles[i]._encoding); //check if already open in main. If so, clone if (_mainDocTab.getIndexByBuffer(lastOpened) != -1) { loadBufferIntoView(lastOpened, SUB_VIEW); } } + else if (isBackupMode && PathFileExists(session._subViewFiles[i]._backupFilePath.c_str())) + { + lastOpened = doOpen(pFn, false, false, session._subViewFiles[i]._encoding, session._subViewFiles[i]._backupFilePath.c_str(), session._subViewFiles[i]._originalFileLastModifTimestamp); + } else { lastOpened = BUFFER_INVALID; @@ -1487,9 +1510,12 @@ bool Notepad_plus::loadSession(Session & session, bool isBackupMode) } buf->setLangType(typeToSet, pLn); buf->setEncoding(session._subViewFiles[k]._encoding); + + if (isBackupMode && session._mainViewFiles[i]._backupFilePath != TEXT("")) + buf->setDirty(true); //Force in the document so we can add the markers - //Dont use default methods because of performance + //Don't use default methods because of performance Document prevDoc = _subEditView.execute(SCI_GETDOCPOINTER); _subEditView.execute(SCI_SETDOCPOINTER, 0, buf->getDocument()); for (size_t j = 0, len = session._subViewFiles[k]._marks.size(); j < len ; ++j) diff --git a/PowerEditor/src/ScitillaComponent/Buffer.cpp b/PowerEditor/src/ScitillaComponent/Buffer.cpp index 7f0af9a6..8bd3933f 100644 --- a/PowerEditor/src/ScitillaComponent/Buffer.cpp +++ b/PowerEditor/src/ScitillaComponent/Buffer.cpp @@ -48,7 +48,6 @@ const int LF = 0x0A; Buffer::Buffer(FileManager * pManager, BufferID id, Document doc, DocFileStatus type, const TCHAR *fileName) //type must be either DOC_REGULAR or DOC_UNNAMED : _pManager(pManager), _id(id), _isDirty(false), _doc(doc), _isFileReadOnly(false), _isUserReadOnly(false), _recentTag(-1), _references(0), _canNotify(false), _timeStamp(0), _needReloading(false), _encoding(-1), _backupFileName(TEXT("")), _isModified(false) - //, _deleteBackupNotification(false), _backupModifiedTimeStamp(0) { NppParameters *pNppParamInst = NppParameters::getInstance(); const NewDocDefaultSettings & ndds = (pNppParamInst->getNppGUI()).getNewDocDefaultSettings(); @@ -457,7 +456,8 @@ void FileManager::closeBuffer(BufferID id, ScintillaEditView * identifier) { } } -BufferID FileManager::loadFile(const TCHAR * filename, Document doc, int encoding) +// backupFileName is sentinel of backup mode: if it's not NULL, then we use it (load it). Otherwise we use filename +BufferID FileManager::loadFile(const TCHAR * filename, Document doc, int encoding, const TCHAR *backupFileName, time_t fileNameTimestamp) { bool ownDoc = false; if (doc == NULL) @@ -469,15 +469,30 @@ BufferID FileManager::loadFile(const TCHAR * filename, Document doc, int encodin TCHAR fullpath[MAX_PATH]; ::GetFullPathName(filename, MAX_PATH, fullpath, NULL); ::GetLongPathName(fullpath, fullpath, MAX_PATH); + + bool isBackupMode = backupFileName != NULL && PathFileExists(backupFileName); + if (isBackupMode && !PathFileExists(fullpath)) // if backup mode and fullpath doesn't exist, we guess is UNTITLED + { + lstrcpy(fullpath, filename); // we restore fullpath with filename, in our case is "new #" + } + Utf8_16_Read UnicodeConvertor; //declare here so we can get information after loading is done formatType format; - bool res = loadFileData(doc, fullpath, &UnicodeConvertor, L_TEXT, encoding, &format); + bool res = loadFileData(doc, backupFileName?backupFileName:fullpath, &UnicodeConvertor, L_TEXT, encoding, &format); if (res) { Buffer * newBuf = new Buffer(this, _nextBufferID, doc, DOC_REGULAR, fullpath); BufferID id = (BufferID) newBuf; newBuf->_id = id; + if (backupFileName != NULL) + { + newBuf->_backupFileName = backupFileName; + if (!PathFileExists(fullpath)) + newBuf->_currentStatus = DOC_UNNAMED; + } + if (fileNameTimestamp != 0) + newBuf->_timeStamp = fileNameTimestamp; _buffers.push_back(newBuf); ++_nrBufs; Buffer * buf = _buffers.at(_nrBufs - 1); diff --git a/PowerEditor/src/ScitillaComponent/Buffer.h b/PowerEditor/src/ScitillaComponent/Buffer.h index 453358b3..16f3722b 100644 --- a/PowerEditor/src/ScitillaComponent/Buffer.h +++ b/PowerEditor/src/ScitillaComponent/Buffer.h @@ -82,7 +82,7 @@ public: void addBufferReference(BufferID id, ScintillaEditView * identifer); //called by Scintilla etc indirectly - BufferID loadFile(const TCHAR * filename, Document doc = NULL, int encoding = -1); //ID == BUFFER_INVALID on failure. If Doc == NULL, a new file is created, otherwise data is loaded in given document + BufferID loadFile(const TCHAR * filename, Document doc = NULL, int encoding = -1, const TCHAR *backupFileName = NULL, time_t fileNameTimestamp = 0); //ID == BUFFER_INVALID on failure. If Doc == NULL, a new file is created, otherwise data is loaded in given document BufferID newEmptyDocument(); //create Buffer from existing Scintilla, used from new Scintillas. If dontIncrease = true, then the new document number isnt increased afterwards. //usefull for temporary but neccesary docs @@ -368,7 +368,6 @@ private : // For backup system generic_string _backupFileName; // default: "" bool _isModified; // default: false - //bool _deleteBackupNotification; // default: false void updateTimeStamp(); diff --git a/PowerEditor/src/ScitillaComponent/DocTabView.cpp b/PowerEditor/src/ScitillaComponent/DocTabView.cpp index d2177ba1..1a1a7ceb 100644 --- a/PowerEditor/src/ScitillaComponent/DocTabView.cpp +++ b/PowerEditor/src/ScitillaComponent/DocTabView.cpp @@ -37,7 +37,8 @@ bool DocTabView::_hideTabBarStatus = false; -void DocTabView::addBuffer(BufferID buffer) { +void DocTabView::addBuffer(BufferID buffer) +{ if (buffer == BUFFER_INVALID) //valid only return; if (this->getIndexByBuffer(buffer) != -1) //no duplicates @@ -117,7 +118,8 @@ BufferID DocTabView::getBufferByIndex(int index) { return (BufferID)tie.lParam; } -void DocTabView::bufferUpdated(Buffer * buffer, int mask) { +void DocTabView::bufferUpdated(Buffer * buffer, int mask) +{ int index = getIndexByBuffer(buffer->getID()); if (index == -1) return; @@ -126,16 +128,18 @@ void DocTabView::bufferUpdated(Buffer * buffer, int mask) { tie.lParam = -1; tie.mask = 0; - - if (mask & BufferChangeReadonly || mask & BufferChangeDirty) { + if (mask & BufferChangeReadonly || mask & BufferChangeDirty) + { tie.mask |= TCIF_IMAGE; tie.iImage = buffer->isDirty()?UNSAVED_IMG_INDEX:SAVED_IMG_INDEX; - if (buffer->isReadOnly()) { + if (buffer->isReadOnly()) + { tie.iImage = REDONLY_IMG_INDEX; } } - if (mask & BufferChangeFilename) { + if (mask & BufferChangeFilename) + { tie.mask |= TCIF_TEXT; tie.pszText = (TCHAR *)buffer->getFileName(); } @@ -148,7 +152,8 @@ void DocTabView::bufferUpdated(Buffer * buffer, int mask) { ::SendMessage(_hParent, WM_SIZE, 0, 0); } -void DocTabView::setBuffer(int index, BufferID id) { +void DocTabView::setBuffer(int index, BufferID id) +{ if (index < 0 || index >= (int)_nbItem) return;