using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive;
using Artemis.Core;
using Artemis.Core.Modules;
using Artemis.UI.Shared.DataModelVisualization.Shared;
using Artemis.UI.Shared.Events;
using Artemis.UI.Shared.Services.Interfaces;
using Avalonia;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
using Avalonia.Media;
using ReactiveUI;
namespace Artemis.UI.Shared.Controls;
public class DataModelPicker : TemplatedControl
{
private static IDataModelUIService? _dataModelUIService;
///
/// Gets or sets data model path.
///
public static readonly StyledProperty DataModelPathProperty =
AvaloniaProperty.Register(nameof(DataModelPath), defaultBindingMode: BindingMode.TwoWay, notifying: DataModelPathPropertyChanged);
///
/// Gets or sets the placeholder to show when nothing is selected.
///
public static readonly StyledProperty PlaceholderProperty =
AvaloniaProperty.Register(nameof(Placeholder), "Click to select");
///
/// Gets or sets a boolean indicating whether the data model picker should show current values when selecting a path.
///
public static readonly StyledProperty ShowDataModelValuesProperty =
AvaloniaProperty.Register(nameof(ShowDataModelValues));
///
/// Gets or sets a boolean indicating whether the data model picker should show the full path of the selected value.
///
public static readonly StyledProperty ShowFullPathProperty =
AvaloniaProperty.Register(nameof(ShowFullPath), notifying: ShowFullPathPropertyChanged);
///
/// Gets or sets the brush to use when drawing the button.
///
public static readonly StyledProperty ButtonBrushProperty =
AvaloniaProperty.Register(nameof(ButtonBrush));
///
/// A list of extra modules to show data models of.
///
public static readonly StyledProperty?> ModulesProperty =
AvaloniaProperty.Register?>(nameof(Modules), new ObservableCollection(), notifying: ModulesPropertyChanged);
///
/// The data model view model to show, if not provided one will be retrieved by the control.
///
public static readonly StyledProperty DataModelViewModelProperty =
AvaloniaProperty.Register(nameof(DataModelViewModel), notifying: DataModelViewModelPropertyChanged);
///
/// A list of data model view models to show
///
public static readonly StyledProperty?> ExtraDataModelViewModelsProperty =
AvaloniaProperty.Register?>(
nameof(ExtraDataModelViewModels),
new ObservableCollection(),
notifying: ExtraDataModelViewModelsPropertyChanged
);
///
/// A list of types to filter the selectable paths on.
///
public static readonly StyledProperty?> FilterTypesProperty =
AvaloniaProperty.Register?>(nameof(FilterTypes), new ObservableCollection());
///
/// Creates a new instance of the class.
///
public DataModelPicker()
{
SelectPropertyCommand = ReactiveCommand.Create(selected => ExecuteSelectPropertyCommand(selected));
}
///
/// Gets a command that selects the path by it's view model.
///
public ReactiveCommand SelectPropertyCommand { get; }
internal static IDataModelUIService DataModelUIService
{
set
{
if (_dataModelUIService != null)
throw new AccessViolationException("This is not for you to touch");
_dataModelUIService = value;
}
}
///
/// Gets or sets data model path.
///
public DataModelPath? DataModelPath
{
get => GetValue(DataModelPathProperty);
set => SetValue(DataModelPathProperty, value);
}
///
/// Gets or sets the placeholder to show when nothing is selected.
///
public string Placeholder
{
get => GetValue(PlaceholderProperty);
set => SetValue(PlaceholderProperty, value);
}
///
/// Gets or sets a boolean indicating whether the data model picker should show the full path of the selected value.
///
public bool ShowFullPath
{
get => GetValue(ShowFullPathProperty);
set => SetValue(ShowFullPathProperty, value);
}
///
/// Gets or sets a boolean indicating whether the data model picker should show current values when selecting a path.
///
public bool ShowDataModelValues
{
get => GetValue(ShowDataModelValuesProperty);
set => SetValue(ShowDataModelValuesProperty, value);
}
///
/// Gets or sets the brush to use when drawing the button.
///
public Brush ButtonBrush
{
get => GetValue(ButtonBrushProperty);
set => SetValue(ButtonBrushProperty, value);
}
///
/// A list of extra modules to show data models of.
///
public ObservableCollection? Modules
{
get => GetValue(ModulesProperty);
set => SetValue(ModulesProperty, value);
}
///
/// The data model view model to show, if not provided one will be retrieved by the control.
///
public DataModelPropertiesViewModel? DataModelViewModel
{
get => GetValue(DataModelViewModelProperty);
set => SetValue(DataModelViewModelProperty, value);
}
///
/// A list of data model view models to show.
///
public ObservableCollection? ExtraDataModelViewModels
{
get => GetValue(ExtraDataModelViewModelsProperty);
set => SetValue(ExtraDataModelViewModelsProperty, value);
}
///
/// A list of types to filter the selectable paths on.
///
public ObservableCollection? FilterTypes
{
get => GetValue(FilterTypesProperty);
set => SetValue(FilterTypesProperty, value);
}
///
/// Occurs when a new path has been selected
///
public event EventHandler? DataModelPathSelected;
///
/// Invokes the event
///
///
protected virtual void OnDataModelPathSelected(DataModelSelectedEventArgs e)
{
DataModelPathSelected?.Invoke(this, e);
}
private void ExecuteSelectPropertyCommand(DataModelVisualizationViewModel selected)
{
if (selected.DataModelPath == null)
return;
if (selected.DataModelPath.Equals(DataModelPath))
return;
DataModelPath = new DataModelPath(selected.DataModelPath);
OnDataModelPathSelected(new DataModelSelectedEventArgs(DataModelPath));
}
private void GetDataModel()
{
if (_dataModelUIService == null)
return;
ChangeDataModel(_dataModelUIService.GetPluginDataModelVisualization(Modules?.ToList() ?? new List(), true));
}
private void ChangeDataModel(DataModelPropertiesViewModel? dataModel)
{
if (DataModelViewModel != null)
{
DataModelViewModel.Dispose();
DataModelViewModel.UpdateRequested -= DataModelOnUpdateRequested;
}
DataModelViewModel = dataModel;
if (DataModelViewModel != null)
DataModelViewModel.UpdateRequested += DataModelOnUpdateRequested;
}
#region Overrides of Visual
///
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
}
///
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnDetachedFromVisualTree(e);
}
#endregion
private void UpdateValueDisplay()
{
ValueDisplay.Visibility = DataModelPath == null || DataModelPath.IsValid ? Visibility.Visible : Visibility.Collapsed;
ValuePlaceholder.Visibility = DataModelPath == null || DataModelPath.IsValid ? Visibility.Collapsed : Visibility.Visible;
string? formattedPath = null;
if (DataModelPath != null && DataModelPath.IsValid)
formattedPath = string.Join(" › ", DataModelPath.Segments.Where(s => s.GetPropertyDescription() != null).Select(s => s.GetPropertyDescription()!.Name));
DataModelButton.ToolTip = formattedPath;
ValueDisplayTextBlock.Text = ShowFullPath
? formattedPath
: DataModelPath?.Segments.LastOrDefault()?.GetPropertyDescription()?.Name ?? DataModelPath?.Segments.LastOrDefault()?.Identifier;
}
private void DataModelOnUpdateRequested(object? sender, EventArgs e)
{
DataModelViewModel?.ApplyTypeFilter(true, FilterTypes?.ToArray() ?? Type.EmptyTypes);
if (ExtraDataModelViewModels == null) return;
foreach (DataModelPropertiesViewModel extraDataModelViewModel in ExtraDataModelViewModels)
extraDataModelViewModel.ApplyTypeFilter(true, FilterTypes?.ToArray() ?? Type.EmptyTypes);
}
private static void DataModelPathPropertyChanged(IAvaloniaObject sender, bool before)
{
}
private static void ShowFullPathPropertyChanged(IAvaloniaObject sender, bool before)
{
}
private static void ModulesPropertyChanged(IAvaloniaObject sender, bool before)
{
}
private static void DataModelViewModelPropertyChanged(IAvaloniaObject sender, bool before)
{
}
private static void ExtraDataModelViewModelsPropertyChanged(IAvaloniaObject sender, bool before)
{
}
}