mirror of
https://github.com/SabreTools/MPF.git
synced 2026-07-02 17:24:48 +00:00
Split logging code a bit more
This commit is contained in:
@@ -28,6 +28,7 @@
|
||||
- Remove unnecessary include
|
||||
- Move element items to Core
|
||||
- Move LogLevel enumeration
|
||||
- Split logging code a bit more
|
||||
|
||||
### 2.6.6 (2023-10-04)
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
using System.Windows.Controls;
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using MPF.Core.Data;
|
||||
using MPF.UI.Core.ViewModels;
|
||||
|
||||
namespace MPF.UI.Core.UserControls
|
||||
@@ -6,14 +9,130 @@ namespace MPF.UI.Core.UserControls
|
||||
public partial class LogOutput : UserControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Read-only access to the current log view model
|
||||
/// Read-only access to the current log output view model
|
||||
/// </summary>
|
||||
public LogViewModel LogViewModel => DataContext as LogViewModel;
|
||||
public LogOutputViewModel LogOutputViewModel => DataContext as LogOutputViewModel;
|
||||
|
||||
public LogOutput()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = new LogViewModel(this);
|
||||
DataContext = new LogOutputViewModel();
|
||||
|
||||
// Add handlers
|
||||
OutputViewer.SizeChanged += OutputViewerSizeChanged;
|
||||
Output.TextChanged += OnTextChanged;
|
||||
ClearButton.Click += OnClearButton;
|
||||
SaveButton.Click += OnSaveButton;
|
||||
|
||||
// Update the internal state
|
||||
Output.Document = LogOutputViewModel.Document;
|
||||
}
|
||||
|
||||
#region Logging
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue text to the log
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
public void Log(string text) => LogInternal(text, LogLevel.USER);
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue text with a newline to the log
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
public void LogLn(string text) => Log(text + "\n");
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue error text to the log
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
public void ErrorLog(string text) => LogInternal(text, LogLevel.ERROR);
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue error text with a newline to the log
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
public void ErrorLogLn(string text) => ErrorLog(text + "\n");
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue secret text to the log
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
public void SecretLog(string text) => LogInternal(text, LogLevel.SECRET);
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue secret text with a newline to the log
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
public void SecretLogLn(string text) => SecretLog(text + "\n");
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue verbose text to the log
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
public void VerboseLog(string text) => LogInternal(text, LogLevel.VERBOSE);
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue verbose text with a newline to the log
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
public void VerboseLogLn(string text) => VerboseLog(text + "\n");
|
||||
|
||||
/// <summary>
|
||||
/// Reset the progress bar state
|
||||
/// </summary>
|
||||
public void ResetProgressBar()
|
||||
{
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
ProgressBar.Value = 0;
|
||||
ProgressLabel.Text = string.Empty;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue text to the log with formatting
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
/// <param name="logLevel">LogLevel for the log</param>
|
||||
private void LogInternal(string text, LogLevel logLevel)
|
||||
{
|
||||
// Null text gets ignored
|
||||
if (text == null)
|
||||
return;
|
||||
|
||||
// Enqueue the text
|
||||
LogOutputViewModel.LogQueue.Enqueue(new LogOutputViewModel.LogLine(text, logLevel));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Scroll the current view to the bottom
|
||||
/// </summary>
|
||||
public void ScrollToBottom() => OutputViewer.ScrollToBottom();
|
||||
|
||||
#endregion
|
||||
|
||||
#region EventHandlers
|
||||
|
||||
private void OnClearButton(object sender, EventArgs e)
|
||||
{
|
||||
LogOutputViewModel.ClearInlines();
|
||||
ResetProgressBar();
|
||||
}
|
||||
|
||||
private void OnSaveButton(object sender, EventArgs e)
|
||||
=> LogOutputViewModel.SaveInlines();
|
||||
|
||||
private void OnTextChanged(object sender, TextChangedEventArgs e)
|
||||
=> ScrollToBottom();
|
||||
|
||||
private void OutputViewerSizeChanged(object sender, SizeChangedEventArgs e)
|
||||
=> ScrollToBottom();
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +1,23 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Media;
|
||||
using MPF.Core.Data;
|
||||
using MPF.UI.Core.UserControls;
|
||||
|
||||
namespace MPF.UI.Core.ViewModels
|
||||
{
|
||||
public class LogViewModel
|
||||
public class LogOutputViewModel
|
||||
{
|
||||
#region Fields
|
||||
/// <summary>
|
||||
/// Document representing the text
|
||||
/// </summary>
|
||||
internal FlowDocument Document { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Parent OptionsWindow object
|
||||
/// Queue of items that need to be logged
|
||||
/// </summary>
|
||||
public LogOutput Parent { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private State Variables
|
||||
internal ProcessingQueue<LogLine> LogQueue { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Paragraph backing the log
|
||||
@@ -32,44 +29,44 @@ namespace MPF.UI.Core.ViewModels
|
||||
/// </summary>
|
||||
private Run lastLine = null;
|
||||
|
||||
/// <summary>
|
||||
/// Queue of items that need to be logged
|
||||
/// </summary>
|
||||
private readonly ProcessingQueue<LogLine> logQueue;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public LogViewModel(LogOutput parent)
|
||||
public LogOutputViewModel()
|
||||
{
|
||||
Parent = parent;
|
||||
|
||||
// Add handlers
|
||||
Parent.OutputViewer.SizeChanged += OutputViewerSizeChanged;
|
||||
Parent.Output.TextChanged += OnTextChanged;
|
||||
Parent.ClearButton.Click += OnClearButton;
|
||||
Parent.SaveButton.Click += OnSaveButton;
|
||||
|
||||
// Update the internal state
|
||||
var document = new FlowDocument()
|
||||
Document = new FlowDocument()
|
||||
{
|
||||
Background = new SolidColorBrush(Color.FromArgb(0xFF, 0x20, 0x20, 0x20))
|
||||
};
|
||||
_paragraph = new Paragraph();
|
||||
document.Blocks.Add(_paragraph);
|
||||
Parent.Output.Document = document;
|
||||
Document.Blocks.Add(_paragraph);
|
||||
|
||||
logQueue = new ProcessingQueue<LogLine>(ProcessLogLine);
|
||||
// Setup the processing queue
|
||||
LogQueue = new ProcessingQueue<LogLine>(ProcessLogLine);
|
||||
}
|
||||
|
||||
#region Logging
|
||||
/// <summary>
|
||||
/// Clear all inlines of the paragraph
|
||||
/// </summary>
|
||||
public void ClearInlines() => _paragraph.Inlines.Clear();
|
||||
|
||||
/// <summary>
|
||||
/// Save all inlines to console.log
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Log line wrapper
|
||||
/// </summary>
|
||||
private struct LogLine
|
||||
internal struct LogLine
|
||||
{
|
||||
public readonly string Text;
|
||||
public readonly LogLevel LogLevel;
|
||||
@@ -110,89 +107,29 @@ namespace MPF.UI.Core.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue text to the log
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
public void Log(string text) => LogInternal(text, LogLevel.USER);
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue text with a newline to the log
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
public void LogLn(string text) => Log(text + "\n");
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue error text to the log
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
public void ErrorLog(string text) => LogInternal(text, LogLevel.ERROR);
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue error text with a newline to the log
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
public void ErrorLogLn(string text) => ErrorLog(text + "\n");
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue secret text to the log
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
public void SecretLog(string text) => LogInternal(text, LogLevel.SECRET);
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue secret text with a newline to the log
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
public void SecretLogLn(string text) => SecretLog(text + "\n");
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue verbose text to the log
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
public void VerboseLog(string text) => LogInternal(text, LogLevel.VERBOSE);
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue verbose text with a newline to the log
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
public void VerboseLogLn(string text) => VerboseLog(text + "\n");
|
||||
|
||||
/// <summary>
|
||||
/// Reset the progress bar state
|
||||
/// </summary>
|
||||
public void ResetProgressBar()
|
||||
{
|
||||
Parent.Dispatcher.Invoke(() =>
|
||||
{
|
||||
Parent.ProgressBar.Value = 0;
|
||||
Parent.ProgressLabel.Text = string.Empty;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue text to the log with formatting
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the log</param>
|
||||
/// <param name="logLevel">LogLevel for the log</param>
|
||||
private void LogInternal(string text, LogLevel logLevel)
|
||||
internal void LogInternal(string text, LogLevel logLevel)
|
||||
{
|
||||
// Null text gets ignored
|
||||
if (text == null)
|
||||
return;
|
||||
|
||||
// Enqueue the text
|
||||
logQueue.Enqueue(new LogLine(text, logLevel));
|
||||
LogQueue.Enqueue(new LogLine(text, logLevel));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process the log lines in the queue
|
||||
/// </summary>
|
||||
/// <param name="nextLogLine">LogLine item to process</param>
|
||||
private void ProcessLogLine(LogLine nextLogLine)
|
||||
internal void ProcessLogLine(LogLine nextLogLine)
|
||||
{
|
||||
// Null text gets ignored
|
||||
string nextText = Parent.Dispatcher.Invoke(() => nextLogLine.Text);
|
||||
string nextText = nextLogLine.Text;
|
||||
if (nextText == null)
|
||||
return;
|
||||
|
||||
@@ -216,7 +153,7 @@ namespace MPF.UI.Core.ViewModels
|
||||
/// <param name="logLine">LogLine value to append</param>
|
||||
private void AppendToTextBox(LogLine logLine)
|
||||
{
|
||||
Parent.Dispatcher.Invoke(() =>
|
||||
Task.Run(() =>
|
||||
{
|
||||
var run = logLine.GenerateRun();
|
||||
_paragraph.Inlines.Add(run);
|
||||
@@ -230,53 +167,11 @@ namespace MPF.UI.Core.ViewModels
|
||||
/// <param name="logLine">LogLine value to append</param>
|
||||
private void ReplaceLastLine(LogLine logLine)
|
||||
{
|
||||
Parent.Dispatcher.Invoke(() =>
|
||||
Task.Run(() =>
|
||||
{
|
||||
lastLine.Text = logLine.Text;
|
||||
lastLine.Foreground = logLine.GetForegroundColor();
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Scroll the current view to the bottom
|
||||
/// </summary>
|
||||
public void ScrollToBottom()
|
||||
{
|
||||
Parent.OutputViewer.ScrollToBottom();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region EventHandlers
|
||||
|
||||
private void OnClearButton(object sender, EventArgs e)
|
||||
{
|
||||
_paragraph.Inlines.Clear();
|
||||
ResetProgressBar();
|
||||
}
|
||||
|
||||
private void OnSaveButton(object sender, EventArgs e)
|
||||
{
|
||||
using (StreamWriter tw = new StreamWriter(File.OpenWrite("console.log")))
|
||||
{
|
||||
foreach (var inline in _paragraph.Inlines)
|
||||
{
|
||||
if (inline is Run run)
|
||||
tw.Write(run.Text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTextChanged(object sender, TextChangedEventArgs e) =>
|
||||
ScrollToBottom();
|
||||
|
||||
private void OutputViewerSizeChanged(object sender, SizeChangedEventArgs e) =>
|
||||
ScrollToBottom();
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ using MPF.Core;
|
||||
using MPF.Core.Data;
|
||||
using MPF.Core.Utilities;
|
||||
using MPF.Core.UI.ComboBoxItems;
|
||||
using MPF.UI.Core.UserControls;
|
||||
using MPF.UI.Core.Windows;
|
||||
using SabreTools.RedumpLib.Data;
|
||||
using WPFCustomMessageBox;
|
||||
@@ -28,7 +29,7 @@ namespace MPF.UI.Core.ViewModels
|
||||
/// <summary>
|
||||
/// LogViewModel associated with the parent window
|
||||
/// </summary>
|
||||
public LogViewModel Logger => Parent.LogOutput.LogViewModel;
|
||||
public LogOutput Logger => Parent.LogOutput;
|
||||
|
||||
/// <summary>
|
||||
/// Access to the current options
|
||||
|
||||
Reference in New Issue
Block a user