[NEW_FEATURE] Automatic Backup System (in progress).

git-svn-id: svn://svn.tuxfamily.org/svnroot/notepadplus/repository/trunk@1216 f5eea248-9336-0410-98b8-ebc06183d4e3
This commit is contained in:
Don Ho 2014-04-06 22:22:54 +00:00
parent b72f302138
commit 5512a9221c
7 changed files with 126 additions and 72 deletions

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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)

View File

@ -35,7 +35,7 @@
#include <TCHAR.h>
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<sessionFileInfo>::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)

View File

@ -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);

View File

@ -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();

View File

@ -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;