diff --git a/build/build.linux.sh b/build/build.linux.sh old mode 100644 new mode 100755 diff --git a/build/resources/_common/usr/bin/sourcegit b/build/resources/_common/usr/bin/sourcegit index f056d708..74670167 100644 --- a/build/resources/_common/usr/bin/sourcegit +++ b/build/resources/_common/usr/bin/sourcegit @@ -1,2 +1,2 @@ #!/bin/bash -exec /opt/sourcegit/sourcegit +exec /opt/sourcegit/sourcegit $1 diff --git a/src/Commands/Branch.cs b/src/Commands/Branch.cs index 21210238..660a5daa 100644 --- a/src/Commands/Branch.cs +++ b/src/Commands/Branch.cs @@ -36,7 +36,7 @@ return cmd.Exec(); } - public static bool Delete(string repo, string name) + public static bool DeleteLocal(string repo, string name) { var cmd = new Command(); cmd.WorkingDirectory = repo; @@ -44,5 +44,25 @@ cmd.Args = $"branch -D {name}"; return cmd.Exec(); } + + public static bool DeleteRemote(string repo, string remote, string name) + { + var cmd = new Command(); + cmd.WorkingDirectory = repo; + cmd.Context = repo; + + var sshKey = new Config(repo).Get($"remote.{remote}.sshkey"); + if (!string.IsNullOrEmpty(sshKey)) + { + cmd.Args = $"-c core.sshCommand=\"ssh -i '{sshKey}'\" "; + } + else + { + cmd.Args = "-c credential.helper=manager "; + } + + cmd.Args += $"push {remote} --delete {name}"; + return cmd.Exec(); + } } } diff --git a/src/Commands/Push.cs b/src/Commands/Push.cs index b3e4814a..0aac37a5 100644 --- a/src/Commands/Push.cs +++ b/src/Commands/Push.cs @@ -33,31 +33,6 @@ namespace SourceGit.Commands Args += $"{remote} {local}:{remoteBranch}"; } - /// - /// Only used to delete a remote branch!!!!!! - /// - /// - /// - /// - public Push(string repo, string remote, string branch) - { - WorkingDirectory = repo; - Context = repo; - TraitErrorAsOutput = true; - - var sshKey = new Config(repo).Get($"remote.{remote}.sshkey"); - if (!string.IsNullOrEmpty(sshKey)) - { - Args = $"-c core.sshCommand=\"ssh -i '{sshKey}'\" "; - } - else - { - Args = "-c credential.helper=manager "; - } - - Args += $"push {remote} --delete {branch}"; - } - public Push(string repo, string remote, string tag, bool isDelete) { WorkingDirectory = repo; diff --git a/src/Commands/Tag.cs b/src/Commands/Tag.cs index f96d3bc7..5fe57f94 100644 --- a/src/Commands/Tag.cs +++ b/src/Commands/Tag.cs @@ -5,12 +5,22 @@ namespace SourceGit.Commands { public static class Tag { - public static bool Add(string repo, string name, string basedOn, string message) + public static bool Add(string repo, string name, string basedOn) { var cmd = new Command(); cmd.WorkingDirectory = repo; cmd.Context = repo; - cmd.Args = $"tag -a {name} {basedOn} "; + cmd.Args = $"tag {name} {basedOn}"; + return cmd.Exec(); + } + + public static bool Add(string repo, string name, string basedOn, string message, bool sign) + { + var param = sign ? "-s -a" : "-a"; + var cmd = new Command(); + cmd.WorkingDirectory = repo; + cmd.Context = repo; + cmd.Args = $"tag {param} {name} {basedOn} "; if (!string.IsNullOrEmpty(message)) { diff --git a/src/Converters/EnumConverters.cs b/src/Converters/EnumConverters.cs new file mode 100644 index 00000000..4b719cba --- /dev/null +++ b/src/Converters/EnumConverters.cs @@ -0,0 +1,9 @@ +using Avalonia.Controls.Converters; + +namespace SourceGit.Converters +{ + public static class EnumConverters + { + public static readonly EnumToBoolConverter Equals = new EnumToBoolConverter(); + } +} diff --git a/src/Converters/WindowStateConverters.cs b/src/Converters/WindowStateConverters.cs index c73c86a8..2c3b2ac6 100644 --- a/src/Converters/WindowStateConverters.cs +++ b/src/Converters/WindowStateConverters.cs @@ -31,7 +31,7 @@ namespace SourceGit.Converters { if (state == WindowState.Maximized) { - return new GridLength(30); + return new GridLength(OperatingSystem.IsMacOS() ? 34 : 30); } else { diff --git a/src/Models/Remote.cs b/src/Models/Remote.cs index e3eaf36d..c1cce340 100644 --- a/src/Models/Remote.cs +++ b/src/Models/Remote.cs @@ -6,9 +6,9 @@ namespace SourceGit.Models { [GeneratedRegex(@"^http[s]?://([\w\-]+@)?[\w\.\-]+(\:[0-9]+)?/[\w\-/]+/[\w\-\.]+\.git$")] private static partial Regex REG_HTTPS(); - [GeneratedRegex(@"^[\w\-]+@[\w\.\-]+(\:[0-9]+)?:[\w\-]+/[\w\-\.]+\.git$")] + [GeneratedRegex(@"^[\w\-]+@[\w\.\-]+(\:[0-9]+)?:[\w\-/]+/[\w\-\.]+\.git$")] private static partial Regex REG_SSH1(); - [GeneratedRegex(@"^ssh://([\w\-]+@)?[\w\.\-]+(\:[0-9]+)?/[\w\-]+/[\w\-\.]+\.git$")] + [GeneratedRegex(@"^ssh://([\w\-]+@)?[\w\.\-]+(\:[0-9]+)?/[\w\-/]+/[\w\-\.]+\.git$")] private static partial Regex REG_SSH2(); private static readonly Regex[] URL_FORMATS = [ diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index a299c320..ab1f2296 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -35,6 +35,7 @@ Checkout${0}$ Copy Branch Name Delete${0}$ + Delete selected {0} branches Discard all changes Fast-Forward to${0}$ Git Flow - Finish${0}$ @@ -85,9 +86,10 @@ Save as Patch ... Squash Into Parent CHANGES - Search Files ... + Search Changes ... FILES LFS File + Search Files ... Submodule Tag Tree @@ -114,20 +116,28 @@ Local Changes : Discard Stash & Reapply + Do Nothing New Branch Name : Enter branch name. Create Local Branch Create Tag New Tag At : + GPG signing Tag Message : Optional. Tag Name : Recommended format :v1.0.0-alpha + Push to all remotes after created + Kind : + annotated + lightweight Cut Delete Branch Branch : You are about to delete a remote branch!!! Also delete remote branch${0}$ + Delete Multiple Branches + You are trying to delete multiple branches at one time. Be sure to double-check before taking action! Delete Remote Remote : Target : @@ -315,8 +325,10 @@ Remote : Push Changes To Remote Remote Branch : + Tracking remote branch(--set-upstream) Push all tags Push Tag To Remote + Push to all remotes Remote : Tag : Quit diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml index 9f464b79..7b496f75 100644 --- a/src/Resources/Locales/zh_CN.axaml +++ b/src/Resources/Locales/zh_CN.axaml @@ -35,6 +35,7 @@ 检出(checkout)${0}$ 复制分支名 删除${0}$ + 删除选中的 {0} 个分支 放弃所有更改 快进(fast-forward)到${0}$ GIT工作流 - 完成${0}$ @@ -80,9 +81,10 @@ 另存为补丁 ... 合并此提交到上一个提交 变更对比 - 查找文件... + 查找变更... 文件列表 LFS文件 + 查找文件... 子模块 标签文件 子树 @@ -107,22 +109,30 @@ 新分支基于 : 完成后切换到新分支 未提交更改 : - 忽略 - 贮藏(stash)并自动恢复 + 放弃所有 + 贮藏并自动恢复 + GIT默认 新分支名 : 填写分支名称。 创建本地分支 新建标签 标签位于 : + 使用GPG签名 标签描述 : 选填。 标签名 : 推荐格式 :v1.0.0-alpha + 推送到所有远程仓库 + 类型 : + 附注标签 + 轻量标签 剪切 删除分支确认 分支名 : 您正在删除远程上的分支,请务必小心!!! 同时删除远程分支${0}$ + 删除多个分支 + 您正在尝试一次性删除多个分支,请务必仔细检查后再执行操作! 删除远程确认 远程名 : 目标 : @@ -310,8 +320,10 @@ 远程仓库 : 推送到远程仓库 远程分支 : + 跟踪远程分支(--set-upstream) 同时推送标签 推送标签到远程仓库 + 推送到所有远程仓库 远程仓库 : 标签 : 退出 diff --git a/src/Resources/Styles.axaml b/src/Resources/Styles.axaml index afac434c..ec4e0221 100644 --- a/src/Resources/Styles.axaml +++ b/src/Resources/Styles.axaml @@ -13,6 +13,9 @@ 12 + + + - - @@ -897,7 +878,7 @@ @@ -1075,11 +1059,11 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Views/DeleteMultipleBranches.axaml.cs b/src/Views/DeleteMultipleBranches.axaml.cs new file mode 100644 index 00000000..7b3552d5 --- /dev/null +++ b/src/Views/DeleteMultipleBranches.axaml.cs @@ -0,0 +1,13 @@ +using Avalonia.Controls; + +namespace SourceGit.Views +{ + public partial class DeleteMultipleBranches : UserControl + { + public DeleteMultipleBranches() + { + InitializeComponent(); + } + } +} + diff --git a/src/Views/EditRemote.axaml b/src/Views/EditRemote.axaml index d719b585..8a51a643 100644 --- a/src/Views/EditRemote.axaml +++ b/src/Views/EditRemote.axaml @@ -12,7 +12,7 @@ + Text="{DynamicResource Text.Remote.EditTitle}"/> diff --git a/src/Views/Preference.axaml b/src/Views/Preference.axaml index 6b696d5a..60ecf610 100644 --- a/src/Views/Preference.axaml +++ b/src/Views/Preference.axaml @@ -396,17 +396,10 @@ - - - - @@ -417,15 +410,19 @@ - - + + diff --git a/src/Views/Preference.axaml.cs b/src/Views/Preference.axaml.cs index 1dd77b50..1b5a432c 100644 --- a/src/Views/Preference.axaml.cs +++ b/src/Views/Preference.axaml.cs @@ -207,10 +207,17 @@ namespace SourceGit.Views private async void SelectGPGExecutable(object sender, RoutedEventArgs e) { - var pattern = OperatingSystem.IsWindows() ? "gpg.exe" : "gpg"; + var patterns = new List(); + if (OperatingSystem.IsWindows()) + patterns.Add("gpg.exe"); + else if (OperatingSystem.IsLinux()) + patterns.AddRange(new string[] { "gpg", "gpg2" }); + else + patterns.Add("gpg"); + var options = new FilePickerOpenOptions() { - FileTypeFilter = [new FilePickerFileType("GPG Executable") { Patterns = [pattern] }], + FileTypeFilter = [new FilePickerFileType("GPG Executable") { Patterns = patterns }], AllowMultiple = false, }; diff --git a/src/Views/Push.axaml b/src/Views/Push.axaml index bb76ad26..00cdafbf 100644 --- a/src/Views/Push.axaml +++ b/src/Views/Push.axaml @@ -13,7 +13,7 @@ Classes="bold" Text="{DynamicResource Text.Push.Title}"/> - + + + - diff --git a/src/Views/PushTag.axaml b/src/Views/PushTag.axaml index f62d538a..1b24dc1b 100644 --- a/src/Views/PushTag.axaml +++ b/src/Views/PushTag.axaml @@ -12,7 +12,7 @@ - + + SelectedItem="{Binding SelectedRemote, Mode=TwoWay}" + IsEnabled="{Binding !PushAllRemotes}"> @@ -41,6 +42,10 @@ + + diff --git a/src/Views/Repository.axaml b/src/Views/Repository.axaml index 6b62a0b1..b06cf587 100644 --- a/src/Views/Repository.axaml +++ b/src/Views/Repository.axaml @@ -109,7 +109,7 @@ - + @@ -119,14 +119,14 @@ - + - + @@ -142,7 +142,7 @@ - + @@ -198,19 +198,31 @@ + + + + - + @@ -250,20 +262,32 @@ + + + + - + @@ -294,7 +318,9 @@ + + + + + + + + + + @@ -364,6 +407,7 @@ + + + + + + + + + + @@ -390,7 +452,7 @@ - + @@ -408,6 +470,7 @@ BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}" Background="{DynamicResource Brush.Contents}" + CornerRadius="4" Watermark="{DynamicResource Text.Repository.SearchTip}" Text="{Binding SearchCommitFilter, Mode=TwoWay}" VerticalContentAlignment="Center" diff --git a/src/Views/Repository.axaml.cs b/src/Views/Repository.axaml.cs index c459dd33..ed26905a 100644 --- a/src/Views/Repository.axaml.cs +++ b/src/Views/Repository.axaml.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Threading.Tasks; using Avalonia; @@ -6,6 +7,7 @@ using Avalonia.Controls; using Avalonia.Controls.Primitives; using Avalonia.Input; using Avalonia.Interactivity; +using Avalonia.VisualTree; namespace SourceGit.Views { @@ -66,56 +68,47 @@ namespace SourceGit.Views if (sender is Button button && DataContext is ViewModels.Repository repo) { var menu = repo.CreateContextMenuForExternalTools(); - if (menu != null) - { - menu.Open(button); - e.Handled = true; - } + button.OpenContextMenu(menu); + e.Handled = true; } } - private void OnLocalBranchTreeLostFocus(object sender, RoutedEventArgs e) - { - if (sender is TreeView tree) - tree.UnselectAll(); - } - - private void OnRemoteBranchTreeLostFocus(object sender, RoutedEventArgs e) - { - if (sender is TreeView tree) - tree.UnselectAll(); - } - - private void OnTagDataGridLostFocus(object sender, RoutedEventArgs e) - { - if (sender is DataGrid datagrid) - datagrid.SelectedItem = null; - } - private void OnLocalBranchTreeSelectionChanged(object sender, SelectionChangedEventArgs e) { - if (sender is TreeView tree && tree.SelectedItem != null) + if (sender is TreeView tree && tree.SelectedItem != null && DataContext is ViewModels.Repository repo) { remoteBranchTree.UnselectAll(); + tagsList.SelectedItem = null; - var node = tree.SelectedItem as ViewModels.BranchTreeNode; - if (node.IsBranch && DataContext is ViewModels.Repository repo) + ViewModels.BranchTreeNode prev = null; + foreach (var node in repo.LocalBranchTrees) + node.UpdateCornerRadius(ref prev); + + if (tree.SelectedItems.Count == 1) { - repo.NavigateToCommit((node.Backend as Models.Branch).Head); + var node = tree.SelectedItem as ViewModels.BranchTreeNode; + if (node.IsBranch) + repo.NavigateToCommit((node.Backend as Models.Branch).Head); } } } private void OnRemoteBranchTreeSelectionChanged(object sender, SelectionChangedEventArgs e) { - if (sender is TreeView tree && tree.SelectedItem != null) + if (sender is TreeView tree && tree.SelectedItem != null && DataContext is ViewModels.Repository repo) { localBranchTree.UnselectAll(); + tagsList.SelectedItem = null; - var node = tree.SelectedItem as ViewModels.BranchTreeNode; - if (node.IsBranch && DataContext is ViewModels.Repository repo) + ViewModels.BranchTreeNode prev = null; + foreach (var node in repo.RemoteBranchTrees) + node.UpdateCornerRadius(ref prev); + + if (tree.SelectedItems.Count == 1) { - repo.NavigateToCommit((node.Backend as Models.Branch).Head); + var node = tree.SelectedItem as ViewModels.BranchTreeNode; + if (node.IsBranch) + repo.NavigateToCommit((node.Backend as Models.Branch).Head); } } } @@ -124,11 +117,12 @@ namespace SourceGit.Views { if (sender is DataGrid datagrid && datagrid.SelectedItem != null) { + localBranchTree.UnselectAll(); + remoteBranchTree.UnselectAll(); + var tag = datagrid.SelectedItem as Models.Tag; if (DataContext is ViewModels.Repository repo) - { repo.NavigateToCommit(tag.SHA); - } } } @@ -136,9 +130,7 @@ namespace SourceGit.Views { var grid = sender as Grid; if (e.Property == IsVisibleProperty && grid.IsVisible) - { txtSearchCommitsBox.Focus(); - } } private void OnSearchKeyDown(object sender, KeyEventArgs e) @@ -146,9 +138,8 @@ namespace SourceGit.Views if (e.Key == Key.Enter) { if (DataContext is ViewModels.Repository repo) - { repo.StartSearchCommits(); - } + e.Handled = true; } } @@ -174,9 +165,7 @@ namespace SourceGit.Views if (toggle.DataContext is ViewModels.BranchTreeNode node) { if (node.IsBranch) - { filter = (node.Backend as Models.Branch).FullName; - } } else if (toggle.DataContext is Models.Tag tag) { @@ -195,16 +184,43 @@ namespace SourceGit.Views private void OnLocalBranchContextMenuRequested(object sender, ContextRequestedEventArgs e) { remoteBranchTree.UnselectAll(); + tagsList.SelectedItem = null; - if (sender is Grid grid && grid.DataContext is ViewModels.BranchTreeNode node) + var repo = DataContext as ViewModels.Repository; + var tree = sender as TreeView; + if (tree.SelectedItems.Count == 0) { - if (node.IsBranch && DataContext is ViewModels.Repository repo) + e.Handled = true; + return; + } + + var branches = new List(); + foreach (var item in tree.SelectedItems) + CollectBranchesFromNode(branches, item as ViewModels.BranchTreeNode); + + if (branches.Count == 1) + { + var item = (e.Source as Control)?.FindAncestorOfType(true); + if (item != null) { - var menu = repo.CreateContextMenuForLocalBranch(node.Backend as Models.Branch); - if (menu != null) - menu.Open(grid); + var menu = repo.CreateContextMenuForLocalBranch(branches[0]); + item.OpenContextMenu(menu); } } + else if (branches.Count > 1 && branches.Find(x => x.IsCurrent) == null) + { + var menu = new ContextMenu(); + var deleteMulti = new MenuItem(); + deleteMulti.Header = App.Text("BranchCM.DeleteMultiBranches", branches.Count); + deleteMulti.Icon = App.CreateMenuIcon("Icons.Clear"); + deleteMulti.Click += (_, ev) => + { + repo.DeleteMultipleBranches(branches, true); + ev.Handled = true; + }; + menu.Items.Add(deleteMulti); + tree.OpenContextMenu(menu); + } e.Handled = true; } @@ -212,22 +228,60 @@ namespace SourceGit.Views private void OnRemoteBranchContextMenuRequested(object sender, ContextRequestedEventArgs e) { localBranchTree.UnselectAll(); - - if (sender is Grid grid && grid.DataContext is ViewModels.BranchTreeNode node && DataContext is ViewModels.Repository repo) + tagsList.SelectedItem = null; + + var repo = DataContext as ViewModels.Repository; + var tree = sender as TreeView; + if (tree.SelectedItems.Count == 0) { - if (node.IsRemote) + e.Handled = true; + return; + } + + if (tree.SelectedItems.Count == 1) + { + var node = tree.SelectedItem as ViewModels.BranchTreeNode; + if (node != null && node.IsRemote) { - var menu = repo.CreateContextMenuForRemote(node.Backend as Models.Remote); - if (menu != null) - menu.Open(grid); + var item = (e.Source as Control)?.FindAncestorOfType(true); + if (item != null && item.DataContext == node) + { + var menu = repo.CreateContextMenuForRemote(node.Backend as Models.Remote); + item.OpenContextMenu(menu); + } + + e.Handled = true; + return; } - else if (node.IsBranch) + } + + var branches = new List(); + foreach (var item in tree.SelectedItems) + CollectBranchesFromNode(branches, item as ViewModels.BranchTreeNode); + + if (branches.Count == 1) + { + var item = (e.Source as Control)?.FindAncestorOfType(true); + if (item != null) { - var menu = repo.CreateContextMenuForRemoteBranch(node.Backend as Models.Branch); - if (menu != null) - menu.Open(grid); + var menu = repo.CreateContextMenuForRemoteBranch(branches[0]); + item.OpenContextMenu(menu); } } + else if (branches.Count > 1) + { + var menu = new ContextMenu(); + var deleteMulti = new MenuItem(); + deleteMulti.Header = App.Text("BranchCM.DeleteMultiBranches", branches.Count); + deleteMulti.Icon = App.CreateMenuIcon("Icons.Clear"); + deleteMulti.Click += (_, ev) => + { + repo.DeleteMultipleBranches(branches, false); + ev.Handled = true; + }; + menu.Items.Add(deleteMulti); + tree.OpenContextMenu(menu); + } e.Handled = true; } @@ -238,8 +292,7 @@ namespace SourceGit.Views { var tag = datagrid.SelectedItem as Models.Tag; var menu = repo.CreateContextMenuForTag(tag); - if (menu != null) - menu.Open(datagrid); + datagrid.OpenContextMenu(menu); } e.Handled = true; @@ -251,8 +304,7 @@ namespace SourceGit.Views { var submodule = datagrid.SelectedItem as string; var menu = repo.CreateContextMenuForSubmodule(submodule); - if (menu != null) - menu.Open(datagrid); + datagrid.OpenContextMenu(menu); } e.Handled = true; @@ -263,8 +315,7 @@ namespace SourceGit.Views if (DataContext is ViewModels.Repository repo) { var menu = repo.CreateContextMenuForGitFlow(); - if (menu != null) - menu.Open(sender as Button); + (sender as Control)?.OpenContextMenu(menu); } e.Handled = true; @@ -313,5 +364,23 @@ namespace SourceGit.Views e.Handled = true; } } + + private void CollectBranchesFromNode(List outs, ViewModels.BranchTreeNode node) + { + if (node == null || node.IsRemote) + return; + + if (node.IsFolder) + { + foreach (var child in node.Children) + CollectBranchesFromNode(outs, child); + } + else + { + var b = node.Backend as Models.Branch; + if (b != null && !outs.Contains(b)) + outs.Add(b); + } + } } } diff --git a/src/Views/RepositoryConfigure.axaml b/src/Views/RepositoryConfigure.axaml index 8e440089..3bcc7fff 100644 --- a/src/Views/RepositoryConfigure.axaml +++ b/src/Views/RepositoryConfigure.axaml @@ -47,23 +47,18 @@ Text="{Binding HttpProxy, Mode=TwoWay}"/> - - - - + Text="{Binding GPGUserSigningKey, Mode=TwoWay}"/> + + diff --git a/src/Views/RevisionCompare.axaml b/src/Views/RevisionCompare.axaml index ae81316a..c541cfe2 100644 --- a/src/Views/RevisionCompare.axaml +++ b/src/Views/RevisionCompare.axaml @@ -61,6 +61,7 @@ Height="26" BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}" Background="Transparent" + CornerRadius="4" Watermark="{DynamicResource Text.CommitDetail.Changes.Search}" Text="{Binding SearchFilter, Mode=TwoWay}"> diff --git a/src/Views/RevisionCompare.axaml.cs b/src/Views/RevisionCompare.axaml.cs index fe71c672..a9e80676 100644 --- a/src/Views/RevisionCompare.axaml.cs +++ b/src/Views/RevisionCompare.axaml.cs @@ -25,7 +25,7 @@ namespace SourceGit.Views { var compare = DataContext as ViewModels.RevisionCompare; var menu = compare.CreateChangeContextMenu(datagrid.SelectedItem as Models.Change); - menu.Open(datagrid); + datagrid.OpenContextMenu(menu); } e.Handled = true; @@ -40,7 +40,7 @@ namespace SourceGit.Views if (node != null && !node.IsFolder) { var menu = compare.CreateChangeContextMenu(node.Backend as Models.Change); - menu.Open(view); + view.OpenContextMenu(menu); } } diff --git a/src/Views/RevisionFiles.axaml b/src/Views/RevisionFiles.axaml index e91c6e0b..2f1eb8d2 100644 --- a/src/Views/RevisionFiles.axaml +++ b/src/Views/RevisionFiles.axaml @@ -23,9 +23,9 @@ Height="26" BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}" Background="Transparent" - Watermark="{DynamicResource Text.CommitDetail.Changes.Search}" - Text="{Binding SearchFileFilter, Mode=TwoWay}" - v:AutoFocusBehaviour.IsEnabled="True"> + CornerRadius="4" + Watermark="{DynamicResource Text.CommitDetail.Files.Search}" + Text="{Binding SearchFileFilter, Mode=TwoWay}"> diff --git a/src/Views/RevisionFiles.axaml.cs b/src/Views/RevisionFiles.axaml.cs index 5d9966ab..7865542d 100644 --- a/src/Views/RevisionFiles.axaml.cs +++ b/src/Views/RevisionFiles.axaml.cs @@ -198,7 +198,8 @@ namespace SourceGit.Views var menu = new ContextMenu(); menu.Items.Add(copy); - menu.Open(TextArea.TextView); + + TextArea.TextView.OpenContextMenu(menu); e.Handled = true; } @@ -219,7 +220,7 @@ namespace SourceGit.Views if (!node.IsFolder) { var menu = detail.CreateRevisionFileContextMenu(node.Backend as Models.Object); - menu.Open(sender as Control); + (sender as Control)?.OpenContextMenu(menu); } e.Handled = true; diff --git a/src/Views/SelfUpdate.axaml b/src/Views/SelfUpdate.axaml index f29da5b5..a83895fb 100644 --- a/src/Views/SelfUpdate.axaml +++ b/src/Views/SelfUpdate.axaml @@ -69,7 +69,7 @@ - + diff --git a/src/Views/Statistics.axaml b/src/Views/Statistics.axaml index 2caa1d02..b0d73bec 100644 --- a/src/Views/Statistics.axaml +++ b/src/Views/Statistics.axaml @@ -172,7 +172,7 @@ diff --git a/src/Views/TextDiffView.axaml.cs b/src/Views/TextDiffView.axaml.cs index 25573b41..20978345 100644 --- a/src/Views/TextDiffView.axaml.cs +++ b/src/Views/TextDiffView.axaml.cs @@ -137,6 +137,9 @@ namespace SourceGit.Views var width = textView.Bounds.Width; foreach (var line in textView.VisualLines) { + if (line.FirstDocumentLine == null) + continue; + var index = line.FirstDocumentLine.LineNumber; if (index > _editor.DiffData.Lines.Count) break; @@ -320,7 +323,8 @@ namespace SourceGit.Views }; menu.Items.Add(copy); - menu.Open(TextArea.TextView); + + TextArea.TextView.OpenContextMenu(menu); e.Handled = true; } @@ -516,6 +520,9 @@ namespace SourceGit.Views var infos = _editor.IsOld ? _editor.DiffData.Old : _editor.DiffData.New; foreach (var line in textView.VisualLines) { + if (line.FirstDocumentLine == null) + continue; + var index = line.FirstDocumentLine.LineNumber; if (index > infos.Count) break; @@ -731,7 +738,8 @@ namespace SourceGit.Views }; menu.Items.Add(copy); - menu.Open(TextArea.TextView); + + TextArea.TextView.OpenContextMenu(menu); e.Handled = true; } diff --git a/src/Views/Welcome.axaml.cs b/src/Views/Welcome.axaml.cs index f0e3a1fc..aa5054c4 100644 --- a/src/Views/Welcome.axaml.cs +++ b/src/Views/Welcome.axaml.cs @@ -42,7 +42,7 @@ namespace SourceGit.Views if (sender is Grid grid && DataContext is ViewModels.Welcome vm) { var menu = vm.CreateContextMenu(grid.DataContext as ViewModels.RepositoryNode); - menu?.Open(grid); + grid.OpenContextMenu(menu); e.Handled = true; } } @@ -248,7 +248,7 @@ namespace SourceGit.Views { Dispatcher.UIThread.Invoke(() => { - (DataContext as ViewModels.Welcome).InitRepository(path); + (DataContext as ViewModels.Welcome).InitRepository(path, parent); }); return; } @@ -257,7 +257,7 @@ namespace SourceGit.Views Dispatcher.UIThread.Invoke(() => { var repo = ViewModels.Preference.AddRepository(root, gitDir); - var node = ViewModels.Preference.FindOrAddNodeByRepositoryPath(repo.FullPath, parent); + var node = ViewModels.Preference.FindOrAddNodeByRepositoryPath(repo.FullPath, parent, true); launcher.OpenRepositoryInTab(node, page); }); }); diff --git a/src/Views/WorkingCopy.axaml.cs b/src/Views/WorkingCopy.axaml.cs index 46c82a40..e4746f1f 100644 --- a/src/Views/WorkingCopy.axaml.cs +++ b/src/Views/WorkingCopy.axaml.cs @@ -205,8 +205,7 @@ namespace SourceGit.Views } var menu = vm.CreateContextMenuForUnstagedChanges(selected); - if (menu != null) - menu.Open(datagrid); + datagrid.OpenContextMenu(menu); } e.Handled = true; @@ -225,8 +224,7 @@ namespace SourceGit.Views } var menu = vm.CreateContextMenuForUnstagedChanges(selected); - if (menu != null) - menu.Open(tree); + tree.OpenContextMenu(menu); } e.Handled = true; @@ -245,8 +243,7 @@ namespace SourceGit.Views } var menu = vm.CreateContextMenuForStagedChanges(selected); - if (menu != null) - menu.Open(datagrid); + datagrid.OpenContextMenu(menu); } e.Handled = true; @@ -265,8 +262,7 @@ namespace SourceGit.Views } var menu = vm.CreateContextMenuForStagedChanges(selected); - if (menu != null) - menu.Open(tree); + tree.OpenContextMenu(menu); } e.Handled = true; @@ -331,7 +327,7 @@ namespace SourceGit.Views { var menu = vm.CreateContextMenuForCommitMessages(); menu.Placement = PlacementMode.TopEdgeAlignedLeft; - menu.Open(button); + button.OpenContextMenu(menu); e.Handled = true; } }