Skip to content

Commit

Permalink
Expose sort by/order in the left panel
Browse files Browse the repository at this point in the history
  • Loading branch information
RussKie committed Sep 11, 2020
1 parent 93831ba commit 04617c5
Show file tree
Hide file tree
Showing 16 changed files with 505 additions and 74 deletions.
3 changes: 0 additions & 3 deletions GitCommands/IDiffListSortService.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GitCommands
{
Expand Down
73 changes: 73 additions & 0 deletions GitUI/BranchTreePanel/ContextMenu/GitRefsSortByContextMenuItem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using System;
using System.Linq;
using System.Windows.Forms;
using GitCommands;
using GitCommands.Utils;
using GitUI.Properties;
using GitUIPluginInterfaces;

namespace GitUI.BranchTreePanel.ContextMenu
{
internal class GitRefsSortByContextMenuItem : ToolStripMenuItem
{
private readonly Action _onSortByChanged;

public GitRefsSortByContextMenuItem(Action onSortByChanged)
{
_onSortByChanged = onSortByChanged;

Image = Images.SortBy;
Text = Strings.SortBy;

foreach (var option in EnumHelper.GetValues<GitRefsSortBy>().Select(e => (Text: e.GetDescription(), Value: e)))
{
var item = new ToolStripMenuItem()
{
Text = option.Text,
Image = null,
Tag = option.Value
};

item.Click += Item_Click;
DropDownItems.Add(item);
}

DropDownOpening += (s, e) => RequerySortingMethod();
RequerySortingMethod();
}

private void RequerySortingMethod()
{
var currentSort = AppSettings.RefsSortBy;
foreach (ToolStripMenuItem item in DropDownItems)
{
item.Checked = currentSort.Equals(item.Tag);
}
}

private void Item_Click(object sender, EventArgs e)
{
if (sender is ToolStripMenuItem item)
{
var sortingType = (GitRefsSortBy)item.Tag;
AppSettings.RefsSortBy = sortingType;

_onSortByChanged?.Invoke();
}
}

internal TestAccessor GetTestAccessor() => new TestAccessor(this);

internal struct TestAccessor
{
private readonly GitRefsSortByContextMenuItem _contextMenuItem;

public TestAccessor(GitRefsSortByContextMenuItem menuitem)
{
_contextMenuItem = menuitem;
}

public void RaiseDropDownOpening() => _contextMenuItem.RequerySortingMethod();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
using System;
using System.Linq;
using System.Windows.Forms;
using GitCommands;
using GitCommands.Utils;
using GitUI.Properties;
using GitUIPluginInterfaces;

namespace GitUI.BranchTreePanel.ContextMenu
{
internal class GitRefsSortOrderContextMenuItem : ToolStripMenuItem
{
internal const string MenuItemName = "GitRefsSortOrderContextMenuItem";
private readonly Action _onSortOrderChanged;

public GitRefsSortOrderContextMenuItem(Action onSortOrderChanged)
{
_onSortOrderChanged = onSortOrderChanged;

Image = Images.SortBy;
Text = Strings.SortOrder;
Name = MenuItemName;

foreach (var option in EnumHelper.GetValues<GitRefsSortOrder>().Select(e => (Text: e.GetDescription(), Value: e)))
{
var item = new ToolStripMenuItem()
{
Text = option.Text,
Image = null,
Tag = option.Value
};

item.Click += Item_Click;
DropDownItems.Add(item);
}

DropDownOpening += (s, e) => RequerySortingMethod();
RequerySortingMethod();
}

private void RequerySortingMethod()
{
var currentSort = AppSettings.RefsSortOrder;
foreach (ToolStripMenuItem item in DropDownItems)
{
item.Checked = currentSort.Equals(item.Tag);
}
}

private void Item_Click(object sender, EventArgs e)
{
if (sender is ToolStripMenuItem item)
{
var sortingType = (GitRefsSortOrder)item.Tag;
AppSettings.RefsSortOrder = sortingType;

_onSortOrderChanged?.Invoke();
}
}

internal TestAccessor GetTestAccessor() => new TestAccessor(this);

internal struct TestAccessor
{
private readonly GitRefsSortOrderContextMenuItem _contextMenuItem;

public TestAccessor(GitRefsSortOrderContextMenuItem menuitem)
{
_contextMenuItem = menuitem;
}

public void RaiseDropDownOpening() => _contextMenuItem.RequerySortingMethod();
}
}
}
50 changes: 45 additions & 5 deletions GitUI/BranchTreePanel/RepoObjectsTree.ContextActions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using GitCommands;
using GitUI.BranchTreePanel.ContextMenu;
using GitUI.BranchTreePanel.Interfaces;
using ResourceManager;
Expand All @@ -13,6 +14,8 @@ namespace GitUI.BranchTreePanel
partial class RepoObjectsTree : IMenuItemFactory
{
private TreeNode _lastRightClickedNode;
private GitRefsSortOrderContextMenuItem _sortOrderContextMenuItem;
private GitRefsSortByContextMenuItem _sortByContextMenuItem;

/// <summary>
/// Local branch context menu [git ref / rename / delete] actions
Expand Down Expand Up @@ -104,7 +107,7 @@ private void ContextMenuBranchSpecific(ContextMenuStrip contextMenu)
}

var node = (contextMenu.SourceControl as TreeView)?.SelectedNode;
if (node == null)
if (node is null)
{
return;
}
Expand All @@ -121,7 +124,7 @@ private void ContextMenuRemoteRepoSpecific(ContextMenuStrip contextMenu)
}

var node = (contextMenu.SourceControl as TreeView)?.SelectedNode?.Tag as RemoteRepoNode;
if (node == null)
if (node is null)
{
return;
}
Expand All @@ -137,10 +140,38 @@ private void ContextMenuRemoteRepoSpecific(ContextMenuStrip contextMenu)
mnubtnEnableRemoteAndFetch.Visible = !node.Enabled;
}

private void ContextMenuSort(ContextMenuStrip contextMenu)
{
// We can only sort refs, i.e. branches and tags
if (contextMenu != menuBranch &&
contextMenu != menuRemote &&
contextMenu != menuTag)
{
return;
}

// Add the following to the every participating context menu:
//
// ---------
// Sort By...
// Sort Order...

if (!contextMenu.Items.Contains(_sortOrderContextMenuItem))
{
AddContextMenuItems(contextMenu,
new ToolStripItem[] { _sortByContextMenuItem, _sortOrderContextMenuItem, new ToolStripSeparator() },
tsmiMainMenuSpacer1);
}

// If refs are sorted by git (GitRefsSortBy = Default) don't show sort order options
contextMenu.Items[GitRefsSortOrderContextMenuItem.MenuItemName].Visible =
AppSettings.RefsSortBy != GitUIPluginInterfaces.GitRefsSortBy.Default;
}

private void ContextMenuSubmoduleSpecific(ContextMenuStrip contextMenu)
{
TreeNode selectedNode = (contextMenu.SourceControl as TreeView)?.SelectedNode;
if (selectedNode == null)
if (selectedNode is null)
{
return;
}
Expand Down Expand Up @@ -184,6 +215,14 @@ private static void RegisterClick(ToolStripItem item, Action onClick)

private void RegisterContextActions()
{
_sortOrderContextMenuItem = new GitRefsSortOrderContextMenuItem(() =>
{
_branchesTree.RefreshRefs();
_remotesTree.RefreshRefs();
_tagTree.RefreshRefs();
});
_sortByContextMenuItem = new GitRefsSortByContextMenuItem(() => _branchesTree.RefreshRefs());

_localBranchMenuItems = new LocalBranchMenuItems<LocalBranchNode>(this);
AddContextMenuItems(menuBranch, _localBranchMenuItems.Select(s => s.Item));

Expand Down Expand Up @@ -247,12 +286,13 @@ private void FilterInRevisionGrid(BaseBranchNode branch)
private void contextMenu_Opening(object sender, CancelEventArgs e)
{
var contextMenu = sender as ContextMenuStrip;
if (contextMenu == null)
if (contextMenu is null)
{
return;
}

ContextMenuAddExpandCollapseTree(contextMenu);
ContextMenuSort(contextMenu);
ContextMenuBranchSpecific(contextMenu);
ContextMenuRemoteRepoSpecific(contextMenu);
ContextMenuSubmoduleSpecific(contextMenu);
Expand All @@ -278,7 +318,7 @@ private void contextMenu_Opening(object sender, CancelEventArgs e)
private void AddContextMenuItems(ContextMenuStrip menu, IEnumerable<ToolStripItem> items, ToolStripItem insertAfter = null)
{
menu.SuspendLayout();
int index = insertAfter == null ? 0 : Math.Max(0, menu.Items.IndexOf(insertAfter) + 1);
int index = insertAfter is null ? 0 : Math.Max(0, menu.Items.IndexOf(insertAfter) + 1);
items.ForEach(item => menu.Items.Insert(index++, item));
menu.ResumeLayout();
}
Expand Down
36 changes: 23 additions & 13 deletions GitUI/BranchTreePanel/RepoObjectsTree.Nodes.Branches.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using GitCommands.Git;
using GitUI.BranchTreePanel.Interfaces;
using GitUI.Properties;
using GitUIPluginInterfaces;
using JetBrains.Annotations;
using Microsoft.VisualStudio.Threading;

Expand Down Expand Up @@ -118,9 +119,10 @@ private class BaseBranchLeafNode : BaseBranchNode

private bool _isMerged = false;

public BaseBranchLeafNode(Tree tree, string fullPath, string imageKeyUnmerged, string imageKeyMerged)
public BaseBranchLeafNode(Tree tree, in ObjectId objectId, string fullPath, string imageKeyUnmerged, string imageKeyMerged)
: base(tree, fullPath)
{
ObjectId = objectId;
_imageKeyUnmerged = imageKeyUnmerged;
_imageKeyMerged = imageKeyMerged;
}
Expand All @@ -141,6 +143,9 @@ public bool IsMerged
}
}

[CanBeNull]
public ObjectId ObjectId { get; }

protected override void ApplyStyle()
{
base.ApplyStyle();
Expand All @@ -150,8 +155,8 @@ protected override void ApplyStyle()

private sealed class LocalBranchNode : BaseBranchLeafNode, IGitRefActions, ICanRename, ICanDelete
{
public LocalBranchNode(Tree tree, string fullPath, bool isCurrent)
: base(tree, fullPath, nameof(Images.BranchLocal), nameof(Images.BranchLocalMerged))
public LocalBranchNode(Tree tree, in ObjectId objectId, string fullPath, bool isCurrent)
: base(tree, objectId, fullPath, nameof(Images.BranchLocal), nameof(Images.BranchLocalMerged))
{
IsActive = isCurrent;
}
Expand Down Expand Up @@ -264,26 +269,31 @@ public BranchTree(TreeNode treeNode, IGitUICommandsSource uiCommands, [CanBeNull
_aheadBehindDataProvider = aheadBehindDataProvider;
}

protected override Task OnAttachedAsync()
{
return ReloadNodesAsync(LoadNodesAsync);
}
protected override Task OnAttachedAsync() => ReloadNodesAsync(LoadNodesAsync);

protected override Task PostRepositoryChangedAsync() => ReloadNodesAsync(LoadNodesAsync);

protected override Task PostRepositoryChangedAsync()
/// <summary>
/// Requests to refresh the data tree retaining the current filtering rules.
/// </summary>
internal void RefreshRefs()
{
return ReloadNodesAsync(LoadNodesAsync);
ThreadHelper.JoinableTaskFactory.RunAsync(async () =>
{
await ReloadNodesAsync(LoadNodesAsync);
});
}

private async Task<Nodes> LoadNodesAsync(CancellationToken token)
{
await TaskScheduler.Default;
token.ThrowIfCancellationRequested();

var branchNames = Module.GetRefs(tags: false, branches: true).Select(b => b.Name);
return FillBranchTree(branchNames, token);
IReadOnlyList<IGitRef> branches = Module.GetRefs(tags: false, branches: true);
return FillBranchTree(branches, token);
}

private Nodes FillBranchTree(IEnumerable<string> branches, CancellationToken token)
private Nodes FillBranchTree(IReadOnlyList<IGitRef> branches, CancellationToken token)
{
#region ex

Expand Down Expand Up @@ -323,7 +333,7 @@ private Nodes FillBranchTree(IEnumerable<string> branches, CancellationToken tok
foreach (var branch in branches)
{
token.ThrowIfCancellationRequested();
var localBranchNode = new LocalBranchNode(this, branch, branch == currentBranch);
var localBranchNode = new LocalBranchNode(this, branch.ObjectId, branch.Name, branch.Name == currentBranch);

if (aheadBehindData != null && aheadBehindData.ContainsKey(localBranchNode.FullPath))
{
Expand Down

0 comments on commit 04617c5

Please sign in to comment.