feature(Submodule): supports git submodule

This commit is contained in:
leo 2020-07-22 20:14:39 +08:00
parent 789231fdc4
commit 0132fc496b
8 changed files with 359 additions and 13 deletions

View file

@ -0,0 +1,72 @@
<UserControl x:Class="SourceGit.UI.AddSubmodule"
x:Name="me"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:helpers="clr-namespace:SourceGit.Helpers"
mc:Ignorable="d"
d:DesignHeight="192" d:DesignWidth="500" Height="192" Width="500">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="32"/>
<RowDefinition Height="16"/>
<RowDefinition Height="32"/>
<RowDefinition Height="32"/>
<RowDefinition Height="32"/>
<RowDefinition Height="16"/>
<RowDefinition Height="32"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.ColumnSpan="2" FontWeight="DemiBold" FontSize="18" Content="Add Submodule"/>
<Label Grid.Row="2" Grid.Column="0" HorizontalAlignment="Right" Content="URL :"/>
<TextBox x:Name="txtRepoUrl" Grid.Row="2" Grid.Column="1"
Height="24"
helpers:TextBoxHelper.Placeholder="Git Repository URL">
<TextBox.Text>
<Binding Path="RepoURL" ElementName="me" UpdateSourceTrigger="PropertyChanged" Mode="TwoWay">
<Binding.ValidationRules>
<helpers:RemoteUriRule/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<Label Grid.Row="3" Grid.Column="0" HorizontalAlignment="Right" Content="Parent Folder :"/>
<TextBox Grid.Row="3" Grid.Column="1"
x:Name="txtPath"
Height="24"
helpers:TextBoxHelper.Placeholder="Relative foler to store this module. Optional.">
<TextBox.Text>
<Binding Path="LocalPath" ElementName="me" UpdateSourceTrigger="PropertyChanged" Mode="TwoWay">
<Binding.ValidationRules>
<helpers:SubmodulePathRequiredRule/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<CheckBox Grid.Row="4" Grid.Column="1"
x:Name="chkRecursive"
IsChecked="True"
Content="Fetch nested submodules"/>
<Grid Grid.Row="6" Grid.ColumnSpan="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="80"/>
<ColumnDefinition Width="8"/>
<ColumnDefinition Width="80"/>
</Grid.ColumnDefinitions>
<Button Grid.Column="1" Click="Sure" Content="SURE" Style="{StaticResource Style.Button.AccentBordered}"/>
<Button Grid.Column="3" Click="Cancel" Content="CANCEL" Style="{StaticResource Style.Button.Bordered}"/>
</Grid>
</Grid>
</UserControl>

View file

@ -0,0 +1,71 @@
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
namespace SourceGit.UI {
/// <summary>
/// Dialog to add new submodule.
/// </summary>
public partial class AddSubmodule : UserControl {
private Git.Repository repo = null;
/// <summary>
/// Submodule's repository URL.
/// </summary>
public string RepoURL { get; set; }
/// <summary>
/// Submodule's relative path.
/// </summary>
public string LocalPath { get; set; }
/// <summary>
/// Constructor.
/// </summary>
/// <param name="opened"></param>
public AddSubmodule(Git.Repository opened) {
repo = opened;
InitializeComponent();
}
/// <summary>
/// Show this dialog.
/// </summary>
/// <param name="repo"></param>
public static void Show(Git.Repository repo) {
PopupManager.Show(new AddSubmodule(repo));
}
#region EVENTS
private void SelectFolder(object sender, RoutedEventArgs e) {
var dialog = new System.Windows.Forms.FolderBrowserDialog();
dialog.Description = "Select Folder To Clone Repository";
dialog.SelectedPath = repo.Path;
dialog.ShowNewFolderButton = true;
if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
txtPath.Text = dialog.SelectedPath;
}
}
private async void Sure(object sender, RoutedEventArgs e) {
txtRepoUrl.GetBindingExpression(TextBox.TextProperty).UpdateSource();
if (Validation.GetHasError(txtRepoUrl)) return;
txtPath.GetBindingExpression(TextBox.TextProperty).UpdateSource();
if (Validation.GetHasError(txtPath)) return;
var recursive = chkRecursive.IsChecked == true;
PopupManager.Lock();
await Task.Run(() => repo.AddSubmodule(RepoURL, LocalPath, recursive, PopupManager.UpdateStatus));
PopupManager.Close(true);
}
private void Cancel(object sender, RoutedEventArgs e) {
PopupManager.Close();
}
#endregion
}
}

View file

