mirror of
				https://github.com/notepad-plus-plus/notepad-plus-plus.git
				synced 2025-11-03 21:14:08 +01: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")
 | 
			
		||||
 | 
			
		||||
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[] = {
 | 
			
		||||
	{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_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_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},
 | 
			
		||||
@ -1923,6 +1924,11 @@ void Notepad_plus::checkDocState()
 | 
			
		||||
 | 
			
		||||
	if (_pAnsiCharPanel)
 | 
			
		||||
		_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()
 | 
			
		||||
@ -3521,19 +3527,25 @@ void Notepad_plus::docGotoAnotherEditView(FileTransferMode mode)
 | 
			
		||||
		showView(viewToGo);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool monitoringWasOn = false;
 | 
			
		||||
 | 
			
		||||
	//Close the document if we transfered the document instead of cloning it
 | 
			
		||||
	if (mode == TransferMove)
 | 
			
		||||
	{
 | 
			
		||||
		Buffer *buf = MainFileManager->getBufferByID(current);
 | 
			
		||||
		monitoringWasOn = buf->isMonitoringOn();
 | 
			
		||||
 | 
			
		||||
		//just close the activate document, since thats the one we moved (no search)
 | 
			
		||||
		doClose(_pEditView->getCurrentBufferID(), currentView());
 | 
			
		||||
		/*
 | 
			
		||||
		if (noOpenedDoc())
 | 
			
		||||
			::SendMessage(_pPublicInterface->getHSelf(), WM_CLOSE, 0, 0);
 | 
			
		||||
		*/
 | 
			
		||||
	} // else it was cone, so leave it
 | 
			
		||||
 | 
			
		||||
	//Activate the other view since thats where the document went
 | 
			
		||||
	switchEditViewTo(viewToGo);
 | 
			
		||||
 | 
			
		||||
	if (monitoringWasOn)
 | 
			
		||||
	{
 | 
			
		||||
		command(IDM_VIEW_MONITORING);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Notepad_plus::activateBuffer(BufferID id, int whichOne)
 | 
			
		||||
 | 
			
		||||
@ -186,7 +186,6 @@ struct VisibleGUIConf final
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class FileDialog;
 | 
			
		||||
class Notepad_plus_Window;
 | 
			
		||||
class AnsiCharPanel;
 | 
			
		||||
@ -643,8 +642,15 @@ private:
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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;
 | 
			
		||||
 | 
			
		||||
		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:
 | 
			
		||||
		{
 | 
			
		||||
			bool isFirstTime = !_runDlg.isCreated();
 | 
			
		||||
 | 
			
		||||
@ -33,121 +33,97 @@
 | 
			
		||||
#include "EncodingMapper.h"
 | 
			
		||||
#include "VerticalFileSwitcher.h"
 | 
			
		||||
#include "functionListPanel.h"
 | 
			
		||||
#include "ReadDirectoryChanges.h"
 | 
			
		||||
#include <tchar.h>
 | 
			
		||||
 | 
			
		||||
using namespace std;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
struct monitorFileParams {
 | 
			
		||||
	WCHAR _fullFilePath[MAX_PATH];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
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];
 | 
			
		||||
	//::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);
 | 
			
		||||
	
 | 
			
		||||
	HANDLE hDirectory = ::CreateFile(folderToMonitor,
 | 
			
		||||
		FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE,
 | 
			
		||||
		NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
 | 
			
		||||
	const DWORD dwNotificationFlags = FILE_NOTIFY_CHANGE_LAST_WRITE;
 | 
			
		||||
 | 
			
		||||
	// buffer qui va récuppérer les informations de mise à jour
 | 
			
		||||
	const int MAX_BUFFER = 1024;
 | 
			
		||||
	BYTE buffer[MAX_BUFFER];
 | 
			
		||||
	DWORD nombreDeByteRetournes = 0;
 | 
			
		||||
	// Create the monitor and add directory to watch.
 | 
			
		||||
	CReadDirectoryChanges changes;
 | 
			
		||||
	changes.AddDirectory(folderToMonitor, true, dwNotificationFlags);
 | 
			
		||||
 | 
			
		||||
	bool cond = true;
 | 
			
		||||
	while (cond)
 | 
			
		||||
	HANDLE changeHandles[] = { buf->getMonitoringEvent(), changes.GetWaitHandle() };
 | 
			
		||||
 | 
			
		||||
	bool toBeContinued = true;
 | 
			
		||||
 | 
			
		||||
	while (toBeContinued)
 | 
			
		||||
	{
 | 
			
		||||
		::Sleep(1000);
 | 
			
		||||
		// surveille un changement dans le répertoire : il attend tant que rien ne se passe : c’est synchrone.
 | 
			
		||||
		BOOL res = ReadDirectoryChangesW(hDirectory, buffer, MAX_BUFFER,
 | 
			
		||||
			TRUE, FILE_NOTIFY_CHANGE_LAST_WRITE, &nombreDeByteRetournes, NULL, NULL);
 | 
			
		||||
 | 
			
		||||
		if (res == FALSE)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		// 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)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		// affiche le fichier qui a été modifié.
 | 
			
		||||
		if (notifyInfo->FileNameLength <= 0)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DWORD WINAPI Notepad_plus::monitorDirectoryOnChange(void * params)
 | 
			
		||||
		DWORD waitStatus = ::WaitForMultipleObjects(_countof(changeHandles), changeHandles, FALSE, INFINITE);
 | 
			
		||||
		switch (waitStatus)
 | 
			
		||||
		{
 | 
			
		||||
	monitorFileParams *mfp = (monitorFileParams *)params;
 | 
			
		||||
			case WAIT_OBJECT_0 + 0:
 | 
			
		||||
				// Mutex was signaled. User removes this folder or file browser is closed
 | 
			
		||||
				toBeContinued = false;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
	//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)
 | 
			
		||||
			case WAIT_OBJECT_0 + 1:
 | 
			
		||||
				// We've received a notification in the queue.
 | 
			
		||||
			{
 | 
			
		||||
		::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;
 | 
			
		||||
				DWORD dwAction;
 | 
			
		||||
				CStringW wstrFilename;
 | 
			
		||||
				if (changes.CheckOverflow())
 | 
			
		||||
					printStr(L"Queue overflowed.");
 | 
			
		||||
				else
 | 
			
		||||
				{
 | 
			
		||||
					changes.Pop(dwAction, wstrFilename);
 | 
			
		||||
 | 
			
		||||
		wchar_t fn[MAX_PATH];
 | 
			
		||||
		memset(fn, 0, MAX_PATH*sizeof(wchar_t));
 | 
			
		||||
					if (dwAction == FILE_ACTION_MODIFIED && lstrcmp(fullFileName, wstrFilename.GetString()) == 0)
 | 
			
		||||
					{
 | 
			
		||||
						MainFileManager->reloadBuffer(buf->getID());
 | 
			
		||||
						buf->updateTimeStamp();
 | 
			
		||||
 | 
			
		||||
		//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);
 | 
			
		||||
						// not only test main view
 | 
			
		||||
						if (buf == mainEditorView->getCurrentBuffer())
 | 
			
		||||
						{
 | 
			
		||||
							int lastLineToShow = mainEditorView->execute(SCI_GETLINECOUNT);
 | 
			
		||||
							mainEditorView->scroll(0, lastLineToShow);
 | 
			
		||||
						}
 | 
			
		||||
	return TRUE;
 | 
			
		||||
						// 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;
 | 
			
		||||
 | 
			
		||||
			case WAIT_IO_COMPLETION:
 | 
			
		||||
				// Nothing to do.
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 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;
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
BufferID Notepad_plus::doOpen(const generic_string& fileName, bool isRecursive, bool isReadOnly, int encoding, const TCHAR *backupFileName, time_t fileNameTimestamp)
 | 
			
		||||
{
 | 
			
		||||
@ -368,20 +344,6 @@ BufferID Notepad_plus::doOpen(const generic_string& fileName, bool isRecursive,
 | 
			
		||||
        _pluginsManager.notify(&scnN);
 | 
			
		||||
        if (_pFileSwitcherPanel)
 | 
			
		||||
            _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
 | 
			
		||||
    {
 | 
			
		||||
@ -671,6 +633,12 @@ void Notepad_plus::doClose(BufferID id, int whichOne, bool doDeleteBackup)
 | 
			
		||||
 | 
			
		||||
	int nrDocs = whichOne==MAIN_VIEW?(_mainDocTab.nbItem()):(_subDocTab.nbItem());
 | 
			
		||||
 | 
			
		||||
	if (buf->isMonitoringOn())
 | 
			
		||||
	{
 | 
			
		||||
		// turn off monitoring
 | 
			
		||||
		command(IDM_VIEW_MONITORING);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//Do all the works
 | 
			
		||||
	bool isBufRemoved = removeBufferFromView(id, whichOne);
 | 
			
		||||
	BufferID hiddenBufferID = BUFFER_INVALID;
 | 
			
		||||
 | 
			
		||||
@ -454,7 +454,7 @@ BOOL Notepad_plus::notify(SCNotification *notification)
 | 
			
		||||
			_tabPopupMenu.checkItem(IDM_EDIT_SETREADONLY, isUserReadOnly);
 | 
			
		||||
 | 
			
		||||
			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);
 | 
			
		||||
 | 
			
		||||
			bool isFileExisting = PathFileExists(buf->getFullPathName()) != FALSE;
 | 
			
		||||
 | 
			
		||||
@ -337,10 +337,25 @@ public:
 | 
			
		||||
		_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();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	int indexOfReference(const ScintillaEditView * identifier) const;
 | 
			
		||||
 | 
			
		||||
	void setStatus(DocFileStatus status)
 | 
			
		||||
@ -395,4 +410,8 @@ private:
 | 
			
		||||
	generic_string _backupFileName;
 | 
			
		||||
	bool _isModified = false;
 | 
			
		||||
	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.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;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -40,6 +40,7 @@
 | 
			
		||||
const int SAVED_IMG_INDEX = 0;
 | 
			
		||||
const int UNSAVED_IMG_INDEX = 1;
 | 
			
		||||
const int REDONLY_IMG_INDEX = 2;
 | 
			
		||||
const int MONITORING_IMG_INDEX = 3;
 | 
			
		||||
 | 
			
		||||
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_TAB_NEXT				  (IDM_VIEW + 95)
 | 
			
		||||
	#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_CLONE_TO_ANOTHER_VIEW    10002
 | 
			
		||||
 | 
			
		||||
@ -131,6 +131,7 @@
 | 
			
		||||
#define IDI_UNSAVED_ICON     502
 | 
			
		||||
#define IDI_READONLY_ICON     503
 | 
			
		||||
#define IDI_FIND_RESULT_ICON  504
 | 
			
		||||
#define IDI_MONITORING_ICON   505
 | 
			
		||||
 | 
			
		||||
#define IDI_PROJECT_WORKSPACE        601
 | 
			
		||||
#define IDI_PROJECT_WORKSPACEDIRTY    602
 | 
			
		||||
@ -192,7 +193,6 @@
 | 
			
		||||
#define IDR_CLOSETAB_INACT     1531
 | 
			
		||||
#define IDR_CLOSETAB_HOVER     1532
 | 
			
		||||
#define IDR_CLOSETAB_PUSH      1533
 | 
			
		||||
 | 
			
		||||
#define IDR_FUNC_LIST_ICO      1534
 | 
			
		||||
#define IDR_DOCMAP_ICO         1535
 | 
			
		||||
#define IDR_PROJECTPANEL_ICO   1536
 | 
			
		||||
@ -200,6 +200,8 @@
 | 
			
		||||
#define IDR_ASCIIPANEL_ICO     1538
 | 
			
		||||
#define IDR_DOCSWITCHER_ICO    1539
 | 
			
		||||
#define IDR_FILEBROWSER_ICO    1540
 | 
			
		||||
#define IDR_FILEMONITORING     1541
 | 
			
		||||
 | 
			
		||||
#define ID_MACRO 20000
 | 
			
		||||
#define ID_MACRO_LIMIT 20200
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user