123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366 |
- using com.sun.corba.se.impl.oa.poa;
- using InABox.Core;
- using InABox.WPF;
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Globalization;
- using System.Linq;
- using System.Runtime.CompilerServices;
- using System.Text;
- using System.Threading.Tasks;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Media;
- namespace InABox.DynamicGrid;
- public class DateTreeDynamicGridColumnFilter : IDynamicGridColumnFilter
- {
- public event Action<IDynamicGridColumnFilter>? FilterChanged;
- public IBaseDynamicGrid Grid { get; set; }
- public DynamicColumnBase Column { get; set; }
- private DateTime[] _dates = [];
- private List<HeaderItem> _items = [];
- private HashSet<DateTime>? _selectedDates = null;
- private enum DateLevel
- {
- Year,
- Month,
- Day,
- Date,
- All
- }
- private class HeaderItem(DateLevel level, object? value, string display, DateTreeDynamicGridColumnFilter filter) : INotifyPropertyChanged
- {
- public event Action<HeaderItem, bool>? CheckedChanged;
- public DateLevel Level { get; set; } = level;
- public object? Value { get; set; } = value;
- public string Display { get; set; } = display;
- private bool? _isChecked;
- public bool? IsChecked
- {
- get => _isChecked;
- set
- {
- if(value != _isChecked)
- {
- _isChecked = value;
- OnPropertyChanged();
- filter.BeginUpdate();
- if(value.HasValue)
- {
- CheckedChanged?.Invoke(this, value.Value);
- if(Parent is not null)
- {
- if(Parent.IsChecked != value)
- {
- Parent.CalculateChecked();
- }
- }
- foreach(var item in Items)
- {
- item.IsChecked = value;
- }
- }
- else
- {
- Parent?.CalculateChecked();
- }
- filter.EndUpdate();
- }
- }
- }
- public List<HeaderItem> Items { get; set; } = new();
- public HeaderItem? Parent { get; set; } = null;
- public void CalculateChecked(bool includeChildren = false)
- {
- if (Items.Count == 0)
- {
- if (includeChildren)
- {
- if(Value is DateTime date)
- {
- IsChecked = filter.IsSelected(date);
- }
- else if(Level == DateLevel.All)
- {
- IsChecked = filter._selectedDates is null;
- }
- }
- return;
- }
- if (includeChildren)
- {
- foreach(var item in Items)
- {
- item.CalculateChecked(true);
- }
- }
- if(Items.All(x => x.IsChecked == true))
- {
- IsChecked = true;
- }
- else if(Items.All(x => x.IsChecked == false))
- {
- IsChecked = false;
- }
- else
- {
- IsChecked = null;
- }
- }
- public void AddItem(HeaderItem item)
- {
- item.CalculateChecked();
- Items.Add(item);
- item.Parent = this;
- }
- public event PropertyChangedEventHandler? PropertyChanged;
- private void OnPropertyChanged([CallerMemberName] string propertyName = "")
- {
- PropertyChanged?.Invoke(this, new(propertyName));
- }
- }
- public DateTreeDynamicGridColumnFilter(IBaseDynamicGrid grid, DynamicColumnBase column)
- {
- Grid = grid;
- Column = column;
- }
- public void ClearFilter()
- {
- BeginUpdate();
- _selectedDates = null;
- foreach(var item in _items)
- {
- item.CalculateChecked(includeChildren: true);
- }
- Changed();
- EndUpdate();
- }
- public FrameworkElement CreateControl()
- {
- var treeView = new TreeView();
- var rows = (this as IDynamicGridColumnFilter).GetRowsToFilter(Grid);
- var data = rows.Select(x => Grid.GetData(x, Column)).OfType<DateTime>().Distinct();
- var dateData = new SortedDictionary<int, SortedDictionary<int, SortedDictionary<int, List<DateTime>>>>();
- _dates = data.ToArray();
- bool hasBlank = false;
- foreach(var date in _dates)
- {
- if(date == DateTime.MinValue)
- {
- hasBlank = true;
- }
- else
- {
- var yearData = dateData.GetValueOrAdd(date.Year);
- var monthData = yearData.GetValueOrAdd(date.Month);
- var dayData = monthData.GetValueOrAdd(date.Day);
- dayData.Add(date);
- }
- }
- var items = new List<HeaderItem>();
- var selectAll = new HeaderItem(DateLevel.All, null, "Select All", this) { IsChecked = _selectedDates is null };
- selectAll.CheckedChanged += SelectAll_CheckedChanged;
- items.Add(selectAll);
- if (hasBlank)
- {
- var item = new HeaderItem(DateLevel.Date, DateTime.MinValue, "(Blank)", this) { IsChecked = IsSelected(DateTime.MinValue) };
- item.CheckedChanged += Item_CheckedChanged;
- items.Add(item);
- }
- foreach(var (year, yearData) in dateData)
- {
- var yearItem = new HeaderItem(DateLevel.Year, year, year.ToString(), this);
- foreach(var (month, monthData) in yearData)
- {
- var monthItem = new HeaderItem(DateLevel.Month, month, CultureInfo.CurrentCulture.DateTimeFormat.GetAbbreviatedMonthName(month), this);
- foreach (var (day, dayData) in monthData)
- {
- var dayItem = new HeaderItem(DateLevel.Day, day, day.ToString(), this);
- foreach(var time in dayData)
- {
- var item = new HeaderItem(DateLevel.Date, time, time.ToString("HH:mm:ss"), this);
- item.IsChecked = IsSelected(time);
- item.CheckedChanged += Item_CheckedChanged;
- dayItem.AddItem(item);
- }
- monthItem.AddItem(dayItem);
- }
- yearItem.AddItem(monthItem);
- }
- yearItem.CalculateChecked();
- items.Add(yearItem);
- }
- var itemFactory = TemplateGenerator.CreateFactory(() =>
- {
- var panel = new DockPanel();
- panel.LastChildFill = true;
- var box = new CheckBox();
- box.VerticalContentAlignment = VerticalAlignment.Center;
- box.HorizontalAlignment = HorizontalAlignment.Stretch;
- box.Bind<HeaderItem, bool?>(CheckBox.IsCheckedProperty, x => x.IsChecked);
- box.Bind<HeaderItem, HeaderItem>(CheckBox.TagProperty, x => x);
- DockPanel.SetDock(box, Dock.Left);
- var label = new Label();
- label.Bind<HeaderItem, string>(Label.ContentProperty, x => x.Display);
- label.IsHitTestVisible = false;
- DockPanel.SetDock(label, Dock.Right);
- panel.Children.Add(box);
- panel.Children.Add(label);
- return panel;
- });
- treeView.HorizontalContentAlignment = HorizontalAlignment.Stretch;
- treeView.ItemTemplate = new HierarchicalDataTemplate
- {
- VisualTree = itemFactory,
- ItemsSource = WPFUtils.CreateBinding<HeaderItem, List<HeaderItem>>(x => x.Items),
- };
- treeView.ItemsSource = items;
- _items = items;
- return treeView;
- }
- private void SelectAll_CheckedChanged(HeaderItem _item, bool value)
- {
- if (value)
- {
- ClearFilter();
- }
- else
- {
- BeginUpdate();
- _selectedDates = new();
- foreach(var item in _items)
- {
- item.CalculateChecked(includeChildren: true);
- }
- Changed();
- EndUpdate();
- }
- }
- private void Item_CheckedChanged(HeaderItem item, bool value)
- {
- if (item.Level != DateLevel.Date || item.Value is not DateTime date) return;
- if (value)
- {
- if(_selectedDates is not null)
- {
- if (_selectedDates.Add(date))
- {
- var selectAll = _items.First(x => x.Level == DateLevel.All);
- selectAll.IsChecked = null;
- Changed();
- }
- }
- }
- else
- {
- if(_selectedDates is null)
- {
- _selectedDates = _dates.ToHashSet();
- _selectedDates.Remove(date);
- var selectAll = _items.First(x => x.Level == DateLevel.All);
- selectAll.IsChecked = _selectedDates.Count == 0 ? false : null;
- Changed();
- }
- else if(_selectedDates.Remove(date))
- {
- var selectAll = _items.First(x => x.Level == DateLevel.All);
- selectAll.IsChecked = _selectedDates.Count == 0 ? false : null;
- Changed();
- }
- }
- }
- private int _updating = 0;
- private bool _changed = false;
- public void BeginUpdate()
- {
- _updating++;
- }
- public void EndUpdate()
- {
- _updating--;
- if (_updating == 0 && _changed)
- {
- _changed = false;
- FilterChanged?.Invoke(this);
- }
- }
- public void Changed()
- {
- if (_updating > 0)
- {
- _changed = true;
- }
- else
- {
- FilterChanged?.Invoke(this);
- }
- }
- public bool IsSelected(DateTime date)
- {
- return _selectedDates is null || _selectedDates.Contains(date);
- }
- public bool FilterRow(CoreRow row)
- {
- if(Grid.GetData(row, Column) is DateTime date)
- {
- return IsSelected(date);
- }
- else
- {
- return true;
- }
- }
- public bool IsFiltered()
- {
- return _selectedDates is not null;
- }
- }
|