PageRenderTime 51ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/GitUI/RevisionGrid.cs

https://github.com/eisnerd/gitextensions
C# | 2372 lines | 1952 code | 370 blank | 50 comment | 366 complexity | c320cf16e8d9c7602f49af41767b31c6 MD5 | raw file
Possible License(s): GPL-3.0, GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Drawing;
  5. using System.Drawing.Drawing2D;
  6. using System.IO;
  7. using System.Linq;
  8. using System.Text.RegularExpressions;
  9. using System.Threading;
  10. using System.Windows.Forms;
  11. using GitCommands;
  12. using GitCommands.Git;
  13. using GitUI.Hotkey;
  14. using GitUI.Script;
  15. using GitUI.Tag;
  16. using Gravatar;
  17. using ResourceManager.Translation;
  18. using System.DirectoryServices;
  19. namespace GitUI
  20. {
  21. public enum RevisionGridLayout
  22. {
  23. FilledBranchesSmall = 1,
  24. FilledBranchesSmallWithGraph = 2,
  25. Small = 3,
  26. SmallWithGraph = 4,
  27. Card = 5,
  28. CardWithGraph = 6,
  29. LargeCard = 7,
  30. LargeCardWithGraph = 8
  31. }
  32. [DefaultEvent("DoubleClick")]
  33. public sealed partial class RevisionGrid : GitExtensionsControl
  34. {
  35. private readonly IndexWatcher _indexWatcher = new IndexWatcher();
  36. private readonly TranslationString _currentWorkingDirChanges = new TranslationString("Current uncommitted changes");
  37. private readonly TranslationString _currentIndex = new TranslationString("Commit index");
  38. private readonly TranslationString _areYouSureYouWantCheckout = new TranslationString("Are you sure to checkout the selected revision?");
  39. private readonly TranslationString _areYouSureYouWantCheckoutCaption = new TranslationString("Checkout revision");
  40. private readonly TranslationString _droppingFilesBlocked = new TranslationString("For you own protection dropping more than 10 patch files at once is blocked!");
  41. private const int NODE_DIMENSION = 8;
  42. private const int LANE_WIDTH = 13;
  43. private const int LANE_LINE_WIDTH = 2;
  44. private Brush selectedItemBrush;
  45. private readonly FormRevisionFilter _revisionFilter = new FormRevisionFilter();
  46. private readonly SynchronizationContext _syncContext;
  47. public string LogParam = "HEAD --all --boundary";
  48. private bool _initialLoad = true;
  49. private string _initialSelectedRevision;
  50. private string _lastQuickSearchString = string.Empty;
  51. private Label _quickSearchLabel;
  52. private string _quickSearchString;
  53. private RevisionGraph _revisionGraphCommand;
  54. private RevisionGridLayout layout;
  55. private int rowHeigth;
  56. public RevisionGrid()
  57. {
  58. _syncContext = SynchronizationContext.Current;
  59. InitLayout();
  60. InitializeComponent();
  61. this.Loading.Image = global::GitUI.Properties.Resources.loadingpanel;
  62. Translate();
  63. NormalFont = SystemFonts.DefaultFont;
  64. Loading.Paint += Loading_Paint;
  65. Revisions.CellPainting += RevisionsCellPainting;
  66. Revisions.CellFormatting += RevisionsCellFormatting;
  67. Revisions.KeyDown += RevisionsKeyDown;
  68. showAuthorDateToolStripMenuItem.Checked = Settings.ShowAuthorDate;
  69. orderRevisionsByDateToolStripMenuItem.Checked = Settings.OrderRevisionByDate;
  70. showRelativeDateToolStripMenuItem.Checked = Settings.RelativeDate;
  71. drawNonrelativesGrayToolStripMenuItem.Checked = Settings.RevisionGraphDrawNonRelativesGray;
  72. showGitNotesToolStripMenuItem.Checked = Settings.ShowGitNotes;
  73. BranchFilter = String.Empty;
  74. SetShowBranches();
  75. Filter = "";
  76. FixedFilter = "";
  77. InMemFilterIgnoreCase = false;
  78. InMemAuthorFilter = "";
  79. InMemCommitterFilter = "";
  80. InMemMessageFilter = "";
  81. AllowGraphWithFilter = false;
  82. _quickSearchString = "";
  83. quickSearchTimer.Tick += QuickSearchTimerTick;
  84. Revisions.Loading += RevisionsLoading;
  85. //Allow to drop patch file on revisiongrid
  86. Revisions.DragEnter += Revisions_DragEnter;
  87. Revisions.DragDrop += Revisions_DragDrop;
  88. Revisions.AllowDrop = true;
  89. Revisions.ColumnHeadersVisible = false;
  90. this.HotkeysEnabled = true;
  91. try
  92. {
  93. SetRevisionsLayout((RevisionGridLayout)Settings.RevisionGraphLayout);
  94. }
  95. catch
  96. {
  97. SetRevisionsLayout(RevisionGridLayout.SmallWithGraph);
  98. }
  99. }
  100. void Loading_Paint(object sender, PaintEventArgs e)
  101. {
  102. // If our loading state has changed since the last paint, update it.
  103. if (Loading != null)
  104. {
  105. if (Loading.Visible != _isLoading)
  106. {
  107. Loading.Visible = _isLoading;
  108. }
  109. }
  110. }
  111. [Browsable(false)]
  112. public Font HeadFont { get; private set; }
  113. [Browsable(false)]
  114. public Font SuperprojectFont { get; private set; }
  115. [Browsable(false)]
  116. public int LastScrollPos { get; private set; }
  117. [Browsable(false)]
  118. public IComparable[] LastSelectedRows { get; private set; }
  119. [Browsable(false)]
  120. public Font RefsFont { get; private set; }
  121. private Font _normalFont;
  122. [Category("Appearance")]
  123. public Font NormalFont
  124. {
  125. get { return _normalFont; }
  126. set
  127. {
  128. _normalFont = value;
  129. Message.DefaultCellStyle.Font = _normalFont;
  130. Date.DefaultCellStyle.Font = _normalFont;
  131. RefsFont = IsFilledBranchesLayout() ? _normalFont : new Font(_normalFont, FontStyle.Bold);
  132. HeadFont = new Font(_normalFont, FontStyle.Bold);
  133. SuperprojectFont = new Font(_normalFont, FontStyle.Underline);
  134. }
  135. }
  136. [Category("Filter")]
  137. public string Filter { get; set; }
  138. [Category("Filter")]
  139. public string FixedFilter { get; set; }
  140. [Category("Filter")]
  141. [DefaultValue(false)]
  142. public bool InMemFilterIgnoreCase { get; set; }
  143. [Category("Filter")]
  144. public string InMemAuthorFilter { get; set; }
  145. [Category("Filter")]
  146. public string InMemCommitterFilter { get; set; }
  147. [Category("Filter")]
  148. public string InMemMessageFilter { get; set; }
  149. [Category("Filter")]
  150. public string BranchFilter { get; set; }
  151. [Category("Filter")]
  152. [DefaultValue(false)]
  153. public bool AllowGraphWithFilter { get; set; }
  154. [Browsable(false)]
  155. public string CurrentCheckout { get; set; }
  156. [Browsable(false)]
  157. public string SuperprojectCurrentCheckout { get; set; }
  158. [Browsable(false)]
  159. public int LastRow { get; set; }
  160. [Description("Indicates whether the user is allowed to select more than one commit at a time.")]
  161. [Category("Behavior")]
  162. [DefaultValue(true)]
  163. [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
  164. public bool MultiSelect
  165. {
  166. get { return Revisions.MultiSelect; }
  167. set { Revisions.MultiSelect = value; }
  168. }
  169. public void SetInitialRevision(GitRevision initialSelectedRevision)
  170. {
  171. _initialSelectedRevision = initialSelectedRevision != null ? initialSelectedRevision.Guid : null;
  172. }
  173. public event EventHandler ActionOnRepositoryPerformed;
  174. private void OnActionOnRepositoryPerformed()
  175. {
  176. if (ActionOnRepositoryPerformed != null)
  177. ActionOnRepositoryPerformed(this, null);
  178. }
  179. private bool _isLoading;
  180. private void RevisionsLoading(bool isLoading)
  181. {
  182. // Since this can happen on a background thread, we'll just set a
  183. // flag and deal with it next time we paint (a bit of a hack, but
  184. // it works)
  185. _isLoading = isLoading;
  186. }
  187. private void ShowQuickSearchString()
  188. {
  189. if (_quickSearchLabel == null)
  190. {
  191. _quickSearchLabel
  192. = new Label
  193. {
  194. Location = new Point(10, 10),
  195. BorderStyle = BorderStyle.FixedSingle,
  196. ForeColor = SystemColors.InfoText,
  197. BackColor = SystemColors.Info
  198. };
  199. Controls.Add(_quickSearchLabel);
  200. }
  201. _quickSearchLabel.Visible = true;
  202. _quickSearchLabel.BringToFront();
  203. _quickSearchLabel.Text = _quickSearchString;
  204. _quickSearchLabel.AutoSize = true;
  205. }
  206. private void HideQuickSearchString()
  207. {
  208. if (_quickSearchLabel != null)
  209. _quickSearchLabel.Visible = false;
  210. }
  211. private void QuickSearchTimerTick(object sender, EventArgs e)
  212. {
  213. quickSearchTimer.Stop();
  214. _quickSearchString = "";
  215. HideQuickSearchString();
  216. }
  217. private void RestartQuickSearchTimer()
  218. {
  219. quickSearchTimer.Stop();
  220. quickSearchTimer.Interval = Settings.RevisionGridQuickSearchTimeout;
  221. quickSearchTimer.Start();
  222. }
  223. private void RevisionsKeyDown(object sender, KeyEventArgs e)
  224. {
  225. var curIndex = -1;
  226. if (Revisions.SelectedRows.Count > 0)
  227. curIndex = Revisions.SelectedRows[0].Index;
  228. if (e.Alt && (e.KeyCode == Keys.Up || e.KeyCode == Keys.Down))
  229. {
  230. RestartQuickSearchTimer();
  231. bool reverse = e.KeyCode == Keys.Up;
  232. var nextIndex = 0;
  233. if (curIndex >= 0)
  234. nextIndex = reverse ? curIndex - 1 : curIndex + 1;
  235. _quickSearchString = _lastQuickSearchString;
  236. FindNextMatch(nextIndex, _quickSearchString, reverse);
  237. ShowQuickSearchString();
  238. e.Handled = true;
  239. return;
  240. }
  241. curIndex = curIndex >= 0 ? curIndex : 0;
  242. int key = e.KeyValue;
  243. if (!e.Alt && !e.Control && key == 8 && _quickSearchString.Length > 1) //backspace
  244. {
  245. RestartQuickSearchTimer();
  246. _quickSearchString = _quickSearchString.Substring(0, _quickSearchString.Length - 1);
  247. FindNextMatch(curIndex, _quickSearchString, false);
  248. _lastQuickSearchString = _quickSearchString;
  249. e.Handled = true;
  250. ShowQuickSearchString();
  251. }
  252. else if (!e.Alt && !e.Control && (char.IsLetterOrDigit((char)key) || char.IsNumber((char)key) || char.IsSeparator((char)key) || key == 191))
  253. {
  254. RestartQuickSearchTimer();
  255. //The code below is meant to fix the weird keyvalues when pressing keys e.g. ".".
  256. switch (key)
  257. {
  258. case 51:
  259. _quickSearchString = e.Shift ? string.Concat(_quickSearchString, "#").ToLower() : string.Concat(_quickSearchString, "3").ToLower();
  260. break;
  261. case 188:
  262. _quickSearchString = string.Concat(_quickSearchString, ",").ToLower();
  263. break;
  264. case 189:
  265. _quickSearchString = e.Shift ? string.Concat(_quickSearchString, "_").ToLower() : string.Concat(_quickSearchString, "-").ToLower();
  266. break;
  267. case 190:
  268. _quickSearchString = string.Concat(_quickSearchString, ".").ToLower();
  269. break;
  270. case 191:
  271. _quickSearchString = string.Concat(_quickSearchString, "/").ToLower();
  272. break;
  273. default:
  274. _quickSearchString = string.Concat(_quickSearchString, (char)e.KeyValue).ToLower();
  275. break;
  276. }
  277. FindNextMatch(curIndex, _quickSearchString, false);
  278. _lastQuickSearchString = _quickSearchString;
  279. e.Handled = true;
  280. ShowQuickSearchString();
  281. }
  282. else
  283. {
  284. _quickSearchString = "";
  285. HideQuickSearchString();
  286. e.Handled = false;
  287. }
  288. }
  289. private void FindNextMatch(int startIndex, string searchString, bool reverse)
  290. {
  291. if (Revisions.RowCount == 0)
  292. return;
  293. var searchResult =
  294. reverse
  295. ? SearchInReverseOrder(startIndex, searchString)
  296. : SearchForward(startIndex, searchString);
  297. if (!searchResult.HasValue)
  298. return;
  299. Revisions.ClearSelection();
  300. Revisions.Rows[searchResult.Value].Selected = true;
  301. Revisions.CurrentCell = Revisions.Rows[searchResult.Value].Cells[1];
  302. }
  303. private int? SearchForward(int startIndex, string searchString)
  304. {
  305. // Check for out of bounds roll over if required
  306. int index;
  307. if (startIndex < 0 || startIndex >= Revisions.RowCount)
  308. startIndex = 0;
  309. for (index = startIndex; index < Revisions.RowCount; ++index)
  310. {
  311. if (GetRevision(index).MatchesSearchString(searchString))
  312. return index;
  313. }
  314. // We didn't find it so start searching from the top
  315. for (index = 0; index < startIndex; ++index)
  316. {
  317. if (GetRevision(index).MatchesSearchString(searchString))
  318. return index;
  319. }
  320. return null;
  321. }
  322. private int? SearchInReverseOrder(int startIndex, string searchString)
  323. {
  324. // Check for out of bounds roll over if required
  325. int index;
  326. if (startIndex < 0 || startIndex >= Revisions.RowCount)
  327. startIndex = Revisions.RowCount - 1;
  328. for (index = startIndex; index >= 0; --index)
  329. {
  330. if (GetRevision(index).MatchesSearchString(searchString))
  331. return index;
  332. }
  333. // We didn't find it so start searching from the bottom
  334. for (index = Revisions.RowCount - 1; index > startIndex; --index)
  335. {
  336. if (GetRevision(index).MatchesSearchString(searchString))
  337. return index;
  338. }
  339. return null;
  340. }
  341. public void DisableContextMenu()
  342. {
  343. Revisions.ContextMenuStrip = null;
  344. }
  345. public void FormatQuickFilter(string filter,
  346. bool[] parameters,
  347. out string revListArgs,
  348. out string inMemMessageFilter,
  349. out string inMemCommitterFilter,
  350. out string inMemAuthorFilter)
  351. {
  352. revListArgs = string.Empty;
  353. inMemMessageFilter = string.Empty;
  354. inMemCommitterFilter = string.Empty;
  355. inMemAuthorFilter = string.Empty;
  356. if (!string.IsNullOrEmpty(filter))
  357. {
  358. // hash filtering only possible in memory
  359. var cmdLineSafe = GitCommandHelpers.VersionInUse.IsRegExStringCmdPassable(filter);
  360. revListArgs = " --regexp-ignore-case ";
  361. if (parameters[0])
  362. if (cmdLineSafe)
  363. revListArgs += "--grep=\"" + filter + "\" ";
  364. else
  365. inMemMessageFilter = filter;
  366. if (parameters[1])
  367. if (cmdLineSafe)
  368. revListArgs += "--committer=\"" + filter + "\" ";
  369. else
  370. inMemCommitterFilter = filter;
  371. if (parameters[2])
  372. if (cmdLineSafe)
  373. revListArgs += "--author=\"" + filter + "\" ";
  374. else
  375. inMemAuthorFilter = filter;
  376. if (parameters[3])
  377. if (cmdLineSafe)
  378. revListArgs += "\"-S" + filter + "\" ";
  379. else
  380. throw new InvalidOperationException("Filter text not valid for \"Diff contains\" filter.");
  381. }
  382. }
  383. public bool SetAndApplyBranchFilter(string filter)
  384. {
  385. if (filter.Equals(_revisionFilter.GetBranchFilter()))
  386. return false;
  387. if (filter.Equals(""))
  388. {
  389. Settings.BranchFilterEnabled = false;
  390. Settings.ShowCurrentBranchOnly = true;
  391. }
  392. else
  393. {
  394. Settings.BranchFilterEnabled = true;
  395. Settings.ShowCurrentBranchOnly = false;
  396. _revisionFilter.SetBranchFilter(filter);
  397. }
  398. SetShowBranches();
  399. return true;
  400. }
  401. public void SetLimit(int limit)
  402. {
  403. _revisionFilter.SetLimit(limit);
  404. }
  405. public override void Refresh()
  406. {
  407. SetRevisionsLayout();
  408. base.Refresh();
  409. Revisions.Refresh();
  410. }
  411. protected override void OnCreateControl()
  412. {
  413. base.OnCreateControl();
  414. _isLoading = true;
  415. Error.Visible = false;
  416. NoCommits.Visible = false;
  417. NoGit.Visible = false;
  418. Revisions.Visible = false;
  419. Loading.Visible = true;
  420. Loading.BringToFront();
  421. }
  422. public new void Load()
  423. {
  424. if (!DesignMode)
  425. ReloadHotkeys();
  426. ForceRefreshRevisions();
  427. }
  428. public event EventHandler SelectionChanged;
  429. public void SetSelectedIndex(int index)
  430. {
  431. if (Revisions.Rows[index].Selected)
  432. return;
  433. Revisions.ClearSelection();
  434. Revisions.Rows[index].Selected = true;
  435. Revisions.CurrentCell = Revisions.Rows[index].Cells[1];
  436. Revisions.Select();
  437. }
  438. public void SetSelectedRevision(GitRevision revision)
  439. {
  440. if (revision != null)
  441. {
  442. for (var i = 0; i < Revisions.RowCount; i++)
  443. {
  444. if (GetRevision(i).Guid == revision.Guid)
  445. {
  446. SetSelectedIndex(i);
  447. return;
  448. }
  449. }
  450. }
  451. Revisions.ClearSelection();
  452. Revisions.Select();
  453. }
  454. private void RevisionsSelectionChanged(object sender, EventArgs e)
  455. {
  456. if (Revisions.SelectedRows.Count > 0)
  457. LastRow = Revisions.SelectedRows[0].Index;
  458. SelectionTimer.Enabled = false;
  459. SelectionTimer.Stop();
  460. SelectionTimer.Enabled = true;
  461. SelectionTimer.Start();
  462. }
  463. public List<GitRevision> GetSelectedRevisions()
  464. {
  465. return GetSelectedRevisions(null);
  466. }
  467. public List<GitRevision> GetSelectedRevisions(SortDirection? direction)
  468. {
  469. var rows = Revisions
  470. .SelectedRows
  471. .Cast<DataGridViewRow>()
  472. .Where(row => Revisions.RowCount > row.Index);
  473. if (direction.HasValue)
  474. {
  475. int d = direction.Value == SortDirection.Ascending ? 1 : -1;
  476. rows = rows.OrderBy((row) => row.Index, (r1, r2) => d * (r1 - r2));
  477. }
  478. return rows
  479. .Select(row => GetRevision(row.Index))
  480. .ToList();
  481. }
  482. public GitRevision GetRevision(int aRow)
  483. {
  484. return Revisions.GetRowData(aRow);
  485. }
  486. public GitRevision GetCurrentRevision()
  487. {
  488. const string formatString =
  489. /* Tree */ "%T%n" +
  490. /* Author Name */ "%aN%n" +
  491. /* Author Date */ "%ai%n" +
  492. /* Committer Name */ "%cN%n" +
  493. /* Committer Date */ "%ci%n" +
  494. /* Commit Message */ "%s";
  495. string cmd = "log -n 1 --pretty=format:" + formatString + " " + CurrentCheckout;
  496. var RevInfo = Settings.Module.RunGitCmd(cmd);
  497. string[] Infos = RevInfo.Split('\n');
  498. var Revision = new GitRevision(CurrentCheckout)
  499. {
  500. TreeGuid = Infos[0],
  501. Author = Infos[1],
  502. Committer = Infos[3],
  503. Message = Infos[5]
  504. };
  505. DateTime date;
  506. DateTime.TryParse(Infos[2], out date);
  507. Revision.AuthorDate = date;
  508. DateTime.TryParse(Infos[4], out date);
  509. Revision.CommitDate = date;
  510. List<GitHead> heads = Settings.Module.GetHeads(true, true);
  511. foreach (GitHead head in heads)
  512. {
  513. if (head.Guid.Equals(Revision.Guid))
  514. Revision.Heads.Add(head);
  515. }
  516. return Revision;
  517. }
  518. public void RefreshRevisions()
  519. {
  520. if (IndexWatcher.IndexChanged)
  521. ForceRefreshRevisions();
  522. }
  523. private class RevisionGraphInMemFilterOr : RevisionGraphInMemFilter
  524. {
  525. private RevisionGraphInMemFilter fFilter1;
  526. private RevisionGraphInMemFilter fFilter2;
  527. public RevisionGraphInMemFilterOr(RevisionGraphInMemFilter aFilter1,
  528. RevisionGraphInMemFilter aFilter2)
  529. {
  530. fFilter1 = aFilter1;
  531. fFilter2 = aFilter2;
  532. }
  533. public override bool PassThru(GitRevision rev)
  534. {
  535. return fFilter1.PassThru(rev) || fFilter2.PassThru(rev);
  536. }
  537. }
  538. private class RevisionGridInMemFilter : RevisionGraphInMemFilter
  539. {
  540. private readonly bool _IgnoreCase;
  541. private readonly string _AuthorFilter;
  542. private readonly Regex _AuthorFilterRegex;
  543. private readonly string _CommitterFilter;
  544. private readonly Regex _CommitterFilterRegex;
  545. private readonly string _MessageFilter;
  546. private readonly Regex _MessageFilterRegex;
  547. public RevisionGridInMemFilter(string authorFilter, string committerFilter, string messageFilter, bool ignoreCase)
  548. {
  549. _IgnoreCase = ignoreCase;
  550. SetUpVars(authorFilter, ref _AuthorFilter, ref _AuthorFilterRegex);
  551. SetUpVars(committerFilter, ref _CommitterFilter, ref _CommitterFilterRegex);
  552. SetUpVars(messageFilter, ref _MessageFilter, ref _MessageFilterRegex);
  553. }
  554. private void SetUpVars(string filterValue,
  555. ref string filterStr,
  556. ref Regex filterRegEx)
  557. {
  558. RegexOptions opts = RegexOptions.None;
  559. if (_IgnoreCase) opts = opts | RegexOptions.IgnoreCase;
  560. filterStr = filterValue != null ? filterValue.Trim() : string.Empty;
  561. try
  562. {
  563. filterRegEx = new Regex(filterStr, opts);
  564. }
  565. catch (ArgumentException)
  566. {
  567. filterRegEx = null;
  568. }
  569. }
  570. private static bool CheckCondition(string filter, Regex regex, string value)
  571. {
  572. return string.IsNullOrEmpty(filter) ||
  573. ((regex != null) && regex.Match(value).Success);
  574. }
  575. public override bool PassThru(GitRevision rev)
  576. {
  577. return CheckCondition(_AuthorFilter, _AuthorFilterRegex, rev.Author) &&
  578. CheckCondition(_CommitterFilter, _CommitterFilterRegex, rev.Committer) &&
  579. CheckCondition(_MessageFilter, _MessageFilterRegex, rev.Message);
  580. }
  581. public static RevisionGridInMemFilter CreateIfNeeded(string authorFilter,
  582. string committerFilter,
  583. string messageFilter,
  584. bool ignoreCase)
  585. {
  586. if (!(string.IsNullOrEmpty(authorFilter) &&
  587. string.IsNullOrEmpty(committerFilter) &&
  588. string.IsNullOrEmpty(messageFilter)))
  589. return new RevisionGridInMemFilter(authorFilter,
  590. committerFilter,
  591. messageFilter,
  592. ignoreCase);
  593. else
  594. return null;
  595. }
  596. }
  597. public void ReloadHotkeys()
  598. {
  599. this.Hotkeys = HotkeySettingsManager.LoadHotkeys(HotkeySettingsName);
  600. }
  601. public void ReloadTranslation()
  602. {
  603. Translate();
  604. }
  605. public void ForceRefreshRevisions()
  606. {
  607. try
  608. {
  609. ApplyFilterFromRevisionFilterDialog();
  610. _initialLoad = true;
  611. LastScrollPos = Revisions.FirstDisplayedScrollingRowIndex;
  612. DisposeRevisionGraphCommand();
  613. var newCurrentCheckout = Settings.Module.GetCurrentCheckout();
  614. var newSuperprojectCurrentCheckout = Settings.Module.GetSuperprojectCurrentCheckout();
  615. // If the current checkout changed, don't get the currently selected rows, select the
  616. // new current checkout instead.
  617. if (newCurrentCheckout == CurrentCheckout)
  618. {
  619. LastSelectedRows = Revisions.SelectedIds;
  620. }
  621. else
  622. {
  623. // This is a new checkout, so ensure the variable is cleared out.
  624. LastSelectedRows = null;
  625. }
  626. Revisions.ClearSelection();
  627. CurrentCheckout = newCurrentCheckout;
  628. SuperprojectCurrentCheckout = newSuperprojectCurrentCheckout;
  629. Revisions.Clear();
  630. Error.Visible = false;
  631. if (!Settings.Module.ValidWorkingDir())
  632. {
  633. Revisions.Visible = false;
  634. NoCommits.Visible = true;
  635. Loading.Visible = false;
  636. NoGit.Visible = true;
  637. string dir = Settings.Module.WorkingDir;
  638. if (String.IsNullOrEmpty(dir) || !Directory.Exists(dir) ||
  639. Directory.GetDirectories(dir).Length == 0 &&
  640. Directory.GetFiles(dir).Length == 0)
  641. CloneRepository.Show();
  642. else
  643. CloneRepository.Hide();
  644. NoGit.BringToFront();
  645. return;
  646. }
  647. NoCommits.Visible = false;
  648. NoGit.Visible = false;
  649. Revisions.Visible = true;
  650. Revisions.BringToFront();
  651. Revisions.Enabled = false;
  652. Loading.Visible = true;
  653. Loading.BringToFront();
  654. _isLoading = true;
  655. base.Refresh();
  656. IndexWatcher.Reset();
  657. if (!Settings.ShowGitNotes && !LogParam.Contains(" --not --glob=notes --not"))
  658. LogParam = LogParam + " --not --glob=notes --not";
  659. if (Settings.ShowGitNotes && LogParam.Contains(" --not --glob=notes --not"))
  660. LogParam = LogParam.Replace(" --not --glob=notes --not", string.Empty);
  661. RevisionGridInMemFilter revisionFilterIMF = RevisionGridInMemFilter.CreateIfNeeded(_revisionFilter.GetInMemAuthorFilter(),
  662. _revisionFilter.GetInMemCommitterFilter(),
  663. _revisionFilter.GetInMemMessageFilter(),
  664. _revisionFilter.GetIgnoreCase());
  665. RevisionGridInMemFilter filterBarIMF = RevisionGridInMemFilter.CreateIfNeeded(InMemAuthorFilter,
  666. InMemCommitterFilter,
  667. InMemMessageFilter,
  668. InMemFilterIgnoreCase);
  669. RevisionGraphInMemFilter revGraphIMF;
  670. if (revisionFilterIMF != null && filterBarIMF != null)
  671. revGraphIMF = new RevisionGraphInMemFilterOr(revisionFilterIMF, filterBarIMF);
  672. else if (revisionFilterIMF != null)
  673. revGraphIMF = revisionFilterIMF;
  674. else
  675. revGraphIMF = filterBarIMF;
  676. _revisionGraphCommand = new RevisionGraph { BranchFilter = BranchFilter, LogParam = LogParam + _revisionFilter.GetFilter() + Filter + FixedFilter };
  677. _revisionGraphCommand.Updated += GitGetCommitsCommandUpdated;
  678. _revisionGraphCommand.Exited += GitGetCommitsCommandExited;
  679. _revisionGraphCommand.Error += _revisionGraphCommand_Error;
  680. _revisionGraphCommand.InMemFilter = revGraphIMF;
  681. //_revisionGraphCommand.BeginUpdate += ((s, e) => Revisions.Invoke((Action) (() => Revisions.Clear())));
  682. _revisionGraphCommand.Execute();
  683. LoadRevisions();
  684. SetRevisionsLayout();
  685. }
  686. catch (Exception exception)
  687. {
  688. Error.Visible = true;
  689. Error.BringToFront();
  690. MessageBox.Show(this, exception.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
  691. }
  692. }
  693. private void _revisionGraphCommand_Error(object sender, EventArgs e)
  694. {
  695. // This has to happen on the UI thread
  696. _syncContext.Send(o =>
  697. {
  698. Error.Visible = true;
  699. //Error.BringToFront();
  700. NoGit.Visible = false;
  701. NoCommits.Visible = false;
  702. Revisions.Visible = false;
  703. Loading.Visible = false;
  704. }, this);
  705. }
  706. private void GitGetCommitsCommandUpdated(object sender, EventArgs e)
  707. {
  708. var updatedEvent = (RevisionGraph.RevisionGraphUpdatedEventArgs)e;
  709. UpdateGraph(updatedEvent.Revision);
  710. }
  711. private bool FilterIsApplied(bool inclBranchFilter)
  712. {
  713. return (inclBranchFilter && !string.IsNullOrEmpty(BranchFilter)) ||
  714. !(string.IsNullOrEmpty(Filter) &&
  715. !_revisionFilter.FilterEnabled() &&
  716. string.IsNullOrEmpty(InMemAuthorFilter) &&
  717. string.IsNullOrEmpty(InMemCommitterFilter) &&
  718. string.IsNullOrEmpty(InMemMessageFilter));
  719. }
  720. private bool ShouldHideGraph(bool inclBranchFilter)
  721. {
  722. return (inclBranchFilter && !string.IsNullOrEmpty(BranchFilter)) ||
  723. !(!_revisionFilter.ShouldHideGraph() &&
  724. string.IsNullOrEmpty(InMemAuthorFilter) &&
  725. string.IsNullOrEmpty(InMemCommitterFilter) &&
  726. string.IsNullOrEmpty(InMemMessageFilter));
  727. }
  728. private void DisposeRevisionGraphCommand()
  729. {
  730. if (_revisionGraphCommand != null)
  731. {
  732. //Dispose command, it is not needed anymore
  733. _revisionGraphCommand.Updated -= GitGetCommitsCommandUpdated;
  734. _revisionGraphCommand.Exited -= GitGetCommitsCommandExited;
  735. _revisionGraphCommand.Error -= _revisionGraphCommand_Error;
  736. _revisionGraphCommand.Dispose();
  737. _revisionGraphCommand = null;
  738. }
  739. }
  740. private void GitGetCommitsCommandExited(object sender, EventArgs e)
  741. {
  742. _isLoading = false;
  743. if (_revisionGraphCommand.RevisionCount == 0 &&
  744. !FilterIsApplied(true))
  745. {
  746. // This has to happen on the UI thread
  747. _syncContext.Send(o =>
  748. {
  749. NoGit.Visible = false;
  750. NoCommits.Visible = true;
  751. //NoCommits.BringToFront();
  752. Revisions.Visible = false;
  753. Loading.Visible = false;
  754. }, this);
  755. }
  756. else
  757. {
  758. // This has to happen on the UI thread
  759. _syncContext.Send(o =>
  760. {
  761. UpdateGraph(null);
  762. Loading.Visible = false;
  763. SelectInitialRevision();
  764. _isLoading = false;
  765. }, this);
  766. }
  767. }
  768. private void SelectInitialRevision()
  769. {
  770. if (string.IsNullOrEmpty(_initialSelectedRevision) || Revisions.SelectedRows.Count != 0)
  771. return;
  772. for (var i = 0; i < Revisions.RowCount; i++)
  773. {
  774. if (GetRevision(i).Guid == _initialSelectedRevision)
  775. SetSelectedIndex(i);
  776. }
  777. }
  778. private static string GetDateHeaderText()
  779. {
  780. return Settings.ShowAuthorDate ? Strings.GetAuthorDateText() : Strings.GetCommitDateText();
  781. }
  782. private void LoadRevisions()
  783. {
  784. if (_revisionGraphCommand == null)
  785. {
  786. return;
  787. }
  788. Revisions.SuspendLayout();
  789. Revisions.Columns[1].HeaderText = Strings.GetMessageText();
  790. Revisions.Columns[2].HeaderText = Strings.GetAuthorText();
  791. Revisions.Columns[3].HeaderText = GetDateHeaderText();
  792. Revisions.SelectionChanged -= RevisionsSelectionChanged;
  793. if (LastSelectedRows != null)
  794. {
  795. Revisions.SelectedIds = LastSelectedRows;
  796. LastSelectedRows = null;
  797. }
  798. else if (_initialSelectedRevision == null)
  799. {
  800. Revisions.SelectedIds = new IComparable[] { CurrentCheckout };
  801. }
  802. if (LastScrollPos > 0 && Revisions.RowCount > LastScrollPos)
  803. {
  804. Revisions.FirstDisplayedScrollingRowIndex = LastScrollPos;
  805. LastScrollPos = -1;
  806. }
  807. Revisions.Enabled = true;
  808. Revisions.Focus();
  809. Revisions.SelectionChanged += RevisionsSelectionChanged;
  810. Revisions.ResumeLayout();
  811. if (!_initialLoad)
  812. return;
  813. _initialLoad = false;
  814. SelectionTimer.Enabled = false;
  815. SelectionTimer.Stop();
  816. SelectionTimer.Enabled = true;
  817. SelectionTimer.Start();
  818. }
  819. private void RevisionsCellPainting(object sender, DataGridViewCellPaintingEventArgs e)
  820. {
  821. // If our loading state has changed since the last paint, update it.
  822. if (Loading != null)
  823. {
  824. if (Loading.Visible != _isLoading)
  825. {
  826. Loading.Visible = _isLoading;
  827. }
  828. }
  829. // The graph column is handled by the DvcsGraph
  830. if (e.ColumnIndex == 0)
  831. {
  832. return;
  833. }
  834. var column = e.ColumnIndex;
  835. if (e.RowIndex < 0 || (e.State & DataGridViewElementStates.Visible) == 0)
  836. return;
  837. if (Revisions.RowCount <= e.RowIndex)
  838. return;
  839. var revision = GetRevision(e.RowIndex);
  840. if (revision == null)
  841. return;
  842. e.Handled = true;
  843. bool isRowSelected = ((e.State & DataGridViewElementStates.Selected) == DataGridViewElementStates.Selected);
  844. if (isRowSelected /*&& !showRevisionCards*/)
  845. e.Graphics.FillRectangle(selectedItemBrush, e.CellBounds);
  846. else
  847. e.Graphics.FillRectangle(new SolidBrush(Color.White), e.CellBounds);
  848. Color foreColor;
  849. if (!Settings.RevisionGraphDrawNonRelativesGray || !Settings.RevisionGraphDrawNonRelativesTextGray || Revisions.RowIsRelative(e.RowIndex))
  850. {
  851. foreColor = isRowSelected && IsFilledBranchesLayout()
  852. ? SystemColors.HighlightText
  853. : e.CellStyle.ForeColor;
  854. }
  855. else
  856. {
  857. foreColor = Color.LightGray;
  858. }
  859. Brush foreBrush = new SolidBrush(foreColor);
  860. var rowFont = NormalFont;
  861. if (revision.Guid == CurrentCheckout /*&& !showRevisionCards*/)
  862. rowFont = HeadFont;
  863. else if (revision.Guid == SuperprojectCurrentCheckout)
  864. rowFont = SuperprojectFont;
  865. switch (column)
  866. {
  867. case 1: //Description!!
  868. {
  869. int baseOffset = 0;
  870. if (IsCardLayout())
  871. {
  872. baseOffset = 5;
  873. Rectangle cellRectangle = new Rectangle(e.CellBounds.Left + baseOffset, e.CellBounds.Top + 1, e.CellBounds.Width - (baseOffset * 2), e.CellBounds.Height - 4);
  874. if (!Settings.RevisionGraphDrawNonRelativesGray || Revisions.RowIsRelative(e.RowIndex))
  875. {
  876. e.Graphics.FillRectangle(
  877. new LinearGradientBrush(cellRectangle,
  878. Color.FromArgb(255, 220, 220, 231),
  879. Color.FromArgb(255, 240, 240, 250), 90, false), cellRectangle);
  880. e.Graphics.DrawRectangle(new Pen(Color.FromArgb(255, 200, 200, 200), 1), cellRectangle);
  881. }
  882. else
  883. {
  884. e.Graphics.FillRectangle(
  885. new LinearGradientBrush(cellRectangle,
  886. Color.FromArgb(255, 240, 240, 240),
  887. Color.FromArgb(255, 250, 250, 250), 90, false), cellRectangle);
  888. }
  889. if ((e.State & DataGridViewElementStates.Selected) == DataGridViewElementStates.Selected)
  890. e.Graphics.DrawRectangle(new Pen(Revisions.RowTemplate.DefaultCellStyle.SelectionBackColor, 1), cellRectangle);
  891. }
  892. float offset = baseOffset;
  893. var heads = revision.Heads;
  894. if (heads.Count > 0)
  895. {
  896. heads.Sort((left, right) =>
  897. {
  898. if (left.IsTag != right.IsTag)
  899. return right.IsTag.CompareTo(left.IsTag);
  900. if (left.IsRemote != right.IsRemote)
  901. return left.IsRemote.CompareTo(right.IsRemote);
  902. return left.Name.CompareTo(right.Name);
  903. });
  904. foreach (var head in heads)
  905. {
  906. if ((head.IsRemote && !ShowRemoteBranches.Checked))
  907. continue;
  908. Font refsFont;
  909. if (IsFilledBranchesLayout())
  910. {
  911. //refsFont = head.Selected ? rowFont : new Font(rowFont, FontStyle.Regular);
  912. refsFont = rowFont;
  913. //refsFont = head.Selected
  914. // ? new Font(rowFont, rowFont.Style | FontStyle.Italic)
  915. // : rowFont;
  916. }
  917. else
  918. {
  919. refsFont = RefsFont;
  920. }
  921. Color headColor = GetHeadColor(head);
  922. Brush textBrush = new SolidBrush(headColor);
  923. string headName;
  924. PointF location;
  925. if (IsCardLayout())
  926. {
  927. headName = head.Name;
  928. offset += e.Graphics.MeasureString(headName, refsFont).Width + 6;
  929. location = new PointF(e.CellBounds.Right - offset, e.CellBounds.Top + 4);
  930. var size = new SizeF(e.Graphics.MeasureString(headName, refsFont).Width,
  931. e.Graphics.MeasureString(headName, RefsFont).Height);
  932. e.Graphics.FillRectangle(new SolidBrush(SystemColors.Info), location.X - 1,
  933. location.Y - 1, size.Width + 3, size.Height + 2);
  934. e.Graphics.DrawRectangle(new Pen(SystemColors.InfoText), location.X - 1,
  935. location.Y - 1, size.Width + 3, size.Height + 2);
  936. e.Graphics.DrawString(headName, refsFont, textBrush, location);
  937. }
  938. else
  939. {
  940. headName = IsFilledBranchesLayout()
  941. ? head.Name
  942. : string.Concat("[", head.Name, "] ");
  943. var headBounds = AdjustCellBounds(e.CellBounds, offset);
  944. SizeF textSize = e.Graphics.MeasureString(headName, refsFont);
  945. offset += textSize.Width;
  946. if (IsFilledBranchesLayout())
  947. {
  948. offset += 9;
  949. float extraOffset = DrawHeadBackground(isRowSelected, e.Graphics,
  950. headColor, headBounds.X,
  951. headBounds.Y,
  952. RoundToEven(textSize.Width + 3),
  953. RoundToEven(textSize.Height), 3,
  954. head.Selected,
  955. head.SelectedHeadMergeSource);
  956. offset += extraOffset;
  957. headBounds.Offset((int)(extraOffset + 1), 0);
  958. }
  959. DrawColumnText(e.Graphics, headName, refsFont, headColor, headBounds);
  960. }
  961. }
  962. }
  963. if (IsCardLayout())
  964. offset = baseOffset;
  965. var text = (string)e.FormattedValue;
  966. var bounds = AdjustCellBounds(e.CellBounds, offset);
  967. DrawColumnText(e.Graphics, text, rowFont, foreColor, bounds);
  968. if (IsCardLayout())
  969. {
  970. int textHeight = (int)e.Graphics.MeasureString(text, rowFont).Height;
  971. int gravatarSize = rowHeigth - textHeight - 12;
  972. int gravatarTop = e.CellBounds.Top + textHeight + 6;
  973. int gravatarLeft = e.CellBounds.Left + baseOffset + 2;
  974. Image gravatar = Gravatar.GravatarService.GetImageFromCache(revision.AuthorEmail + gravatarSize.ToString() + ".png", revision.AuthorEmail, Settings.AuthorImageCacheDays, gravatarSize, Settings.GravatarCachePath, FallBackService.MonsterId);
  975. if (gravatar == null && !string.IsNullOrEmpty(revision.AuthorEmail))
  976. {
  977. ThreadPool.QueueUserWorkItem(o =>
  978. Gravatar.GravatarService.LoadCachedImage(revision.AuthorEmail + gravatarSize.ToString() + ".png", revision.AuthorEmail, null, Settings.AuthorImageCacheDays, gravatarSize, Settings.GravatarCachePath, RefreshGravatar, FallBackService.MonsterId));
  979. }
  980. if (gravatar != null)
  981. e.Graphics.DrawImage(gravatar, gravatarLeft + 1, gravatarTop + 1, gravatarSize, gravatarSize);
  982. e.Graphics.DrawRectangle(Pens.Black, gravatarLeft, gravatarTop, gravatarSize + 1, gravatarSize + 1);
  983. string authorText;
  984. string timeText;
  985. if (rowHeigth >= 60)
  986. {
  987. authorText = revision.Author;
  988. timeText = TimeToString(Settings.ShowAuthorDate ? revision.AuthorDate : revision.CommitDate);
  989. }
  990. else
  991. {
  992. timeText = string.Concat(revision.Author, " (", TimeToString(Settings.ShowAuthorDate ? revision.AuthorDate : revision.CommitDate), ")");
  993. authorText = string.Empty;
  994. }
  995. e.Graphics.DrawString(authorText, rowFont, foreBrush,
  996. new PointF(gravatarLeft + gravatarSize + 5, gravatarTop + 6));
  997. e.Graphics.DrawString(timeText, rowFont, foreBrush,
  998. new PointF(gravatarLeft + gravatarSize + 5, e.CellBounds.Bottom - textHeight - 4));
  999. }
  1000. }
  1001. break;
  1002. case 2:
  1003. {
  1004. var text = (string)e.FormattedValue;
  1005. e.Graphics.DrawString(text, rowFont, foreBrush,
  1006. new PointF(e.CellBounds.Left, e.CellBounds.Top + 4));
  1007. }
  1008. break;
  1009. case 3:
  1010. {
  1011. var time = Settings.ShowAuthorDate ? revision.AuthorDate : revision.CommitDate;
  1012. var text = TimeToString(time);
  1013. e.Graphics.DrawString(text, rowFont, foreBrush,
  1014. new PointF(e.CellBounds.Left, e.CellBounds.Top + 4));
  1015. }
  1016. break;
  1017. }
  1018. }
  1019. private void RevisionsCellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
  1020. {
  1021. var column = e.ColumnIndex;
  1022. if (

Large files files are truncated, but you can click here to view the full file