using CommunityToolkit.Mvvm.ComponentModel;
using OpenTap;
using OpenTap.Diagnostic;
using OpenTapEditor.Util;
using System.Collections.ObjectModel;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Threading;
using UtilLib;
namespace OpenTapEditor
{
public enum LevelType
{
///
/// Recoverable error.
///
Error = 10,
///
/// Noncritical problem.
///
Warning = 20,
///
/// Informational message.
///
Info = 30,
///
/// Debugging trace.
///
Debug = 40
}
public class LogItem
{
public Event e { get; internal set; }
public int Type => e.EventType;
public override string ToString()
{
return $"{(LevelType)e.EventType} {new DateTime(e.Timestamp).ToString("HH:mm:ss.fff")} : {e.Source} : {e.Message}";
}
}
///
/// LogControl.xaml 的交互逻辑
///
[ObservableObject]
public partial class LogControl : UserControl, ILogListener
{
[ObservableProperty]
private ObservableCollection datasource = new ObservableCollection();
[ObservableProperty]
private string searchText = string.Empty;
[ObservableProperty]
private bool showError = true;
[ObservableProperty]
private bool showWarn = true;
[ObservableProperty]
private bool showInfo = true;
[ObservableProperty]
private bool showDebug = true;
[ObservableProperty]
private bool showAll = false;
[ObservableProperty]
private CollectionViewSource viewSource;
private readonly SolidColorBrush _debugBrush;
private readonly SolidColorBrush _successBrush;
private readonly SolidColorBrush _warnBrush;
private readonly SolidColorBrush _errorBrush;
public LogControl()
{
_debugBrush = new SolidColorBrush(Color.FromArgb(0xaa, 0x71, 0x80, 0x8A)); // 灰色
_successBrush = new SolidColorBrush(Color.FromArgb(0xaa, 0x30, 0xC5, 0x30));
_warnBrush = new SolidColorBrush(Color.FromArgb(0xaa, 0xD6, 0x9E, 0x2E)); // 橙黄色
_errorBrush = new SolidColorBrush(Color.FromArgb(0xaa, 0xC5, 0x30, 0x30)); // 红色
DataContext = this;
ViewSource = new CollectionViewSource();
ViewSource.Filter += CollectionViewSource_Filter;
BindingOperations.SetBinding(viewSource, CollectionViewSource.SourceProperty,
new Binding(nameof(Datasource))
{
Source = this,
Mode = BindingMode.TwoWay,
NotifyOnSourceUpdated = true,
});
InitializeComponent();
InitFromSetting();
}
private void InitFromSetting()
{
ShowError = bool.Parse(IniHelper.ReadIniData("Log", nameof(ShowError), "True", PathHelper.SettingIniPath));
ShowWarn = bool.Parse(IniHelper.ReadIniData("Log", nameof(ShowWarn), "True", PathHelper.SettingIniPath));
ShowInfo = bool.Parse(IniHelper.ReadIniData("Log", nameof(ShowInfo), "True", PathHelper.SettingIniPath));
ShowDebug = bool.Parse(IniHelper.ReadIniData("Log", nameof(ShowDebug), "True", PathHelper.SettingIniPath));
ShowAll = bool.Parse(IniHelper.ReadIniData("Log", nameof(ShowAll), "False", PathHelper.SettingIniPath));
}
private void WriteSetting(string name, object value)
{
IniHelper.WriteIniData("Log", name, value.ToString(), PathHelper.SettingIniPath);
}
partial void OnShowErrorChanged(bool value)
{
WriteSetting(nameof(ShowError), value);
ViewSource.View.Refresh();
}
partial void OnShowWarnChanged(bool value)
{
WriteSetting(nameof(ShowWarn), value);
ViewSource.View.Refresh();
}
partial void OnShowInfoChanged(bool value)
{
WriteSetting(nameof(ShowInfo), value);
ViewSource.View.Refresh();
}
partial void OnShowDebugChanged(bool value)
{
WriteSetting(nameof(ShowDebug), value);
ViewSource.View.Refresh();
}
partial void OnShowAllChanged(bool value)
{
WriteSetting(nameof(ShowAll), value);
ViewSource.View.Refresh();
}
partial void OnSearchTextChanged(string value)
{
ViewSource.View.Refresh();
}
public void EventsLogged(IEnumerable Events)
{
foreach (var e in Events)
{
HandleLog(e);
}
}
private void HandleLog(Event e)
{
Dispatcher.BeginInvoke(() =>
{
lock (this)
{
var item = new LogItem()
{
e = e
};
while (Datasource.Count >= 1000)
{
Datasource.RemoveAt(0);
}
Datasource.Add(item);
log.ScrollIntoView(item);
}
}, DispatcherPriority.Background);
}
public void Flush()
{
Log.Flush();
}
private void CollectionViewSource_Filter(object sender, System.Windows.Data.FilterEventArgs e)
{
if (e.Item is LogItem item)
{
bool res = true;
switch (item.Type)
{
case 10:
res = ShowError || ShowAll;
break;
case 20:
res = ShowWarn || ShowAll;
break;
case 30:
res = ShowInfo || ShowAll;
break;
case 40:
res = ShowDebug || ShowAll;
break;
default:
res = true;
break;
}
if (!string.IsNullOrEmpty(SearchText))
{
res &= item.ToString().Contains(SearchText);
}
e.Accepted = res;
}
}
private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
{
Datasource.Clear();
}
private volatile bool showingResult = false;
public void ShowResult(Verdict verdict)
{
if (showingResult)
{
return;
}
showingResult = true;
Task.Run(() =>
{
Dispatcher.BeginInvoke(() =>
{
string title = "PASS";
resultShow.Background = _successBrush;
if (verdict == Verdict.Aborted)
{
resultShow.Background = _warnBrush;
title = "Aborted";
}
else if (verdict == Verdict.NotSet)
{
resultShow.Background = _debugBrush;
title = "NotSet";
}
else if (verdict == Verdict.Fail)
{
resultShow.Background = _errorBrush;
title = "FAIL";
}
else if (verdict == Verdict.Error)
{
resultShow.Background = _errorBrush;
title = "Error";
}
resultLabel.Content = title;
resultShow.Visibility = System.Windows.Visibility.Visible;
});
Thread.Sleep(3000);
Dispatcher.BeginInvoke(() =>
{
resultShow.Visibility = System.Windows.Visibility.Collapsed;
});
showingResult = false;
});
}
}
}