public bool SearchForText(string searchText, bool matchCase, bool searchForward, bool lineHighlights) { if (_tailListView.VirtualListSize == 0) return false; if (lineHighlights && (_keywordHighlight == null || _keywordHighlight.Count == 0) && _bookmarks.Count==0) return false; // Use selection if it is below top-index int startIndex = _tailListView.VirtualListSize - 1; if (_tailListView.SelectedIndices.Count > 0) { if (_tailListView.TopItem == null || _tailListView.TopItem.Index - 1 < _tailListView.SelectedIndices[0]) startIndex = _tailListView.SelectedIndices[0]; } if (!searchForward) { // First use the visual cache, when that have failed, then revert to search from the beginning // and find the last match startIndex -= 1; for (int i = startIndex; i >= 0; --i) { if (i % _logFileCache.Items.Count == 0) SetStatusBar("Searching...", _tailListView.VirtualListSize - i, _tailListView.VirtualListSize); string lineText; ListViewItem lvi = _logFileCache.LookupCache(i); if (lvi != null) lineText = lvi.Text; else { LogFileCache searchFileCache = null; int matchFound = -1; int lastMatchFound = -1; startIndex = 0; int endIndex = i + 1; do { matchFound = SearchForTextForward(searchText, matchCase, lineHighlights, startIndex, endIndex, ref searchFileCache); if (matchFound != -1) { lastMatchFound = matchFound; startIndex = matchFound + 1; _tailListView.SelectedIndices.Clear(); if (searchFileCache != null) { _logFileCache = searchFileCache; // Store the cache of the last match searchFileCache = new LogFileCache(_logFileCache.Items.Count); searchFileCache.Items = _logFileCache.Items.GetRange(0, _logFileCache.Items.Count); searchFileCache.FirstIndex = _logFileCache.FirstIndex; } } } while (matchFound != -1); if (lastMatchFound != -1) { SetStatusBar(null); _tailListView.SelectedIndices.Clear(); _tailListView.EnsureVisible(lastMatchFound); _tailListView.SelectedIndices.Add(lastMatchFound); _tailListView.Items[lastMatchFound].Focused = true; return true; } else { SetStatusBar(null); return false; } } if (MatchTextSearch(i, lineText, searchText, matchCase, lineHighlights)) { SetStatusBar(null); _tailListView.SelectedIndices.Clear(); _tailListView.EnsureVisible(i); _tailListView.SelectedIndices.Add(i); _tailListView.Items[i].Focused = true; return true; } } SetStatusBar(null); return false; } else { LogFileCache searchFileCache = null; startIndex += 1; int endIndex = _tailListView.VirtualListSize; int matchFound = SearchForTextForward(searchText, matchCase, lineHighlights, startIndex, endIndex, ref searchFileCache); if (matchFound != -1) { SetStatusBar(null); _tailListView.SelectedIndices.Clear(); // Clear selection before changing cache to avoid cache miss if (searchFileCache != null) _logFileCache = searchFileCache; // Swap cache before displaying search result _tailListView.EnsureVisible(matchFound); _tailListView.SelectedIndices.Add(matchFound); // Set selection after having scrolled to avoid top-index cache miss _tailListView.Items[matchFound].Focused = true; return true; } else { SetStatusBar(null); return false; } } }
public void LoadConfig(TailFileConfig tailConfig, string configPath) { _configPath = configPath; try { new DirectoryInfo(Path.GetDirectoryName(Path.Combine(configPath, tailConfig.FilePath))); } catch (System.ArgumentException ex) { MessageBox.Show(this, String.Format("Failed to open file:\n\n{0}\n\nError:{1}", tailConfig.FilePath, ex.Message), "Invalid filename", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); Close(); return; } if (tailConfig.FileCacheSize <= 0) tailConfig.FileCacheSize = 1000; if (tailConfig.FormBackColor != null) _tailListView.BackColor = tailConfig.FormBackColor.Value; if (tailConfig.FormTextColor != null) _tailListView.ForeColor = tailConfig.FormTextColor.Value; if (tailConfig.FormFont != null) _tailListView.Font = tailConfig.FormFont; if (tailConfig.FormBookmarkBackColor != null) _bookmarkBackColor = tailConfig.FormBookmarkBackColor.Value; if (tailConfig.FormBookmarkTextColor != null) _bookmarkTextColor = tailConfig.FormBookmarkTextColor.Value; if (tailConfig.FileChangeCheckInterval > 0) _tailTimer.Interval = tailConfig.FileChangeCheckInterval; _externalTools = tailConfig.ExternalTools; externalToolsToolStripMenuItem.DropDownItems.Clear(); externalToolsToolStripMenuItem.Enabled = false; if (_externalTools != null) { foreach (ExternalToolConfig externalTool in _externalTools) { ToolStripMenuItem toolItem = externalToolsToolStripMenuItem.DropDownItems.Add(externalTool.Name) as ToolStripMenuItem; if (toolItem != null) { toolItem.Tag = externalTool; toolItem.Click += new EventHandler(externalToolMenuItem_Click); if (externalTool.ShortcutKeyEnum.HasValue) toolItem.ShortcutKeys = externalTool.ShortcutKeyEnum.Value; } externalToolsToolStripMenuItem.Enabled = true; } } _loghitCounter = -1; _keywordHighlight = tailConfig.KeywordHighlight; if (_keywordHighlight != null) { foreach (TailKeywordConfig keyword in _keywordHighlight) { if (keyword.MatchRegularExpression) { if (keyword.MatchCaseSensitive) keyword.KeywordRegex = new System.Text.RegularExpressions.Regex(keyword.Keyword); else keyword.KeywordRegex = new System.Text.RegularExpressions.Regex(keyword.Keyword, System.Text.RegularExpressions.RegexOptions.IgnoreCase); } else keyword.KeywordRegex = null; if (keyword.LogHitCounter) _loghitCounter = 0; if (!string.IsNullOrEmpty(keyword.ExternalToolName)) { keyword.ExternalToolConfig = _externalTools.Find((externalTool) => string.Compare(externalTool.Name, keyword.ExternalToolName) == 0); if (_threadPoolQueue == null) _threadPoolQueue = new ThreadPoolQueue(); // Prepare the threadpool for use } } } Encoding fileEncoding = tailConfig.EnumFileEncoding; if (_logTailStream != null) _logTailStream.Reset(); if (_logFileStream == null || _logFileStream.FilePath != tailConfig.FilePath || _logFileStream.FileEncoding != fileEncoding || _logFileStream.FileCheckInterval != tailConfig.FileCheckInterval || _logFileStream.FileCheckPattern != tailConfig.FileCheckPattern) { if (_logFileStream != null) _logFileStream.Dispose(); _logFileStream = new LogFileStream(configPath, tailConfig.FilePath, fileEncoding, tailConfig.FileCheckInterval, tailConfig.FileCheckPattern); } if (_logTailStream == null || _logTailStream.FilePath != tailConfig.FilePath || _logTailStream.FileEncoding != fileEncoding || _logTailStream.FileCheckInterval != tailConfig.FileCheckInterval || _logTailStream.FileCheckPattern != tailConfig.FileCheckPattern) { if (_logTailStream != null) _logTailStream.Dispose(); _logTailStream = new LogFileStream(configPath, tailConfig.FilePath, fileEncoding, tailConfig.FileCheckInterval, tailConfig.FileCheckPattern); if (_logTailStream.Length > 500 * 1024 * 1024) { if (MessageBox.Show(this, String.Format("The file is very large, sure you want to open it?\n\nFile Name: {0}\nFile Size: {1} Megabytes", _logTailStream.FilePath, _logTailStream.Length / 1024 / 1024), "Large file detected", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.No) { Close(); return; } } if (_logFileCache != null) { _logFileCache.Reset(); _logFileCache = null; // Reset Cache, as the file contents can have changed } } _logTailStream.FileReloadedEvent += new EventHandler(_logTailStream_FileReloadedEvent); if (_logFileCache != null) _logFileCache.Reset(); if (_logFileCache == null || _logFileCache.Items.Count != tailConfig.FileCacheSize) { _logFileCache = new LogFileCache(tailConfig.FileCacheSize); _logFileCache.LoadingFileEvent += new EventHandler(_logFileCache_LoadingFileEvent); _logFileCache.FillCacheEvent += new EventHandler(_logFileCache_FillCacheEvent); // Add loading of cache while counting lines in file int lineCount = _logFileCache.FillTailCache(_logTailStream); _tailListView.VirtualListSize = lineCount; } else { _logFileCache.LoadingFileEvent += new EventHandler(_logFileCache_LoadingFileEvent); _logFileCache.FillCacheEvent += new EventHandler(_logFileCache_FillCacheEvent); } if (_taskMonitor != null) { _taskMonitor.Dispose(); _taskMonitor = null; } if (!string.IsNullOrEmpty(tailConfig.ServiceName)) _taskMonitor = new TaskMonitor(tailConfig.ServiceName); _formTitleMatchFilename = tailConfig.TitleMatchFilename; if (_formTitleMatchFilename) _formTitle = Path.GetFileName(_logTailStream.Name); else if (tailConfig.Title != null) _formTitle = tailConfig.Title; else _formTitle = Path.GetFileName(tailConfig.FilePath); UpdateFormTitle(true); _displayTabIcon = tailConfig.DisplayTabIcon; if (!string.IsNullOrEmpty(tailConfig.IconFile)) { _formIconFile = tailConfig.IconFile; string formIconFilePathAbsolute = System.IO.Path.Combine(configPath, _formIconFile); try { _formCustomIcon = System.Drawing.Icon.ExtractAssociatedIcon(formIconFilePathAbsolute); _formMaximizedIcon = Icon; Icon = _formCustomIcon; } catch (Exception ex) { MessageBox.Show(this, "Failed to load icon\n\n " + formIconFilePathAbsolute + "\n\n" + ex.Message, null, MessageBoxButtons.OK, MessageBoxIcon.Error); } } UpdateFormTitle(true); if (Visible) { if (_tailListView.VirtualListSize > 0) { _tailListView.EnsureVisible(_tailListView.VirtualListSize - 1); _tailListView.FocusedItem = _tailListView.Items[_tailListView.VirtualListSize - 1]; _tailListView.SelectedIndices.Add(_tailListView.VirtualListSize - 1); _tailListView.Invalidate(); _tailListView.Update(); } } }
private void _tailTimer_Tick(object sender, EventArgs e) { if (!_tailTimer.Enabled) return; UpdateFormTitle(false); CheckExternalToolResults(); int lineCount = _tailListView.VirtualListSize; bool listAtBottom = ListAtBottom(); bool warningIcon = false; if (_displayTabIcon) { TabPage parentTab = this.Tag as TabPage; if (parentTab != null && parentTab.ImageIndex == 1) warningIcon = true; } else warningIcon = true; string line = _logTailStream.ReadLine(lineCount + 1); while(line != null) { ++lineCount; _logFileCache.AppendTailCache(line, lineCount); TailKeywordConfig keywordMatch = MatchesKeyword(line, false, false); if (keywordMatch != null) { if (keywordMatch.LogHitCounter) _loghitCounter++; if (keywordMatch.ExternalToolConfig != null) { CheckExternalToolResults(); if (_threadPoolQueue != null) _threadPoolQueue.QueueRequest(ExecuteExternalTool, GenerateExternalTool(keywordMatch.ExternalToolConfig, line, lineCount, keywordMatch.Keyword)); } if (keywordMatch.AlertHighlight.Value) warningIcon = true; } line = _logTailStream.ReadLine(lineCount + 1); } if (lineCount == _tailListView.VirtualListSize) { if (lineCount == 1 && _logTailStream.Length == 0) { // Check if the open file error has changed if (_tailListView.Items[0].Text == _logTailStream.ReadLine(1)) return; } else if (_logTailStream.ValidLineCount(lineCount)) return; lineCount = 0; } if (_displayTabIcon) { TabPage parentTab = this.Tag as TabPage; if (parentTab != null && parentTab.Parent != null && parentTab.Parent.Visible && !parentTab.Visible) { if (warningIcon) parentTab.ImageIndex = 1; else parentTab.ImageIndex = 0; } } if (lineCount < _tailListView.VirtualListSize) { _logFileStream.CheckLogFile(true); _logFileCache = new LogFileCache(_logFileCache.Items.Count); _tailListView.TopItem = null; _tailListView.VirtualListSize = lineCount; _tailListView.Invalidate(); } else { //_tailListView.VirtualListSize = linecount; ListViewUtil.SetVirtualListSizeWithoutRefresh(_tailListView, lineCount); if (listAtBottom && _tailListView.VirtualListSize > 0) _tailListView.EnsureVisible(_tailListView.VirtualListSize - 1); } }
private int SearchForTextForward(string searchText, bool matchCase, bool lineHighlights, int startIndex, int endIndex, ref LogFileCache searchFileCache) { for (int i = startIndex; i < endIndex; ++i) { if (i % _logFileCache.Items.Count == 0) SetStatusBar("Searching...", i, endIndex); string lineText = null; if (searchFileCache == null) { ListViewItem lvi = _logFileCache.LookupCache(i); if (lvi != null) lineText = lvi.Text; else { // Copy the current cache position, in case the search hit is the next line searchFileCache = new LogFileCache(_logFileCache.Items.Count); searchFileCache.Items = _logFileCache.Items.GetRange(0, _logFileCache.Items.Count); searchFileCache.FirstIndex = _logFileCache.FirstIndex; } } if (searchFileCache != null) { ListViewItem lvi = searchFileCache.LookupCache(i); if (lvi == null) { searchFileCache.PrepareCache(i, i + searchFileCache.Items.Count / 2, true); searchFileCache.FillCache(_logFileStream, i + searchFileCache.Items.Count / 2); lvi = searchFileCache.LookupCache(i); } lineText = lvi.Text; } if (MatchTextSearch(i, lineText, searchText, matchCase, lineHighlights)) return i; } return -1; }
public bool SearchForText(string searchText, bool matchCase, bool searchForward, bool lineHighlights, bool wrapAround) { if (_tailListView.VirtualListSize == 0) return false; if (lineHighlights && (_keywordHighlight == null || _keywordHighlight.Count == 0) && _bookmarks.Count == 0) return false; // Use selection if it is below top-index int startIndex = _tailListView.VirtualListSize - 1; if (_tailListView.SelectedIndices.Count > 0) { if (_tailListView.TopItem == null || _tailListView.TopItem.Index - 1 < _tailListView.SelectedIndices[0]) startIndex = _tailListView.SelectedIndices[0]; } int matchFound = -1; if (!searchForward) { matchFound = SearchForTextBackward(searchText, matchCase, lineHighlights, startIndex - 1, 0); //Retry if not found if (matchFound == -1 && wrapAround) { matchFound = SearchForTextBackward(searchText, matchCase, lineHighlights, _tailListView.VirtualListSize - 1, startIndex); } } else { LogFileCache searchFileCache = null; matchFound = SearchForTextForward(searchText, matchCase, lineHighlights, startIndex + 1, _tailListView.VirtualListSize, ref searchFileCache); //Retry if not found if (matchFound == -1 && wrapAround) { matchFound = SearchForTextForward(searchText, matchCase, lineHighlights, 0, startIndex + 1, ref searchFileCache); } if (matchFound != -1) { // Swap cache before displaying search result if (searchFileCache != null) _logFileCache = searchFileCache; } } SetStatusBar(null); if (matchFound != -1) { _tailListView.SelectedIndices.Clear(); _tailListView.EnsureVisible(matchFound); _tailListView.SelectedIndices.Add(matchFound); _tailListView.Items[matchFound].Focused = true; return true; } return false; }
private int SearchForwardForLastMatch(string searchText, bool matchCase, bool lineHighlights, int endIndex) { LogFileCache searchFileCache = null; int matchFound = -1; int lastMatchFound = -1; int startIndex = 0; do { matchFound = SearchForTextForward(searchText, matchCase, lineHighlights, startIndex, endIndex, ref searchFileCache); if (matchFound != -1) { lastMatchFound = matchFound; startIndex = matchFound + 1; _tailListView.SelectedIndices.Clear(); if (searchFileCache != null) { _logFileCache = searchFileCache; // Store the cache of the last match searchFileCache = new LogFileCache(_logFileCache.Items.Count); searchFileCache.Items = _logFileCache.Items.GetRange(0, _logFileCache.Items.Count); searchFileCache.FirstIndex = _logFileCache.FirstIndex; } } } while (matchFound != -1); return lastMatchFound; }