mirror of
https://fastgit.cc/github.com/sourcegit-scm/sourcegit
synced 2026-04-21 13:20:30 +08:00
339 lines
13 KiB
C#
339 lines
13 KiB
C#
using System;
|
|
|
|
using Avalonia;
|
|
using Avalonia.Controls;
|
|
using Avalonia.Controls.Primitives;
|
|
using Avalonia.Input;
|
|
using Avalonia.Interactivity;
|
|
using Avalonia.Layout;
|
|
using Avalonia.Media;
|
|
using Avalonia.VisualTree;
|
|
|
|
namespace SourceGit.Views
|
|
{
|
|
public class SubmoduleTreeNodeToggleButton : ToggleButton
|
|
{
|
|
protected override Type StyleKeyOverride => typeof(ToggleButton);
|
|
|
|
protected override void OnPointerPressed(PointerPressedEventArgs e)
|
|
{
|
|
if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed &&
|
|
DataContext is ViewModels.SubmoduleTreeNode { IsFolder: true } node)
|
|
{
|
|
var view = this.FindAncestorOfType<SubmodulesView>();
|
|
view?.ToggleNodeIsExpanded(node);
|
|
}
|
|
|
|
e.Handled = true;
|
|
}
|
|
}
|
|
|
|
public class SubmoduleTreeNodeIcon : UserControl
|
|
{
|
|
public static readonly StyledProperty<bool> IsExpandedProperty =
|
|
AvaloniaProperty.Register<SubmoduleTreeNodeIcon, bool>(nameof(IsExpanded));
|
|
|
|
public bool IsExpanded
|
|
{
|
|
get => GetValue(IsExpandedProperty);
|
|
set => SetValue(IsExpandedProperty, value);
|
|
}
|
|
|
|
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
|
|
{
|
|
base.OnPropertyChanged(change);
|
|
|
|
if (change.Property == IsExpandedProperty)
|
|
UpdateContent();
|
|
}
|
|
|
|
protected override void OnDataContextChanged(EventArgs e)
|
|
{
|
|
base.OnDataContextChanged(e);
|
|
UpdateContent();
|
|
}
|
|
|
|
private void UpdateContent()
|
|
{
|
|
if (DataContext is not ViewModels.SubmoduleTreeNode node)
|
|
{
|
|
Content = null;
|
|
return;
|
|
}
|
|
|
|
if (node.Module != null)
|
|
CreateContent(new Thickness(0, 0, 0, 0), "Icons.Submodule");
|
|
else if (node.IsExpanded)
|
|
CreateContent(new Thickness(0, 2, 0, 0), "Icons.Folder.Open");
|
|
else
|
|
CreateContent(new Thickness(0, 2, 0, 0), "Icons.Folder");
|
|
}
|
|
|
|
private void CreateContent(Thickness margin, string iconKey)
|
|
{
|
|
if (this.FindResource(iconKey) is not StreamGeometry geo)
|
|
return;
|
|
|
|
Content = new Avalonia.Controls.Shapes.Path()
|
|
{
|
|
Width = 12,
|
|
Height = 12,
|
|
HorizontalAlignment = HorizontalAlignment.Left,
|
|
VerticalAlignment = VerticalAlignment.Center,
|
|
Margin = margin,
|
|
Data = geo,
|
|
};
|
|
}
|
|
}
|
|
|
|
public partial class SubmodulesView : UserControl
|
|
{
|
|
public static readonly RoutedEvent<RoutedEventArgs> RowsChangedEvent =
|
|
RoutedEvent.Register<TagsView, RoutedEventArgs>(nameof(RowsChanged), RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
|
|
|
|
public event EventHandler<RoutedEventArgs> RowsChanged
|
|
{
|
|
add { AddHandler(RowsChangedEvent, value); }
|
|
remove { RemoveHandler(RowsChangedEvent, value); }
|
|
}
|
|
|
|
public static readonly RoutedEvent<RoutedEventArgs> SearchRequestedEvent =
|
|
RoutedEvent.Register<BranchTree, RoutedEventArgs>(nameof(SearchRequested), RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
|
|
|
|
public event EventHandler<RoutedEventArgs> SearchRequested
|
|
{
|
|
add { AddHandler(SearchRequestedEvent, value); }
|
|
remove { RemoveHandler(SearchRequestedEvent, value); }
|
|
}
|
|
|
|
public int Rows
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
public SubmodulesView()
|
|
{
|
|
InitializeComponent();
|
|
}
|
|
|
|
public void ToggleNodeIsExpanded(ViewModels.SubmoduleTreeNode node)
|
|
{
|
|
if (Content is ViewModels.SubmoduleCollectionAsTree tree)
|
|
{
|
|
tree.ToggleExpand(node);
|
|
Rows = tree.Rows.Count;
|
|
RaiseEvent(new RoutedEventArgs(RowsChangedEvent));
|
|
}
|
|
}
|
|
|
|
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
|
|
{
|
|
base.OnPropertyChanged(change);
|
|
|
|
if (change.Property == ContentProperty)
|
|
{
|
|
if (Content is ViewModels.SubmoduleCollectionAsTree tree)
|
|
Rows = tree.Rows.Count;
|
|
else if (Content is ViewModels.SubmoduleCollectionAsList list)
|
|
Rows = list.Submodules.Count;
|
|
else
|
|
Rows = 0;
|
|
|
|
RaiseEvent(new RoutedEventArgs(RowsChangedEvent));
|
|
}
|
|
else if (change.Property == IsVisibleProperty)
|
|
{
|
|
RaiseEvent(new RoutedEventArgs(RowsChangedEvent));
|
|
}
|
|
}
|
|
|
|
private void OnItemDoubleTapped(object sender, TappedEventArgs e)
|
|
{
|
|
if (sender is Control control && DataContext is ViewModels.Repository repo)
|
|
{
|
|
if (control.DataContext is ViewModels.SubmoduleTreeNode node)
|
|
{
|
|
if (node.IsFolder)
|
|
ToggleNodeIsExpanded(node);
|
|
else if (node.Module.Status != Models.SubmoduleStatus.NotInited)
|
|
repo.OpenSubmodule(node.Module.Path);
|
|
}
|
|
else if (control.DataContext is Models.Submodule m && m.Status != Models.SubmoduleStatus.NotInited)
|
|
{
|
|
repo.OpenSubmodule(m.Path);
|
|
}
|
|
}
|
|
|
|
e.Handled = true;
|
|
}
|
|
|
|
private void OnItemContextRequested(object sender, ContextRequestedEventArgs e)
|
|
{
|
|
if (sender is Control control && DataContext is ViewModels.Repository repo)
|
|
{
|
|
var submodule = control.DataContext switch
|
|
{
|
|
ViewModels.SubmoduleTreeNode node => node.Module,
|
|
Models.Submodule m => m,
|
|
_ => null,
|
|
};
|
|
|
|
if (submodule != null)
|
|
{
|
|
var open = new MenuItem();
|
|
open.Header = App.Text("Submodule.Open");
|
|
open.Icon = this.CreateMenuIcon("Icons.Folder.Open");
|
|
open.IsEnabled = submodule.Status != Models.SubmoduleStatus.NotInited;
|
|
open.Click += (_, ev) =>
|
|
{
|
|
repo.OpenSubmodule(submodule.Path);
|
|
ev.Handled = true;
|
|
};
|
|
|
|
var update = new MenuItem();
|
|
update.Header = App.Text("Submodule.Update");
|
|
update.Icon = this.CreateMenuIcon("Icons.Loading");
|
|
update.Click += (_, ev) =>
|
|
{
|
|
if (repo.CanCreatePopup())
|
|
repo.ShowPopup(new ViewModels.UpdateSubmodules(repo, submodule));
|
|
ev.Handled = true;
|
|
};
|
|
|
|
var move = new MenuItem();
|
|
move.Header = App.Text("Submodule.Move");
|
|
move.Icon = this.CreateMenuIcon("Icons.MoveTo");
|
|
move.Click += (_, ev) =>
|
|
{
|
|
if (repo.CanCreatePopup())
|
|
repo.ShowPopup(new ViewModels.MoveSubmodule(repo, submodule));
|
|
ev.Handled = true;
|
|
};
|
|
|
|
var setURL = new MenuItem();
|
|
setURL.Header = App.Text("Submodule.SetURL");
|
|
setURL.Icon = this.CreateMenuIcon("Icons.Edit");
|
|
setURL.Click += (_, ev) =>
|
|
{
|
|
if (repo.CanCreatePopup())
|
|
repo.ShowPopup(new ViewModels.ChangeSubmoduleUrl(repo, submodule));
|
|
ev.Handled = true;
|
|
};
|
|
|
|
var setBranch = new MenuItem();
|
|
setBranch.Header = App.Text("Submodule.SetBranch");
|
|
setBranch.Icon = this.CreateMenuIcon("Icons.Track");
|
|
setBranch.Click += (_, ev) =>
|
|
{
|
|
if (repo.CanCreatePopup())
|
|
repo.ShowPopup(new ViewModels.SetSubmoduleBranch(repo, submodule));
|
|
ev.Handled = true;
|
|
};
|
|
|
|
var deinit = new MenuItem();
|
|
deinit.Header = App.Text("Submodule.Deinit");
|
|
deinit.Icon = this.CreateMenuIcon("Icons.Undo");
|
|
deinit.IsEnabled = submodule.Status != Models.SubmoduleStatus.NotInited;
|
|
deinit.Click += (_, ev) =>
|
|
{
|
|
if (repo.CanCreatePopup())
|
|
repo.ShowPopup(new ViewModels.DeinitSubmodule(repo, submodule.Path));
|
|
ev.Handled = true;
|
|
};
|
|
|
|
var rm = new MenuItem();
|
|
rm.Header = App.Text("Submodule.Remove");
|
|
rm.Icon = this.CreateMenuIcon("Icons.Clear");
|
|
rm.Click += (_, ev) =>
|
|
{
|
|
if (repo.CanCreatePopup())
|
|
repo.ShowPopup(new ViewModels.DeleteSubmodule(repo, submodule.Path));
|
|
ev.Handled = true;
|
|
};
|
|
|
|
var histories = new MenuItem();
|
|
histories.Header = App.Text("Submodule.Histories");
|
|
histories.Icon = this.CreateMenuIcon("Icons.Histories");
|
|
histories.Click += (_, ev) =>
|
|
{
|
|
this.ShowWindow(new ViewModels.FileHistories(repo.FullPath, submodule.Path));
|
|
ev.Handled = true;
|
|
};
|
|
|
|
var copySHA = new MenuItem();
|
|
copySHA.Header = App.Text("CommitDetail.Info.SHA");
|
|
copySHA.Icon = this.CreateMenuIcon("Icons.Hash");
|
|
copySHA.Click += async (_, ev) =>
|
|
{
|
|
await this.CopyTextAsync(submodule.SHA);
|
|
ev.Handled = true;
|
|
};
|
|
|
|
var copyBranch = new MenuItem();
|
|
copyBranch.Header = App.Text("Submodule.CopyBranch");
|
|
copyBranch.Icon = this.CreateMenuIcon("Icons.Branch");
|
|
copyBranch.Click += async (_, ev) =>
|
|
{
|
|
await this.CopyTextAsync(submodule.Branch);
|
|
ev.Handled = true;
|
|
};
|
|
|
|
var copyRelativePath = new MenuItem();
|
|
copyRelativePath.Header = App.Text("Submodule.CopyPath");
|
|
copyRelativePath.Icon = this.CreateMenuIcon("Icons.Folder");
|
|
copyRelativePath.Click += async (_, ev) =>
|
|
{
|
|
await this.CopyTextAsync(submodule.Path);
|
|
ev.Handled = true;
|
|
};
|
|
|
|
var copyURL = new MenuItem();
|
|
copyURL.Header = App.Text("Submodule.URL");
|
|
copyURL.Icon = this.CreateMenuIcon("Icons.Link");
|
|
copyURL.Click += async (_, ev) =>
|
|
{
|
|
await this.CopyTextAsync(submodule.URL);
|
|
ev.Handled = true;
|
|
};
|
|
|
|
var copy = new MenuItem();
|
|
copy.Header = App.Text("Copy");
|
|
copy.Icon = this.CreateMenuIcon("Icons.Copy");
|
|
copy.Items.Add(copySHA);
|
|
copy.Items.Add(copyBranch);
|
|
copy.Items.Add(copyRelativePath);
|
|
copy.Items.Add(copyURL);
|
|
|
|
var menu = new ContextMenu();
|
|
menu.Items.Add(open);
|
|
menu.Items.Add(new MenuItem() { Header = "-" });
|
|
menu.Items.Add(update);
|
|
menu.Items.Add(setURL);
|
|
menu.Items.Add(setBranch);
|
|
menu.Items.Add(move);
|
|
menu.Items.Add(deinit);
|
|
menu.Items.Add(rm);
|
|
menu.Items.Add(new MenuItem() { Header = "-" });
|
|
menu.Items.Add(histories);
|
|
menu.Items.Add(new MenuItem() { Header = "-" });
|
|
menu.Items.Add(copy);
|
|
menu.Open(control);
|
|
}
|
|
}
|
|
|
|
e.Handled = true;
|
|
}
|
|
|
|
private void OnKeyDown(object sender, KeyEventArgs e)
|
|
{
|
|
if (e.Key == Key.F && e.KeyModifiers == (OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control))
|
|
{
|
|
RaiseEvent(new RoutedEventArgs(SearchRequestedEvent));
|
|
e.Handled = true;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|