@ -51,9 +51,18 @@
<StackPanel Orientation="Horizontal">
<Path Style="{StaticResource Style.Icon}" Data="{StaticResource Icon.Manager}"/>
<Label Content="Repositories"/>
<Path Width="12" Style="{StaticResource Style.Icon}" Data="{StaticResource Icon.Navigator}"/>
</StackPanel>
</Button>
<Button x:Name="btnParent" Click="GotoParent" ToolTip="Open Parent Repository" Padding="0" Margin="6,0,0,0" Visibility="Collapsed">
<StackPanel Orientation="Horizontal">
<Path Style="{StaticResource Style.Icon}" Data="{StaticResource Icon.Git}"/>
<Label x:Name="txtParent"/>
<Path Width="12" Style="{StaticResource Style.Icon}" Data="{StaticResource Icon.Navigator}"/>
</StackPanel>
</Button>
<Path Width="12" Style="{StaticResource Style.Icon}" Data="{StaticResource Icon.Navigator}"/>
<Path Margin="6,0,0,0" Style="{StaticResource Style.Icon}" Data="{StaticResource Icon.Git}"/>
<Label x:Name="repoName"/>
</StackPanel>
@ -133,13 +142,16 @@
<!-- Left panel -->
<Grid Grid.Column="0" x:Name="main" Background="{StaticResource Brush.BG4}">
<Grid.RowDefinitions>
<RowDefinition Height="24"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="24"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="24"/>
<RowDefinition Height="*"/>
<RowDefinition Height="24"/>
<RowDefinition Height="1"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="24"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
@ -194,7 +206,7 @@
</ListView>
<!-- LOCAL BRANCHES -->
<Grid Grid.Row="2" Margin="4,0,0,0">
<Grid Grid.Row="2" Margin="4,0,2,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="16"/>
@ -275,7 +287,7 @@
</TreeView>
<!-- REMOTES -->
<Grid Grid.Row="4" Margin="4,0,0,0">
<Grid Grid.Row="4" Margin="4,0,2,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="16"/>
@ -362,7 +374,7 @@
Grid.Row="6"
Style="{StaticResource Style.ToggleButton.Expender}"
IsChecked="{Binding Source={x:Static source:App.Preference}, Path=UIShowTags, Mode=TwoWay}">
<Grid Margin="4,0,0,0">
<Grid Margin="4,0,2,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="16"/>
@ -374,8 +386,9 @@
</Button>
</Grid>
</ToggleButton>
<Rectangle Grid.Row="7" Height="1" Fill="{StaticResource Brush.BG3}"/>
<DataGrid
Grid.Row="7"
Grid.Row="8"
x:Name="tagList"
Visibility="{Binding ElementName=tagListToggle, Path=IsChecked, Converter={StaticResource Bool2Collapsed}}"
Background="{StaticResource Brush.BG3}"
@ -383,12 +396,12 @@
Height="200"
LostFocus="TagLostFocus"
SelectionChanged="TagSelectionChanged"
ContextMenuOpening="TagContextMenuOpening"
ContextMenuOpening="TagContextMenuOpening"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto"
SelectionMode="Single"
SelectionUnit="FullRow">
<DataGrid.Resources>
<DataGrid.Resources>
<Style x:Key="Style.DataGridText.TagName" TargetType="{x:Type TextBlock}">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Foreground" Value="{StaticResource Brush.FG}"/>
@ -421,6 +434,63 @@
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<!-- SUBMODULES -->
<ToggleButton
x:Name="submoduleListToggle"
Grid.Row="9"
Style="{StaticResource Style.ToggleButton.Expender}"
IsChecked="False">
<Grid Margin="4,0,2,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="16"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" x:Name="submoduleCount" Content="SUBMODULES" Style="{StaticResource Style.Label.GroupHeader}"/>
<Button Grid.Column="1" Click="OpenAddSubmodule" ToolTip="ADD SUBMODULE">
<Path Width="14" Height="14" Style="{StaticResource Style.Icon}" Data="{StaticResource Icon.Submodule}"/>
</Button>
</Grid>
</ToggleButton>
<DataGrid
Grid.Row="11"
x:Name="submoduleList"
Visibility="{Binding ElementName=submoduleListToggle, Path=IsChecked, Converter={StaticResource Bool2Collapsed}}"
Background="{StaticResource Brush.BG3}"
RowHeight="24"
Height="200"
LostFocus="SubmoduleLostFocus"
ContextMenuOpening="SubmoduleContextMenuOpening"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto"
SelectionMode="Single"
SelectionUnit="FullRow">
<DataGrid.Resources>
<Style x:Key="Style.DataGridText.SubmodulePath" TargetType="{x:Type TextBlock}">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Foreground" Value="{StaticResource Brush.FG}"/>
</Style>
</DataGrid.Resources>
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}" BasedOn="{StaticResource Style.DataGridRow}">
<EventSetter Event="MouseDoubleClick" Handler="SubmoduleMouseDoubleClick"/>
</Style>
</DataGrid.RowStyle>
<DataGrid.Columns>
<DataGridTemplateColumn Width="26">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Path Width="10" Style="{StaticResource Style.Icon}" Data="{StaticResource Icon.Submodule}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Width="*" IsReadOnly="True" Binding="{Binding}" ElementStyle="{StaticResource Style.DataGridText.SubmodulePath}"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
<!-- Splitter -->

