sourcegit/src/Views/ChangeCollectionView.axaml.cs

330 lines
11 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.VisualTree;
namespace SourceGit.Views
{
public class ChangeTreeNodeToggleButton : ToggleButton
{
protected override Type StyleKeyOverride => typeof(ToggleButton);
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed &&
2024-07-14 00:55:15 -07:00
DataContext is ViewModels.ChangeTreeNode { IsFolder: true } node)
{
var tree = this.FindAncestorOfType<ChangeCollectionView>();
2024-07-14 00:55:15 -07:00
tree?.ToggleNodeIsExpanded(node);
}
e.Handled = true;
}
}
public class ChangeCollectionContainer : ListBox
{
protected override Type StyleKeyOverride => typeof(ListBox);
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.Key != Key.Space)
base.OnKeyDown(e);
}
}
public partial class ChangeCollectionView : UserControl
{
public static readonly StyledProperty<bool> IsWorkingCopyChangeProperty =
2024-07-14 00:55:15 -07:00
AvaloniaProperty.Register<ChangeCollectionView, bool>(nameof(IsWorkingCopyChange));
2024-05-31 21:13:57 -07:00
public bool IsWorkingCopyChange
{
get => GetValue(IsWorkingCopyChangeProperty);
set => SetValue(IsWorkingCopyChangeProperty, value);
}
public static readonly StyledProperty<SelectionMode> SelectionModeProperty =
2024-07-14 00:55:15 -07:00
AvaloniaProperty.Register<ChangeCollectionView, SelectionMode>(nameof(SelectionMode));
public SelectionMode SelectionMode
{
get => GetValue(SelectionModeProperty);
set => SetValue(SelectionModeProperty, value);
}
public static readonly StyledProperty<Models.ChangeViewMode> ViewModeProperty =
AvaloniaProperty.Register<ChangeCollectionView, Models.ChangeViewMode>(nameof(ViewMode), Models.ChangeViewMode.Tree);
public Models.ChangeViewMode ViewMode
{
get => GetValue(ViewModeProperty);
set => SetValue(ViewModeProperty, value);
}
public static readonly StyledProperty<List<Models.Change>> ChangesProperty =
2024-07-14 00:55:15 -07:00
AvaloniaProperty.Register<ChangeCollectionView, List<Models.Change>>(nameof(Changes));
public List<Models.Change> Changes
{
get => GetValue(ChangesProperty);
set => SetValue(ChangesProperty, value);
}
public static readonly StyledProperty<List<Models.Change>> SelectedChangesProperty =
2024-07-14 00:55:15 -07:00
AvaloniaProperty.Register<ChangeCollectionView, List<Models.Change>>(nameof(SelectedChanges));
public List<Models.Change> SelectedChanges
{
get => GetValue(SelectedChangesProperty);
set => SetValue(SelectedChangesProperty, value);
}
public static readonly RoutedEvent<RoutedEventArgs> ChangeDoubleTappedEvent =
RoutedEvent.Register<ChangeCollectionView, RoutedEventArgs>(nameof(ChangeDoubleTapped), RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
public event EventHandler<RoutedEventArgs> ChangeDoubleTapped
{
add { AddHandler(ChangeDoubleTappedEvent, value); }
remove { RemoveHandler(ChangeDoubleTappedEvent, value); }
}
public ChangeCollectionView()
{
InitializeComponent();
}
2024-07-14 00:55:15 -07:00
public void ToggleNodeIsExpanded(ViewModels.ChangeTreeNode node)
{
2024-07-14 00:55:15 -07:00
if (_displayContext is ViewModels.ChangeCollectionAsTree tree)
{
node.IsExpanded = !node.IsExpanded;
var depth = node.Depth;
var idx = tree.Rows.IndexOf(node);
if (idx == -1)
return;
if (node.IsExpanded)
{
2024-07-14 00:55:15 -07:00
var subrows = new List<ViewModels.ChangeTreeNode>();
MakeTreeRows(subrows, node.Children);
tree.Rows.InsertRange(idx + 1, subrows);
}
else
{
var removeCount = 0;
for (int i = idx + 1; i < tree.Rows.Count; i++)
{
var row = tree.Rows[i];
if (row.Depth <= depth)
break;
removeCount++;
}
tree.Rows.RemoveRange(idx + 1, removeCount);
}
}
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (change.Property == ViewModeProperty || change.Property == ChangesProperty)
{
_disableSelectionChangingEvent = change.Property == ChangesProperty;
var changes = Changes;
if (changes == null || changes.Count == 0)
{
Content = null;
_displayContext = null;
_disableSelectionChangingEvent = false;
return;
}
if (ViewMode == Models.ChangeViewMode.Tree)
{
HashSet<string> oldFolded = new HashSet<string>();
2024-07-14 00:55:15 -07:00
if (_displayContext is ViewModels.ChangeCollectionAsTree oldTree)
{
foreach (var row in oldTree.Rows)
{
if (row.IsFolder && !row.IsExpanded)
oldFolded.Add(row.FullPath);
}
}
2024-07-14 00:55:15 -07:00
var tree = new ViewModels.ChangeCollectionAsTree();
tree.Tree = ViewModels.ChangeTreeNode.Build(changes, oldFolded);
2024-07-14 00:55:15 -07:00
var rows = new List<ViewModels.ChangeTreeNode>();
MakeTreeRows(rows, tree.Tree);
tree.Rows.AddRange(rows);
_displayContext = tree;
}
else if (ViewMode == Models.ChangeViewMode.Grid)
{
2024-07-14 00:55:15 -07:00
var grid = new ViewModels.ChangeCollectionAsGrid();
grid.Changes.AddRange(changes);
_displayContext = grid;
}
else
{
2024-07-14 00:55:15 -07:00
var list = new ViewModels.ChangeCollectionAsList();
list.Changes.AddRange(changes);
_displayContext = list;
}
Content = _displayContext;
_disableSelectionChangingEvent = false;
}
else if (change.Property == SelectedChangesProperty)
{
if (_disableSelectionChangingEvent)
return;
var list = this.FindDescendantOfType<ChangeCollectionContainer>();
if (list == null)
return;
_disableSelectionChangingEvent = true;
var selected = SelectedChanges;
if (selected == null || selected.Count == 0)
{
list.SelectedItem = null;
}
2024-07-14 00:55:15 -07:00
else if (_displayContext is ViewModels.ChangeCollectionAsTree tree)
{
var sets = new HashSet<Models.Change>();
foreach (var c in selected)
sets.Add(c);
2024-07-14 00:55:15 -07:00
var nodes = new List<ViewModels.ChangeTreeNode>();
foreach (var row in tree.Rows)
{
if (row.Change != null && sets.Contains(row.Change))
nodes.Add(row);
}
list.SelectedItems = nodes;
}
else
{
list.SelectedItems = selected;
}
_disableSelectionChangingEvent = false;
}
}
private void OnRowDoubleTapped(object sender, TappedEventArgs e)
{
var grid = sender as Grid;
2024-07-14 00:55:15 -07:00
if (grid?.DataContext is ViewModels.ChangeTreeNode node)
{
if (node.IsFolder)
{
var posX = e.GetPosition(this).X;
if (posX < node.Depth * 16 + 16)
return;
ToggleNodeIsExpanded(node);
}
else
{
RaiseEvent(new RoutedEventArgs(ChangeDoubleTappedEvent));
}
}
2024-07-14 00:55:15 -07:00
else if (grid?.DataContext is Models.Change)
{
RaiseEvent(new RoutedEventArgs(ChangeDoubleTappedEvent));
}
}
2024-07-14 00:55:15 -07:00
private void OnRowSelectionChanged(object sender, SelectionChangedEventArgs _)
{
if (_disableSelectionChangingEvent)
return;
_disableSelectionChangingEvent = true;
var selected = new List<Models.Change>();
2024-07-14 00:55:15 -07:00
if (sender is ListBox { SelectedItems: not null } list)
{
2024-07-14 00:55:15 -07:00
foreach (var item in list.SelectedItems)
{
if (item is Models.Change c)
selected.Add(c);
else if (item is ViewModels.ChangeTreeNode node)
CollectChangesInNode(selected, node);
}
}
2024-07-14 00:55:15 -07:00
TrySetSelected(selected);
_disableSelectionChangingEvent = false;
}
2024-07-14 00:55:15 -07:00
private void MakeTreeRows(List<ViewModels.ChangeTreeNode> rows, List<ViewModels.ChangeTreeNode> nodes)
{
foreach (var node in nodes)
{
rows.Add(node);
if (!node.IsExpanded || !node.IsFolder)
continue;
MakeTreeRows(rows, node.Children);
}
}
2024-07-14 00:55:15 -07:00
private void CollectChangesInNode(List<Models.Change> outs, ViewModels.ChangeTreeNode node)
{
if (node.IsFolder)
{
foreach (var child in node.Children)
CollectChangesInNode(outs, child);
}
else if (!outs.Contains(node.Change))
{
outs.Add(node.Change);
}
}
private void TrySetSelected(List<Models.Change> changes)
{
var old = SelectedChanges;
if (old == null && changes.Count == 0)
return;
if (old != null && old.Count == changes.Count)
{
bool allEquals = true;
foreach (var c in old)
{
if (!changes.Contains(c))
{
allEquals = false;
break;
}
}
if (allEquals)
return;
}
_disableSelectionChangingEvent = true;
SetCurrentValue(SelectedChangesProperty, changes);
_disableSelectionChangingEvent = false;
}
private bool _disableSelectionChangingEvent = false;
private object _displayContext = null;
}
}