using InABox.Configuration; using InABox.Core; using InABox.WPF; using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; namespace InABox.DynamicGrid; public class DynamicGridSelectedFilterSettings { public string? TemporaryFilter { get; set; } public List SelectedFilters { get; set; } public bool MultipleFilters { get; set; } public DynamicGridSelectedFilterSettings() { SelectedFilters = new List(); MultipleFilters = false; } public DynamicGridSelectedFilterSettings(List selectedFilters, bool multipleFilters, string? temporaryFilter) { SelectedFilters = selectedFilters; MultipleFilters = multipleFilters || selectedFilters.Count > 1; TemporaryFilter = temporaryFilter; } } public abstract class DynamicGridFilterComponent { #region Private Fields private class FilterItem { public string Name { get; set; } public Filter? Filter { get; } public CoreFilterDefinition Definition { get; set; } public FilterItem(string name, Filter? filter, CoreFilterDefinition definition) { Name = name; Filter = filter; Definition = definition; } } private List SelectedFilters = new(); private Filter? TemporaryFilter = null; private int NumberOfFilters => SelectedFilters.Count + (TemporaryFilter is null ? 0 : 1); #endregion #region Public Properties public IConfiguration GlobalConfiguration { get; set; } public IConfiguration UserConfiguration { get; set; } private bool _multipleFilters = false; private bool MultipleFilters { get => _multipleFilters; set { if (_multipleFilters != value) { _multipleFilters = value; if (!_multipleFilters && NumberOfFilters > 1) { ClearFilters(true); } } } } private string? _buttonText; public string? ButtonText { get => _buttonText; set { if (!string.Equals(_buttonText, value)) { _buttonText = value; UpdateButton(); } } } #endregion #region Events public delegate void FilterSelectedHandler(DynamicGridSelectedFilterSettings filters); public event FilterSelectedHandler? OnFiltersSelected; public delegate void FilterRefreshHandler(); public event FilterRefreshHandler? OnFilterRefresh; #endregion public DynamicGridFilterComponent( IConfiguration globalConfiguration, IConfiguration userConfiguration) { GlobalConfiguration = globalConfiguration; UserConfiguration = userConfiguration; } public void SetSettings(DynamicGridSelectedFilterSettings settings, bool refresh) { _multipleFilters = settings.MultipleFilters; TemporaryFilter = Serialization.Deserialize>(settings.TemporaryFilter); SelectFilters(settings.SelectedFilters, refresh); } #region Menu private ContextMenu? Menu; private void RebuildMenu(ContextMenu menu) { menu.Items.Clear(); if (TemporaryFilter is null) { menu.AddCheckItem("Filter...", TemporaryFilter_Click, isChecked: false); } else { menu.AddCheckItem("", TemporaryFilter_Click, isChecked: true); } menu.AddItem("Clear Filters", null, ClearFilter_Click); var multipleFilters = menu.AddCheckItem("Use Multiple Filters", MultipleFilters_Click, MultipleFilters); multipleFilters.StaysOpenOnClick = true; menu.AddSeparatorIfNeeded(); var globalFilters = Security.IsAllowed() ? GlobalConfiguration.Load() : new CoreFilterDefinitions(); var userFilters = UserConfiguration.Load(); var filters = new CoreFilterDefinitions(globalFilters.Count + userFilters.Count); foreach (var filter in globalFilters.Concat(userFilters)) { var item = menu.AddCheckItem(filter.Name, filter, Filter_Toggle); item.StaysOpenOnClick = true; if (SelectedFilters.Any(x => x.Name.Equals(filter.Name))) { item.IsChecked = true; } filters.Add(filter); } if (Security.IsAllowed()) { menu.AddSeparatorIfNeeded(); menu.AddItem("Manage Filters", null, () => { var window = new DynamicGridFilterEditor(filters, typeof(T)); if (window.ShowDialog() == true) { globalFilters.Clear(); globalFilters.AddRange(filters.Where(x => !x.Private)); userFilters.Clear(); userFilters.AddRange(filters.Where(x => x.Private)); if (Security.IsAllowed()) { GlobalConfiguration.Save(globalFilters); } UserConfiguration.Save(userFilters); } }); } } private void TemporaryFilter_Click(bool isChecked) { var window = new FilterEditorWindow(); window.SetFilter(TemporaryFilter ?? new Filter()); if (window.ShowDialog() == true) { TemporaryFilter = window.GetFilter(); if (TemporaryFilter is not null && !MultipleFilters) { SelectedFilters.Clear(); } UpdateFilters(true); } } protected void DoFilter() { Menu = new ContextMenu(); RebuildMenu(Menu); Menu.IsOpen = true; Menu.Closed += Menu_Closed; } private void Menu_Closed(object sender, RoutedEventArgs e) { if (Menu == sender) { Menu = null; } } private void ClearFilter_Click() { ClearFilters(true); } private void MultipleFilters_Click(bool isChecked) { MultipleFilters = isChecked; if (Menu is not null) { RebuildMenu(Menu); } SaveSettings(); } private void Filter_Toggle(CoreFilterDefinition tag, bool isChecked) { if (MultipleFilters) { if (isChecked) { SelectFilter(tag, true, true); } else { DeselectFilter(tag, true); } } else { SelectFilter(tag, false, true); if (Menu is not null) { Menu.IsOpen = false; } } } #endregion public void ClearFilters(bool refresh) { if (NumberOfFilters > 0) { SelectedFilters.Clear(); TemporaryFilter = null; UpdateFilters(refresh); } } public void DeselectFilter(CoreFilterDefinition filter, bool refresh) { var removed = SelectedFilters.RemoveAll(x => x.Name.Equals(filter.Name)); if (removed > 0) { UpdateFilters(refresh); } } /// /// Select a new filter. If is , adds it to the list of selected filters; /// otherwise, it sets this as the only filter. /// /// /// /// public void SelectFilter(CoreFilterDefinition? filter, bool additional, bool refresh) { var originalCount = SelectedFilters.Count; var alreadyHas = filter is null || SelectedFilters.Any(x => x.Name.Equals(filter.Name)); if (!additional) { SelectedFilters.Clear(); TemporaryFilter = null; } if (filter is not null && !SelectedFilters.Any(x => x.Name.Equals(filter.Name))) { SelectedFilters.Add(new(filter.Name, filter.AsFilter(), filter)); } if (SelectedFilters.Count != originalCount || !alreadyHas) { UpdateFilters(refresh); } } public void SelectFilters(IEnumerable filters, bool refresh) { SelectedFilters.Clear(); foreach (var filter in filters) { SelectedFilters.Add(new(filter.Name, filter.AsFilter(), filter)); } if (NumberOfFilters > 1 && !MultipleFilters) { MultipleFilters = true; } UpdateFilters(refresh); } private void UpdateFilters(bool refresh) { UpdateButton(); SaveSettings(); if (refresh) { OnFilterRefresh?.Invoke(); } } protected abstract void UpdateButtonText(Bitmap image, string text); private void UpdateButton() { var image = NumberOfFilters > 0 ? Wpf.Resources.filter_set : Wpf.Resources.filter; var filterNames = SelectedFilters.Select(x => x.Name); if (TemporaryFilter is not null) { filterNames = CoreUtils.One("Custom").Concat(filterNames); } var text = string.Join(", ", filterNames); if (!ButtonText.IsNullOrWhiteSpace()) { if (text.IsNullOrWhiteSpace()) { text = ButtonText; } else { text = $"{ButtonText}: {text}"; } } UpdateButtonText(image, text); } private void SaveSettings() { OnFiltersSelected?.Invoke(new DynamicGridSelectedFilterSettings( SelectedFilters.Select(x => x.Definition).ToList(), MultipleFilters, TemporaryFilter is not null ? Serialization.Serialize(TemporaryFilter) : null)); } public Filter? GetFilter() { var filters = new Filters(); filters.AddRange(SelectedFilters.Select(x => x.Filter)); filters.Add(TemporaryFilter); return filters.Combine(); } } public class DynamicGridFilterButtonComponent : DynamicGridFilterComponent where T : BaseObject, new() { private readonly IDynamicGrid Grid; private Button FilterBtn = null!; private bool _showFilterList; public bool ShowFilterList { get => _showFilterList; set { _showFilterList = value; if (FilterBtn != null) FilterBtn.Visibility = value ? Visibility.Visible : Visibility.Collapsed; } } public DynamicGridFilterButtonComponent( IDynamicGrid grid, IConfiguration globalConfiguration, IConfiguration userConfiguration) : base(globalConfiguration, userConfiguration) { Grid = grid; CreateButton(); } private void CreateButton() { FilterBtn = Grid.AddButton("", Wpf.Resources.filter.AsBitmapImage(), Click); FilterBtn.Margin = new Thickness(0, 2, 7, 0); FilterBtn.Padding = new Thickness(0); } private bool Click(Button _arg1, CoreRow[] _arg2) { DoFilter(); return false; } protected override void UpdateButtonText(Bitmap image, string text) { Grid.UpdateButton(FilterBtn, image.AsBitmapImage(), text); } }