View file

@ -55,7 +55,8 @@ namespace SourceGit.UI {
opened.OnTagChanged = UpdateTags;
opened.OnStashChanged = UpdateStashes;
opened.OnBranchChanged = () => UpdateBranches(false);
opened.OnCommitsChanged = UpdateHistories;
opened.OnCommitsChanged = UpdateHistories;
opened.OnSubmoduleChanged = UpdateSubmodules;
opened.OnNavigateCommit = commit => {
Dispatcher.Invoke(() => {
workspace.SelectedItem = historiesSwitch;
@ -70,11 +71,19 @@ namespace SourceGit.UI {
histories.Repo = opened;
commits.Repo = opened;
if (repo.Parent != null) {
btnParent.Visibility = Visibility.Visible;
txtParent.Content = repo.Parent.Name;
} else {
btnParent.Visibility = Visibility.Collapsed;
}
UpdateBranches();
UpdateHistories();
UpdateLocalChanges();
UpdateStashes();
UpdateTags();
UpdateSubmodules();
}
#region DATA_UPDATE
@ -270,6 +279,16 @@ namespace SourceGit.UI {
});
}
private void UpdateSubmodules() {
Task.Run(() => {
var submodules = repo.Submodules();
Dispatcher.Invoke(() => {
submoduleCount.Content = $"SUBMODULES ({submodules.Count})";
submoduleList.ItemsSource = submodules;
});
});
}
private void Cleanup(object sender, RoutedEventArgs e) {
localBranchTree.ItemsSource = null;
remoteBranchTree.ItemsSource = null;
@ -290,6 +309,12 @@ namespace SourceGit.UI {
repo.Close();
}
private void GotoParent(object sender, RoutedEventArgs e) {
if (repo.Parent == null) return;
repo.Parent.Open();
e.Handled = true;
}
private void OpenFetch(object sender, RoutedEventArgs e) {
Fetch.Show(repo);
}
@ -897,6 +922,58 @@ namespace SourceGit.UI {
}
#endregion
#region SUBMODULES
private void OpenAddSubmodule(object sender, RoutedEventArgs e) {
AddSubmodule.Show(repo);
}
private void SubmoduleLostFocus(object sender, RoutedEventArgs e) {
(sender as DataGrid).UnselectAll();
}
private void SubmoduleContextMenuOpening(object sender, ContextMenuEventArgs e) {
var path = (sender as DataGrid).SelectedItem as string;
if (path == null) return;
var open = new MenuItem();
open.Header = "Open Submodule Repository";
open.Click += (o, ev) => {
var sub = new Git.Repository();
sub.Path = Path.Combine(repo.Path, path);
sub.Name = Path.GetFileName(path);
sub.Parent = repo;
sub.Open();
ev.Handled = true;
};
var copy = new MenuItem();
copy.Header = "Copy Relative Path";
copy.Click += (o, ev) => {
Clipboard.SetText(path);
ev.Handled = true;
};
var menu = new ContextMenu();
menu.Items.Add(open);
menu.Items.Add(copy);
menu.IsOpen = true;
e.Handled = true;
}
private void SubmoduleMouseDoubleClick(object sender, MouseButtonEventArgs e) {
var path = (sender as DataGridRow).DataContext as string;
if (path == null) return;
var sub = new Git.Repository();
sub.Path = Path.Combine(repo.Path, path);
sub.Name = Path.GetFileName(path);
sub.Parent = repo;
sub.Open();
}
#endregion
#region TREES
private TreeViewItem FindTreeViewItem(ItemsControl item, BranchNode node) {
if (item == null) return null;

View file

@ -53,7 +53,6 @@ namespace SourceGit.UI {
/// <param name="repo"></param>
private void ShowDashboard(Git.Repository repo) {
Dispatcher.Invoke(() => {
if (body.Content is Dashboard) return;
body.Content = new Dashboard(repo);
});
}