diff --git a/CHANGELIST.md b/CHANGELIST.md index c3555ef6..21fecb78 100644 --- a/CHANGELIST.md +++ b/CHANGELIST.md @@ -51,6 +51,7 @@ - Detected type and selected type are different - Remove message boxes from MainViewModel - Move MainViewModel to Core +- Remove LogOutputViewModel ### 2.6.6 (2023-10-04) diff --git a/MPF.UI.Core/UserControls/LogOutput.xaml.cs b/MPF.UI.Core/UserControls/LogOutput.xaml.cs index ef9ebffd..7ba86777 100644 --- a/MPF.UI.Core/UserControls/LogOutput.xaml.cs +++ b/MPF.UI.Core/UserControls/LogOutput.xaml.cs @@ -1,22 +1,50 @@ using System; +using System.IO; using System.Windows; using System.Windows.Controls; +using System.Windows.Documents; +using System.Windows.Media; +using System.Windows.Threading; using MPF.Core.Data; -using MPF.UI.Core.ViewModels; namespace MPF.UI.Core.UserControls { public partial class LogOutput : UserControl { /// - /// Read-only access to the current log output view model + /// Document representing the text /// - public LogOutputViewModel LogOutputViewModel => DataContext as LogOutputViewModel; + internal FlowDocument Document { get; private set; } + + /// + /// Queue of items that need to be logged + /// + internal ProcessingQueue LogQueue { get; private set; } + + /// + /// Paragraph backing the log + /// + private readonly Paragraph _paragraph; + + /// + /// Cached value of the last line written + /// + private Run lastLine = null; public LogOutput() { InitializeComponent(); - DataContext = new LogOutputViewModel(Dispatcher); + + // Update the internal state + Document = new FlowDocument() + { + Background = new SolidColorBrush(Color.FromArgb(0xFF, 0x20, 0x20, 0x20)) + }; + _paragraph = new Paragraph(); + Document.Blocks.Add(_paragraph); + + // Setup the processing queue + LogQueue = new ProcessingQueue(ProcessLogLine); // Add handlers OutputViewer.SizeChanged += OutputViewerSizeChanged; @@ -25,7 +53,7 @@ namespace MPF.UI.Core.UserControls SaveButton.Click += OnSaveButton; // Update the internal state - Output.Document = LogOutputViewModel.Document; + Output.Document = Document; } #region Logging @@ -42,13 +70,129 @@ namespace MPF.UI.Core.UserControls return; // Enqueue the text - LogOutputViewModel.LogQueue.Enqueue(new LogOutputViewModel.LogLine(text, logLevel)); + LogQueue.Enqueue(new LogLine(text, logLevel)); + } + + /// + /// Log line wrapper + /// + internal readonly struct LogLine + { + public readonly string Text; + public readonly LogLevel LogLevel; + + public LogLine(string text, LogLevel logLevel) + { + this.Text = text; + this.LogLevel = logLevel; + } + + /// + /// Get the foreground Brush for the current LogLevel + /// + /// Brush representing the color + public Brush GetForegroundColor() + { + switch (this.LogLevel) + { + case LogLevel.SECRET: + return Brushes.Blue; + case LogLevel.ERROR: + return Brushes.Red; + case LogLevel.VERBOSE: + return Brushes.Yellow; + case LogLevel.USER: + default: + return Brushes.White; + } + } + + /// + /// Generate a Run object from the current LogLine + /// + /// Run object based on internal values + public Run GenerateRun() + { + return new Run { Text = this.Text, Foreground = GetForegroundColor() }; + } + } + + /// + /// Process the log lines in the queue + /// + /// LogLine item to process + internal void ProcessLogLine(LogLine nextLogLine) + { + // Null text gets ignored + string nextText = nextLogLine.Text; + if (nextText == null) + return; + + try + { + if (nextText.StartsWith("\r")) + ReplaceLastLine(nextLogLine); + else + AppendToTextBox(nextLogLine); + } + catch (Exception ex) + { + // In the event that something fails horribly, we want to log + AppendToTextBox(new LogLine(ex.ToString(), LogLevel.ERROR)); + } + } + + /// + /// Append log line to the log text box + /// + /// LogLine value to append + private void AppendToTextBox(LogLine logLine) + { + Dispatcher.Invoke(() => + { + var run = logLine.GenerateRun(); + _paragraph.Inlines.Add(run); + lastLine = run; + }); + } + + /// + /// Replace the last line written to the log text box + /// + /// LogLine value to append + private void ReplaceLastLine(LogLine logLine) + { + Dispatcher.Invoke(() => + { + lastLine.Text = logLine.Text; + lastLine.Foreground = logLine.GetForegroundColor(); + }); } #endregion #region Helpers + /// + /// Clear all inlines of the paragraph + /// + private void ClearInlines() => _paragraph.Inlines.Clear(); + + /// + /// Save all inlines to console.log + /// + private void SaveInlines() + { + using (StreamWriter tw = new StreamWriter(File.OpenWrite("console.log"))) + { + foreach (var inline in _paragraph.Inlines) + { + if (inline is Run run) + tw.Write(run.Text); + } + } + } + /// /// Scroll the current view to the bottom /// @@ -59,12 +203,10 @@ namespace MPF.UI.Core.UserControls #region EventHandlers private void OnClearButton(object sender, EventArgs e) - { - LogOutputViewModel.ClearInlines(); - } + => ClearInlines(); private void OnSaveButton(object sender, EventArgs e) - => LogOutputViewModel.SaveInlines(); + => SaveInlines(); private void OnTextChanged(object sender, TextChangedEventArgs e) => ScrollToBottom(); diff --git a/MPF.UI.Core/ViewModels/LogOutputViewModel.cs b/MPF.UI.Core/ViewModels/LogOutputViewModel.cs deleted file mode 100644 index 8642f129..00000000 --- a/MPF.UI.Core/ViewModels/LogOutputViewModel.cs +++ /dev/null @@ -1,183 +0,0 @@ -using System; -using System.IO; -using System.Windows.Documents; -using System.Windows.Media; -using System.Windows.Threading; -using MPF.Core.Data; - -namespace MPF.UI.Core.ViewModels -{ - public class LogOutputViewModel - { - /// - /// Document representing the text - /// - internal FlowDocument Document { get; private set; } - - /// - /// Queue of items that need to be logged - /// - internal ProcessingQueue LogQueue { get; private set; } - - /// - /// Dispatcher from the parent view for invocation - /// - internal Dispatcher Dispatcher { get; private set; } - - /// - /// Paragraph backing the log - /// - private readonly Paragraph _paragraph; - - /// - /// Cached value of the last line written - /// - private Run lastLine = null; - - public LogOutputViewModel(Dispatcher dispatcher) - { - // Update the internal state - Document = new FlowDocument() - { - Background = new SolidColorBrush(Color.FromArgb(0xFF, 0x20, 0x20, 0x20)) - }; - _paragraph = new Paragraph(); - Document.Blocks.Add(_paragraph); - - // Setup the processing queue - LogQueue = new ProcessingQueue(ProcessLogLine); - Dispatcher = dispatcher; - } - - /// - /// Clear all inlines of the paragraph - /// - public void ClearInlines() => _paragraph.Inlines.Clear(); - - /// - /// Save all inlines to console.log - /// - public void SaveInlines() - { - using (StreamWriter tw = new StreamWriter(File.OpenWrite("console.log"))) - { - foreach (var inline in _paragraph.Inlines) - { - if (inline is Run run) - tw.Write(run.Text); - } - } - } - - /// - /// Log line wrapper - /// - internal struct LogLine - { - public readonly string Text; - public readonly LogLevel LogLevel; - - public LogLine(string text, LogLevel logLevel) - { - this.Text = text; - this.LogLevel = logLevel; - } - - /// - /// Get the foreground Brush for the current LogLevel - /// - /// Brush representing the color - public Brush GetForegroundColor() - { - switch (this.LogLevel) - { - case LogLevel.SECRET: - return Brushes.Blue; - case LogLevel.ERROR: - return Brushes.Red; - case LogLevel.VERBOSE: - return Brushes.Yellow; - case LogLevel.USER: - default: - return Brushes.White; - } - } - - /// - /// Generate a Run object from the current LogLine - /// - /// Run object based on internal values - public Run GenerateRun() - { - return new Run { Text = this.Text, Foreground = GetForegroundColor() }; - } - } - - /// - /// Enqueue text to the log with formatting - /// - /// Text to write to the log - /// LogLevel for the log - internal void LogInternal(string text, LogLevel logLevel) - { - // Null text gets ignored - if (text == null) - return; - - // Enqueue the text - LogQueue.Enqueue(new LogLine(text, logLevel)); - } - - /// - /// Process the log lines in the queue - /// - /// LogLine item to process - internal void ProcessLogLine(LogLine nextLogLine) - { - // Null text gets ignored - string nextText = nextLogLine.Text; - if (nextText == null) - return; - - try - { - if (nextText.StartsWith("\r")) - ReplaceLastLine(nextLogLine); - else - AppendToTextBox(nextLogLine); - } - catch (Exception ex) - { - // In the event that something fails horribly, we want to log - AppendToTextBox(new LogLine(ex.ToString(), LogLevel.ERROR)); - } - } - - /// - /// Append log line to the log text box - /// - /// LogLine value to append - private void AppendToTextBox(LogLine logLine) - { - Dispatcher.Invoke(() => - { - var run = logLine.GenerateRun(); - _paragraph.Inlines.Add(run); - lastLine = run; - }); - } - - /// - /// Replace the last line written to the log text box - /// - /// LogLine value to append - private void ReplaceLastLine(LogLine logLine) - { - Dispatcher.Invoke(() => - { - lastLine.Text = logLine.Text; - lastLine.Foreground = logLine.GetForegroundColor(); - }); - } - } -}