mirror of
https://github.com/notepad-plus-plus/notepad-plus-plus.git
synced 2025-07-04 20:44:43 +02:00
New feature: Log Mornitoring (tail -f)
This feature allows users to monitor log files' writing, as Unix "tail -f" command. Here are the conditions of monitoring: 1. file to monitor should exist. 2. file will be set as readonly during monitoring. 3. each update will scroll to the last line.
This commit is contained in:
parent
50c7e228ff
commit
2ff03fe250
@ -58,7 +58,7 @@ enum tb_stat {tb_saved, tb_unsaved, tb_ro};
|
|||||||
|
|
||||||
#define NPP_INTERNAL_FUCTION_STR TEXT("Notepad++::InternalFunction")
|
#define NPP_INTERNAL_FUCTION_STR TEXT("Notepad++::InternalFunction")
|
||||||
|
|
||||||
int docTabIconIDs[] = {IDI_SAVED_ICON, IDI_UNSAVED_ICON, IDI_READONLY_ICON};
|
int docTabIconIDs[] = {IDI_SAVED_ICON, IDI_UNSAVED_ICON, IDI_READONLY_ICON, IDI_MONITORING_ICON};
|
||||||
|
|
||||||
ToolBarButtonUnit toolBarIcons[] = {
|
ToolBarButtonUnit toolBarIcons[] = {
|
||||||
{IDM_FILE_NEW, IDI_NEW_OFF_ICON, IDI_NEW_ON_ICON, IDI_NEW_OFF_ICON, IDR_FILENEW},
|
{IDM_FILE_NEW, IDI_NEW_OFF_ICON, IDI_NEW_ON_ICON, IDI_NEW_OFF_ICON, IDR_FILENEW},
|
||||||
@ -112,6 +112,7 @@ ToolBarButtonUnit toolBarIcons[] = {
|
|||||||
{IDM_VIEW_DOC_MAP, IDI_VIEW_UD_DLG_OFF_ICON, IDI_VIEW_UD_DLG_ON_ICON, IDI_VIEW_UD_DLG_OFF_ICON, IDR_DOCMAP},
|
{IDM_VIEW_DOC_MAP, IDI_VIEW_UD_DLG_OFF_ICON, IDI_VIEW_UD_DLG_ON_ICON, IDI_VIEW_UD_DLG_OFF_ICON, IDR_DOCMAP},
|
||||||
{IDM_VIEW_FUNC_LIST, IDI_VIEW_UD_DLG_OFF_ICON, IDI_VIEW_UD_DLG_ON_ICON, IDI_VIEW_UD_DLG_OFF_ICON, IDR_FUNC_LIST},
|
{IDM_VIEW_FUNC_LIST, IDI_VIEW_UD_DLG_OFF_ICON, IDI_VIEW_UD_DLG_ON_ICON, IDI_VIEW_UD_DLG_OFF_ICON, IDR_FUNC_LIST},
|
||||||
{IDM_VIEW_FILEBROWSER, IDI_VIEW_UD_DLG_OFF_ICON, IDI_VIEW_UD_DLG_ON_ICON, IDI_VIEW_UD_DLG_OFF_ICON, IDR_FILEBROWSER},
|
{IDM_VIEW_FILEBROWSER, IDI_VIEW_UD_DLG_OFF_ICON, IDI_VIEW_UD_DLG_ON_ICON, IDI_VIEW_UD_DLG_OFF_ICON, IDR_FILEBROWSER},
|
||||||
|
{IDM_VIEW_MONITORING, IDI_VIEW_UD_DLG_OFF_ICON, IDI_VIEW_UD_DLG_ON_ICON, IDI_VIEW_UD_DLG_OFF_ICON, IDR_FILEMONITORING},
|
||||||
|
|
||||||
//-------------------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------------------//
|
||||||
{0, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON},
|
{0, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON},
|
||||||
@ -1923,6 +1924,11 @@ void Notepad_plus::checkDocState()
|
|||||||
|
|
||||||
if (_pAnsiCharPanel)
|
if (_pAnsiCharPanel)
|
||||||
_pAnsiCharPanel->switchEncoding();
|
_pAnsiCharPanel->switchEncoding();
|
||||||
|
|
||||||
|
enableCommand(IDM_VIEW_MONITORING, not curBuf->isUntitled(), MENU | TOOLBAR);
|
||||||
|
enableCommand(IDM_EDIT_SETREADONLY, not curBuf->isMonitoringOn(), MENU);
|
||||||
|
checkMenuItem(IDM_VIEW_MONITORING, curBuf->isMonitoringOn());
|
||||||
|
_toolBar.setCheck(IDM_VIEW_MONITORING, curBuf->isMonitoringOn());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Notepad_plus::checkUndoState()
|
void Notepad_plus::checkUndoState()
|
||||||
@ -3507,7 +3513,7 @@ void Notepad_plus::docGotoAnotherEditView(FileTransferMode mode)
|
|||||||
else //open the document, also copying the position
|
else //open the document, also copying the position
|
||||||
{
|
{
|
||||||
loadBufferIntoView(current, viewToGo);
|
loadBufferIntoView(current, viewToGo);
|
||||||
Buffer * buf = MainFileManager->getBufferByID(current);
|
Buffer *buf = MainFileManager->getBufferByID(current);
|
||||||
_pEditView->saveCurrentPos(); //allow copying of position
|
_pEditView->saveCurrentPos(); //allow copying of position
|
||||||
buf->setPosition(buf->getPosition(_pEditView), _pNonEditView);
|
buf->setPosition(buf->getPosition(_pEditView), _pNonEditView);
|
||||||
_pNonEditView->restoreCurrentPos(); //set position
|
_pNonEditView->restoreCurrentPos(); //set position
|
||||||
@ -3521,19 +3527,25 @@ void Notepad_plus::docGotoAnotherEditView(FileTransferMode mode)
|
|||||||
showView(viewToGo);
|
showView(viewToGo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool monitoringWasOn = false;
|
||||||
|
|
||||||
//Close the document if we transfered the document instead of cloning it
|
//Close the document if we transfered the document instead of cloning it
|
||||||
if (mode == TransferMove)
|
if (mode == TransferMove)
|
||||||
{
|
{
|
||||||
|
Buffer *buf = MainFileManager->getBufferByID(current);
|
||||||
|
monitoringWasOn = buf->isMonitoringOn();
|
||||||
|
|
||||||
//just close the activate document, since thats the one we moved (no search)
|
//just close the activate document, since thats the one we moved (no search)
|
||||||
doClose(_pEditView->getCurrentBufferID(), currentView());
|
doClose(_pEditView->getCurrentBufferID(), currentView());
|
||||||
/*
|
|
||||||
if (noOpenedDoc())
|
|
||||||
::SendMessage(_pPublicInterface->getHSelf(), WM_CLOSE, 0, 0);
|
|
||||||
*/
|
|
||||||
} // else it was cone, so leave it
|
} // else it was cone, so leave it
|
||||||
|
|
||||||
//Activate the other view since thats where the document went
|
//Activate the other view since thats where the document went
|
||||||
switchEditViewTo(viewToGo);
|
switchEditViewTo(viewToGo);
|
||||||
|
|
||||||
|
if (monitoringWasOn)
|
||||||
|
{
|
||||||
|
command(IDM_VIEW_MONITORING);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Notepad_plus::activateBuffer(BufferID id, int whichOne)
|
bool Notepad_plus::activateBuffer(BufferID id, int whichOne)
|
||||||
|
@ -186,7 +186,6 @@ struct VisibleGUIConf final
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class FileDialog;
|
class FileDialog;
|
||||||
class Notepad_plus_Window;
|
class Notepad_plus_Window;
|
||||||
class AnsiCharPanel;
|
class AnsiCharPanel;
|
||||||
@ -643,8 +642,15 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static DWORD WINAPI backupDocument(void *params);
|
static DWORD WINAPI backupDocument(void *params);
|
||||||
//static DWORD WINAPI monitorFileOnChange(void * params);
|
|
||||||
//static DWORD WINAPI monitorDirectoryOnChange(void * params);
|
static DWORD WINAPI monitorFileOnChange(void * params);
|
||||||
|
struct MonitorInfo final {
|
||||||
|
MonitorInfo(Buffer *buf, ScintillaEditView *mainEditorView, ScintillaEditView *subEditorView) :
|
||||||
|
_buffer(buf), _mainEditorView(mainEditorView), _subEditorView(subEditorView) {};
|
||||||
|
Buffer *_buffer = nullptr;
|
||||||
|
ScintillaEditView *_mainEditorView = nullptr;
|
||||||
|
ScintillaEditView *_subEditorView = nullptr;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
File diff suppressed because one or more lines are too long
@ -1754,6 +1754,48 @@ void Notepad_plus::command(int id)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case IDM_VIEW_MONITORING:
|
||||||
|
{
|
||||||
|
static HANDLE hThread = nullptr;
|
||||||
|
Buffer * curBuf = _pEditView->getCurrentBuffer();
|
||||||
|
if (curBuf->isMonitoringOn())
|
||||||
|
{
|
||||||
|
curBuf->stopMonitoring();
|
||||||
|
::CloseHandle(hThread);
|
||||||
|
hThread = nullptr;
|
||||||
|
checkMenuItem(IDM_VIEW_MONITORING, false);
|
||||||
|
_toolBar.setCheck(IDM_VIEW_MONITORING, false);
|
||||||
|
curBuf->setUserReadOnly(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const TCHAR *longFileName = curBuf->getFullPathName();
|
||||||
|
if (::PathFileExists(longFileName))
|
||||||
|
{
|
||||||
|
if (curBuf->isDirty())
|
||||||
|
{
|
||||||
|
::MessageBox(_pPublicInterface->getHSelf(), TEXT("The document is dirty. Please save the modification before monitoring it."), TEXT("Monitoring problem"), MB_OK);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
curBuf->startMonitoring(); // monitoring firstly for making monitoring icon
|
||||||
|
curBuf->setUserReadOnly(true);
|
||||||
|
|
||||||
|
MonitorInfo *monitorInfo = new MonitorInfo(curBuf, &_mainEditView, &_subEditView);
|
||||||
|
hThread = ::CreateThread(NULL, 0, monitorFileOnChange, (void *)monitorInfo, 0, NULL); // will be deallocated while quitting thread
|
||||||
|
checkMenuItem(IDM_VIEW_MONITORING, true);
|
||||||
|
_toolBar.setCheck(IDM_VIEW_MONITORING, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
::MessageBox(_pPublicInterface->getHSelf(), TEXT("The file should exist to be monitored."), TEXT("Monitoring problem"), MB_OK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case IDM_EXECUTE:
|
case IDM_EXECUTE:
|
||||||
{
|
{
|
||||||
bool isFirstTime = !_runDlg.isCreated();
|
bool isFirstTime = !_runDlg.isCreated();
|
||||||
|
@ -33,122 +33,98 @@
|
|||||||
#include "EncodingMapper.h"
|
#include "EncodingMapper.h"
|
||||||
#include "VerticalFileSwitcher.h"
|
#include "VerticalFileSwitcher.h"
|
||||||
#include "functionListPanel.h"
|
#include "functionListPanel.h"
|
||||||
|
#include "ReadDirectoryChanges.h"
|
||||||
#include <tchar.h>
|
#include <tchar.h>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
/*
|
|
||||||
struct monitorFileParams {
|
|
||||||
WCHAR _fullFilePath[MAX_PATH];
|
|
||||||
};
|
|
||||||
|
|
||||||
DWORD WINAPI Notepad_plus::monitorFileOnChange(void * params)
|
DWORD WINAPI Notepad_plus::monitorFileOnChange(void * params)
|
||||||
{
|
{
|
||||||
monitorFileParams *mfp = (monitorFileParams *)params;
|
MonitorInfo *monitorInfo = (MonitorInfo *)params;
|
||||||
|
Buffer *buf = monitorInfo->_buffer;
|
||||||
|
ScintillaEditView *mainEditorView = monitorInfo->_mainEditorView;
|
||||||
|
ScintillaEditView *subEditorView = monitorInfo->_subEditorView;
|
||||||
|
|
||||||
//Le répertoire à surveiller :
|
const TCHAR *fullFileName = (const TCHAR *)buf->getFullPathName();
|
||||||
|
|
||||||
|
//The folder to watch :
|
||||||
WCHAR folderToMonitor[MAX_PATH];
|
WCHAR folderToMonitor[MAX_PATH];
|
||||||
//::MessageBoxW(NULL, mfp->_fullFilePath, TEXT("PATH AFTER thread"), MB_OK);
|
//::MessageBoxW(NULL, mfp->_fullFilePath, TEXT("PATH AFTER thread"), MB_OK);
|
||||||
lstrcpy(folderToMonitor, mfp->_fullFilePath);
|
lstrcpy(folderToMonitor, fullFileName);
|
||||||
|
//MessageBox(NULL, fullFileName, TEXT("fullFileName"), MB_OK);
|
||||||
|
|
||||||
|
::PathRemoveFileSpecW(folderToMonitor);
|
||||||
|
|
||||||
//::PathRemoveFileSpecW(folderToMonitor);
|
//MessageBox(NULL, folderToMonitor, TEXT("folderToMonitor"), MB_OK);
|
||||||
|
|
||||||
|
const DWORD dwNotificationFlags = FILE_NOTIFY_CHANGE_LAST_WRITE;
|
||||||
|
|
||||||
HANDLE hDirectory = ::CreateFile(folderToMonitor,
|
// Create the monitor and add directory to watch.
|
||||||
FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
CReadDirectoryChanges changes;
|
||||||
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
changes.AddDirectory(folderToMonitor, true, dwNotificationFlags);
|
||||||
|
|
||||||
// buffer qui va récuppérer les informations de mise à jour
|
HANDLE changeHandles[] = { buf->getMonitoringEvent(), changes.GetWaitHandle() };
|
||||||
const int MAX_BUFFER = 1024;
|
|
||||||
BYTE buffer[MAX_BUFFER];
|
|
||||||
DWORD nombreDeByteRetournes = 0;
|
|
||||||
|
|
||||||
bool cond = true;
|
bool toBeContinued = true;
|
||||||
while (cond)
|
|
||||||
|
while (toBeContinued)
|
||||||
{
|
{
|
||||||
::Sleep(1000);
|
DWORD waitStatus = ::WaitForMultipleObjects(_countof(changeHandles), changeHandles, FALSE, INFINITE);
|
||||||
// surveille un changement dans le répertoire : il attend tant que rien ne se passe : c’est synchrone.
|
switch (waitStatus)
|
||||||
BOOL res = ReadDirectoryChangesW(hDirectory, buffer, MAX_BUFFER,
|
{
|
||||||
TRUE, FILE_NOTIFY_CHANGE_LAST_WRITE, &nombreDeByteRetournes, NULL, NULL);
|
case WAIT_OBJECT_0 + 0:
|
||||||
|
// Mutex was signaled. User removes this folder or file browser is closed
|
||||||
|
toBeContinued = false;
|
||||||
|
break;
|
||||||
|
|
||||||
if (res == FALSE)
|
case WAIT_OBJECT_0 + 1:
|
||||||
continue;
|
// We've received a notification in the queue.
|
||||||
|
{
|
||||||
|
DWORD dwAction;
|
||||||
|
CStringW wstrFilename;
|
||||||
|
if (changes.CheckOverflow())
|
||||||
|
printStr(L"Queue overflowed.");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
changes.Pop(dwAction, wstrFilename);
|
||||||
|
|
||||||
// puis on transforme le buffer pour être lisible.
|
if (dwAction == FILE_ACTION_MODIFIED && lstrcmp(fullFileName, wstrFilename.GetString()) == 0)
|
||||||
FILE_NOTIFY_INFORMATION *notifyInfo = (FILE_NOTIFY_INFORMATION *)buffer;
|
{
|
||||||
|
MainFileManager->reloadBuffer(buf->getID());
|
||||||
|
buf->updateTimeStamp();
|
||||||
|
|
||||||
wchar_t fn[MAX_PATH];
|
// not only test main view
|
||||||
memset(fn, 0, MAX_PATH*sizeof(wchar_t));
|
if (buf == mainEditorView->getCurrentBuffer())
|
||||||
if (notifyInfo->Action != FILE_ACTION_MODIFIED)
|
{
|
||||||
continue;
|
int lastLineToShow = mainEditorView->execute(SCI_GETLINECOUNT);
|
||||||
|
mainEditorView->scroll(0, lastLineToShow);
|
||||||
|
}
|
||||||
|
// but also test sub-view, because the buffer could be clonned
|
||||||
|
if (buf == subEditorView->getCurrentBuffer())
|
||||||
|
{
|
||||||
|
int lastLineToShow = subEditorView->execute(SCI_GETLINECOUNT);
|
||||||
|
subEditorView->scroll(0, lastLineToShow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
// affiche le fichier qui a été modifié.
|
case WAIT_IO_COMPLETION:
|
||||||
if (notifyInfo->FileNameLength <= 0)
|
// Nothing to do.
|
||||||
continue;
|
break;
|
||||||
|
}
|
||||||
TCHAR str2Display[512];
|
|
||||||
generic_strncpy(fn, notifyInfo->FileName, notifyInfo->FileNameLength / sizeof(wchar_t));
|
|
||||||
generic_sprintf(str2Display, TEXT("offset : %d\raction : %d\rfn len : %d\rfn : %s"), notifyInfo->NextEntryOffset, notifyInfo->Action, notifyInfo->FileNameLength, notifyInfo->FileName);
|
|
||||||
// on peut vérifier avec ceci :
|
|
||||||
//printInt(notifyInfo->NextEntryOffset);
|
|
||||||
//printInt(notifyInfo->FileNameLength);
|
|
||||||
MessageBox(NULL, str2Display, TEXT("name"), MB_OK);
|
|
||||||
}
|
}
|
||||||
return TRUE;
|
|
||||||
|
// Just for sample purposes. The destructor will
|
||||||
|
// call Terminate() automatically.
|
||||||
|
changes.Terminate();
|
||||||
|
//MessageBox(NULL, TEXT("FREEDOM !!!"), TEXT("out"), MB_OK);
|
||||||
|
delete monitorInfo;
|
||||||
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD WINAPI Notepad_plus::monitorDirectoryOnChange(void * params)
|
|
||||||
{
|
|
||||||
monitorFileParams *mfp = (monitorFileParams *)params;
|
|
||||||
|
|
||||||
//Le répertoire à surveiller :
|
|
||||||
WCHAR folderToMonitor[MAX_PATH];
|
|
||||||
//::MessageBoxW(NULL, mfp->_fullFilePath, TEXT("PATH AFTER thread"), MB_OK);
|
|
||||||
lstrcpy(folderToMonitor, mfp->_fullFilePath);
|
|
||||||
|
|
||||||
|
|
||||||
//::PathRemoveFileSpecW(folderToMonitor);
|
|
||||||
|
|
||||||
HANDLE hDirectory = ::CreateFile(folderToMonitor,
|
|
||||||
FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
|
||||||
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL);
|
|
||||||
|
|
||||||
// buffer qui va récuppérer les informations de mise à jour
|
|
||||||
const int MAX_BUFFER = 1024;
|
|
||||||
BYTE buffer[MAX_BUFFER];
|
|
||||||
DWORD nombreDeByteRetournes = 0;
|
|
||||||
|
|
||||||
bool cond = true;
|
|
||||||
while (cond)
|
|
||||||
{
|
|
||||||
::Sleep(1000);
|
|
||||||
// surveille un changement dans le répertoire : il attend tant que rien ne se passe : c’est synchrone.
|
|
||||||
ReadDirectoryChangesW(hDirectory, buffer, MAX_BUFFER,
|
|
||||||
TRUE, FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_FILE_NAME, &nombreDeByteRetournes, NULL, NULL);
|
|
||||||
// puis on transforme le buffer pour être lisible.
|
|
||||||
FILE_NOTIFY_INFORMATION *notifyInfo = (FILE_NOTIFY_INFORMATION *)buffer;
|
|
||||||
|
|
||||||
wchar_t fn[MAX_PATH];
|
|
||||||
memset(fn, 0, MAX_PATH*sizeof(wchar_t));
|
|
||||||
|
|
||||||
//if (notifyInfo->Action != FILE_ACTION_MODIFIED)
|
|
||||||
if (notifyInfo->Action != FILE_ACTION_ADDED && notifyInfo->Action != FILE_ACTION_REMOVED && notifyInfo->Action != FILE_ACTION_RENAMED_OLD_NAME && notifyInfo->Action != FILE_ACTION_RENAMED_NEW_NAME)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// affiche le fichier qui a été modifié.
|
|
||||||
//if (notifyInfo->FileNameLength <= 0)
|
|
||||||
//continue;
|
|
||||||
|
|
||||||
generic_strncpy(fn, notifyInfo->FileName, notifyInfo->FileNameLength / sizeof(wchar_t));
|
|
||||||
|
|
||||||
// on peut vérifier avec ceci :
|
|
||||||
//printInt(notifyInfo->FileNameLength);
|
|
||||||
MessageBox(NULL, fn, TEXT("name"), MB_OK);
|
|
||||||
}
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
BufferID Notepad_plus::doOpen(const generic_string& fileName, bool isRecursive, bool isReadOnly, int encoding, const TCHAR *backupFileName, time_t fileNameTimestamp)
|
BufferID Notepad_plus::doOpen(const generic_string& fileName, bool isRecursive, bool isReadOnly, int encoding, const TCHAR *backupFileName, time_t fileNameTimestamp)
|
||||||
{
|
{
|
||||||
const rsize_t longFileNameBufferSize = MAX_PATH; // TODO stop using fixed-size buffer
|
const rsize_t longFileNameBufferSize = MAX_PATH; // TODO stop using fixed-size buffer
|
||||||
@ -368,20 +344,6 @@ BufferID Notepad_plus::doOpen(const generic_string& fileName, bool isRecursive,
|
|||||||
_pluginsManager.notify(&scnN);
|
_pluginsManager.notify(&scnN);
|
||||||
if (_pFileSwitcherPanel)
|
if (_pFileSwitcherPanel)
|
||||||
_pFileSwitcherPanel->newItem(buf, currentView());
|
_pFileSwitcherPanel->newItem(buf, currentView());
|
||||||
|
|
||||||
/*
|
|
||||||
if (::PathFileExists(longFileName))
|
|
||||||
{
|
|
||||||
// Thread to
|
|
||||||
monitorFileParams *params = new monitorFileParams;
|
|
||||||
lstrcpy(params->_fullFilePath, longFileName);
|
|
||||||
//::MessageBoxW(NULL, params._fullFilePath, TEXT("PATH b4 thread"), MB_OK);
|
|
||||||
//HANDLE hThread = ::CreateThread(NULL, 0, monitorFileOnChange, params, 0, NULL);
|
|
||||||
HANDLE hThread = ::CreateThread(NULL, 0, monitorFileOnChange, params, 0, NULL);
|
|
||||||
::CloseHandle(hThread);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -671,6 +633,12 @@ void Notepad_plus::doClose(BufferID id, int whichOne, bool doDeleteBackup)
|
|||||||
|
|
||||||
int nrDocs = whichOne==MAIN_VIEW?(_mainDocTab.nbItem()):(_subDocTab.nbItem());
|
int nrDocs = whichOne==MAIN_VIEW?(_mainDocTab.nbItem()):(_subDocTab.nbItem());
|
||||||
|
|
||||||
|
if (buf->isMonitoringOn())
|
||||||
|
{
|
||||||
|
// turn off monitoring
|
||||||
|
command(IDM_VIEW_MONITORING);
|
||||||
|
}
|
||||||
|
|
||||||
//Do all the works
|
//Do all the works
|
||||||
bool isBufRemoved = removeBufferFromView(id, whichOne);
|
bool isBufRemoved = removeBufferFromView(id, whichOne);
|
||||||
BufferID hiddenBufferID = BUFFER_INVALID;
|
BufferID hiddenBufferID = BUFFER_INVALID;
|
||||||
|
@ -454,7 +454,7 @@ BOOL Notepad_plus::notify(SCNotification *notification)
|
|||||||
_tabPopupMenu.checkItem(IDM_EDIT_SETREADONLY, isUserReadOnly);
|
_tabPopupMenu.checkItem(IDM_EDIT_SETREADONLY, isUserReadOnly);
|
||||||
|
|
||||||
bool isSysReadOnly = buf->getFileReadOnly();
|
bool isSysReadOnly = buf->getFileReadOnly();
|
||||||
_tabPopupMenu.enableItem(IDM_EDIT_SETREADONLY, !isSysReadOnly);
|
_tabPopupMenu.enableItem(IDM_EDIT_SETREADONLY, not isSysReadOnly && not buf->isMonitoringOn());
|
||||||
_tabPopupMenu.enableItem(IDM_EDIT_CLEARREADONLY, isSysReadOnly);
|
_tabPopupMenu.enableItem(IDM_EDIT_CLEARREADONLY, isSysReadOnly);
|
||||||
|
|
||||||
bool isFileExisting = PathFileExists(buf->getFullPathName()) != FALSE;
|
bool isFileExisting = PathFileExists(buf->getFullPathName()) != FALSE;
|
||||||
|
@ -134,7 +134,7 @@ private:
|
|||||||
|
|
||||||
class Buffer final
|
class Buffer final
|
||||||
{
|
{
|
||||||
friend class FileManager;
|
friend class FileManager;
|
||||||
public:
|
public:
|
||||||
//Loading a document:
|
//Loading a document:
|
||||||
//constructor with ID.
|
//constructor with ID.
|
||||||
@ -167,21 +167,21 @@ public:
|
|||||||
|
|
||||||
bool checkFileState();
|
bool checkFileState();
|
||||||
|
|
||||||
bool isDirty() const {
|
bool isDirty() const {
|
||||||
return _isDirty;
|
return _isDirty;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isReadOnly() const {
|
bool isReadOnly() const {
|
||||||
return (_isUserReadOnly || _isFileReadOnly);
|
return (_isUserReadOnly || _isFileReadOnly);
|
||||||
};
|
};
|
||||||
|
|
||||||
bool isUntitled() const {
|
bool isUntitled() const {
|
||||||
return (_currentStatus == DOC_UNNAMED);
|
return (_currentStatus == DOC_UNNAMED);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool getFileReadOnly() const {
|
bool getFileReadOnly() const {
|
||||||
return _isFileReadOnly;
|
return _isFileReadOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setFileReadOnly(bool ro) {
|
void setFileReadOnly(bool ro) {
|
||||||
_isFileReadOnly = ro;
|
_isFileReadOnly = ro;
|
||||||
@ -189,13 +189,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool getUserReadOnly() const {
|
bool getUserReadOnly() const {
|
||||||
return _isUserReadOnly;
|
return _isUserReadOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setUserReadOnly(bool ro) {
|
void setUserReadOnly(bool ro) {
|
||||||
_isUserReadOnly = ro;
|
_isUserReadOnly = ro;
|
||||||
doNotify(BufferChangeReadonly);
|
doNotify(BufferChangeReadonly);
|
||||||
}
|
}
|
||||||
|
|
||||||
EolType getEolFormat() const {
|
EolType getEolFormat() const {
|
||||||
return _eolFormat;
|
return _eolFormat;
|
||||||
@ -234,7 +234,7 @@ public:
|
|||||||
|
|
||||||
void setDirty(bool dirty);
|
void setDirty(bool dirty);
|
||||||
|
|
||||||
void setPosition(const Position & pos, ScintillaEditView * identifier);
|
void setPosition(const Position & pos, ScintillaEditView * identifier);
|
||||||
Position & getPosition(ScintillaEditView * identifier);
|
Position & getPosition(ScintillaEditView * identifier);
|
||||||
|
|
||||||
void setHeaderLineState(const std::vector<size_t> & folds, ScintillaEditView * identifier);
|
void setHeaderLineState(const std::vector<size_t> & folds, ScintillaEditView * identifier);
|
||||||
@ -266,7 +266,7 @@ public:
|
|||||||
return l->_pCommentStart;
|
return l->_pCommentStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TCHAR * getCommentEnd() const
|
const TCHAR * getCommentEnd() const
|
||||||
{
|
{
|
||||||
Lang *l = getCurrentLang();
|
Lang *l = getCurrentLang();
|
||||||
if (!l)
|
if (!l)
|
||||||
@ -316,16 +316,16 @@ public:
|
|||||||
|
|
||||||
int getFileLength() const; // return file length. -1 if file is not existing.
|
int getFileLength() const; // return file length. -1 if file is not existing.
|
||||||
|
|
||||||
enum fileTimeType {ft_created, ft_modified, ft_accessed};
|
enum fileTimeType { ft_created, ft_modified, ft_accessed };
|
||||||
generic_string getFileTime(fileTimeType ftt) const;
|
generic_string getFileTime(fileTimeType ftt) const;
|
||||||
|
|
||||||
Lang * getCurrentLang() const;
|
Lang * getCurrentLang() const;
|
||||||
|
|
||||||
bool isModified() const {return _isModified;}
|
bool isModified() const { return _isModified; }
|
||||||
void setModifiedStatus(bool isModified) {_isModified = isModified;}
|
void setModifiedStatus(bool isModified) { _isModified = isModified; }
|
||||||
generic_string getBackupFileName() const {return _backupFileName;}
|
generic_string getBackupFileName() const { return _backupFileName; }
|
||||||
void setBackupFileName(generic_string fileName) {_backupFileName = fileName;}
|
void setBackupFileName(generic_string fileName) { _backupFileName = fileName; }
|
||||||
time_t getLastModifiedTimestamp() const {return _timeStamp;}
|
time_t getLastModifiedTimestamp() const { return _timeStamp; }
|
||||||
|
|
||||||
bool isLoadedDirty() const
|
bool isLoadedDirty() const
|
||||||
{
|
{
|
||||||
@ -337,10 +337,25 @@ public:
|
|||||||
_isLoadedDirty = val;
|
_isLoadedDirty = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void startMonitoring() {
|
||||||
|
_isMonitoringOn = true;
|
||||||
|
_eventHandle = ::CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
HANDLE getMonitoringEvent() const {
|
||||||
|
return _eventHandle;
|
||||||
|
};
|
||||||
|
|
||||||
|
void stopMonitoring() {
|
||||||
|
_isMonitoringOn = false;
|
||||||
|
::SetEvent(_eventHandle);
|
||||||
|
::CloseHandle(_eventHandle);
|
||||||
|
};
|
||||||
|
|
||||||
|
bool isMonitoringOn() const { return _isMonitoringOn; };
|
||||||
void updateTimeStamp();
|
void updateTimeStamp();
|
||||||
|
|
||||||
|
private:
|
||||||
int indexOfReference(const ScintillaEditView * identifier) const;
|
int indexOfReference(const ScintillaEditView * identifier) const;
|
||||||
|
|
||||||
void setStatus(DocFileStatus status)
|
void setStatus(DocFileStatus status)
|
||||||
@ -395,4 +410,8 @@ private:
|
|||||||
generic_string _backupFileName;
|
generic_string _backupFileName;
|
||||||
bool _isModified = false;
|
bool _isModified = false;
|
||||||
bool _isLoadedDirty = false; // it's the indicator for finding buffer's initial state
|
bool _isLoadedDirty = false; // it's the indicator for finding buffer's initial state
|
||||||
|
|
||||||
|
// For the monitoring
|
||||||
|
HANDLE _eventHandle = nullptr;
|
||||||
|
bool _isMonitoringOn = false;
|
||||||
};
|
};
|
@ -145,7 +145,11 @@ void DocTabView::bufferUpdated(Buffer * buffer, int mask)
|
|||||||
{
|
{
|
||||||
tie.mask |= TCIF_IMAGE;
|
tie.mask |= TCIF_IMAGE;
|
||||||
tie.iImage = buffer->isDirty()?UNSAVED_IMG_INDEX:SAVED_IMG_INDEX;
|
tie.iImage = buffer->isDirty()?UNSAVED_IMG_INDEX:SAVED_IMG_INDEX;
|
||||||
if (buffer->isReadOnly())
|
if (buffer->isMonitoringOn())
|
||||||
|
{
|
||||||
|
tie.iImage = MONITORING_IMG_INDEX;
|
||||||
|
}
|
||||||
|
else if (buffer->isReadOnly())
|
||||||
{
|
{
|
||||||
tie.iImage = REDONLY_IMG_INDEX;
|
tie.iImage = REDONLY_IMG_INDEX;
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
const int SAVED_IMG_INDEX = 0;
|
const int SAVED_IMG_INDEX = 0;
|
||||||
const int UNSAVED_IMG_INDEX = 1;
|
const int UNSAVED_IMG_INDEX = 1;
|
||||||
const int REDONLY_IMG_INDEX = 2;
|
const int REDONLY_IMG_INDEX = 2;
|
||||||
|
const int MONITORING_IMG_INDEX = 3;
|
||||||
|
|
||||||
class DocTabView : public TabBarPlus
|
class DocTabView : public TabBarPlus
|
||||||
{
|
{
|
||||||
|
BIN
PowerEditor/src/icons/fileMonitoring.bmp
Normal file
BIN
PowerEditor/src/icons/fileMonitoring.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
BIN
PowerEditor/src/icons/monitoring.ico
Normal file
BIN
PowerEditor/src/icons/monitoring.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.9 KiB |
Binary file not shown.
Before Width: | Height: | Size: 822 B |
@ -333,6 +333,7 @@
|
|||||||
#define IDM_VIEW_TAB9 (IDM_VIEW + 94)
|
#define IDM_VIEW_TAB9 (IDM_VIEW + 94)
|
||||||
#define IDM_VIEW_TAB_NEXT (IDM_VIEW + 95)
|
#define IDM_VIEW_TAB_NEXT (IDM_VIEW + 95)
|
||||||
#define IDM_VIEW_TAB_PREV (IDM_VIEW + 96)
|
#define IDM_VIEW_TAB_PREV (IDM_VIEW + 96)
|
||||||
|
#define IDM_VIEW_MONITORING (IDM_VIEW + 97)
|
||||||
|
|
||||||
#define IDM_VIEW_GOTO_ANOTHER_VIEW 10001
|
#define IDM_VIEW_GOTO_ANOTHER_VIEW 10001
|
||||||
#define IDM_VIEW_CLONE_TO_ANOTHER_VIEW 10002
|
#define IDM_VIEW_CLONE_TO_ANOTHER_VIEW 10002
|
||||||
|
@ -131,6 +131,7 @@
|
|||||||
#define IDI_UNSAVED_ICON 502
|
#define IDI_UNSAVED_ICON 502
|
||||||
#define IDI_READONLY_ICON 503
|
#define IDI_READONLY_ICON 503
|
||||||
#define IDI_FIND_RESULT_ICON 504
|
#define IDI_FIND_RESULT_ICON 504
|
||||||
|
#define IDI_MONITORING_ICON 505
|
||||||
|
|
||||||
#define IDI_PROJECT_WORKSPACE 601
|
#define IDI_PROJECT_WORKSPACE 601
|
||||||
#define IDI_PROJECT_WORKSPACEDIRTY 602
|
#define IDI_PROJECT_WORKSPACEDIRTY 602
|
||||||
@ -159,47 +160,48 @@
|
|||||||
#define IDC_MACRO_RECORDING 1408
|
#define IDC_MACRO_RECORDING 1408
|
||||||
|
|
||||||
#define IDR_SAVEALL 1500
|
#define IDR_SAVEALL 1500
|
||||||
#define IDR_CLOSEFILE 1501
|
#define IDR_CLOSEFILE 1501
|
||||||
#define IDR_CLOSEALL 1502
|
#define IDR_CLOSEALL 1502
|
||||||
#define IDR_FIND 1503
|
#define IDR_FIND 1503
|
||||||
#define IDR_REPLACE 1504
|
#define IDR_REPLACE 1504
|
||||||
#define IDR_ZOOMIN 1505
|
#define IDR_ZOOMIN 1505
|
||||||
#define IDR_ZOOMOUT 1506
|
#define IDR_ZOOMOUT 1506
|
||||||
#define IDR_WRAP 1507
|
#define IDR_WRAP 1507
|
||||||
#define IDR_INVISIBLECHAR 1508
|
#define IDR_INVISIBLECHAR 1508
|
||||||
#define IDR_INDENTGUIDE 1509
|
#define IDR_INDENTGUIDE 1509
|
||||||
#define IDR_SHOWPANNEL 1510
|
#define IDR_SHOWPANNEL 1510
|
||||||
#define IDR_STARTRECORD 1511
|
#define IDR_STARTRECORD 1511
|
||||||
#define IDR_STOPRECORD 1512
|
#define IDR_STOPRECORD 1512
|
||||||
#define IDR_PLAYRECORD 1513
|
#define IDR_PLAYRECORD 1513
|
||||||
#define IDR_SAVERECORD 1514
|
#define IDR_SAVERECORD 1514
|
||||||
#define IDR_SYNCV 1515
|
#define IDR_SYNCV 1515
|
||||||
#define IDR_SYNCH 1516
|
#define IDR_SYNCH 1516
|
||||||
#define IDR_FILENEW 1517
|
#define IDR_FILENEW 1517
|
||||||
#define IDR_FILEOPEN 1518
|
#define IDR_FILEOPEN 1518
|
||||||
#define IDR_FILESAVE 1519
|
#define IDR_FILESAVE 1519
|
||||||
#define IDR_PRINT 1520
|
#define IDR_PRINT 1520
|
||||||
#define IDR_CUT 1521
|
#define IDR_CUT 1521
|
||||||
#define IDR_COPY 1522
|
#define IDR_COPY 1522
|
||||||
#define IDR_PASTE 1523
|
#define IDR_PASTE 1523
|
||||||
#define IDR_UNDO 1524
|
#define IDR_UNDO 1524
|
||||||
#define IDR_REDO 1525
|
#define IDR_REDO 1525
|
||||||
#define IDR_M_PLAYRECORD 1526
|
#define IDR_M_PLAYRECORD 1526
|
||||||
#define IDR_DOCMAP 1527
|
#define IDR_DOCMAP 1527
|
||||||
#define IDR_FUNC_LIST 1528
|
#define IDR_FUNC_LIST 1528
|
||||||
#define IDR_FILEBROWSER 1529
|
#define IDR_FILEBROWSER 1529
|
||||||
#define IDR_CLOSETAB 1530
|
#define IDR_CLOSETAB 1530
|
||||||
#define IDR_CLOSETAB_INACT 1531
|
#define IDR_CLOSETAB_INACT 1531
|
||||||
#define IDR_CLOSETAB_HOVER 1532
|
#define IDR_CLOSETAB_HOVER 1532
|
||||||
#define IDR_CLOSETAB_PUSH 1533
|
#define IDR_CLOSETAB_PUSH 1533
|
||||||
|
#define IDR_FUNC_LIST_ICO 1534
|
||||||
|
#define IDR_DOCMAP_ICO 1535
|
||||||
|
#define IDR_PROJECTPANEL_ICO 1536
|
||||||
|
#define IDR_CLIPBOARDPANEL_ICO 1537
|
||||||
|
#define IDR_ASCIIPANEL_ICO 1538
|
||||||
|
#define IDR_DOCSWITCHER_ICO 1539
|
||||||
|
#define IDR_FILEBROWSER_ICO 1540
|
||||||
|
#define IDR_FILEMONITORING 1541
|
||||||
|
|
||||||
#define IDR_FUNC_LIST_ICO 1534
|
|
||||||
#define IDR_DOCMAP_ICO 1535
|
|
||||||
#define IDR_PROJECTPANEL_ICO 1536
|
|
||||||
#define IDR_CLIPBOARDPANEL_ICO 1537
|
|
||||||
#define IDR_ASCIIPANEL_ICO 1538
|
|
||||||
#define IDR_DOCSWITCHER_ICO 1539
|
|
||||||
#define IDR_FILEBROWSER_ICO 1540
|
|
||||||
#define ID_MACRO 20000
|
#define ID_MACRO 20000
|
||||||
#define ID_MACRO_LIMIT 20200
|
#define ID_MACRO_LIMIT 20200
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user