/GitUI/UserControls/RevisionGrid.cs
C# | 3198 lines | 2619 code | 491 blank | 88 comment | 524 complexity | aa1cc62956e1d2e0cf91aa051420d9e9 MD5 | raw file
Possible License(s): GPL-3.0
Large files files are truncated, but you can click here to view the full file
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.DirectoryServices;
- using System.Drawing;
- using System.Drawing.Drawing2D;
- using System.IO;
- using System.Linq;
- using System.Text.RegularExpressions;
- using System.Threading;
- using System.Threading.Tasks;
- using System.Windows.Forms;
- using GitCommands;
- using GitCommands.Git;
- using GitUI.BuildServerIntegration;
- using GitUI.CommandsDialogs;
- using GitUI.CommandsDialogs.BrowseDialog;
- using GitUI.HelperDialogs;
- using GitUI.Hotkey;
- using GitUI.RevisionGridClasses;
- using GitUI.Script;
- using GitUI.UserControls;
- using GitUI.UserControls.RevisionGridClasses;
- using GitUIPluginInterfaces;
- using Gravatar;
- using ResourceManager;
- namespace GitUI
- {
- public enum RevisionGridLayout
- {
- FilledBranchesSmall = 1,
- FilledBranchesSmallWithGraph = 2,
- Small = 3,
- SmallWithGraph = 4,
- Card = 5,
- CardWithGraph = 6,
- LargeCard = 7,
- LargeCardWithGraph = 8
- }
- public enum RevisionGraphDrawStyleEnum
- {
- Normal,
- DrawNonRelativesGray,
- HighlightSelected
- }
- [DefaultEvent("DoubleClick")]
- public sealed partial class RevisionGrid : GitModuleControl
- {
- private readonly TranslationString _droppingFilesBlocked = new TranslationString("For you own protection dropping more than 10 patch files at once is blocked!");
- private readonly TranslationString _cannotHighlightSelectedBranch = new TranslationString("Cannot highlight selected branch when revision graph is loading.");
- private readonly TranslationString _noRevisionFoundError = new TranslationString("No revision found.");
- private const int NodeDimension = 8;
- private const int LaneWidth = 13;
- private const int LaneLineWidth = 2;
- private const int MaxSuperprojectRefs = 4;
- private Brush _selectedItemBrush;
- private SolidBrush _authoredRevisionsBrush;
- private Brush _filledItemBrush; // disposable brush
- private readonly FormRevisionFilter _revisionFilter = new FormRevisionFilter();
- private RefsFiltringOptions _refsOptions = RefsFiltringOptions.All | RefsFiltringOptions.Boundary;
- private bool _initialLoad = true;
- private string _initialSelectedRevision;
- private string _lastQuickSearchString = string.Empty;
- private Label _quickSearchLabel;
- private string _quickSearchString;
- private RevisionGraph _revisionGraphCommand;
- public BuildServerWatcher BuildServerWatcher { get; private set; }
- private RevisionGridLayout _layout;
- private int _rowHeigth;
- public event EventHandler<GitModuleEventArgs> GitModuleChanged;
- public event EventHandler<DoubleClickRevisionEventArgs> DoubleClickRevision;
- public event EventHandler<EventArgs> ShowFirstParentsToggled;
- private readonly RevisionGridMenuCommands _revisionGridMenuCommands;
- bool _showCurrentBranchOnlyToolStripMenuItemChecked; // refactoring
- bool _showAllBranchesToolStripMenuItemChecked; // refactoring
- bool _showFilteredBranchesToolStripMenuItemChecked; // refactoring
- private readonly ParentChildNavigationHistory _parentChildNavigationHistory;
- private readonly NavigationHistory _navigationHistory = new NavigationHistory();
- private AuthorEmailBasedRevisionHighlighting _revisionHighlighting;
- private GitRevision _baseCommitToCompare = null;
- /// <summary>
- /// Refs loaded while the latest processing of git log
- /// </summary>
- private IEnumerable<IGitRef> LatestRefs = Enumerable.Empty<IGitRef>();
- public RevisionGrid()
- {
- InitLayout();
- InitializeComponent();
- // Parent-child navigation can expect that SetSelectedRevision is always successfull since it always uses first-parents
- _parentChildNavigationHistory = new ParentChildNavigationHistory(revision => SetSelectedRevision(revision));
- _revisionHighlighting = new AuthorEmailBasedRevisionHighlighting();
- this.Loading.Image = global::GitUI.Properties.Resources.loadingpanel;
- Translate();
- _revisionGridMenuCommands = new RevisionGridMenuCommands(this);
- _revisionGridMenuCommands.CreateOrUpdateMenuCommands();
- // fill View context menu from MenuCommands
- var viewMenuCommands = _revisionGridMenuCommands.GetViewMenuCommands();
- FillMenuFromMenuCommands(viewMenuCommands, viewToolStripMenuItem);
- // fill Navigate context menu from MenuCommands
- var navigateMenuCommands = _revisionGridMenuCommands.GetNavigateMenuCommands();
- FillMenuFromMenuCommands(navigateMenuCommands, navigateToolStripMenuItem);
- NormalFont = AppSettings.Font;
- Loading.Paint += Loading_Paint;
- Revisions.CellPainting += RevisionsCellPainting;
- Revisions.CellFormatting += RevisionsCellFormatting;
- Revisions.KeyPress += RevisionsKeyPress;
- Revisions.KeyDown += RevisionsKeyDown;
- Revisions.MouseDown += RevisionsMouseDown;
- showMergeCommitsToolStripMenuItem.Checked = AppSettings.ShowMergeCommits;
- BranchFilter = String.Empty;
- SetShowBranches();
- QuickRevisionFilter = "";
- FixedRevisionFilter = "";
- FixedPathFilter = "";
- InMemFilterIgnoreCase = true;
- InMemAuthorFilter = "";
- InMemCommitterFilter = "";
- InMemMessageFilter = "";
- AllowGraphWithFilter = false;
- _quickSearchString = "";
- quickSearchTimer.Tick += QuickSearchTimerTick;
- Revisions.Loading += RevisionsLoading;
- //Allow to drop patch file on revisiongrid
- Revisions.DragEnter += Revisions_DragEnter;
- Revisions.DragDrop += Revisions_DragDrop;
- Revisions.AllowDrop = true;
- Revisions.ColumnHeadersVisible = false;
- Revisions.IdColumn.Visible = AppSettings.ShowIds;
- IsMessageMultilineDataGridViewColumn.Width = 25;
- IsMessageMultilineDataGridViewColumn.DisplayIndex = 2;
- IsMessageMultilineDataGridViewColumn.Resizable = DataGridViewTriState.False;
- this.HotkeysEnabled = true;
- try
- {
- SetRevisionsLayout((RevisionGridLayout)AppSettings.RevisionGraphLayout);
- }
- catch
- {
- SetRevisionsLayout(RevisionGridLayout.SmallWithGraph);
- }
- compareToBaseToolStripMenuItem.Enabled = false;
- }
- private void FillMenuFromMenuCommands(IEnumerable<MenuCommand> menuCommands, ToolStripMenuItem targetMenuItem)
- {
- foreach (var menuCommand in menuCommands)
- {
- var toolStripItem = (ToolStripItem)MenuCommand.CreateToolStripItem(menuCommand);
- var toolStripMenuItem = toolStripItem as ToolStripMenuItem;
- if (toolStripMenuItem != null)
- {
- menuCommand.RegisterMenuItem(toolStripMenuItem);
- }
- targetMenuItem.DropDownItems.Add(toolStripItem);
- }
- }
- void Loading_Paint(object sender, PaintEventArgs e)
- {
- // If our loading state has changed since the last paint, update it.
- if (Loading != null)
- {
- if (Loading.Visible != _isLoading)
- {
- Loading.Visible = _isLoading;
- }
- }
- }
- [Browsable(false)]
- public Font HeadFont { get; private set; }
- [Browsable(false)]
- public Font SuperprojectFont { get; private set; }
- [Browsable(false)]
- public int LastScrollPos { get; private set; }
- [Browsable(false)]
- public string[] LastSelectedRows { get; private set; }
- [Browsable(false)]
- public Font RefsFont { get; private set; }
- private Font _normalFont;
- [Browsable(false)]
- [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
- public Font NormalFont
- {
- get { return _normalFont; }
- set
- {
- _normalFont = value;
- MessageDataGridViewColumn.DefaultCellStyle.Font = _normalFont;
- DateDataGridViewColumn.DefaultCellStyle.Font = _normalFont;
- IdDataGridViewColumn.DefaultCellStyle.Font = new Font("Consolas", _normalFont.SizeInPoints);
- IsMessageMultilineDataGridViewColumn.DefaultCellStyle.Font = _normalFont;
- RefsFont = IsFilledBranchesLayout() ? _normalFont : new Font(_normalFont, FontStyle.Bold);
- HeadFont = new Font(_normalFont, FontStyle.Bold);
- SuperprojectFont = new Font(_normalFont, FontStyle.Underline);
- }
- }
- [Category("Filter")]
- [DefaultValue("")]
- public string QuickRevisionFilter { get; set; }
- [Category("Filter")]
- [DefaultValue("")]
- public string FixedRevisionFilter { get; set; }
- [Category("Filter")]
- [DefaultValue("")]
- public string FixedPathFilter { get; set; }
- [Category("Filter")]
- [DefaultValue(true)]
- public bool InMemFilterIgnoreCase { get; set; }
- [Category("Filter")]
- [DefaultValue("")]
- public string InMemAuthorFilter { get; set; }
- [Category("Filter")]
- [DefaultValue("")]
- public string InMemCommitterFilter { get; set; }
- [Category("Filter")]
- [DefaultValue("")]
- public string InMemMessageFilter { get; set; }
- [Category("Filter")]
- [DefaultValue("")]
- public string BranchFilter { get; set; }
- [Category("Filter")]
- [DefaultValue(false)]
- public bool AllowGraphWithFilter { get; set; }
- [Browsable(false)]
- public string CurrentCheckout { get; private set; }
- [Browsable(false)]
- [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
- public string FiltredFileName { get; set; }
- [Browsable(false)]
- public Task<SuperProjectInfo> SuperprojectCurrentCheckout { get; private set; }
- [Browsable(false)]
- public int LastRowIndex { get; private set; }
- [Description("Indicates whether the user is allowed to select more than one commit at a time.")]
- [Category("Behavior")]
- [DefaultValue(true)]
- public bool MultiSelect
- {
- get { return Revisions.MultiSelect; }
- set { Revisions.MultiSelect = value; }
- }
- [Description("Show uncommited changes in revision grid if enabled in settings.")]
- [Category("Behavior")]
- [DefaultValue(false)]
- public bool ShowUncommitedChangesIfPossible
- {
- get;
- set;
- }
- [Description("Show build server information in revision grid if enabled in settings.")]
- [Category("Behavior")]
- [DefaultValue(false)]
- public bool ShowBuildServerInfo
- {
- get;
- set;
- }
- [Description("Do not open the commit info dialog on double click. This is used if the double click event is handled elseswhere.")]
- [Category("Behavior")]
- [DefaultValue(false)]
- public bool DoubleClickDoesNotOpenCommitInfo
- {
- get;
- set;
- }
- private IndexWatcher _indexWatcher;
- [Browsable(false)]
- public IndexWatcher IndexWatcher
- {
- get
- {
- if (_indexWatcher == null)
- _indexWatcher = new IndexWatcher(UICommandsSource);
- return _indexWatcher;
- }
- }
- public void SetInitialRevision(GitRevision initialSelectedRevision)
- {
- _initialSelectedRevision = initialSelectedRevision != null ? initialSelectedRevision.Guid : null;
- }
- private bool _isLoading;
- private void RevisionsLoading(object sender, DvcsGraph.LoadingEventArgs e)
- {
- // Since this can happen on a background thread, we'll just set a
- // flag and deal with it next time we paint (a bit of a hack, but
- // it works)
- _isLoading = e.IsLoading;
- }
- private void ShowQuickSearchString()
- {
- if (_quickSearchLabel == null)
- {
- _quickSearchLabel
- = new Label
- {
- Location = new Point(10, 10),
- BorderStyle = BorderStyle.FixedSingle,
- ForeColor = SystemColors.InfoText,
- BackColor = SystemColors.Info
- };
- Controls.Add(_quickSearchLabel);
- }
- _quickSearchLabel.Visible = true;
- _quickSearchLabel.BringToFront();
- _quickSearchLabel.Text = _quickSearchString;
- _quickSearchLabel.AutoSize = true;
- }
- private void HideQuickSearchString()
- {
- if (_quickSearchLabel != null)
- _quickSearchLabel.Visible = false;
- }
- private void QuickSearchTimerTick(object sender, EventArgs e)
- {
- quickSearchTimer.Stop();
- _quickSearchString = "";
- HideQuickSearchString();
- }
- private void RestartQuickSearchTimer()
- {
- quickSearchTimer.Stop();
- quickSearchTimer.Interval = AppSettings.RevisionGridQuickSearchTimeout;
- quickSearchTimer.Start();
- }
- private void RevisionsKeyPress(object sender, KeyPressEventArgs e)
- {
- var curIndex = -1;
- if (Revisions.SelectedRows.Count > 0)
- curIndex = Revisions.SelectedRows[0].Index;
- curIndex = curIndex >= 0 ? curIndex : 0;
- if (e.KeyChar == 8 && _quickSearchString.Length > 1) //backspace
- {
- RestartQuickSearchTimer();
- _quickSearchString = _quickSearchString.Substring(0, _quickSearchString.Length - 1);
- FindNextMatch(curIndex, _quickSearchString, false);
- _lastQuickSearchString = _quickSearchString;
- e.Handled = true;
- ShowQuickSearchString();
- }
- else if (!char.IsControl(e.KeyChar))
- {
- RestartQuickSearchTimer();
- //The code below is meant to fix the weird keyvalues when pressing keys e.g. ".".
- _quickSearchString = string.Concat(_quickSearchString, char.ToLower(e.KeyChar));
- FindNextMatch(curIndex, _quickSearchString, false);
- _lastQuickSearchString = _quickSearchString;
- e.Handled = true;
- ShowQuickSearchString();
- }
- else
- {
- _quickSearchString = "";
- HideQuickSearchString();
- e.Handled = false;
- }
- }
- private void RevisionsKeyDown(object sender, KeyEventArgs e)
- {
- // BrowserBack/BrowserForward keys and additional handling for Alt+Right/Left sent by some keyboards
- if ((e.KeyCode == Keys.BrowserBack) || ((e.KeyCode == Keys.Left) && (e.Modifiers.HasFlag(Keys.Alt))))
- {
- NavigateBackward();
- }
- else if ((e.KeyCode == Keys.BrowserForward) || ((e.KeyCode == Keys.Right) && (e.Modifiers.HasFlag(Keys.Alt))))
- {
- NavigateForward();
- }
- }
- private void RevisionsMouseDown(object sender, MouseEventArgs e)
- {
- if (e.Button == MouseButtons.XButton1)
- {
- NavigateBackward();
- }
- else if (e.Button == MouseButtons.XButton2)
- {
- NavigateForward();
- }
- }
- public void ResetNavigationHistory()
- {
- var selectedRevisions = GetSelectedRevisions();
- if (selectedRevisions.Count == 1)
- {
- _navigationHistory.Push(selectedRevisions[0].Guid);
- }
- else
- {
- _navigationHistory.Clear();
- }
- }
- public void NavigateBackward()
- {
- if (_navigationHistory.CanNavigateBackward)
- {
- InternalSetSelectedRevision(_navigationHistory.NavigateBackward());
- }
- }
- public void NavigateForward()
- {
- if (_navigationHistory.CanNavigateForward)
- {
- InternalSetSelectedRevision(_navigationHistory.NavigateForward());
- }
- }
- private void FindNextMatch(int startIndex, string searchString, bool reverse)
- {
- if (Revisions.RowCount == 0)
- return;
- int? searchResult;
- if (reverse)
- searchResult = SearchInReverseOrder(startIndex, searchString);
- else
- searchResult = SearchForward(startIndex, searchString);
- if (!searchResult.HasValue)
- return;
- Revisions.ClearSelection();
- Revisions.Rows[searchResult.Value].Selected = true;
- Revisions.CurrentCell = Revisions.Rows[searchResult.Value].Cells[1];
- }
- private int? SearchForward(int startIndex, string searchString)
- {
- // Check for out of bounds roll over if required
- int index;
- if (startIndex < 0 || startIndex >= Revisions.RowCount)
- startIndex = 0;
- for (index = startIndex; index < Revisions.RowCount; ++index)
- {
- if (GetRevision(index).MatchesSearchString(searchString))
- return index;
- }
- // We didn't find it so start searching from the top
- for (index = 0; index < startIndex; ++index)
- {
- if (GetRevision(index).MatchesSearchString(searchString))
- return index;
- }
- return null;
- }
- private int? SearchInReverseOrder(int startIndex, string searchString)
- {
- // Check for out of bounds roll over if required
- int index;
- if (startIndex < 0 || startIndex >= Revisions.RowCount)
- startIndex = Revisions.RowCount - 1;
- for (index = startIndex; index >= 0; --index)
- {
- if (GetRevision(index).MatchesSearchString(searchString))
- return index;
- }
- // We didn't find it so start searching from the bottom
- for (index = Revisions.RowCount - 1; index > startIndex; --index)
- {
- if (GetRevision(index).MatchesSearchString(searchString))
- return index;
- }
- return null;
- }
- public void DisableContextMenu()
- {
- Revisions.ContextMenuStrip = null;
- }
- public void FormatQuickFilter(string filter,
- bool[] parameters,
- out string revListArgs,
- out string inMemMessageFilter,
- out string inMemCommitterFilter,
- out string inMemAuthorFilter)
- {
- revListArgs = string.Empty;
- inMemMessageFilter = string.Empty;
- inMemCommitterFilter = string.Empty;
- inMemAuthorFilter = string.Empty;
- if (!string.IsNullOrEmpty(filter))
- {
- // hash filtering only possible in memory
- var cmdLineSafe = GitCommandHelpers.VersionInUse.IsRegExStringCmdPassable(filter);
- revListArgs = " --regexp-ignore-case ";
- if (parameters[0])
- if (cmdLineSafe && !MessageFilterCouldBeSHA(filter))
- revListArgs += "--grep=\"" + filter + "\" ";
- else
- inMemMessageFilter = filter;
- if (parameters[1] && !filter.IsNullOrWhiteSpace())
- if (cmdLineSafe)
- revListArgs += "--committer=\"" + filter + "\" ";
- else
- inMemCommitterFilter = filter;
- if (parameters[2] && !filter.IsNullOrWhiteSpace())
- if (cmdLineSafe)
- revListArgs += "--author=\"" + filter + "\" ";
- else
- inMemAuthorFilter = filter;
- if (parameters[3])
- if (cmdLineSafe)
- revListArgs += "\"-S" + filter + "\" ";
- else
- throw new InvalidOperationException("Filter text not valid for \"Diff contains\" filter.");
- }
- }
- public bool SetAndApplyBranchFilter(string filter)
- {
- if (filter.Equals(_revisionFilter.GetBranchFilter()))
- return false;
- if (filter.Equals(""))
- {
- AppSettings.BranchFilterEnabled = false;
- AppSettings.ShowCurrentBranchOnly = true;
- }
- else
- {
- AppSettings.BranchFilterEnabled = true;
- AppSettings.ShowCurrentBranchOnly = false;
- _revisionFilter.SetBranchFilter(filter);
- }
- SetShowBranches();
- return true;
- }
- public void SetLimit(int limit)
- {
- _revisionFilter.SetLimit(limit);
- }
- public override void Refresh()
- {
- if (IsDisposed)
- return;
- SetRevisionsLayout();
- base.Refresh();
- Revisions.Refresh();
- }
- protected override void OnCreateControl()
- {
- base.OnCreateControl();
- _isLoading = true;
- Error.Visible = false;
- NoCommits.Visible = false;
- NoGit.Visible = false;
- Revisions.Visible = false;
- Loading.Visible = true;
- Loading.BringToFront();
- BuildServerWatcher = new BuildServerWatcher(this, Revisions);
- }
- public new void Load()
- {
- if (!DesignMode)
- ReloadHotkeys();
- ForceRefreshRevisions();
- }
- public event EventHandler SelectionChanged;
- public void SetSelectedIndex(int index)
- {
- if (Revisions.Rows[index].Selected)
- return;
- Revisions.ClearSelection();
- Revisions.Rows[index].Selected = true;
- Revisions.CurrentCell = Revisions.Rows[index].Cells[1];
- Revisions.Select();
- }
- // Selects row containing revision given its revisionId
- // Returns whether the required revision was found and selected
- private bool InternalSetSelectedRevision(string revision)
- {
- int index = FindRevisionIndex(revision);
- if( index >= 0 )
- {
- SetSelectedIndex(index);
- return true;
- }
- else
- {
- Revisions.ClearSelection();
- Revisions.Select();
- return false;
- }
- }
- /// <summary>
- /// Find specified revision in known to the grid revisions
- /// </summary>
- /// <param name="revision">Revision to lookup</param>
- /// <returns>Index of the found revision or -1 if nothing was found</returns>
- private int FindRevisionIndex(string revision)
- {
- int? revIdx = Revisions.TryGetRevisionIndex(revision);
- return revIdx.HasValue ? revIdx.Value : -1;
- }
- public bool SetSelectedRevision(string revision)
- {
- var found = InternalSetSelectedRevision(revision);
- if (found)
- {
- _navigationHistory.Push(revision);
- }
- return found;
- }
- public GitRevision GetRevision(string guid)
- {
- return Revisions.GetRevision(guid);
- }
- public bool SetSelectedRevision(GitRevision revision)
- {
- return SetSelectedRevision(revision != null ? revision.Guid : null);
- }
- public void HighlightBranch(string aId)
- {
- RevisionGraphDrawStyle = RevisionGraphDrawStyleEnum.HighlightSelected;
- Revisions.HighlightBranch(aId);
- }
- private void RevisionsSelectionChanged(object sender, EventArgs e)
- {
- _parentChildNavigationHistory.RevisionsSelectionChanged();
- if (Revisions.SelectedRows.Count > 0)
- LastRowIndex = Revisions.SelectedRows[0].Index;
- SelectionTimer.Enabled = false;
- SelectionTimer.Stop();
- SelectionTimer.Enabled = true;
- SelectionTimer.Start();
- var selectedRevisions = GetSelectedRevisions();
- var firstSelectedRevision = selectedRevisions.FirstOrDefault();
- if (selectedRevisions.Count == 1 && firstSelectedRevision != null)
- _navigationHistory.Push(firstSelectedRevision.Guid);
- if (this.Parent != null && !Revisions.UpdatingVisibleRows &&
- _revisionHighlighting.ProcessRevisionSelectionChange(Module, selectedRevisions) ==
- AuthorEmailBasedRevisionHighlighting.SelectionChangeAction.RefreshUserInterface)
- {
- Refresh();
- }
- }
- public RevisionGraphDrawStyleEnum RevisionGraphDrawStyle
- {
- get
- {
- return Revisions.RevisionGraphDrawStyle;
- }
- set
- {
- Revisions.RevisionGraphDrawStyle = value;
- }
- }
- public List<GitRevision> GetSelectedRevisions()
- {
- return GetSelectedRevisions(null);
- }
- public List<GitRevision> GetSelectedRevisions(SortDirection? direction)
- {
- var rows = Revisions
- .SelectedRows
- .Cast<DataGridViewRow>()
- .Where(row => Revisions.RowCount > row.Index);
- if (direction.HasValue)
- {
- int d = direction.Value == SortDirection.Ascending ? 1 : -1;
- rows = rows.OrderBy((row) => row.Index, (r1, r2) => d * (r1 - r2));
- }
- return rows
- .Select(row => GetRevision(row.Index))
- .ToList();
- }
- public List<string> GetRevisionChildren(string revision)
- {
- return Revisions.GetRevisionChildren(revision);
- }
- public GitRevision GetRevision(int aRow)
- {
- return Revisions.GetRowData(aRow);
- }
- public GitRevision GetCurrentRevision()
- {
- var revision = Module.GetRevision(CurrentCheckout, true);
- var refs = Module.GetRefs(true, true);
- foreach (var gitRef in refs)
- {
- if (gitRef.Guid.Equals(revision.Guid))
- {
- revision.Refs.Add(gitRef);
- }
- }
- return revision;
- }
- public void RefreshRevisions()
- {
- if (IndexWatcher.IndexChanged)
- ForceRefreshRevisions();
- }
- private class RevisionGraphInMemFilterOr : RevisionGraphInMemFilter
- {
- private RevisionGraphInMemFilter fFilter1;
- private RevisionGraphInMemFilter fFilter2;
- public RevisionGraphInMemFilterOr(RevisionGraphInMemFilter aFilter1,
- RevisionGraphInMemFilter aFilter2)
- {
- fFilter1 = aFilter1;
- fFilter2 = aFilter2;
- }
- public override bool PassThru(GitRevision rev)
- {
- return fFilter1.PassThru(rev) || fFilter2.PassThru(rev);
- }
- }
- private class RevisionGridInMemFilter : RevisionGraphInMemFilter
- {
- private readonly string _AuthorFilter;
- private readonly Regex _AuthorFilterRegex;
- private readonly string _CommitterFilter;
- private readonly Regex _CommitterFilterRegex;
- private readonly string _MessageFilter;
- private readonly Regex _MessageFilterRegex;
- private readonly string _ShaFilter;
- private readonly Regex _ShaFilterRegex;
- public RevisionGridInMemFilter(string authorFilter, string committerFilter, string messageFilter, bool ignoreCase)
- {
- SetUpVars(authorFilter, ref _AuthorFilter, ref _AuthorFilterRegex, ignoreCase);
- SetUpVars(committerFilter, ref _CommitterFilter, ref _CommitterFilterRegex, ignoreCase);
- SetUpVars(messageFilter, ref _MessageFilter, ref _MessageFilterRegex, ignoreCase);
- if (!string.IsNullOrEmpty(_MessageFilter) && MessageFilterCouldBeSHA(_MessageFilter))
- {
- SetUpVars(messageFilter, ref _ShaFilter, ref _ShaFilterRegex, false);
- }
- }
- private static void SetUpVars(string filterValue,
- ref string filterStr,
- ref Regex filterRegEx,
- bool ignoreCase)
- {
- RegexOptions opts = RegexOptions.None;
- if (ignoreCase) opts = opts | RegexOptions.IgnoreCase;
- filterStr = filterValue != null ? filterValue.Trim() : string.Empty;
- try
- {
- filterRegEx = new Regex(filterStr, opts);
- }
- catch (ArgumentException)
- {
- filterRegEx = null;
- }
- }
- private static bool CheckCondition(string filter, Regex regex, string value)
- {
- return string.IsNullOrEmpty(filter) ||
- ((regex != null) && (value != null) && regex.Match(value).Success);
- }
- public override bool PassThru(GitRevision rev)
- {
- return CheckCondition(_AuthorFilter, _AuthorFilterRegex, rev.Author) &&
- CheckCondition(_CommitterFilter, _CommitterFilterRegex, rev.Committer) &&
- (CheckCondition(_MessageFilter, _MessageFilterRegex, rev.Body) ||
- CheckCondition(_ShaFilter, _ShaFilterRegex, rev.Guid));
- }
- public static RevisionGridInMemFilter CreateIfNeeded(string authorFilter,
- string committerFilter,
- string messageFilter,
- bool ignoreCase)
- {
- if (!(string.IsNullOrEmpty(authorFilter) &&
- string.IsNullOrEmpty(committerFilter) &&
- string.IsNullOrEmpty(messageFilter) &&
- !MessageFilterCouldBeSHA(messageFilter)))
- return new RevisionGridInMemFilter(authorFilter,
- committerFilter,
- messageFilter,
- ignoreCase);
- else
- return null;
- }
- }
- public void ReloadHotkeys()
- {
- this.Hotkeys = HotkeySettingsManager.LoadHotkeys(HotkeySettingsName);
- _revisionGridMenuCommands.CreateOrUpdateMenuCommands();
- }
- public void ReloadTranslation()
- {
- Translate();
- }
- public bool ShowRemoteRef(IGitRef r)
- {
- if (r.IsTag)
- return AppSettings.ShowSuperprojectTags;
- if (r.IsHead)
- return AppSettings.ShowSuperprojectBranches;
- if (r.IsRemote)
- return AppSettings.ShowSuperprojectRemoteBranches;
- return false;
- }
- [Browsable(false)]
- public Task<bool> UnstagedChanges { get; private set; }
- [Browsable(false)]
- public Task<bool> StagedChanges { get; private set; }
- private string _filtredCurrentCheckout;
- public void ForceRefreshRevisions()
- {
- try
- {
- RevisionGraphDrawStyle = RevisionGraphDrawStyleEnum.DrawNonRelativesGray;
- IsMessageMultilineDataGridViewColumn.Visible = AppSettings.ShowIndicatorForMultilineMessage;
- ApplyFilterFromRevisionFilterDialog();
- _initialLoad = true;
- BuildServerWatcher.CancelBuildStatusFetchOperation();
- DisposeRevisionGraphCommand();
- var newCurrentCheckout = Module.GetCurrentCheckout();
- Task<SuperProjectInfo> newSuperPrjectInfo =
- Task.Factory.StartNew(() => GetSuperprojectCheckout(ShowRemoteRef));
- newSuperPrjectInfo.ContinueWith((task) => Refresh(),
- TaskScheduler.FromCurrentSynchronizationContext());
- //Only check for tracked files. This usually makes more sense and it performs a lot
- //better then checking for untracked files.
- // TODO: Check FiltredFileName
- Task<bool> unstagedChanges =
- Task.Factory.StartNew(() => Module.GetUnstagedFiles().Any());
- Task<bool> stagedChanges =
- Task.Factory.StartNew(() => Module.GetStagedFiles().Any());
- // If the current checkout changed, don't get the currently selected rows, select the
- // new current checkout instead.
- if (newCurrentCheckout == CurrentCheckout)
- {
- LastSelectedRows = Revisions.SelectedIds;
- }
- else
- {
- // This is a new checkout, so ensure the variable is cleared out.
- LastSelectedRows = null;
- }
- Revisions.ClearSelection();
- CurrentCheckout = newCurrentCheckout;
- _filtredCurrentCheckout = null;
- _currentCheckoutParents = null;
- SuperprojectCurrentCheckout = newSuperPrjectInfo;
- UnstagedChanges = unstagedChanges;
- StagedChanges = stagedChanges;
- Revisions.Clear();
- Error.Visible = false;
- if (!Module.IsValidGitWorkingDir())
- {
- Revisions.Visible = false;
- NoCommits.Visible = true;
- Loading.Visible = false;
- NoGit.Visible = true;
- string dir = Module.WorkingDir;
- if (String.IsNullOrEmpty(dir) || !Directory.Exists(dir) ||
- Directory.GetDirectories(dir).Length == 0 &&
- Directory.GetFiles(dir).Length == 0)
- CloneRepository.Show();
- else
- CloneRepository.Hide();
- NoGit.BringToFront();
- return;
- }
- NoCommits.Visible = false;
- NoGit.Visible = false;
- Revisions.Visible = true;
- Revisions.BringToFront();
- Revisions.Enabled = false;
- Loading.Visible = true;
- Loading.BringToFront();
- _isLoading = true;
- base.Refresh();
- IndexWatcher.Reset();
- if (!AppSettings.ShowGitNotes && (_refsOptions & (RefsFiltringOptions.All | RefsFiltringOptions.Boundary)) == (RefsFiltringOptions.All | RefsFiltringOptions.Boundary))
- _refsOptions |= RefsFiltringOptions.ShowGitNotes;
- if (AppSettings.ShowGitNotes)
- _refsOptions &= ~RefsFiltringOptions.ShowGitNotes;
- if (!AppSettings.ShowMergeCommits)
- _refsOptions |= RefsFiltringOptions.NoMerges;
- if (AppSettings.ShowFirstParent)
- _refsOptions |= RefsFiltringOptions.FirstParent;
- if (AppSettings.ShowSimplifyByDecoration)
- _refsOptions |= RefsFiltringOptions.SimplifyByDecoration;
- RevisionGridInMemFilter revisionFilterIMF = RevisionGridInMemFilter.CreateIfNeeded(_revisionFilter.GetInMemAuthorFilter(),
- _revisionFilter.GetInMemCommitterFilter(),
- _revisionFilter.GetInMemMessageFilter(),
- _revisionFilter.GetIgnoreCase());
- RevisionGridInMemFilter filterBarIMF = RevisionGridInMemFilter.CreateIfNeeded(InMemAuthorFilter,
- InMemCommitterFilter,
- InMemMessageFilter,
- InMemFilterIgnoreCase);
- RevisionGraphInMemFilter revGraphIMF;
- if (revisionFilterIMF != null && filterBarIMF != null)
- revGraphIMF = new RevisionGraphInMemFilterOr(revisionFilterIMF, filterBarIMF);
- else if (revisionFilterIMF != null)
- revGraphIMF = revisionFilterIMF;
- else
- revGraphIMF = filterBarIMF;
- _revisionGraphCommand = new RevisionGraph(Module) {
- BranchFilter = BranchFilter,
- RefsOptions = _refsOptions,
- RevisionFilter = _revisionFilter.GetRevisionFilter() + QuickRevisionFilter + FixedRevisionFilter,
- PathFilter = _revisionFilter.GetPathFilter() + FixedPathFilter,
- };
- _revisionGraphCommand.Updated += GitGetCommitsCommandUpdated;
- _revisionGraphCommand.Exited += GitGetCommitsCommandExited;
- _revisionGraphCommand.Error += _revisionGraphCommand_Error;
- _revisionGraphCommand.InMemFilter = revGraphIMF;
- _revisionGraphCommand.Execute();
- LoadRevisions();
- SetRevisionsLayout();
- ResetNavigationHistory();
- }
- catch (Exception)
- {
- Error.Visible = true;
- Error.BringToFront();
- throw;
- }
- }
- public class SuperProjectInfo
- {
- public string CurrentBranch;
- public string Conflict_Base;
- public string Conflict_Remote;
- public string Conflict_Local;
- public Dictionary<string, List<IGitRef>> Refs;
- }
- private SuperProjectInfo GetSuperprojectCheckout(Func<IGitRef, bool> showRemoteRef)
- {
- if (Module.SuperprojectModule == null)
- return null;
- SuperProjectInfo spi = new SuperProjectInfo();
- var currentCheckout = Module.GetSuperprojectCurrentCheckout();
- if (currentCheckout.Key == 'U')
- {
- // return local and remote hashes
- var array = Module.SuperprojectModule.GetConflict(Module.SubmodulePath);
- spi.Conflict_Base = array.Base.Hash;
- spi.Conflict_Local = array.Local.Hash;
- spi.Conflict_Remote = array.Remote.Hash;
- }
- else
- {
- spi.CurrentBranch = currentCheckout.Value;
- }
- var refs = Module.SuperprojectModule.GetSubmoduleItemsForEachRef(Module.SubmodulePath, showRemoteRef);
- if (refs != null)
- {
- spi.Refs = refs.Where(a => a.Value != null).GroupBy(a => a.Value.Guid).ToDictionary(gr => gr.Key, gr => gr.Select(a => a.Key).ToList());
- }
- return spi;
- }
- private static readonly Regex PotentialShaPattern = new Regex(@"^[a-f0-9]{5,}", RegexOptions.Compiled);
- public static bool MessageFilterCouldBeSHA(string filter)
- {
- bool result = PotentialShaPattern.IsMatch(filter);
- return result;
- }
- private void _revisionGraphCommand_Error(object sender, AsyncErrorEventArgs e)
- {
- // This has to happen on the UI thread
- this.InvokeAsync(o =>
- {
- Error.Visible = true;
- //Error.BringToFront();
- NoGit.Visible = false;
- NoCommits.Visible = false;
- Revisions.Visible = false;
- Loading.Visible = false;
- }, this);
- DisposeRevisionGraphCommand();
- this.InvokeAsync(() =>
- {
- throw e.Exception;
- }
- );
- e.Handled = true;
- }
- private void GitGetCommitsCommandUpdated(object sender, EventArgs e)
- {
- var updatedEvent = (RevisionGraph.RevisionGraphUpdatedEventArgs)e;
- UpdateGraph(updatedEvent.Revision);
- }
- internal bool FilterIsApplied(bool inclBranchFilter)
- {
- return (inclBranchFilter && !string.IsNullOrEmpty(BranchFilter)) ||
- !(string.IsNullOrEmpty(QuickRevisionFilter) &&
- !_revisionFilter.FilterEnabled() &&
- string.IsNullOrEmpty(InMemAuthorFilter) &&
- string.IsNullOrEmpty(InMemCommitterFilter) &&
- string.IsNullOrEmpty(InMemMessageFilter));
- }
- private bool ShouldHideGraph(bool inclBranchFilter)
- {
- return (inclBranchFilter && !string.IsNullOrEmpty(BranchFilter)) ||
- !(!_revisionFilter.ShouldHideGraph() &&
- string.IsNullOrEmpty(InMemAuthorFilter) &&
- string.IsNullOrEmpty(InMemCommitterFilter) &&
- string.IsNullOrEmpty(InMemMessageFilter));
- }
- private void DisposeRevisionGraphCommand()
- {
- if (_revisionGraphCommand != null)
- {
- LatestRefs = _revisionGraphCommand.LatestRefs();
- //Dispose command, it is not needed anymore
- _revisionGraphCommand.Updated -= GitGetCommitsCommandUpdated;
- _revisionGraphCommand.Exited -= GitGetCommitsCommandExited;
- _revisionGraphCommand.Error -= _revisionGraphCommand_Error;
- _revisionGraphCommand.Dispose();
- _revisionGraphCommand = null;
- }
- }
- private void GitGetCommitsCommandExited(object sender, EventArgs e)
- {
- _isLoading = false;
- if (_revisionGraphCommand.RevisionCount == 0 &&
- !FilterIsApplied(true))
- {
- // This has to happen on the UI thread
- this.InvokeAsync(o =>
- {
- NoGit.Visible = false;
- NoCommits.Visible = true;
- //NoCommits.BringToFront();
- Revisions.Visible = false;
- Loading.Visible = false;
- }, this);
- }
- else
- {
- // This has to happen on the UI thread
- this.InvokeAsync(o =>
- {
- UpdateGraph(null);
- Loading.Visible = false;
- SelectInitialRevision();
- _isLoading = false;
- if (ShowBuildServerInfo)
- BuildServerWatcher.LaunchBuildServerInfoFetchOperation();
- }, this);
- }
- DisposeRevisionGraphCommand();
- }
- private void SelectInitialRevision()
- {
- string filtredCurrentCheckout = _filtredCurrentCheckout;
- string[] lastSelectedRows = LastSelectedRows ?? new string[0];
- //filter out all unavailable commits from LastSelectedRows.
- lastSelectedRows = lastSelectedRows.Where(revision => FindRevisionIndex(revision) >= 0).ToArray();
- if (lastSelectedRows.Any())
- {
- Revisions.SelectedIds = lastSelectedRows;
- LastSelectedRows = null;
- }
- else
- {
- if (!string.IsNullOrEmpty(_initialSelectedRevision))
- {
- int index = SearchRevision(_initialSelectedRevision);
- if (index >= 0)
- SetSelectedIndex(index);
- }
- else
- {
- SetSelectedRevision(filtredCurrentCheckout);
- }
- }
- if (string.IsNullOrEmpty(filtredCurrentCheckout))
- return;
- if (!Revisions.IsRevisionRelative(filtredCurrentCheckout))
- {
- HighlightBranch(filtredCurrentCheckout);
- }
- }
- private string[] GetAllParents(string initRevision)
- {
- var revListParams = "rev-list ";
- if (AppSettings.OrderRevisionByDate)
- revListParams += "--date-order ";
- else
- revListParams += "--topo-order ";
- if (AppSettings.MaxRevisionGraphCommits > 0)
- revListParams += string.Format("--max-count=\"{0}\" ", (int)AppSettings.MaxRevisionGraphCommits);
- return Module.ReadGitOutputLines(revListParams + initRevision).ToArray();
- }
- private int SearchRevision(string initRevision)
- {
- var exactIndex = Revisions.TryGetRevisionIndex(initRevision);
- if (exactIndex.HasValue)
- return exactIndex.Value;
- foreach (var parentHash in GetAllParents(initRevision))
- {
- var parentIndex = Revisions.TryGetRevisionIndex(parentHash);
- if (parentIndex.HasValue)
- return parentIndex.Value;
- }
- return -1;
- }
- private static string GetDateHeaderText()
- {
- return AppSettings.ShowAuthorDate ? Strings.GetAuthorDateText() : Strings.GetCommitDateText();
- }
- private void LoadRevisions()
- {
- if (_revisionGraphCommand == null)
- {
- return;
- }
- Revisions.SuspendLayout();
- Revisions.MessageColumn.HeaderText = Strings.GetMessageText();
- Revisions.AuthorColumn.HeaderText = Strings.GetAuthorText();
- Revisions.DateColumn.HeaderText = GetDateHeaderText();
- Revisions.SelectionChanged -= RevisionsSelectionChanged;
- Revisions.Enabled = true;
- Revisions.Focus();
- Revisions.SelectionChanged += RevisionsSelectionChanged;
- Revisions.ResumeLayout();
- if (!_initialLoad)
- return;
- _initialLoad = false;
- SelectionTimer.Enabled = false;
- SelectionTimer.Stop();
- SelectionTimer.Enabled = true;
- SelectionTimer.Start();
- }
- public struct DrawRefArgs
- {
- public Graphics Graphics;
- public Rectangle CellBounds;
- public bool IsRowSelected;
- public Font RefsFont;
- }
- private void RevisionsCellPainting(object sender, DataGridViewCellPaintingEventArgs e)
- {
- // If our loading state has changed since the last paint, update it.
- if (Loading != null)
- {
- if (Loading.Visible != _isLoading)
- {
- Loading.Visible = _isLoading;
- }
- }
- var columnIndex = e.ColumnIndex;
- int graphColIndex = GraphDataGridViewColumn.Index;
- int messageColIndex = MessageDataGridViewColumn.Index;
- int authorColIndex = AuthorDataGridViewColumn.Index;
- int dateColIndex = DateDataGridViewColumn.Index;
- int idColIndex = IdDataGridViewColumn.Index;
- int isMsgMultilineColIndex = IsMessageMultilineDataGridViewColumn.Index;
- // The graph column is handled by the DvcsGraph
- if (e.ColumnIndex == graphColIndex)
- {
- return;
- }
- if (e.RowIndex < 0 || (e.State & DataGridViewElementStates.Visible) == 0)
- return;
- if (Revisions.RowCount <= e.RowIndex)
- …
Large files files are truncated, but you can click here to view the full file