| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398 | using System;using System.Collections.Generic;using System.Collections.ObjectModel;using System.ComponentModel;using System.IO;using System.Runtime.CompilerServices;using System.Text.RegularExpressions;using System.Windows;using System.Windows.Controls;using System.Windows.Data;using System.Windows.Input;using System.Windows.Media;using com.sun.org.glassfish.gmbal;using FastReport.DataVisualization.Charting;using Microsoft.Win32;using NPOI.XWPF.Usermodel;namespace InABox.Wpf.Console;public static class ItemsControlExtensions{    public static void ScrollIntoView(        this ItemsControl control,        object item)    {        var framework =            control.ItemContainerGenerator.ContainerFromItem(item)                as FrameworkElement;        if (framework == null) return;        framework.BringIntoView();    }    public static void ScrollIntoView(this ItemsControl control)    {        var count = control.Items.Count;        if (count == 0) return;        var item = control.Items[count - 1];        control.ScrollIntoView(item);    }}/// <summary>///     Interaction logic for Console.xaml/// </summary>public partial class ConsoleControl : UserControl, INotifyPropertyChanged{    public static readonly DependencyProperty EnabledProperty        = DependencyProperty.Register(nameof(Enabled), typeof(bool), typeof(ConsoleControl));    private CollectionViewSource _filtered;    public CollectionViewSource Filtered    {        get => _filtered;        set        {            _filtered = value;            OnPropertyChanged();        }    }    public readonly ObservableCollection<LogEntry> LogEntries;    private readonly TimeSpan regexTimeOut = TimeSpan.FromMilliseconds(100);    private Regex? searchRegex;    public event PropertyChangedEventHandler? PropertyChanged;    public event Action? OnLoadLog;    public event Action? OnCloseLog;    public bool _allowLoadLogButton = true;    public bool AllowLoadLogButton    {        get => _allowLoadLogButton;        set        {            _allowLoadLogButton = value;            OnPropertyChanged();            OnPropertyChanged(nameof(ShowLoadLogButton));            OnPropertyChanged(nameof(ShowCloseLogButton));        }    }    private bool _loadedLog = false;    public bool LoadedLog    {        get => _loadedLog;        set        {            _loadedLog = value;            OnPropertyChanged();            OnPropertyChanged(nameof(ShowLoadLogButton));            OnPropertyChanged(nameof(ShowCloseLogButton));        }    }    public bool ShowLoadLogButton => !LoadedLog && AllowLoadLogButton;    public bool ShowCloseLogButton => LoadedLog && AllowLoadLogButton;    public bool Enabled    {        get => (bool)GetValue(EnabledProperty);        set => SetValue(EnabledProperty, value);    }    public ConsoleControl()    {        InitializeComponent();        Filtered = new CollectionViewSource();        LogEntries = new ObservableCollection<LogEntry>();        Filtered.Source = LogEntries;        Filtered.Filter += (sender, args) =>        {            var logEntry = (LogEntry)args.Item;            if (ShowImportant.IsChecked == true && !IsImportant(logEntry))            {                args.Accepted = false;                return;            }            if (UseRegEx.IsChecked == true && searchRegex != null)                args.Accepted = string.IsNullOrWhiteSpace(Search.Text)                                || searchRegex.IsMatch(logEntry.DateTime)                                || searchRegex.IsMatch(logEntry.Type)                                || searchRegex.IsMatch(logEntry.User)                                || searchRegex.IsMatch(logEntry.Message);            else                args.Accepted = string.IsNullOrWhiteSpace(Search.Text)                                || logEntry.DateTime.Contains(Search.Text)                                || logEntry.Type.Contains(Search.Text)                                || logEntry.User.Contains(Search.Text)                                || logEntry.Message.Contains(Search.Text);        };    }    protected void OnPropertyChanged([CallerMemberName] string propertyName = "")    {        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));    }    private static bool IsImportant(LogEntry entry)    {        return entry.Type == "IMPTNT";    }    // DATE  TRANSACTION  TYPE  USERID  MESSAGE    [GeneratedRegex("(\\d\\d:\\d\\d:\\d\\d\\.\\d\\d\\d)\\s*([0-9a-zA-Z]{8}(?:\\-[0-9a-zA-Z]{4}){3}\\-[0-9a-zA-Z]{12})?\\s*(\\S+) (.+)", RegexOptions.Singleline)]    internal static partial Regex LogEntryParseRegex();    public static LogEntry? ParseLogMessage(string logLine)    {        var match = LogEntryParseRegex().Match(logLine);        if (match.Success)        {            var date = match.Groups[1].Value;            if (!Guid.TryParse(match.Groups[2].Value, out var transaction))            {                transaction = Guid.Empty;            }            var type = match.Groups[3].Value;            var remaining = match.Groups[4].Value;            var user = remaining.Length >= 12 ? remaining[..12] : "";            var msg = remaining.Length >= 12 ? remaining[13..] : "";            return new LogEntry            {                DateTime = date,                Type = type,                User = user,                Message = msg,                Transaction = transaction            };        }        else        {            return null;        }    }    public void LoadLogEntries(IEnumerable<string> lines)    {        var logEntries = new List<LogEntry>();        var numberSkipped = 0;        foreach (var line in lines)        {            var logEntry = ParseLogMessage(line ?? "");            if(logEntry is not null)            {                var logType = logEntry.Type;                if (logType == "ERROR" || logType == "INFO" || logType == "IMPTNT")                    logEntries.Add(logEntry);                else if (string.IsNullOrWhiteSpace(logType)) numberSkipped++;            }        }        if (numberSkipped > 0)        {            if (logEntries.Count == 0)                SetErrorMessage("File does not contain valid log information!");            else                SetErrorMessage(string.Format("Skipped {0} lines that did not contain valid log information", numberSkipped));        }        Filtered.Source = logEntries;    }    public void LoadLogEntry(string line)    {        var logEntry = ParseLogMessage(line);        if(logEntry is not null)        {            var logType = logEntry.Type;            if (logType == "INFO" || logType == "ERROR" || logType == "IMPTNT")            {                LogEntries.Insert(0, logEntry);            }        }    }    private void Search_KeyDown(object sender, KeyEventArgs e)    {        if (e.Key == Key.Enter && UseRegEx.IsChecked == true)        {            try            {                searchRegex = new Regex(Search.Text, RegexOptions.Compiled, regexTimeOut);            }            catch (ArgumentException)            {                searchRegex = null;            }            Filtered.View.Refresh();            SetSearchStyleNormal();        }    }    private void SetSearchStyleChanged()    {        Search.Background = Brushes.White;    }    private void SetSearchStyleNormal()    {        Search.Background = Brushes.LightYellow;    }    private void Search_TextChanged(object sender, TextChangedEventArgs e)    {        if (UseRegEx.IsChecked != true)        {            Filtered.View.Refresh();        }        else        {            if (string.IsNullOrWhiteSpace(Search.Text))            {                searchRegex = null;                Filtered.View.Refresh();                SetSearchStyleNormal();            }            else            {                SetSearchStyleChanged();            }        }    }    private void UseRegEx_Checked(object sender, RoutedEventArgs e)    {        try        {            searchRegex = new Regex(Search.Text, RegexOptions.Compiled, regexTimeOut);        }        catch (ArgumentException ex)        {            searchRegex = null;        }        Filtered.View.Refresh();    }    private void UseRegEx_Unchecked(object sender, RoutedEventArgs e)    {        searchRegex = null;        Filtered.View.Refresh();        SetSearchStyleNormal();    }    public void SetErrorMessage(string? error)    {        if (string.IsNullOrWhiteSpace(error))        {            Error.Content = "";            Error.Visibility = Visibility.Collapsed;        }        else        {            Error.Content = error;            Error.Visibility = Visibility.Visible;        }    }    private void CloseLog_Click(object sender, RoutedEventArgs e)    {        Filtered.Source = LogEntries;        OnCloseLog?.Invoke();    }    private void ShowImportant_Checked(object sender, RoutedEventArgs e)    {        Filtered.View.Refresh();    }    private void ShowImportant_Unchecked(object sender, RoutedEventArgs e)    {        Filtered.View.Refresh();    }    private void LoadLog_Click(object sender, RoutedEventArgs e)    {        OnLoadLog?.Invoke();    }}public abstract class Console : Window{    public ConsoleControl ConsoleControl { get; set; }    private readonly string Description;    public Console(string description)    {        ConsoleControl = new ConsoleControl();        ConsoleControl.OnLoadLog += ConsoleControl_OnLoadLog;        ConsoleControl.OnCloseLog += ConsoleControl_OnCloseLog;        Content = ConsoleControl;        Height = 800;        Width = 1200;        Loaded += Console_Loaded;        Closing += Console_Closing;        Title = description;        Description = description;    }    private void ConsoleControl_OnCloseLog()    {        Title = Description;        ConsoleControl.LoadedLog = false;    }    private void ConsoleControl_OnLoadLog()    {        var dialog = new OpenFileDialog        {            InitialDirectory = GetLogDirectory()        };        if (dialog.ShowDialog() == true)        {            var lines = File.ReadLines(dialog.FileName);            ConsoleControl.LoadLogEntries(lines);            ConsoleControl.LoadedLog = true;            Title = dialog.FileName;        }    }    protected virtual void OnLoaded()    {    }    protected virtual void OnClosing()    {    }    private void Console_Closing(object? sender, CancelEventArgs e)    {        OnClosing();    }    private void Console_Loaded(object sender, RoutedEventArgs e)    {        OnLoaded();    }    protected abstract string GetLogDirectory();}
 |