PageRenderTime 38ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/GitUI/UserControls/RevisionGrid.cs

https://github.com/qgppl/gitextensions
C# | 3198 lines | 2619 code | 491 blank | 88 comment | 524 complexity | aa1cc62956e1d2e0cf91aa051420d9e9 MD5 | raw file
Possible License(s): GPL-3.0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.DirectoryServices;
  5. using System.Drawing;
  6. using System.Drawing.Drawing2D;
  7. using System.IO;
  8. using System.Linq;
  9. using System.Text.RegularExpressions;
  10. using System.Threading;
  11. using System.Threading.Tasks;
  12. using System.Windows.Forms;
  13. using GitCommands;
  14. using GitCommands.Git;
  15. using GitUI.BuildServerIntegration;
  16. using GitUI.CommandsDialogs;
  17. using GitUI.CommandsDialogs.BrowseDialog;
  18. using GitUI.HelperDialogs;
  19. using GitUI.Hotkey;
  20. using GitUI.RevisionGridClasses;
  21. using GitUI.Script;
  22. using GitUI.UserControls;
  23. using GitUI.UserControls.RevisionGridClasses;
  24. using GitUIPluginInterfaces;
  25. using Gravatar;
  26. using ResourceManager;
  27. namespace GitUI
  28. {
  29. public enum RevisionGridLayout
  30. {
  31. FilledBranchesSmall = 1,
  32. FilledBranchesSmallWithGraph = 2,
  33. Small = 3,
  34. SmallWithGraph = 4,
  35. Card = 5,
  36. CardWithGraph = 6,
  37. LargeCard = 7,
  38. LargeCardWithGraph = 8
  39. }
  40. public enum RevisionGraphDrawStyleEnum
  41. {
  42. Normal,
  43. DrawNonRelativesGray,
  44. HighlightSelected
  45. }
  46. [DefaultEvent("DoubleClick")]
  47. public sealed partial class RevisionGrid : GitModuleControl
  48. {
  49. private readonly TranslationString _droppingFilesBlocked = new TranslationString("For you own protection dropping more than 10 patch files at once is blocked!");
  50. private readonly TranslationString _cannotHighlightSelectedBranch = new TranslationString("Cannot highlight selected branch when revision graph is loading.");
  51. private readonly TranslationString _noRevisionFoundError = new TranslationString("No revision found.");
  52. private const int NodeDimension = 8;
  53. private const int LaneWidth = 13;
  54. private const int LaneLineWidth = 2;
  55. private const int MaxSuperprojectRefs = 4;
  56. private Brush _selectedItemBrush;
  57. private SolidBrush _authoredRevisionsBrush;
  58. private Brush _filledItemBrush; // disposable brush
  59. private readonly FormRevisionFilter _revisionFilter = new FormRevisionFilter();
  60. private RefsFiltringOptions _refsOptions = RefsFiltringOptions.All | RefsFiltringOptions.Boundary;
  61. private bool _initialLoad = true;
  62. private string _initialSelectedRevision;
  63. private string _lastQuickSearchString = string.Empty;
  64. private Label _quickSearchLabel;
  65. private string _quickSearchString;
  66. private RevisionGraph _revisionGraphCommand;
  67. public BuildServerWatcher BuildServerWatcher { get; private set; }
  68. private RevisionGridLayout _layout;
  69. private int _rowHeigth;
  70. public event EventHandler<GitModuleEventArgs> GitModuleChanged;
  71. public event EventHandler<DoubleClickRevisionEventArgs> DoubleClickRevision;
  72. public event EventHandler<EventArgs> ShowFirstParentsToggled;
  73. private readonly RevisionGridMenuCommands _revisionGridMenuCommands;
  74. bool _showCurrentBranchOnlyToolStripMenuItemChecked; // refactoring
  75. bool _showAllBranchesToolStripMenuItemChecked; // refactoring
  76. bool _showFilteredBranchesToolStripMenuItemChecked; // refactoring
  77. private readonly ParentChildNavigationHistory _parentChildNavigationHistory;
  78. private readonly NavigationHistory _navigationHistory = new NavigationHistory();
  79. private AuthorEmailBasedRevisionHighlighting _revisionHighlighting;
  80. private GitRevision _baseCommitToCompare = null;
  81. /// <summary>
  82. /// Refs loaded while the latest processing of git log
  83. /// </summary>
  84. private IEnumerable<IGitRef> LatestRefs = Enumerable.Empty<IGitRef>();
  85. public RevisionGrid()
  86. {
  87. InitLayout();
  88. InitializeComponent();
  89. // Parent-child navigation can expect that SetSelectedRevision is always successfull since it always uses first-parents
  90. _parentChildNavigationHistory = new ParentChildNavigationHistory(revision => SetSelectedRevision(revision));
  91. _revisionHighlighting = new AuthorEmailBasedRevisionHighlighting();
  92. this.Loading.Image = global::GitUI.Properties.Resources.loadingpanel;
  93. Translate();
  94. _revisionGridMenuCommands = new RevisionGridMenuCommands(this);
  95. _revisionGridMenuCommands.CreateOrUpdateMenuCommands();
  96. // fill View context menu from MenuCommands
  97. var viewMenuCommands = _revisionGridMenuCommands.GetViewMenuCommands();
  98. FillMenuFromMenuCommands(viewMenuCommands, viewToolStripMenuItem);
  99. // fill Navigate context menu from MenuCommands
  100. var navigateMenuCommands = _revisionGridMenuCommands.GetNavigateMenuCommands();
  101. FillMenuFromMenuCommands(navigateMenuCommands, navigateToolStripMenuItem);
  102. NormalFont = AppSettings.Font;
  103. Loading.Paint += Loading_Paint;
  104. Revisions.CellPainting += RevisionsCellPainting;
  105. Revisions.CellFormatting += RevisionsCellFormatting;
  106. Revisions.KeyPress += RevisionsKeyPress;
  107. Revisions.KeyDown += RevisionsKeyDown;
  108. Revisions.MouseDown += RevisionsMouseDown;
  109. showMergeCommitsToolStripMenuItem.Checked = AppSettings.ShowMergeCommits;
  110. BranchFilter = String.Empty;
  111. SetShowBranches();
  112. QuickRevisionFilter = "";
  113. FixedRevisionFilter = "";
  114. FixedPathFilter = "";
  115. InMemFilterIgnoreCase = true;
  116. InMemAuthorFilter = "";
  117. InMemCommitterFilter = "";
  118. InMemMessageFilter = "";
  119. AllowGraphWithFilter = false;
  120. _quickSearchString = "";
  121. quickSearchTimer.Tick += QuickSearchTimerTick;
  122. Revisions.Loading += RevisionsLoading;
  123. //Allow to drop patch file on revisiongrid
  124. Revisions.DragEnter += Revisions_DragEnter;
  125. Revisions.DragDrop += Revisions_DragDrop;
  126. Revisions.AllowDrop = true;
  127. Revisions.ColumnHeadersVisible = false;
  128. Revisions.IdColumn.Visible = AppSettings.ShowIds;
  129. IsMessageMultilineDataGridViewColumn.Width = 25;
  130. IsMessageMultilineDataGridViewColumn.DisplayIndex = 2;
  131. IsMessageMultilineDataGridViewColumn.Resizable = DataGridViewTriState.False;
  132. this.HotkeysEnabled = true;
  133. try
  134. {
  135. SetRevisionsLayout((RevisionGridLayout)AppSettings.RevisionGraphLayout);
  136. }
  137. catch
  138. {
  139. SetRevisionsLayout(RevisionGridLayout.SmallWithGraph);
  140. }
  141. compareToBaseToolStripMenuItem.Enabled = false;
  142. }
  143. private void FillMenuFromMenuCommands(IEnumerable<MenuCommand> menuCommands, ToolStripMenuItem targetMenuItem)
  144. {
  145. foreach (var menuCommand in menuCommands)
  146. {
  147. var toolStripItem = (ToolStripItem)MenuCommand.CreateToolStripItem(menuCommand);
  148. var toolStripMenuItem = toolStripItem as ToolStripMenuItem;
  149. if (toolStripMenuItem != null)
  150. {
  151. menuCommand.RegisterMenuItem(toolStripMenuItem);
  152. }
  153. targetMenuItem.DropDownItems.Add(toolStripItem);
  154. }
  155. }
  156. void Loading_Paint(object sender, PaintEventArgs e)
  157. {
  158. // If our loading state has changed since the last paint, update it.
  159. if (Loading != null)
  160. {
  161. if (Loading.Visible != _isLoading)
  162. {
  163. Loading.Visible = _isLoading;
  164. }
  165. }
  166. }
  167. [Browsable(false)]
  168. public Font HeadFont { get; private set; }
  169. [Browsable(false)]
  170. public Font SuperprojectFont { get; private set; }
  171. [Browsable(false)]
  172. public int LastScrollPos { get; private set; }
  173. [Browsable(false)]
  174. public string[] LastSelectedRows { get; private set; }
  175. [Browsable(false)]
  176. public Font RefsFont { get; private set; }
  177. private Font _normalFont;
  178. [Browsable(false)]
  179. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  180. public Font NormalFont
  181. {
  182. get { return _normalFont; }
  183. set
  184. {
  185. _normalFont = value;
  186. MessageDataGridViewColumn.DefaultCellStyle.Font = _normalFont;
  187. DateDataGridViewColumn.DefaultCellStyle.Font = _normalFont;
  188. IdDataGridViewColumn.DefaultCellStyle.Font = new Font("Consolas", _normalFont.SizeInPoints);
  189. IsMessageMultilineDataGridViewColumn.DefaultCellStyle.Font = _normalFont;
  190. RefsFont = IsFilledBranchesLayout() ? _normalFont : new Font(_normalFont, FontStyle.Bold);
  191. HeadFont = new Font(_normalFont, FontStyle.Bold);
  192. SuperprojectFont = new Font(_normalFont, FontStyle.Underline);
  193. }
  194. }
  195. [Category("Filter")]
  196. [DefaultValue("")]
  197. public string QuickRevisionFilter { get; set; }
  198. [Category("Filter")]
  199. [DefaultValue("")]
  200. public string FixedRevisionFilter { get; set; }
  201. [Category("Filter")]
  202. [DefaultValue("")]
  203. public string FixedPathFilter { get; set; }
  204. [Category("Filter")]
  205. [DefaultValue(true)]
  206. public bool InMemFilterIgnoreCase { get; set; }
  207. [Category("Filter")]
  208. [DefaultValue("")]
  209. public string InMemAuthorFilter { get; set; }
  210. [Category("Filter")]
  211. [DefaultValue("")]
  212. public string InMemCommitterFilter { get; set; }
  213. [Category("Filter")]
  214. [DefaultValue("")]
  215. public string InMemMessageFilter { get; set; }
  216. [Category("Filter")]
  217. [DefaultValue("")]
  218. public string BranchFilter { get; set; }
  219. [Category("Filter")]
  220. [DefaultValue(false)]
  221. public bool AllowGraphWithFilter { get; set; }
  222. [Browsable(false)]
  223. public string CurrentCheckout { get; private set; }
  224. [Browsable(false)]
  225. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  226. public string FiltredFileName { get; set; }
  227. [Browsable(false)]
  228. public Task<SuperProjectInfo> SuperprojectCurrentCheckout { get; private set; }
  229. [Browsable(false)]
  230. public int LastRowIndex { get; private set; }
  231. [Description("Indicates whether the user is allowed to select more than one commit at a time.")]
  232. [Category("Behavior")]
  233. [DefaultValue(true)]
  234. public bool MultiSelect
  235. {
  236. get { return Revisions.MultiSelect; }
  237. set { Revisions.MultiSelect = value; }
  238. }
  239. [Description("Show uncommited changes in revision grid if enabled in settings.")]
  240. [Category("Behavior")]
  241. [DefaultValue(false)]
  242. public bool ShowUncommitedChangesIfPossible
  243. {
  244. get;
  245. set;
  246. }
  247. [Description("Show build server information in revision grid if enabled in settings.")]
  248. [Category("Behavior")]
  249. [DefaultValue(false)]
  250. public bool ShowBuildServerInfo
  251. {
  252. get;
  253. set;
  254. }
  255. [Description("Do not open the commit info dialog on double click. This is used if the double click event is handled elseswhere.")]
  256. [Category("Behavior")]
  257. [DefaultValue(false)]
  258. public bool DoubleClickDoesNotOpenCommitInfo
  259. {
  260. get;
  261. set;
  262. }
  263. private IndexWatcher _indexWatcher;
  264. [Browsable(false)]
  265. public IndexWatcher IndexWatcher
  266. {
  267. get
  268. {
  269. if (_indexWatcher == null)
  270. _indexWatcher = new IndexWatcher(UICommandsSource);
  271. return _indexWatcher;
  272. }
  273. }
  274. public void SetInitialRevision(GitRevision initialSelectedRevision)
  275. {
  276. _initialSelectedRevision = initialSelectedRevision != null ? initialSelectedRevision.Guid : null;
  277. }
  278. private bool _isLoading;
  279. private void RevisionsLoading(object sender, DvcsGraph.LoadingEventArgs e)
  280. {
  281. // Since this can happen on a background thread, we'll just set a
  282. // flag and deal with it next time we paint (a bit of a hack, but
  283. // it works)
  284. _isLoading = e.IsLoading;
  285. }
  286. private void ShowQuickSearchString()
  287. {
  288. if (_quickSearchLabel == null)
  289. {
  290. _quickSearchLabel
  291. = new Label
  292. {
  293. Location = new Point(10, 10),
  294. BorderStyle = BorderStyle.FixedSingle,
  295. ForeColor = SystemColors.InfoText,
  296. BackColor = SystemColors.Info
  297. };
  298. Controls.Add(_quickSearchLabel);
  299. }
  300. _quickSearchLabel.Visible = true;
  301. _quickSearchLabel.BringToFront();
  302. _quickSearchLabel.Text = _quickSearchString;
  303. _quickSearchLabel.AutoSize = true;
  304. }
  305. private void HideQuickSearchString()
  306. {
  307. if (_quickSearchLabel != null)
  308. _quickSearchLabel.Visible = false;
  309. }
  310. private void QuickSearchTimerTick(object sender, EventArgs e)
  311. {
  312. quickSearchTimer.Stop();
  313. _quickSearchString = "";
  314. HideQuickSearchString();
  315. }
  316. private void RestartQuickSearchTimer()
  317. {
  318. quickSearchTimer.Stop();
  319. quickSearchTimer.Interval = AppSettings.RevisionGridQuickSearchTimeout;
  320. quickSearchTimer.Start();
  321. }
  322. private void RevisionsKeyPress(object sender, KeyPressEventArgs e)
  323. {
  324. var curIndex = -1;
  325. if (Revisions.SelectedRows.Count > 0)
  326. curIndex = Revisions.SelectedRows[0].Index;
  327. curIndex = curIndex >= 0 ? curIndex : 0;
  328. if (e.KeyChar == 8 && _quickSearchString.Length > 1) //backspace
  329. {
  330. RestartQuickSearchTimer();
  331. _quickSearchString = _quickSearchString.Substring(0, _quickSearchString.Length - 1);
  332. FindNextMatch(curIndex, _quickSearchString, false);
  333. _lastQuickSearchString = _quickSearchString;
  334. e.Handled = true;
  335. ShowQuickSearchString();
  336. }
  337. else if (!char.IsControl(e.KeyChar))
  338. {
  339. RestartQuickSearchTimer();
  340. //The code below is meant to fix the weird keyvalues when pressing keys e.g. ".".
  341. _quickSearchString = string.Concat(_quickSearchString, char.ToLower(e.KeyChar));
  342. FindNextMatch(curIndex, _quickSearchString, false);
  343. _lastQuickSearchString = _quickSearchString;
  344. e.Handled = true;
  345. ShowQuickSearchString();
  346. }
  347. else
  348. {
  349. _quickSearchString = "";
  350. HideQuickSearchString();
  351. e.Handled = false;
  352. }
  353. }
  354. private void RevisionsKeyDown(object sender, KeyEventArgs e)
  355. {
  356. // BrowserBack/BrowserForward keys and additional handling for Alt+Right/Left sent by some keyboards
  357. if ((e.KeyCode == Keys.BrowserBack) || ((e.KeyCode == Keys.Left) && (e.Modifiers.HasFlag(Keys.Alt))))
  358. {
  359. NavigateBackward();
  360. }
  361. else if ((e.KeyCode == Keys.BrowserForward) || ((e.KeyCode == Keys.Right) && (e.Modifiers.HasFlag(Keys.Alt))))
  362. {
  363. NavigateForward();
  364. }
  365. }
  366. private void RevisionsMouseDown(object sender, MouseEventArgs e)
  367. {
  368. if (e.Button == MouseButtons.XButton1)
  369. {
  370. NavigateBackward();
  371. }
  372. else if (e.Button == MouseButtons.XButton2)
  373. {
  374. NavigateForward();
  375. }
  376. }
  377. public void ResetNavigationHistory()
  378. {
  379. var selectedRevisions = GetSelectedRevisions();
  380. if (selectedRevisions.Count == 1)
  381. {
  382. _navigationHistory.Push(selectedRevisions[0].Guid);
  383. }
  384. else
  385. {
  386. _navigationHistory.Clear();
  387. }
  388. }
  389. public void NavigateBackward()
  390. {
  391. if (_navigationHistory.CanNavigateBackward)
  392. {
  393. InternalSetSelectedRevision(_navigationHistory.NavigateBackward());
  394. }
  395. }
  396. public void NavigateForward()
  397. {
  398. if (_navigationHistory.CanNavigateForward)
  399. {
  400. InternalSetSelectedRevision(_navigationHistory.NavigateForward());
  401. }
  402. }
  403. private void FindNextMatch(int startIndex, string searchString, bool reverse)
  404. {
  405. if (Revisions.RowCount == 0)
  406. return;
  407. int? searchResult;
  408. if (reverse)
  409. searchResult = SearchInReverseOrder(startIndex, searchString);
  410. else
  411. searchResult = SearchForward(startIndex, searchString);
  412. if (!searchResult.HasValue)
  413. return;
  414. Revisions.ClearSelection();
  415. Revisions.Rows[searchResult.Value].Selected = true;
  416. Revisions.CurrentCell = Revisions.Rows[searchResult.Value].Cells[1];
  417. }
  418. private int? SearchForward(int startIndex, string searchString)
  419. {
  420. // Check for out of bounds roll over if required
  421. int index;
  422. if (startIndex < 0 || startIndex >= Revisions.RowCount)
  423. startIndex = 0;
  424. for (index = startIndex; index < Revisions.RowCount; ++index)
  425. {
  426. if (GetRevision(index).MatchesSearchString(searchString))
  427. return index;
  428. }
  429. // We didn't find it so start searching from the top
  430. for (index = 0; index < startIndex; ++index)
  431. {
  432. if (GetRevision(index).MatchesSearchString(searchString))
  433. return index;
  434. }
  435. return null;
  436. }
  437. private int? SearchInReverseOrder(int startIndex, string searchString)
  438. {
  439. // Check for out of bounds roll over if required
  440. int index;
  441. if (startIndex < 0 || startIndex >= Revisions.RowCount)
  442. startIndex = Revisions.RowCount - 1;
  443. for (index = startIndex; index >= 0; --index)
  444. {
  445. if (GetRevision(index).MatchesSearchString(searchString))
  446. return index;
  447. }
  448. // We didn't find it so start searching from the bottom
  449. for (index = Revisions.RowCount - 1; index > startIndex; --index)
  450. {
  451. if (GetRevision(index).MatchesSearchString(searchString))
  452. return index;
  453. }
  454. return null;
  455. }
  456. public void DisableContextMenu()
  457. {
  458. Revisions.ContextMenuStrip = null;
  459. }
  460. public void FormatQuickFilter(string filter,
  461. bool[] parameters,
  462. out string revListArgs,
  463. out string inMemMessageFilter,
  464. out string inMemCommitterFilter,
  465. out string inMemAuthorFilter)
  466. {
  467. revListArgs = string.Empty;
  468. inMemMessageFilter = string.Empty;
  469. inMemCommitterFilter = string.Empty;
  470. inMemAuthorFilter = string.Empty;
  471. if (!string.IsNullOrEmpty(filter))
  472. {
  473. // hash filtering only possible in memory
  474. var cmdLineSafe = GitCommandHelpers.VersionInUse.IsRegExStringCmdPassable(filter);
  475. revListArgs = " --regexp-ignore-case ";
  476. if (parameters[0])
  477. if (cmdLineSafe && !MessageFilterCouldBeSHA(filter))
  478. revListArgs += "--grep=\"" + filter + "\" ";
  479. else
  480. inMemMessageFilter = filter;
  481. if (parameters[1] && !filter.IsNullOrWhiteSpace())
  482. if (cmdLineSafe)
  483. revListArgs += "--committer=\"" + filter + "\" ";
  484. else
  485. inMemCommitterFilter = filter;
  486. if (parameters[2] && !filter.IsNullOrWhiteSpace())
  487. if (cmdLineSafe)
  488. revListArgs += "--author=\"" + filter + "\" ";
  489. else
  490. inMemAuthorFilter = filter;
  491. if (parameters[3])
  492. if (cmdLineSafe)
  493. revListArgs += "\"-S" + filter + "\" ";
  494. else
  495. throw new InvalidOperationException("Filter text not valid for \"Diff contains\" filter.");
  496. }
  497. }
  498. public bool SetAndApplyBranchFilter(string filter)
  499. {
  500. if (filter.Equals(_revisionFilter.GetBranchFilter()))
  501. return false;
  502. if (filter.Equals(""))
  503. {
  504. AppSettings.BranchFilterEnabled = false;
  505. AppSettings.ShowCurrentBranchOnly = true;
  506. }
  507. else
  508. {
  509. AppSettings.BranchFilterEnabled = true;
  510. AppSettings.ShowCurrentBranchOnly = false;
  511. _revisionFilter.SetBranchFilter(filter);
  512. }
  513. SetShowBranches();
  514. return true;
  515. }
  516. public void SetLimit(int limit)
  517. {
  518. _revisionFilter.SetLimit(limit);
  519. }
  520. public override void Refresh()
  521. {
  522. if (IsDisposed)
  523. return;
  524. SetRevisionsLayout();
  525. base.Refresh();
  526. Revisions.Refresh();
  527. }
  528. protected override void OnCreateControl()
  529. {
  530. base.OnCreateControl();
  531. _isLoading = true;
  532. Error.Visible = false;
  533. NoCommits.Visible = false;
  534. NoGit.Visible = false;
  535. Revisions.Visible = false;
  536. Loading.Visible = true;
  537. Loading.BringToFront();
  538. BuildServerWatcher = new BuildServerWatcher(this, Revisions);
  539. }
  540. public new void Load()
  541. {
  542. if (!DesignMode)
  543. ReloadHotkeys();
  544. ForceRefreshRevisions();
  545. }
  546. public event EventHandler SelectionChanged;
  547. public void SetSelectedIndex(int index)
  548. {
  549. if (Revisions.Rows[index].Selected)
  550. return;
  551. Revisions.ClearSelection();
  552. Revisions.Rows[index].Selected = true;
  553. Revisions.CurrentCell = Revisions.Rows[index].Cells[1];
  554. Revisions.Select();
  555. }
  556. // Selects row containing revision given its revisionId
  557. // Returns whether the required revision was found and selected
  558. private bool InternalSetSelectedRevision(string revision)
  559. {
  560. int index = FindRevisionIndex(revision);
  561. if( index >= 0 )
  562. {
  563. SetSelectedIndex(index);
  564. return true;
  565. }
  566. else
  567. {
  568. Revisions.ClearSelection();
  569. Revisions.Select();
  570. return false;
  571. }
  572. }
  573. /// <summary>
  574. /// Find specified revision in known to the grid revisions
  575. /// </summary>
  576. /// <param name="revision">Revision to lookup</param>
  577. /// <returns>Index of the found revision or -1 if nothing was found</returns>
  578. private int FindRevisionIndex(string revision)
  579. {
  580. int? revIdx = Revisions.TryGetRevisionIndex(revision);
  581. return revIdx.HasValue ? revIdx.Value : -1;
  582. }
  583. public bool SetSelectedRevision(string revision)
  584. {
  585. var found = InternalSetSelectedRevision(revision);
  586. if (found)
  587. {
  588. _navigationHistory.Push(revision);
  589. }
  590. return found;
  591. }
  592. public GitRevision GetRevision(string guid)
  593. {
  594. return Revisions.GetRevision(guid);
  595. }
  596. public bool SetSelectedRevision(GitRevision revision)
  597. {
  598. return SetSelectedRevision(revision != null ? revision.Guid : null);
  599. }
  600. public void HighlightBranch(string aId)
  601. {
  602. RevisionGraphDrawStyle = RevisionGraphDrawStyleEnum.HighlightSelected;
  603. Revisions.HighlightBranch(aId);
  604. }
  605. private void RevisionsSelectionChanged(object sender, EventArgs e)
  606. {
  607. _parentChildNavigationHistory.RevisionsSelectionChanged();
  608. if (Revisions.SelectedRows.Count > 0)
  609. LastRowIndex = Revisions.SelectedRows[0].Index;
  610. SelectionTimer.Enabled = false;
  611. SelectionTimer.Stop();
  612. SelectionTimer.Enabled = true;
  613. SelectionTimer.Start();
  614. var selectedRevisions = GetSelectedRevisions();
  615. var firstSelectedRevision = selectedRevisions.FirstOrDefault();
  616. if (selectedRevisions.Count == 1 && firstSelectedRevision != null)
  617. _navigationHistory.Push(firstSelectedRevision.Guid);
  618. if (this.Parent != null && !Revisions.UpdatingVisibleRows &&
  619. _revisionHighlighting.ProcessRevisionSelectionChange(Module, selectedRevisions) ==
  620. AuthorEmailBasedRevisionHighlighting.SelectionChangeAction.RefreshUserInterface)
  621. {
  622. Refresh();
  623. }
  624. }
  625. public RevisionGraphDrawStyleEnum RevisionGraphDrawStyle
  626. {
  627. get
  628. {
  629. return Revisions.RevisionGraphDrawStyle;
  630. }
  631. set
  632. {
  633. Revisions.RevisionGraphDrawStyle = value;
  634. }
  635. }
  636. public List<GitRevision> GetSelectedRevisions()
  637. {
  638. return GetSelectedRevisions(null);
  639. }
  640. public List<GitRevision> GetSelectedRevisions(SortDirection? direction)
  641. {
  642. var rows = Revisions
  643. .SelectedRows
  644. .Cast<DataGridViewRow>()
  645. .Where(row => Revisions.RowCount > row.Index);
  646. if (direction.HasValue)
  647. {
  648. int d = direction.Value == SortDirection.Ascending ? 1 : -1;
  649. rows = rows.OrderBy((row) => row.Index, (r1, r2) => d * (r1 - r2));
  650. }
  651. return rows
  652. .Select(row => GetRevision(row.Index))
  653. .ToList();
  654. }
  655. public List<string> GetRevisionChildren(string revision)
  656. {
  657. return Revisions.GetRevisionChildren(revision);
  658. }
  659. public GitRevision GetRevision(int aRow)
  660. {
  661. return Revisions.GetRowData(aRow);
  662. }
  663. public GitRevision GetCurrentRevision()
  664. {
  665. var revision = Module.GetRevision(CurrentCheckout, true);
  666. var refs = Module.GetRefs(true, true);
  667. foreach (var gitRef in refs)
  668. {
  669. if (gitRef.Guid.Equals(revision.Guid))
  670. {
  671. revision.Refs.Add(gitRef);
  672. }
  673. }
  674. return revision;
  675. }
  676. public void RefreshRevisions()
  677. {
  678. if (IndexWatcher.IndexChanged)
  679. ForceRefreshRevisions();
  680. }
  681. private class RevisionGraphInMemFilterOr : RevisionGraphInMemFilter
  682. {
  683. private RevisionGraphInMemFilter fFilter1;
  684. private RevisionGraphInMemFilter fFilter2;
  685. public RevisionGraphInMemFilterOr(RevisionGraphInMemFilter aFilter1,
  686. RevisionGraphInMemFilter aFilter2)
  687. {
  688. fFilter1 = aFilter1;
  689. fFilter2 = aFilter2;
  690. }
  691. public override bool PassThru(GitRevision rev)
  692. {
  693. return fFilter1.PassThru(rev) || fFilter2.PassThru(rev);
  694. }
  695. }
  696. private class RevisionGridInMemFilter : RevisionGraphInMemFilter
  697. {
  698. private readonly string _AuthorFilter;
  699. private readonly Regex _AuthorFilterRegex;
  700. private readonly string _CommitterFilter;
  701. private readonly Regex _CommitterFilterRegex;
  702. private readonly string _MessageFilter;
  703. private readonly Regex _MessageFilterRegex;
  704. private readonly string _ShaFilter;
  705. private readonly Regex _ShaFilterRegex;
  706. public RevisionGridInMemFilter(string authorFilter, string committerFilter, string messageFilter, bool ignoreCase)
  707. {
  708. SetUpVars(authorFilter, ref _AuthorFilter, ref _AuthorFilterRegex, ignoreCase);
  709. SetUpVars(committerFilter, ref _CommitterFilter, ref _CommitterFilterRegex, ignoreCase);
  710. SetUpVars(messageFilter, ref _MessageFilter, ref _MessageFilterRegex, ignoreCase);
  711. if (!string.IsNullOrEmpty(_MessageFilter) && MessageFilterCouldBeSHA(_MessageFilter))
  712. {
  713. SetUpVars(messageFilter, ref _ShaFilter, ref _ShaFilterRegex, false);
  714. }
  715. }
  716. private static void SetUpVars(string filterValue,
  717. ref string filterStr,
  718. ref Regex filterRegEx,
  719. bool ignoreCase)
  720. {
  721. RegexOptions opts = RegexOptions.None;
  722. if (ignoreCase) opts = opts | RegexOptions.IgnoreCase;
  723. filterStr = filterValue != null ? filterValue.Trim() : string.Empty;
  724. try
  725. {
  726. filterRegEx = new Regex(filterStr, opts);
  727. }
  728. catch (ArgumentException)
  729. {
  730. filterRegEx = null;
  731. }
  732. }
  733. private static bool CheckCondition(string filter, Regex regex, string value)
  734. {
  735. return string.IsNullOrEmpty(filter) ||
  736. ((regex != null) && (value != null) && regex.Match(value).Success);
  737. }
  738. public override bool PassThru(GitRevision rev)
  739. {
  740. return CheckCondition(_AuthorFilter, _AuthorFilterRegex, rev.Author) &&
  741. CheckCondition(_CommitterFilter, _CommitterFilterRegex, rev.Committer) &&
  742. (CheckCondition(_MessageFilter, _MessageFilterRegex, rev.Body) ||
  743. CheckCondition(_ShaFilter, _ShaFilterRegex, rev.Guid));
  744. }
  745. public static RevisionGridInMemFilter CreateIfNeeded(string authorFilter,
  746. string committerFilter,
  747. string messageFilter,
  748. bool ignoreCase)
  749. {
  750. if (!(string.IsNullOrEmpty(authorFilter) &&
  751. string.IsNullOrEmpty(committerFilter) &&
  752. string.IsNullOrEmpty(messageFilter) &&
  753. !MessageFilterCouldBeSHA(messageFilter)))
  754. return new RevisionGridInMemFilter(authorFilter,
  755. committerFilter,
  756. messageFilter,
  757. ignoreCase);
  758. else
  759. return null;
  760. }
  761. }
  762. public void ReloadHotkeys()
  763. {
  764. this.Hotkeys = HotkeySettingsManager.LoadHotkeys(HotkeySettingsName);
  765. _revisionGridMenuCommands.CreateOrUpdateMenuCommands();
  766. }
  767. public void ReloadTranslation()
  768. {
  769. Translate();
  770. }
  771. public bool ShowRemoteRef(IGitRef r)
  772. {
  773. if (r.IsTag)
  774. return AppSettings.ShowSuperprojectTags;
  775. if (r.IsHead)
  776. return AppSettings.ShowSuperprojectBranches;
  777. if (r.IsRemote)
  778. return AppSettings.ShowSuperprojectRemoteBranches;
  779. return false;
  780. }
  781. [Browsable(false)]
  782. public Task<bool> UnstagedChanges { get; private set; }
  783. [Browsable(false)]
  784. public Task<bool> StagedChanges { get; private set; }
  785. private string _filtredCurrentCheckout;
  786. public void ForceRefreshRevisions()
  787. {
  788. try
  789. {
  790. RevisionGraphDrawStyle = RevisionGraphDrawStyleEnum.DrawNonRelativesGray;
  791. IsMessageMultilineDataGridViewColumn.Visible = AppSettings.ShowIndicatorForMultilineMessage;
  792. ApplyFilterFromRevisionFilterDialog();
  793. _initialLoad = true;
  794. BuildServerWatcher.CancelBuildStatusFetchOperation();
  795. DisposeRevisionGraphCommand();
  796. var newCurrentCheckout = Module.GetCurrentCheckout();
  797. Task<SuperProjectInfo> newSuperPrjectInfo =
  798. Task.Factory.StartNew(() => GetSuperprojectCheckout(ShowRemoteRef));
  799. newSuperPrjectInfo.ContinueWith((task) => Refresh(),
  800. TaskScheduler.FromCurrentSynchronizationContext());
  801. //Only check for tracked files. This usually makes more sense and it performs a lot
  802. //better then checking for untracked files.
  803. // TODO: Check FiltredFileName
  804. Task<bool> unstagedChanges =
  805. Task.Factory.StartNew(() => Module.GetUnstagedFiles().Any());
  806. Task<bool> stagedChanges =
  807. Task.Factory.StartNew(() => Module.GetStagedFiles().Any());
  808. // If the current checkout changed, don't get the currently selected rows, select the
  809. // new current checkout instead.
  810. if (newCurrentCheckout == CurrentCheckout)
  811. {
  812. LastSelectedRows = Revisions.SelectedIds;
  813. }
  814. else
  815. {
  816. // This is a new checkout, so ensure the variable is cleared out.
  817. LastSelectedRows = null;
  818. }
  819. Revisions.ClearSelection();
  820. CurrentCheckout = newCurrentCheckout;
  821. _filtredCurrentCheckout = null;
  822. _currentCheckoutParents = null;
  823. SuperprojectCurrentCheckout = newSuperPrjectInfo;
  824. UnstagedChanges = unstagedChanges;
  825. StagedChanges = stagedChanges;
  826. Revisions.Clear();
  827. Error.Visible = false;
  828. if (!Module.IsValidGitWorkingDir())
  829. {
  830. Revisions.Visible = false;
  831. NoCommits.Visible = true;
  832. Loading.Visible = false;
  833. NoGit.Visible = true;
  834. string dir = Module.WorkingDir;
  835. if (String.IsNullOrEmpty(dir) || !Directory.Exists(dir) ||
  836. Directory.GetDirectories(dir).Length == 0 &&
  837. Directory.GetFiles(dir).Length == 0)
  838. CloneRepository.Show();
  839. else
  840. CloneRepository.Hide();
  841. NoGit.BringToFront();
  842. return;
  843. }
  844. NoCommits.Visible = false;
  845. NoGit.Visible = false;
  846. Revisions.Visible = true;
  847. Revisions.BringToFront();
  848. Revisions.Enabled = false;
  849. Loading.Visible = true;
  850. Loading.BringToFront();
  851. _isLoading = true;
  852. base.Refresh();
  853. IndexWatcher.Reset();
  854. if (!AppSettings.ShowGitNotes && (_refsOptions & (RefsFiltringOptions.All | RefsFiltringOptions.Boundary)) == (RefsFiltringOptions.All | RefsFiltringOptions.Boundary))
  855. _refsOptions |= RefsFiltringOptions.ShowGitNotes;
  856. if (AppSettings.ShowGitNotes)
  857. _refsOptions &= ~RefsFiltringOptions.ShowGitNotes;
  858. if (!AppSettings.ShowMergeCommits)
  859. _refsOptions |= RefsFiltringOptions.NoMerges;
  860. if (AppSettings.ShowFirstParent)
  861. _refsOptions |= RefsFiltringOptions.FirstParent;
  862. if (AppSettings.ShowSimplifyByDecoration)
  863. _refsOptions |= RefsFiltringOptions.SimplifyByDecoration;
  864. RevisionGridInMemFilter revisionFilterIMF = RevisionGridInMemFilter.CreateIfNeeded(_revisionFilter.GetInMemAuthorFilter(),
  865. _revisionFilter.GetInMemCommitterFilter(),
  866. _revisionFilter.GetInMemMessageFilter(),
  867. _revisionFilter.GetIgnoreCase());
  868. RevisionGridInMemFilter filterBarIMF = RevisionGridInMemFilter.CreateIfNeeded(InMemAuthorFilter,
  869. InMemCommitterFilter,
  870. InMemMessageFilter,
  871. InMemFilterIgnoreCase);
  872. RevisionGraphInMemFilter revGraphIMF;
  873. if (revisionFilterIMF != null && filterBarIMF != null)
  874. revGraphIMF = new RevisionGraphInMemFilterOr(revisionFilterIMF, filterBarIMF);
  875. else if (revisionFilterIMF != null)
  876. revGraphIMF = revisionFilterIMF;
  877. else
  878. revGraphIMF = filterBarIMF;
  879. _revisionGraphCommand = new RevisionGraph(Module) {
  880. BranchFilter = BranchFilter,
  881. RefsOptions = _refsOptions,
  882. RevisionFilter = _revisionFilter.GetRevisionFilter() + QuickRevisionFilter + FixedRevisionFilter,
  883. PathFilter = _revisionFilter.GetPathFilter() + FixedPathFilter,
  884. };
  885. _revisionGraphCommand.Updated += GitGetCommitsCommandUpdated;
  886. _revisionGraphCommand.Exited += GitGetCommitsCommandExited;
  887. _revisionGraphCommand.Error += _revisionGraphCommand_Error;
  888. _revisionGraphCommand.InMemFilter = revGraphIMF;
  889. _revisionGraphCommand.Execute();
  890. LoadRevisions();
  891. SetRevisionsLayout();
  892. ResetNavigationHistory();
  893. }
  894. catch (Exception)
  895. {
  896. Error.Visible = true;
  897. Error.BringToFront();
  898. throw;
  899. }
  900. }
  901. public class SuperProjectInfo
  902. {
  903. public string CurrentBranch;
  904. public string Conflict_Base;
  905. public string Conflict_Remote;
  906. public string Conflict_Local;
  907. public Dictionary<string, List<IGitRef>> Refs;
  908. }
  909. private SuperProjectInfo GetSuperprojectCheckout(Func<IGitRef, bool> showRemoteRef)
  910. {
  911. if (Module.SuperprojectModule == null)
  912. return null;
  913. SuperProjectInfo spi = new SuperProjectInfo();
  914. var currentCheckout = Module.GetSuperprojectCurrentCheckout();
  915. if (currentCheckout.Key == 'U')
  916. {
  917. // return local and remote hashes
  918. var array = Module.SuperprojectModule.GetConflict(Module.SubmodulePath);
  919. spi.Conflict_Base = array.Base.Hash;
  920. spi.Conflict_Local = array.Local.Hash;
  921. spi.Conflict_Remote = array.Remote.Hash;
  922. }
  923. else
  924. {
  925. spi.CurrentBranch = currentCheckout.Value;
  926. }
  927. var refs = Module.SuperprojectModule.GetSubmoduleItemsForEachRef(Module.SubmodulePath, showRemoteRef);
  928. if (refs != null)
  929. {
  930. spi.Refs = refs.Where(a => a.Value != null).GroupBy(a => a.Value.Guid).ToDictionary(gr => gr.Key, gr => gr.Select(a => a.Key).ToList());
  931. }
  932. return spi;
  933. }
  934. private static readonly Regex PotentialShaPattern = new Regex(@"^[a-f0-9]{5,}", RegexOptions.Compiled);
  935. public static bool MessageFilterCouldBeSHA(string filter)
  936. {
  937. bool result = PotentialShaPattern.IsMatch(filter);
  938. return result;
  939. }
  940. private void _revisionGraphCommand_Error(object sender, AsyncErrorEventArgs e)
  941. {
  942. // This has to happen on the UI thread
  943. this.InvokeAsync(o =>
  944. {
  945. Error.Visible = true;
  946. //Error.BringToFront();
  947. NoGit.Visible = false;
  948. NoCommits.Visible = false;
  949. Revisions.Visible = false;
  950. Loading.Visible = false;
  951. }, this);
  952. DisposeRevisionGraphCommand();
  953. this.InvokeAsync(() =>
  954. {
  955. throw e.Exception;
  956. }
  957. );
  958. e.Handled = true;
  959. }
  960. private void GitGetCommitsCommandUpdated(object sender, EventArgs e)
  961. {
  962. var updatedEvent = (RevisionGraph.RevisionGraphUpdatedEventArgs)e;
  963. UpdateGraph(updatedEvent.Revision);
  964. }
  965. internal bool FilterIsApplied(bool inclBranchFilter)
  966. {
  967. return (inclBranchFilter && !string.IsNullOrEmpty(BranchFilter)) ||
  968. !(string.IsNullOrEmpty(QuickRevisionFilter) &&
  969. !_revisionFilter.FilterEnabled() &&
  970. string.IsNullOrEmpty(InMemAuthorFilter) &&
  971. string.IsNullOrEmpty(InMemCommitterFilter) &&
  972. string.IsNullOrEmpty(InMemMessageFilter));
  973. }
  974. private bool ShouldHideGraph(bool inclBranchFilter)
  975. {
  976. return (inclBranchFilter && !string.IsNullOrEmpty(BranchFilter)) ||
  977. !(!_revisionFilter.ShouldHideGraph() &&
  978. string.IsNullOrEmpty(InMemAuthorFilter) &&
  979. string.IsNullOrEmpty(InMemCommitterFilter) &&
  980. string.IsNullOrEmpty(InMemMessageFilter));
  981. }
  982. private void DisposeRevisionGraphCommand()
  983. {
  984. if (_revisionGraphCommand != null)
  985. {
  986. LatestRefs = _revisionGraphCommand.LatestRefs();
  987. //Dispose command, it is not needed anymore
  988. _revisionGraphCommand.Updated -= GitGetCommitsCommandUpdated;
  989. _revisionGraphCommand.Exited -= GitGetCommitsCommandExited;
  990. _revisionGraphCommand.Error -= _revisionGraphCommand_Error;
  991. _revisionGraphCommand.Dispose();
  992. _revisionGraphCommand = null;
  993. }
  994. }
  995. private void GitGetCommitsCommandExited(object sender, EventArgs e)
  996. {
  997. _isLoading = false;
  998. if (_revisionGraphCommand.RevisionCount == 0 &&
  999. !FilterIsApplied(true))
  1000. {
  1001. // This has to happen on the UI thread
  1002. this.InvokeAsync(o =>
  1003. {
  1004. NoGit.Visible = false;
  1005. NoCommits.Visible = true;
  1006. //NoCommits.BringToFront();
  1007. Revisions.Visible = false;
  1008. Loading.Visible = false;
  1009. }, this);
  1010. }
  1011. else
  1012. {
  1013. // This has to happen on the UI thread
  1014. this.InvokeAsync(o =>
  1015. {
  1016. UpdateGraph(null);
  1017. Loading.Visible = false;
  1018. SelectInitialRevision();
  1019. _isLoading = false;
  1020. if (ShowBuildServerInfo)
  1021. BuildServerWatcher.LaunchBuildServerInfoFetchOperation();
  1022. }, this);
  1023. }
  1024. DisposeRevisionGraphCommand();
  1025. }
  1026. private void SelectInitialRevision()
  1027. {
  1028. string filtredCurrentCheckout = _filtredCurrentCheckout;
  1029. string[] lastSelectedRows = LastSelectedRows ?? new string[0];
  1030. //filter out all unavailable commits from LastSelectedRows.
  1031. lastSelectedRows = lastSelectedRows.Where(revision => FindRevisionIndex(revision) >= 0).ToArray();
  1032. if (lastSelectedRows.Any())
  1033. {
  1034. Revisions.SelectedIds = lastSelectedRows;
  1035. LastSelectedRows = null;
  1036. }
  1037. else
  1038. {
  1039. if (!string.IsNullOrEmpty(_initialSelectedRevision))
  1040. {
  1041. int index = SearchRevision(_initialSelectedRevision);
  1042. if (index >= 0)
  1043. SetSelectedIndex(index);
  1044. }
  1045. else
  1046. {
  1047. SetSelectedRevision(filtredCurrentCheckout);
  1048. }
  1049. }
  1050. if (string.IsNullOrEmpty(filtredCurrentCheckout))
  1051. return;
  1052. if (!Revisions.IsRevisionRelative(filtredCurrentCheckout))
  1053. {
  1054. HighlightBranch(filtredCurrentCheckout);
  1055. }
  1056. }
  1057. private string[] GetAllParents(string initRevision)
  1058. {
  1059. var revListParams = "rev-list ";
  1060. if (AppSettings.OrderRevisionByDate)
  1061. revListParams += "--date-order ";
  1062. else
  1063. revListParams += "--topo-order ";
  1064. if (AppSettings.MaxRevisionGraphCommits > 0)
  1065. revListParams += string.Format("--max-count=\"{0}\" ", (int)AppSettings.MaxRevisionGraphCommits);
  1066. return Module.ReadGitOutputLines(revListParams + initRevision).ToArray();
  1067. }
  1068. private int SearchRevision(string initRevision)
  1069. {
  1070. var exactIndex = Revisions.TryGetRevisionIndex(initRevision);
  1071. if (exactIndex.HasValue)
  1072. return exactIndex.Value;
  1073. foreach (var parentHash in GetAllParents(initRevision))
  1074. {
  1075. var parentIndex = Revisions.TryGetRevisionIndex(parentHash);
  1076. if (parentIndex.HasValue)
  1077. return parentIndex.Value;
  1078. }
  1079. return -1;
  1080. }
  1081. private static string GetDateHeaderText()
  1082. {
  1083. return AppSettings.ShowAuthorDate ? Strings.GetAuthorDateText() : Strings.GetCommitDateText();
  1084. }
  1085. private void LoadRevisions()
  1086. {
  1087. if (_revisionGraphCommand == null)
  1088. {
  1089. return;
  1090. }
  1091. Revisions.SuspendLayout();
  1092. Revisions.MessageColumn.HeaderText = Strings.GetMessageText();
  1093. Revisions.AuthorColumn.HeaderText = Strings.GetAuthorText();
  1094. Revisions.DateColumn.HeaderText = GetDateHeaderText();
  1095. Revisions.SelectionChanged -= RevisionsSelectionChanged;
  1096. Revisions.Enabled = true;
  1097. Revisions.Focus();
  1098. Revisions.SelectionChanged += RevisionsSelectionChanged;
  1099. Revisions.ResumeLayout();
  1100. if (!_initialLoad)
  1101. return;
  1102. _initialLoad = false;
  1103. SelectionTimer.Enabled = false;
  1104. SelectionTimer.Stop();
  1105. SelectionTimer.Enabled = true;
  1106. SelectionTimer.Start();
  1107. }
  1108. public struct DrawRefArgs
  1109. {
  1110. public Graphics Graphics;
  1111. public Rectangle CellBounds;
  1112. public bool IsRowSelected;
  1113. public Font RefsFont;
  1114. }
  1115. private void RevisionsCellPainting(object sender, DataGridViewCellPaintingEventArgs e)
  1116. {
  1117. // If our loading state has changed since the last paint, update it.
  1118. if (Loading != null)
  1119. {
  1120. if (Loading.Visible != _isLoading)
  1121. {
  1122. Loading.Visible = _isLoading;
  1123. }
  1124. }
  1125. var columnIndex = e.ColumnIndex;
  1126. int graphColIndex = GraphDataGridViewColumn.Index;
  1127. int messageColIndex = MessageDataGridViewColumn.Index;
  1128. int authorColIndex = AuthorDataGridViewColumn.Index;
  1129. int dateColIndex = DateDataGridViewColumn.Index;
  1130. int idColIndex = IdDataGridViewColumn.Index;
  1131. int isMsgMultilineColIndex = IsMessageMultilineDataGridViewColumn.Index;
  1132. // The graph column is handled by the DvcsGraph
  1133. if (e.ColumnIndex == graphColIndex)
  1134. {
  1135. return;
  1136. }
  1137. if (e.RowIndex < 0 || (e.State & DataGridViewElementStates.Visible) == 0)
  1138. return;
  1139. if (Revisions.RowCount <= e.RowIndex)
  1140. return;
  1141. var revision = GetRevision(e.RowIndex);
  1142. if (revision == null)
  1143. return;
  1144. var spi = SuperprojectCurrentCheckout.IsCompleted ? SuperprojectCurrentCheckout.Result : null;
  1145. var superprojectRefs = new List<IGitRef>();
  1146. if (spi != null && spi.Refs != null && spi.Refs.ContainsKey(revision.Guid))
  1147. {
  1148. superprojectRefs.AddRange(spi.Refs[revision.Guid].Where(ShowRemoteRef));
  1149. }
  1150. e.Handled = true;
  1151. var drawRefArgs = new DrawRefArgs();
  1152. drawRefArgs.Graphics = e.Graphics;
  1153. drawRefArgs.CellBounds = e.CellBounds;
  1154. drawRefArgs.IsRowSelected = ((e.State & DataGridViewElementStates.Selected) == DataGridViewElementStates.Selected);
  1155. if (drawRefArgs.IsRowSelected /*&& !showRevisionCards*/)
  1156. {
  1157. e.Graphics.FillRectangle(_selectedItemBrush, e.CellBounds);
  1158. }
  1159. else if (ShouldHighlightRevisionByAuthor(revision))
  1160. {
  1161. e.Graphics.FillRectangle(_authoredRevisionsBrush, e.CellBounds);
  1162. }
  1163. else
  1164. {
  1165. e.Graphics.FillRectangle(Brushes.White, e.CellBounds);
  1166. }
  1167. Color foreColor;
  1168. if (!AppSettings.RevisionGraphDrawNonRelativesTextGray || Revisions.RowIsRelative(e.RowIndex))
  1169. {
  1170. foreColor = drawRefArgs.IsRowSelected && IsFilledBranchesLayout()
  1171. ? SystemColors.HighlightText
  1172. : e.CellStyle.ForeColor;
  1173. }
  1174. else
  1175. {
  1176. foreColor = drawRefArgs.IsRowSelected ? SystemColors.HighlightText : Color.Gray;
  1177. }
  1178. using (Brush foreBrush = new SolidBrush(foreColor))
  1179. {
  1180. var rowFont = NormalFont;
  1181. if (revision.Guid == CurrentCheckout /*&& !showRevisionCards*/)
  1182. rowFont = HeadFont;
  1183. else if (spi != null && spi.CurrentBranch == revision.Guid)
  1184. rowFont = SuperprojectFont;
  1185. if (columnIndex == messageColIndex)
  1186. {
  1187. int baseOffset = 0;
  1188. if (IsCardLayout())
  1189. {
  1190. baseOffset = 5;
  1191. Rectangle cellRectangle = new Rectangle(e.CellBounds.Left + baseOffset, e.CellBounds.Top + 1, e.CellBounds.Width - (baseOffset * 2), e.CellBounds.Height - 4);
  1192. if (!AppSettings.RevisionGraphDrawNonRelativesGray || Revisions.RowIsRelative(e.RowIndex))
  1193. {
  1194. e.Graphics.FillRectangle(
  1195. new LinearGradientBrush(cellRectangle,
  1196. Color.FromArgb(255, 220, 220, 231),
  1197. Color.FromArgb(255, 240, 240, 250), 90, false), cellRectangle);
  1198. using (var pen = new Pen(Color.FromArgb(255, 200, 200, 200), 1))
  1199. {
  1200. e.Graphics.DrawRectangle(pen, cellRectangle);
  1201. }
  1202. }
  1203. else
  1204. {
  1205. e.Graphics.FillRectangle(
  1206. new LinearGradientBrush(cellRectangle,
  1207. Color.FromArgb(255, 240, 240, 240),
  1208. Color.FromArgb(255, 250, 250, 250), 90, false), cellRectangle);
  1209. }
  1210. if ((e.State & DataGridViewElementStates.Selected) == DataGridViewElementStates.Selected)
  1211. {
  1212. using (var penSelectionBackColor = new Pen(Revisions.RowTemplate.DefaultCellStyle.SelectionBackColor, 1))
  1213. e.Graphics.DrawRectangle(penSelectionBackColor, cellRectangle);
  1214. }
  1215. }
  1216. float offset = baseOffset;
  1217. var gitRefs = revision.Refs;
  1218. drawRefArgs.RefsFont = IsFilledBranchesLayout() ? rowFont : RefsFont;
  1219. if (spi != null)
  1220. {
  1221. if (spi.Conflict_Base == revision.Guid)
  1222. offset = DrawRef(drawRefArgs, offset, "Base", Color.OrangeRed, ArrowType.NotFilled);
  1223. if (spi.Conflict_Local == revision.Guid)
  1224. offset = DrawRef(drawRefArgs, offset, "Local", Color.OrangeRed, ArrowType.NotFilled);
  1225. if (spi.Conflict_Remote == revision.Guid)
  1226. offset = DrawRef(drawRefArgs, offset, "Remote", Color.OrangeRed, ArrowType.NotFilled);
  1227. }
  1228. if (gitRefs.Any())
  1229. {
  1230. gitRefs.Sort((left, right) =>
  1231. {
  1232. if (left.IsTag != right.IsTag)
  1233. return right.IsTag.CompareTo(left.IsTag);
  1234. if (left.IsRemote != right.IsRemote)
  1235. return left.IsRemote.CompareTo(right.IsRemote);
  1236. return left.Name.CompareTo(right.Name);
  1237. });
  1238. foreach (var gitRef in gitRefs.Where(head => (!head.IsRemote || AppSettings.ShowRemoteBranches)))
  1239. {
  1240. if (gitRef.IsTag)
  1241. {
  1242. if (!AppSettings.ShowTags)
  1243. {
  1244. continue;
  1245. }
  1246. }
  1247. Color headColor = GetHeadColor(gitRef);
  1248. ArrowType arrowType = gitRef.Selected ? ArrowType.Filled :
  1249. gitRef.SelectedHeadMergeSource ? ArrowType.NotFilled : ArrowType.None;
  1250. var superprojectRef = superprojectRefs.FirstOrDefault(spGitRef => gitRef.CompleteName == spGitRef.CompleteName);
  1251. if (superprojectRef != null)
  1252. superprojectRefs.Remove(superprojectRef);
  1253. string name = gitRef.Name;
  1254. if ( gitRef.IsTag
  1255. && gitRef.IsDereference // see note on using IsDereference in CommitInfo class.
  1256. && AppSettings.ShowAnnotatedTagsMessages
  1257. && AppSettings.ShowIndicatorForMultilineMessage )
  1258. {
  1259. name = name + " " + MultilineMessageIndicator;
  1260. }
  1261. offset = DrawRef(drawRefArgs, offset, name, headColor, arrowType, superprojectRef != null, true);
  1262. }
  1263. }
  1264. for (int i = 0; i < Math.Min(MaxSuperprojectRefs, superprojectRefs.Count); i++)
  1265. {
  1266. var gitRef = superprojectRefs[i];
  1267. Color headColor = GetHeadColor(gitRef);
  1268. var gitRefName = i < (MaxSuperprojectRefs - 1) ? gitRef.Name : "…";
  1269. ArrowType arrowType = gitRef.Selected ? ArrowType.Filled :
  1270. gitRef.SelectedHeadMergeSource ? ArrowType.NotFilled : ArrowType.None;
  1271. offset = DrawRef(drawRefArgs, offset, gitRefName, headColor, arrowType, true, false);
  1272. }
  1273. if (IsCardLayout())
  1274. offset = baseOffset;
  1275. var text = (string)e.FormattedValue;
  1276. var bounds = AdjustCellBounds(e.CellBounds, offset);
  1277. DrawColumnText(e.Graphics, text, rowFont, foreColor, bounds);
  1278. if (IsCardLayout())
  1279. {
  1280. int textHeight = (int)e.Graphics.MeasureString(text, rowFont).Height;
  1281. int gravatarSize = _rowHeigth - textHeight - 12;
  1282. int gravatarTop = e.CellBounds.Top + textHeight + 6;
  1283. int gravatarLeft = e.CellBounds.Left + baseOffset + 2;
  1284. Image gravatar = Gravatar.GravatarService.GetImageFromCache(revision.AuthorEmail + gravatarSize.ToString() + ".png", revision.AuthorEmail, AppSettings.AuthorImageCacheDays, gravatarSize, AppSettings.GravatarCachePath, FallBackService.MonsterId);
  1285. if (gravatar == null && !string.IsNullOrEmpty(revision.AuthorEmail))
  1286. {
  1287. ThreadPool.QueueUserWorkItem(o =>
  1288. Gravatar.GravatarService.LoadCachedImage(revision.AuthorEmail + gravatarSize.ToString() + ".png", revision.AuthorEmail, null, AppSettings.AuthorImageCacheDays, gravatarSize, AppSettings.GravatarCachePath, RefreshGravatar, FallBackService.MonsterId));
  1289. }
  1290. if (gravatar != null)
  1291. e.Graphics.DrawImage(gravatar, gravatarLeft + 1, gravatarTop + 1, gravatarSize, gravatarSize);
  1292. e.Graphics.DrawRectangle(Pens.Black, gravatarLeft, gravatarTop, gravatarSize + 1, gravatarSize + 1);
  1293. string authorText;
  1294. string timeText;
  1295. if (_rowHeigth >= 60)
  1296. {
  1297. authorText = revision.Author;
  1298. timeText = TimeToString(AppSettings.ShowAuthorDate ? revision.AuthorDate : revision.CommitDate);
  1299. }
  1300. else
  1301. {
  1302. timeText = string.Concat(revision.Author, " (", TimeToString(AppSettings.ShowAuthorDate ? revision.AuthorDate : revision.CommitDate), ")");
  1303. authorText = string.Empty;
  1304. }
  1305. e.Graphics.DrawString(authorText, rowFont, foreBrush,
  1306. new PointF(gravatarLeft + gravatarSize + 5, gravatarTop + 6));
  1307. e.Graphics.DrawString(timeText, rowFont, foreBrush,
  1308. new PointF(gravatarLeft + gravatarSize + 5, e.CellBounds.Bottom - textHeight - 4));
  1309. }
  1310. }
  1311. else if (columnIndex == authorColIndex)
  1312. {
  1313. var text = (string)e.FormattedValue;
  1314. e.Graphics.DrawString(text, rowFont, foreBrush,
  1315. new PointF(e.CellBounds.Left, e.CellBounds.Top + 4));
  1316. }
  1317. else if (columnIndex == dateColIndex)
  1318. {
  1319. var time = AppSettings.ShowAuthorDate ? revision.AuthorDate : revision.CommitDate;
  1320. var text = TimeToString(time);
  1321. e.Graphics.DrawString(text, rowFont, foreBrush,
  1322. new PointF(e.CellBounds.Left, e.CellBounds.Top + 4));
  1323. }
  1324. else if (columnIndex == idColIndex)
  1325. {
  1326. if (!revision.IsArtificial())
  1327. {
  1328. var text = revision.Guid;
  1329. e.Graphics.DrawString(text, new Font("Consolas", rowFont.SizeInPoints), foreBrush,
  1330. new PointF(e.CellBounds.Left, e.CellBounds.Top + 4));
  1331. }
  1332. }
  1333. else if (columnIndex == BuildServerWatcher.BuildStatusImageColumnIndex)
  1334. {
  1335. BuildInfoDrawingLogic.BuildStatusImageColumnCellPainting(e, revision, foreBrush, rowFont);
  1336. }
  1337. else if (columnIndex == BuildServerWatcher.BuildStatusMessageColumnIndex)
  1338. {
  1339. BuildInfoDrawingLogic.BuildStatusMessageCellPainting(e, revision, foreBrush, rowFont);
  1340. }
  1341. else if (AppSettings.ShowIndicatorForMultilineMessage && columnIndex == isMsgMultilineColIndex)
  1342. {
  1343. var text = (string)e.FormattedValue;
  1344. e.Graphics.DrawString(text, rowFont, foreBrush,
  1345. new PointF(e.CellBounds.Left, e.CellBounds.Top + 4));
  1346. }
  1347. }
  1348. }
  1349. private bool ShouldHighlightRevisionByAuthor(GitRevision revision)
  1350. {
  1351. return AppSettings.HighlightAuthoredRevisions &&
  1352. AuthorEmailEqualityComparer.Instance.Equals(revision.AuthorEmail,
  1353. _revisionHighlighting.AuthorEmailToHighlight);
  1354. }
  1355. private float DrawRef(DrawRefArgs drawRefArgs, float offset, string name, Color headColor, ArrowType arrowType, bool dashedLine = false, bool fill = false)
  1356. {
  1357. var textColor = fill ? headColor : Lerp(headColor, Color.White, 0.5f);
  1358. if (IsCardLayout())
  1359. {
  1360. using (Brush textBrush = new SolidBrush(textColor))
  1361. {
  1362. string headName = name;
  1363. offset += drawRefArgs.Graphics.MeasureString(headName, drawRefArgs.RefsFont).Width + 6;
  1364. var location = new PointF(drawRefArgs.CellBounds.Right - offset, drawRefArgs.CellBounds.Top + 4);
  1365. var size = new SizeF(drawRefArgs.Graphics.MeasureString(headName, drawRefArgs.RefsFont).Width,
  1366. drawRefArgs.Graphics.MeasureString(headName, drawRefArgs.RefsFont).Height);
  1367. if (fill)
  1368. drawRefArgs.Graphics.FillRectangle(SystemBrushes.Info, location.X - 1,
  1369. location.Y - 1, size.Width + 3, size.Height + 2);
  1370. drawRefArgs.Graphics.DrawRectangle(SystemPens.InfoText, location.X - 1,
  1371. location.Y - 1, size.Width + 3, size.Height + 2);
  1372. drawRefArgs.Graphics.DrawString(headName, drawRefArgs.RefsFont, textBrush, location);
  1373. }
  1374. }
  1375. else
  1376. {
  1377. string headName = IsFilledBranchesLayout()
  1378. ? name
  1379. : string.Concat("[", name, "] ");
  1380. var headBounds = AdjustCellBounds(drawRefArgs.CellBounds, offset);
  1381. SizeF textSize = drawRefArgs.Graphics.MeasureString(headName, drawRefArgs.RefsFont);
  1382. offset += textSize.Width;
  1383. if (IsFilledBranchesLayout())
  1384. {
  1385. offset += 9;
  1386. float extraOffset = DrawHeadBackground(drawRefArgs.IsRowSelected, drawRefArgs.Graphics,
  1387. headColor, headBounds.X,
  1388. headBounds.Y,
  1389. RoundToEven(textSize.Width + 3),
  1390. RoundToEven(textSize.Height), 3,
  1391. arrowType, dashedLine, fill);
  1392. offset += extraOffset;
  1393. headBounds.Offset((int)(extraOffset + 1), 0);
  1394. }
  1395. DrawColumnText(drawRefArgs.Graphics, headName, drawRefArgs.RefsFont, textColor, headBounds);
  1396. }
  1397. return offset;
  1398. }
  1399. private static readonly string MultilineMessageIndicator = "[...]";
  1400. private void RevisionsCellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
  1401. {
  1402. var columnIndex = e.ColumnIndex;
  1403. if (e.RowIndex < 0)
  1404. return;
  1405. if (Revisions.RowCount <= e.RowIndex)
  1406. return;
  1407. var revision = GetRevision(e.RowIndex);
  1408. if (revision == null)
  1409. return;
  1410. e.FormattingApplied = true;
  1411. int graphColIndex = GraphDataGridViewColumn.Index;
  1412. int messageColIndex = MessageDataGridViewColumn.Index;
  1413. int authorColIndex = AuthorDataGridViewColumn.Index;
  1414. int dateColIndex = DateDataGridViewColumn.Index;
  1415. int isMsgMultilineColIndex = IsMessageMultilineDataGridViewColumn.Index;
  1416. if (columnIndex == graphColIndex)
  1417. {
  1418. e.Value = revision.Guid;
  1419. }
  1420. else if (columnIndex == messageColIndex)
  1421. {
  1422. e.Value = revision.Subject;
  1423. }
  1424. else if (columnIndex == authorColIndex)
  1425. {
  1426. e.Value = revision.Author ?? "";
  1427. }
  1428. else if (columnIndex == dateColIndex)
  1429. {
  1430. var time = AppSettings.ShowAuthorDate ? revision.AuthorDate : revision.CommitDate;
  1431. if (time == DateTime.MinValue || time == DateTime.MaxValue)
  1432. e.Value = "";
  1433. else
  1434. e.Value = string.Format("{0} {1}", time.ToShortDateString(), time.ToLongTimeString());
  1435. }
  1436. else if (columnIndex == BuildServerWatcher.BuildStatusImageColumnIndex)
  1437. {
  1438. BuildInfoDrawingLogic.BuildStatusImageColumnCellFormatting(e, Revisions, revision);
  1439. }
  1440. else if (columnIndex == BuildServerWatcher.BuildStatusMessageColumnIndex)
  1441. {
  1442. BuildInfoDrawingLogic.BuildStatusMessageCellFormatting(e, revision);
  1443. }
  1444. else if (AppSettings.ShowIndicatorForMultilineMessage && columnIndex == isMsgMultilineColIndex)
  1445. {
  1446. if (revision.Body == null && !revision.IsArtificial())
  1447. {
  1448. var moduleRef = Module;
  1449. ThreadPool.QueueUserWorkItem(o => LoadIsMultilineMessageInfo(revision, columnIndex, e.RowIndex, Revisions.RowCount, moduleRef));
  1450. }
  1451. if (revision.Body != null)
  1452. {
  1453. e.Value = revision.Body.TrimEnd().Contains("\n") ? MultilineMessageIndicator : "";
  1454. }
  1455. else
  1456. {
  1457. e.Value = "";
  1458. }
  1459. }
  1460. else
  1461. {
  1462. e.FormattingApplied = false;
  1463. }
  1464. }
  1465. /// <summary>
  1466. ///
  1467. /// </summary>
  1468. /// <param name="revision"></param>
  1469. /// <param name="totalRowCount">check if grid has changed while thread is queued</param>
  1470. /// <param name="colIndex"></param>
  1471. /// <param name="rowIndex"></param>
  1472. private void LoadIsMultilineMessageInfo(GitRevision revision, int colIndex, int rowIndex, int totalRowCount, GitModule aModule)
  1473. {
  1474. // code taken from CommitInfo.cs
  1475. CommitData commitData = CommitData.CreateFromRevision(revision);
  1476. string error = "";
  1477. if (revision.Body == null)
  1478. {
  1479. CommitData.UpdateCommitMessage(commitData, aModule, revision.Guid, ref error);
  1480. revision.Body = commitData.Body;
  1481. }
  1482. // now that Body is filled (not null anymore) the revision grid can be refreshed to display the new information
  1483. this.InvokeAsync(() =>
  1484. {
  1485. if (Revisions == null || Revisions.RowCount == 0 || Revisions.RowCount <= rowIndex || Revisions.RowCount != totalRowCount)
  1486. {
  1487. return;
  1488. }
  1489. Revisions.InvalidateCell(colIndex, rowIndex);
  1490. });
  1491. }
  1492. private void DrawColumnText(Graphics gc, string text, Font font, Color color, Rectangle bounds)
  1493. {
  1494. TextRenderer.DrawText(gc, text, font, bounds, color, TextFormatFlags.EndEllipsis | TextFormatFlags.NoPrefix);
  1495. }
  1496. private static Rectangle AdjustCellBounds(Rectangle cellBounds, float offset)
  1497. {
  1498. return new Rectangle((int)(cellBounds.Left + offset), cellBounds.Top + 4,
  1499. cellBounds.Width - (int)offset, cellBounds.Height);
  1500. }
  1501. private static Color GetHeadColor(IGitRef gitRef)
  1502. {
  1503. if (gitRef.IsTag)
  1504. return AppSettings.TagColor;
  1505. if (gitRef.IsHead)
  1506. return AppSettings.BranchColor;
  1507. if (gitRef.IsRemote)
  1508. return AppSettings.RemoteBranchColor;
  1509. return AppSettings.OtherTagColor;
  1510. }
  1511. private float RoundToEven(float value)
  1512. {
  1513. int result = ((int)value / 2) * 2;
  1514. return result < value ? result + 2 : result;
  1515. }
  1516. enum ArrowType
  1517. {
  1518. None,
  1519. Filled,
  1520. NotFilled
  1521. }
  1522. static readonly float[] dashPattern = new float[] { 4, 4 };
  1523. private float DrawHeadBackground(bool isSelected, Graphics graphics, Color color,
  1524. float x, float y, float width, float height, float radius, ArrowType arrowType, bool dashedLine, bool fill)
  1525. {
  1526. float additionalOffset = arrowType != ArrowType.None ? GetArrowSize(height) : 0;
  1527. width += additionalOffset;
  1528. var oldMode = graphics.SmoothingMode;
  1529. graphics.SmoothingMode = SmoothingMode.AntiAlias;
  1530. try
  1531. {
  1532. // shade
  1533. if (fill)
  1534. using (var shadePath = CreateRoundRectPath(x + 1, y + 1, width, height, radius))
  1535. {
  1536. var shadeBrush = isSelected ? Brushes.Black : Brushes.Gray;
  1537. graphics.FillPath(shadeBrush, shadePath);
  1538. }
  1539. using (var forePath = CreateRoundRectPath(x, y, width, height, radius))
  1540. {
  1541. Color fillColor = Lerp(color, Color.White, 0.92F);
  1542. if (fill)
  1543. using (var fillBrush = new LinearGradientBrush(new RectangleF(x, y, width, height), fillColor, Lerp(fillColor, Color.White, 0.9F), 90))
  1544. graphics.FillPath(fillBrush, forePath);
  1545. else if (isSelected)
  1546. graphics.FillPath(Brushes.White, forePath);
  1547. // frame
  1548. using (var pen = new Pen(Lerp(color, Color.White, 0.83F)))
  1549. {
  1550. if (dashedLine)
  1551. pen.DashPattern = dashPattern;
  1552. graphics.DrawPath(pen, forePath);
  1553. }
  1554. // arrow if the head is the current branch
  1555. if (arrowType != ArrowType.None)
  1556. DrawArrow(graphics, x, y, height, color, arrowType == ArrowType.Filled);
  1557. }
  1558. }
  1559. finally
  1560. {
  1561. graphics.SmoothingMode = oldMode;
  1562. }
  1563. return additionalOffset;
  1564. }
  1565. private float GetArrowSize(float rowHeight)
  1566. {
  1567. return rowHeight - 6;
  1568. }
  1569. private void DrawArrow(Graphics graphics, float x, float y, float rowHeight, Color color, bool filled)
  1570. {
  1571. const float horShift = 4;
  1572. const float verShift = 3;
  1573. float height = rowHeight - verShift * 2;
  1574. float width = height / 2;
  1575. var points = new[]
  1576. {
  1577. new PointF(x + horShift, y + verShift),
  1578. new PointF(x + horShift + width, y + verShift + height/2),
  1579. new PointF(x + horShift, y + verShift + height),
  1580. new PointF(x + horShift, y + verShift)
  1581. };
  1582. if (filled)
  1583. {
  1584. using (var solidBrush = new SolidBrush(color))
  1585. graphics.FillPolygon(solidBrush, points);
  1586. }
  1587. else
  1588. {
  1589. using (var pen = new Pen(color))
  1590. graphics.DrawPolygon(pen, points);
  1591. }
  1592. }
  1593. private static GraphicsPath CreateRoundRectPath(float x, float y, float width, float height, float radius)
  1594. {
  1595. var path = new GraphicsPath();
  1596. path.AddLine(x + radius, y, x + width - (radius * 2), y);
  1597. path.AddArc(x + width - (radius * 2), y, radius * 2, radius * 2, 270, 90);
  1598. path.AddLine(x + width, y + radius, x + width, y + height - (radius * 2));
  1599. path.AddArc(x + width - (radius * 2), y + height - (radius * 2), radius * 2, radius * 2, 0, 90);
  1600. path.AddLine(x + width - (radius * 2), y + height, x + radius, y + height);
  1601. path.AddArc(x, y + height - (radius * 2), radius * 2, radius * 2, 90, 90);
  1602. path.AddLine(x, y + height - (radius * 2), x, y + radius);
  1603. path.AddArc(x, y, radius * 2, radius * 2, 180, 90);
  1604. path.CloseFigure();
  1605. return path;
  1606. }
  1607. private static float Lerp(float start, float end, float amount)
  1608. {
  1609. float difference = end - start;
  1610. float adjusted = difference * amount;
  1611. return start + adjusted;
  1612. }
  1613. private static Color Lerp(Color colour, Color to, float amount)
  1614. {
  1615. // start colours as lerp-able floats
  1616. float sr = colour.R, sg = colour.G, sb = colour.B;
  1617. // end colours as lerp-able floats
  1618. float er = to.R, eg = to.G, eb = to.B;
  1619. // lerp the colours to get the difference
  1620. byte r = (byte)Lerp(sr, er, amount),
  1621. g = (byte)Lerp(sg, eg, amount),
  1622. b = (byte)Lerp(sb, eb, amount);
  1623. // return the new colour
  1624. return Color.FromArgb(r, g, b);
  1625. }
  1626. private void RefreshGravatar(Image image)
  1627. {
  1628. this.InvokeAsync(Revisions.Refresh);
  1629. }
  1630. private void RevisionsDoubleClick(object sender, MouseEventArgs e)
  1631. {
  1632. if (e.Button != MouseButtons.Left)
  1633. return;
  1634. if (DoubleClickRevision != null)
  1635. {
  1636. var selectedRevisions = GetSelectedRevisions();
  1637. DoubleClickRevision(this, new DoubleClickRevisionEventArgs(selectedRevisions.FirstOrDefault()));
  1638. }
  1639. if (!DoubleClickDoesNotOpenCommitInfo)
  1640. {
  1641. ViewSelectedRevisions();
  1642. }
  1643. }
  1644. public void ViewSelectedRevisions()
  1645. {
  1646. var selectedRevisions = GetSelectedRevisions();
  1647. if (selectedRevisions.Any(rev => !GitRevision.IsArtificial(rev.Guid)))
  1648. {
  1649. using (var form = new FormCommitDiff(UICommands, selectedRevisions[0].Guid))
  1650. {
  1651. form.ShowDialog(this);
  1652. }
  1653. }
  1654. else if (!selectedRevisions.Any())
  1655. {
  1656. UICommands.StartCompareRevisionsDialog(this);
  1657. }
  1658. }
  1659. private void SelectionTimerTick(object sender, EventArgs e)
  1660. {
  1661. SelectionTimer.Enabled = false;
  1662. SelectionTimer.Stop();
  1663. if (SelectionChanged != null)
  1664. SelectionChanged(this, e);
  1665. }
  1666. private void CreateTagToolStripMenuItemClick(object sender, EventArgs e)
  1667. {
  1668. if (Revisions.RowCount <= LastRowIndex || LastRowIndex < 0)
  1669. return;
  1670. using (var frm = new FormCreateTag(UICommands, GetRevision(LastRowIndex)))
  1671. {
  1672. if (frm.ShowDialog(this) == DialogResult.OK)
  1673. {
  1674. RefreshRevisions();
  1675. }
  1676. }
  1677. }
  1678. private void ResetCurrentBranchToHereToolStripMenuItemClick(object sender, EventArgs e)
  1679. {
  1680. if (Revisions.RowCount <= LastRowIndex || LastRowIndex < 0)
  1681. return;
  1682. var frm = new FormResetCurrentBranch(UICommands, GetRevision(LastRowIndex));
  1683. frm.ShowDialog(this);
  1684. }
  1685. private void CreateNewBranchToolStripMenuItemClick(object sender, EventArgs e)
  1686. {
  1687. if (Revisions.RowCount <= LastRowIndex || LastRowIndex < 0)
  1688. return;
  1689. UICommands.DoActionOnRepo(() =>
  1690. {
  1691. var frm = new FormCreateBranch(UICommands, GetRevision(LastRowIndex));
  1692. return frm.ShowDialog(this) == DialogResult.OK;
  1693. });
  1694. }
  1695. private void RevisionsMouseClick(object sender, MouseEventArgs e)
  1696. {
  1697. var pt = Revisions.PointToClient(Cursor.Position);
  1698. var hti = Revisions.HitTest(pt.X, pt.Y);
  1699. LastRowIndex = hti.RowIndex;
  1700. }
  1701. private void RevisionsCellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
  1702. {
  1703. if (e.Button != MouseButtons.Right)
  1704. return;
  1705. var pt = Revisions.PointToClient(Cursor.Position);
  1706. var hti = Revisions.HitTest(pt.X, pt.Y);
  1707. if (LastRowIndex == hti.RowIndex)
  1708. return;
  1709. LastRowIndex = hti.RowIndex;
  1710. Revisions.ClearSelection();
  1711. if (LastRowIndex >= 0 && Revisions.Rows.Count > LastRowIndex)
  1712. Revisions.Rows[LastRowIndex].Selected = true;
  1713. }
  1714. private void CommitClick(object sender, EventArgs e)
  1715. {
  1716. UICommands.StartCommitDialog(this);
  1717. }
  1718. private void GitIgnoreClick(object sender, EventArgs e)
  1719. {
  1720. UICommands.StartEditGitIgnoreDialog(this);
  1721. }
  1722. internal void InvalidateRevisions()
  1723. {
  1724. Revisions.Invalidate();
  1725. }
  1726. // internal because used by RevisonGridMenuCommands
  1727. internal void ShowCurrentBranchOnly_ToolStripMenuItemClick(object sender, EventArgs e)
  1728. {
  1729. if (_showCurrentBranchOnlyToolStripMenuItemChecked)
  1730. return;
  1731. AppSettings.BranchFilterEnabled = true;
  1732. AppSettings.ShowCurrentBranchOnly = true;
  1733. SetShowBranches();
  1734. ForceRefreshRevisions();
  1735. }
  1736. // internal because used by RevisonGridMenuCommands
  1737. internal void ShowAllBranches_ToolStripMenuItemClick(object sender, EventArgs e)
  1738. {
  1739. if (_showAllBranchesToolStripMenuItemChecked)
  1740. return;
  1741. AppSettings.BranchFilterEnabled = false;
  1742. SetShowBranches();
  1743. ForceRefreshRevisions();
  1744. }
  1745. // internal because used by RevisonGridMenuCommands
  1746. internal void ShowFilteredBranches_ToolStripMenuItemClick(object sender, EventArgs e)
  1747. {
  1748. if (_showFilteredBranchesToolStripMenuItemChecked)
  1749. return;
  1750. AppSettings.BranchFilterEnabled = true;
  1751. AppSettings.ShowCurrentBranchOnly = false;
  1752. SetShowBranches();
  1753. ForceRefreshRevisions();
  1754. }
  1755. internal bool ShowCurrentBranchOnly_ToolStripMenuItemChecked { get { return _showCurrentBranchOnlyToolStripMenuItemChecked; } }
  1756. internal bool ShowAllBranches_ToolStripMenuItemChecked { get { return _showAllBranchesToolStripMenuItemChecked; } }
  1757. internal bool ShowFilteredBranches_ToolStripMenuItemChecked { get { return _showFilteredBranchesToolStripMenuItemChecked; } }
  1758. private void SetShowBranches()
  1759. {
  1760. _showAllBranchesToolStripMenuItemChecked = !AppSettings.BranchFilterEnabled;
  1761. _showCurrentBranchOnlyToolStripMenuItemChecked =
  1762. AppSettings.BranchFilterEnabled && AppSettings.ShowCurrentBranchOnly;
  1763. _showFilteredBranchesToolStripMenuItemChecked =
  1764. AppSettings.BranchFilterEnabled && !AppSettings.ShowCurrentBranchOnly;
  1765. BranchFilter = _revisionFilter.GetBranchFilter();
  1766. if (!AppSettings.BranchFilterEnabled)
  1767. _refsOptions = RefsFiltringOptions.All | RefsFiltringOptions.Boundary;
  1768. else if (AppSettings.ShowCurrentBranchOnly)
  1769. _refsOptions = 0;
  1770. else
  1771. _refsOptions = BranchFilter.Length > 0
  1772. ? 0
  1773. : RefsFiltringOptions.All | RefsFiltringOptions.Boundary;
  1774. _revisionGridMenuCommands.TriggerMenuChanged(); // apply checkboxes changes also to FormBrowse main menu
  1775. }
  1776. private void RevertCommitToolStripMenuItemClick(object sender, EventArgs e)
  1777. {
  1778. if (Revisions.RowCount <= LastRowIndex || LastRowIndex < 0)
  1779. return;
  1780. UICommands.StartRevertCommitDialog(this, GetRevision(LastRowIndex));
  1781. }
  1782. internal void FilterToolStripMenuItemClick(object sender, EventArgs e)
  1783. {
  1784. _revisionFilter.ShowDialog(this);
  1785. ForceRefreshRevisions();
  1786. }
  1787. private void ApplyFilterFromRevisionFilterDialog()
  1788. {
  1789. BranchFilter = _revisionFilter.GetBranchFilter();
  1790. SetShowBranches();
  1791. }
  1792. private void ContextMenuOpening(object sender, CancelEventArgs e)
  1793. {
  1794. if (Revisions.RowCount < LastRowIndex || LastRowIndex < 0 || Revisions.RowCount == 0)
  1795. return;
  1796. var inTheMiddleOfBisect = Module.InTheMiddleOfBisect();
  1797. markRevisionAsBadToolStripMenuItem.Visible = inTheMiddleOfBisect;
  1798. markRevisionAsGoodToolStripMenuItem.Visible = inTheMiddleOfBisect;
  1799. bisectSkipRevisionToolStripMenuItem.Visible = inTheMiddleOfBisect;
  1800. stopBisectToolStripMenuItem.Visible = inTheMiddleOfBisect;
  1801. bisectSeparator.Visible = inTheMiddleOfBisect;
  1802. compareWithCurrentBranchToolStripMenuItem.Visible = Module.GetSelectedBranch().IsNotNullOrWhitespace();
  1803. var revision = GetRevision(LastRowIndex);
  1804. var deleteTagDropDown = new ContextMenuStrip();
  1805. var deleteBranchDropDown = new ContextMenuStrip();
  1806. var checkoutBranchDropDown = new ContextMenuStrip();
  1807. var mergeBranchDropDown = new ContextMenuStrip();
  1808. var rebaseDropDown = new ContextMenuStrip();
  1809. var renameDropDown = new ContextMenuStrip();
  1810. var gitRefListsForRevision = new GitRefListsForRevision(revision);
  1811. ISet<string> ambiguosuRefs = GitRef.GetAmbiguousRefNames(LatestRefs);
  1812. Func<IGitRef, string> getRefUnambiguousName = (IGitRef gitRef) =>
  1813. {
  1814. if (ambiguosuRefs.Contains(gitRef.Name))
  1815. {
  1816. return gitRef.CompleteName;
  1817. }
  1818. return gitRef.Name;
  1819. };
  1820. foreach (var head in gitRefListsForRevision.AllTags)
  1821. {
  1822. ToolStripItem toolStripItem = new ToolStripMenuItem(head.Name);
  1823. toolStripItem.Tag = head.Name;
  1824. toolStripItem.Click += ToolStripItemClickDeleteTag;
  1825. deleteTagDropDown.Items.Add(toolStripItem);
  1826. toolStripItem = new ToolStripMenuItem(head.Name);
  1827. toolStripItem.Tag = getRefUnambiguousName(head);
  1828. toolStripItem.Click += ToolStripItemClickMergeBranch;
  1829. mergeBranchDropDown.Items.Add(toolStripItem);
  1830. }
  1831. //For now there is no action that could be done on currentBranch
  1832. bool bareRepository = Module.IsBareRepository();
  1833. string currentBranch = Module.GetSelectedBranch();
  1834. var allBranches = gitRefListsForRevision.AllBranches;
  1835. var branchesWithNoIdenticalRemotes = gitRefListsForRevision.BranchesWithNoIdenticalRemotes;
  1836. bool currentBranchPointsToRevision = false;
  1837. foreach (var head in branchesWithNoIdenticalRemotes)
  1838. {
  1839. if (head.Name.Equals(currentBranch))
  1840. currentBranchPointsToRevision = true;
  1841. else
  1842. {
  1843. ToolStripItem toolStripItem = new ToolStripMenuItem(head.Name);
  1844. toolStripItem.Tag = getRefUnambiguousName(head);
  1845. toolStripItem.Click += ToolStripItemClickMergeBranch;
  1846. mergeBranchDropDown.Items.Add(toolStripItem);
  1847. toolStripItem = new ToolStripMenuItem(head.Name);
  1848. toolStripItem.Tag = getRefUnambiguousName(head);
  1849. toolStripItem.Click += ToolStripItemClickRebaseBranch;
  1850. rebaseDropDown.Items.Add(toolStripItem);
  1851. }
  1852. }
  1853. //if there is no branch to rebase on, then allow user to rebase on selected commit
  1854. if (rebaseDropDown.Items.Count == 0 && !currentBranchPointsToRevision)
  1855. {
  1856. ToolStripItem toolStripItem = new ToolStripMenuItem(revision.Guid);
  1857. toolStripItem.Tag = revision.Guid;
  1858. toolStripItem.Click += ToolStripItemClickRebaseBranch;
  1859. rebaseDropDown.Items.Add(toolStripItem);
  1860. }
  1861. //if there is no branch to merge, then let user to merge selected commit into current branch
  1862. if (mergeBranchDropDown.Items.Count == 0 && !currentBranchPointsToRevision)
  1863. {
  1864. ToolStripItem toolStripItem = new ToolStripMenuItem(revision.Guid);
  1865. toolStripItem.Tag = revision.Guid;
  1866. toolStripItem.Click += ToolStripItemClickMergeBranch;
  1867. mergeBranchDropDown.Items.Add(toolStripItem);
  1868. }
  1869. // clipboard branch and tag menu handling
  1870. {
  1871. branchNameCopyToolStripMenuItem.Tag = "caption";
  1872. tagNameCopyToolStripMenuItem.Tag = "caption";
  1873. MenuUtil.SetAsCaptionMenuItem(branchNameCopyToolStripMenuItem, mainContextMenu);
  1874. MenuUtil.SetAsCaptionMenuItem(tagNameCopyToolStripMenuItem, mainContextMenu);
  1875. var branchNames = gitRefListsForRevision.GetAllBranchNames();
  1876. CopyToClipboardMenuHelper.SetCopyToClipboardMenuItems(
  1877. copyToClipboardToolStripMenuItem, branchNameCopyToolStripMenuItem, branchNames, "branchNameItem");
  1878. var tagNames = gitRefListsForRevision.GetAllTagNames();
  1879. CopyToClipboardMenuHelper.SetCopyToClipboardMenuItems(
  1880. copyToClipboardToolStripMenuItem, tagNameCopyToolStripMenuItem, tagNames, "tagNameItem");
  1881. toolStripSeparator6.Visible = branchNames.Any() || tagNames.Any();
  1882. }
  1883. foreach (var head in allBranches)
  1884. {
  1885. ToolStripItem toolStripItem = new ToolStripMenuItem(head.Name);
  1886. //skip remote branches - they can not be deleted this way
  1887. if (!head.IsRemote)
  1888. {
  1889. if (!head.Name.Equals(currentBranch))
  1890. {
  1891. toolStripItem = new ToolStripMenuItem(head.Name);
  1892. toolStripItem.Tag = head.Name;
  1893. toolStripItem.Click += ToolStripItemClickDeleteBranch;
  1894. deleteBranchDropDown.Items.Add(toolStripItem); //Add to delete branch
  1895. }
  1896. toolStripItem = new ToolStripMenuItem(head.Name);
  1897. toolStripItem.Tag = head.Name;
  1898. toolStripItem.Click += ToolStripItemClickRenameBranch;
  1899. renameDropDown.Items.Add(toolStripItem); //Add to rename branch
  1900. }
  1901. if (!head.Name.Equals(currentBranch))
  1902. {
  1903. toolStripItem = new ToolStripMenuItem(head.Name);
  1904. if (head.IsRemote)
  1905. toolStripItem.Click += ToolStripItemClickCheckoutRemoteBranch;
  1906. else
  1907. toolStripItem.Click += ToolStripItemClickCheckoutBranch;
  1908. checkoutBranchDropDown.Items.Add(toolStripItem);
  1909. }
  1910. }
  1911. deleteTagToolStripMenuItem.DropDown = deleteTagDropDown;
  1912. deleteTagToolStripMenuItem.Enabled = deleteTagDropDown.Items.Count > 0;
  1913. deleteBranchToolStripMenuItem.DropDown = deleteBranchDropDown;
  1914. deleteBranchToolStripMenuItem.Enabled = deleteBranchDropDown.Items.Count > 0;
  1915. checkoutBranchToolStripMenuItem.DropDown = checkoutBranchDropDown;
  1916. checkoutBranchToolStripMenuItem.Enabled = !bareRepository && checkoutBranchDropDown.Items.Count > 0;
  1917. mergeBranchToolStripMenuItem.DropDown = mergeBranchDropDown;
  1918. mergeBranchToolStripMenuItem.Enabled = !bareRepository && mergeBranchDropDown.Items.Count > 0;
  1919. rebaseOnToolStripMenuItem.DropDown = rebaseDropDown;
  1920. rebaseOnToolStripMenuItem.Enabled = !bareRepository && rebaseDropDown.Items.Count > 0;
  1921. renameBranchToolStripMenuItem.DropDown = renameDropDown;
  1922. renameBranchToolStripMenuItem.Enabled = renameDropDown.Items.Count > 0;
  1923. checkoutRevisionToolStripMenuItem.Enabled = !bareRepository;
  1924. revertCommitToolStripMenuItem.Enabled = !bareRepository;
  1925. cherryPickCommitToolStripMenuItem.Enabled = !bareRepository;
  1926. manipulateCommitToolStripMenuItem.Enabled = !bareRepository;
  1927. toolStripSeparator6.Enabled = branchNameCopyToolStripMenuItem.Enabled || tagNameCopyToolStripMenuItem.Enabled;
  1928. RefreshOwnScripts();
  1929. }
  1930. private void ToolStripItemClickDeleteTag(object sender, EventArgs e)
  1931. {
  1932. var toolStripItem = sender as ToolStripItem;
  1933. if (toolStripItem == null)
  1934. return;
  1935. UICommands.StartDeleteTagDialog(this, toolStripItem.Tag as string);
  1936. }
  1937. private void ToolStripItemClickDeleteBranch(object sender, EventArgs e)
  1938. {
  1939. var toolStripItem = sender as ToolStripItem;
  1940. if (toolStripItem == null)
  1941. return;
  1942. UICommands.StartDeleteBranchDialog(this, toolStripItem.Tag as string);
  1943. }
  1944. private void ToolStripItemClickCheckoutBranch(object sender, EventArgs e)
  1945. {
  1946. var toolStripItem = sender as ToolStripItem;
  1947. if (toolStripItem == null)
  1948. return;
  1949. string branch = toolStripItem.Text;
  1950. UICommands.StartCheckoutBranch(this, branch, false);
  1951. }
  1952. private void ToolStripItemClickCheckoutRemoteBranch(object sender, EventArgs e)
  1953. {
  1954. var toolStripItem = sender as ToolStripItem;
  1955. if (toolStripItem == null)
  1956. return;
  1957. UICommands.StartCheckoutRemoteBranch(this, toolStripItem.Text);
  1958. }
  1959. private void ToolStripItemClickMergeBranch(object sender, EventArgs e)
  1960. {
  1961. var toolStripItem = sender as ToolStripItem;
  1962. if (toolStripItem == null)
  1963. return;
  1964. UICommands.StartMergeBranchDialog(this, toolStripItem.Tag as string);
  1965. }
  1966. private void ToolStripItemClickRebaseBranch(object sender, EventArgs e)
  1967. {
  1968. var toolStripItem = sender as ToolStripItem;
  1969. if (toolStripItem == null)
  1970. return;
  1971. UICommands.StartRebaseDialog(this, toolStripItem.Tag as string);
  1972. }
  1973. private void ToolStripItemClickRenameBranch(object sender, EventArgs e)
  1974. {
  1975. var toolStripItem = sender as ToolStripItem;
  1976. if (toolStripItem == null)
  1977. return;
  1978. UICommands.StartRenameDialog(this, toolStripItem.Tag as string);
  1979. }
  1980. private void CheckoutRevisionToolStripMenuItemClick(object sender, EventArgs e)
  1981. {
  1982. if (Revisions.RowCount <= LastRowIndex || LastRowIndex < 0)
  1983. return;
  1984. string revision = GetRevision(LastRowIndex).Guid;
  1985. UICommands.StartCheckoutRevisionDialog(this, revision);
  1986. }
  1987. private void ArchiveRevisionToolStripMenuItemClick(object sender, EventArgs e)
  1988. {
  1989. var selectedRevisions = GetSelectedRevisions();
  1990. if (selectedRevisions.Count > 2)
  1991. {
  1992. MessageBox.Show(this, "Select only one or two revisions. Abort.", "Archive revision");
  1993. return;
  1994. }
  1995. GitRevision mainRevision = selectedRevisions.First();
  1996. GitRevision diffRevision = null;
  1997. if (selectedRevisions.Count == 2)
  1998. diffRevision = selectedRevisions.Last();
  1999. UICommands.StartArchiveDialog(this, mainRevision, diffRevision);
  2000. }
  2001. internal void ShowAuthorDate_ToolStripMenuItemClick(object sender, EventArgs e)
  2002. {
  2003. AppSettings.ShowAuthorDate = !AppSettings.ShowAuthorDate;
  2004. ForceRefreshRevisions();
  2005. }
  2006. internal void OrderRevisionsByDate_ToolStripMenuItemClick(object sender, EventArgs e)
  2007. {
  2008. AppSettings.OrderRevisionByDate = !AppSettings.OrderRevisionByDate;
  2009. ForceRefreshRevisions();
  2010. }
  2011. internal void ShowRemoteBranches_ToolStripMenuItemClick(object sender, EventArgs e)
  2012. {
  2013. AppSettings.ShowRemoteBranches = !AppSettings.ShowRemoteBranches;
  2014. InvalidateRevisions();
  2015. }
  2016. internal void ShowSuperprojectTags_ToolStripMenuItemClick(object sender, EventArgs e)
  2017. {
  2018. AppSettings.ShowSuperprojectTags = !AppSettings.ShowSuperprojectTags;
  2019. ForceRefreshRevisions();
  2020. }
  2021. internal void ShowSuperprojectBranches_ToolStripMenuItemClick(object sender, EventArgs e)
  2022. {
  2023. AppSettings.ShowSuperprojectBranches = !AppSettings.ShowSuperprojectBranches;
  2024. ForceRefreshRevisions();
  2025. }
  2026. internal void ShowSuperprojectRemoteBranches_ToolStripMenuItemClick(object sender, EventArgs e)
  2027. {
  2028. AppSettings.ShowSuperprojectRemoteBranches = !AppSettings.ShowSuperprojectRemoteBranches;
  2029. ForceRefreshRevisions();
  2030. }
  2031. private void CherryPickCommitToolStripMenuItemClick(object sender, EventArgs e)
  2032. {
  2033. var revisions = GetSelectedRevisions(SortDirection.Descending);
  2034. UICommands.StartCherryPickDialog(this, revisions);
  2035. }
  2036. private void FixupCommitToolStripMenuItemClick(object sender, EventArgs e)
  2037. {
  2038. if (Revisions.RowCount <= LastRowIndex || LastRowIndex < 0)
  2039. return;
  2040. UICommands.StartFixupCommitDialog(this, GetRevision(LastRowIndex));
  2041. }
  2042. private void SquashCommitToolStripMenuItemClick(object sender, EventArgs e)
  2043. {
  2044. if (Revisions.RowCount <= LastRowIndex || LastRowIndex < 0)
  2045. return;
  2046. UICommands.StartSquashCommitDialog(this, GetRevision(LastRowIndex));
  2047. }
  2048. internal void ShowRelativeDate_ToolStripMenuItemClick(object sender, EventArgs e)
  2049. {
  2050. AppSettings.RelativeDate = !AppSettings.RelativeDate;
  2051. ForceRefreshRevisions();
  2052. }
  2053. private string TimeToString(DateTime time)
  2054. {
  2055. if (time == DateTime.MinValue || time == DateTime.MaxValue)
  2056. return "";
  2057. if (!AppSettings.RelativeDate)
  2058. return string.Format("{0} {1}", time.ToShortDateString(), time.ToLongTimeString());
  2059. return LocalizationHelpers.GetRelativeDateString(DateTime.Now, time, false);
  2060. }
  2061. private bool ShowUncommitedChanges()
  2062. {
  2063. return ShowUncommitedChangesIfPossible && AppSettings.RevisionGraphShowWorkingDirChanges;
  2064. }
  2065. private string[] _currentCheckoutParents;
  2066. private void UpdateGraph(GitRevision rev)
  2067. {
  2068. if (rev == null)
  2069. {
  2070. // Prune the graph and make sure the row count matches reality
  2071. Revisions.Prune();
  2072. return;
  2073. }
  2074. if (_filtredCurrentCheckout == null)
  2075. {
  2076. if (rev.Guid == CurrentCheckout)
  2077. {
  2078. _filtredCurrentCheckout = CurrentCheckout;
  2079. }
  2080. else
  2081. {
  2082. if (_currentCheckoutParents == null)
  2083. {
  2084. _currentCheckoutParents = GetAllParents(CurrentCheckout);
  2085. }
  2086. _filtredCurrentCheckout = _currentCheckoutParents.FirstOrDefault(parent => parent == rev.Guid);
  2087. }
  2088. }
  2089. string filtredCurrentCheckout = _filtredCurrentCheckout;
  2090. if (filtredCurrentCheckout == rev.Guid && ShowUncommitedChanges())
  2091. {
  2092. CheckUncommitedChanged( filtredCurrentCheckout );
  2093. }
  2094. var dataType = DvcsGraph.DataType.Normal;
  2095. if (rev.Guid == filtredCurrentCheckout)
  2096. dataType = DvcsGraph.DataType.Active;
  2097. else if (rev.Refs.Any())
  2098. dataType = DvcsGraph.DataType.Special;
  2099. Revisions.Add(rev.Guid, rev.ParentGuids, dataType, rev);
  2100. }
  2101. private void CheckUncommitedChanged(string filtredCurrentCheckout)
  2102. {
  2103. if (UnstagedChanges.Result)
  2104. {
  2105. //Add working directory as virtual commit
  2106. var workingDir = new GitRevision(Module, GitRevision.UnstagedGuid)
  2107. {
  2108. Subject = Strings.GetCurrentUnstagedChanges(),
  2109. ParentGuids =
  2110. StagedChanges.Result
  2111. ? new[] { GitRevision.IndexGuid }
  2112. : new[] { filtredCurrentCheckout }
  2113. };
  2114. Revisions.Add(workingDir.Guid, workingDir.ParentGuids, DvcsGraph.DataType.Normal, workingDir);
  2115. }
  2116. if (StagedChanges.Result)
  2117. {
  2118. //Add index as virtual commit
  2119. var index = new GitRevision(Module, GitRevision.IndexGuid)
  2120. {
  2121. Subject = Strings.GetCurrentIndex(),
  2122. ParentGuids = new[] { filtredCurrentCheckout }
  2123. };
  2124. Revisions.Add(index.Guid, index.ParentGuids, DvcsGraph.DataType.Normal, index);
  2125. }
  2126. }
  2127. internal void DrawNonrelativesGray_ToolStripMenuItemClick(object sender, EventArgs e)
  2128. {
  2129. AppSettings.RevisionGraphDrawNonRelativesGray = !AppSettings.RevisionGraphDrawNonRelativesGray;
  2130. _revisionGridMenuCommands.TriggerMenuChanged();
  2131. Revisions.Refresh();
  2132. }
  2133. private void MessageToolStripMenuItemClick(object sender, EventArgs e)
  2134. {
  2135. Clipboard.SetText(GetRevision(LastRowIndex).Subject);
  2136. }
  2137. private void AuthorToolStripMenuItemClick(object sender, EventArgs e)
  2138. {
  2139. Clipboard.SetText(GetRevision(LastRowIndex).Author);
  2140. }
  2141. private void DateToolStripMenuItemClick(object sender, EventArgs e)
  2142. {
  2143. Clipboard.SetText(GetRevision(LastRowIndex).CommitDate.ToString());
  2144. }
  2145. private void HashToolStripMenuItemClick(object sender, EventArgs e)
  2146. {
  2147. Clipboard.SetText(GetRevision(LastRowIndex).Guid);
  2148. }
  2149. private void MarkRevisionAsBadToolStripMenuItemClick(object sender, EventArgs e)
  2150. {
  2151. ContinueBisect(GitBisectOption.Bad);
  2152. }
  2153. private void MarkRevisionAsGoodToolStripMenuItemClick(object sender, EventArgs e)
  2154. {
  2155. ContinueBisect(GitBisectOption.Good);
  2156. }
  2157. private void BisectSkipRevisionToolStripMenuItemClick(object sender, EventArgs e)
  2158. {
  2159. ContinueBisect(GitBisectOption.Skip);
  2160. }
  2161. private void ContinueBisect(GitBisectOption bisectOption)
  2162. {
  2163. if (Revisions.RowCount <= LastRowIndex || LastRowIndex < 0)
  2164. return;
  2165. FormProcess.ShowDialog(this, Module, GitCommandHelpers.ContinueBisectCmd(bisectOption, GetRevision(LastRowIndex).Guid), false);
  2166. RefreshRevisions();
  2167. }
  2168. private void StopBisectToolStripMenuItemClick(object sender, EventArgs e)
  2169. {
  2170. FormProcess.ShowDialog(this, Module, GitCommandHelpers.StopBisectCmd());
  2171. RefreshRevisions();
  2172. }
  2173. private void RefreshOwnScripts()
  2174. {
  2175. RemoveOwnScripts();
  2176. AddOwnScripts();
  2177. }
  2178. private void AddOwnScripts()
  2179. {
  2180. IList<ScriptInfo> scripts = ScriptManager.GetScripts();
  2181. if (scripts == null)
  2182. return;
  2183. int lastIndex = mainContextMenu.Items.Count;
  2184. foreach (ScriptInfo scriptInfo in scripts)
  2185. {
  2186. if (scriptInfo.Enabled)
  2187. {
  2188. ToolStripItem item = new ToolStripMenuItem(scriptInfo.Name);
  2189. item.Name = item.Text + "_ownScript";
  2190. item.Click += RunScript;
  2191. if (scriptInfo.AddToRevisionGridContextMenu)
  2192. mainContextMenu.Items.Add(item);
  2193. else
  2194. runScriptToolStripMenuItem.DropDown.Items.Add(item);
  2195. }
  2196. }
  2197. if (lastIndex != mainContextMenu.Items.Count)
  2198. mainContextMenu.Items.Insert(lastIndex, new ToolStripSeparator());
  2199. bool showScriptsMenu = runScriptToolStripMenuItem.DropDown.Items.Count > 0;
  2200. runScriptToolStripMenuItem.Visible = showScriptsMenu;
  2201. }
  2202. private void RemoveOwnScripts()
  2203. {
  2204. runScriptToolStripMenuItem.DropDown.Items.Clear();
  2205. List<ToolStripItem> list = new List<ToolStripItem>();
  2206. foreach (ToolStripItem item in mainContextMenu.Items)
  2207. list.Add(item);
  2208. foreach (ToolStripItem item in list)
  2209. if (item.Name.Contains("_ownScript"))
  2210. mainContextMenu.Items.RemoveByKey(item.Name);
  2211. if (mainContextMenu.Items[mainContextMenu.Items.Count - 1] is ToolStripSeparator)
  2212. mainContextMenu.Items.RemoveAt(mainContextMenu.Items.Count - 1);
  2213. }
  2214. private bool _settingsLoaded;
  2215. private void RunScript(object sender, EventArgs e)
  2216. {
  2217. if (_settingsLoaded == false)
  2218. {
  2219. new FormSettings(UICommands).LoadSettings();
  2220. _settingsLoaded = true;
  2221. }
  2222. if (ScriptRunner.RunScript(this, Module, sender.ToString(), this))
  2223. RefreshRevisions();
  2224. }
  2225. #region Drag/drop patch files on revision grid
  2226. void Revisions_DragDrop(object sender, DragEventArgs e)
  2227. {
  2228. var fileNameArray = e.Data.GetData(DataFormats.FileDrop) as Array;
  2229. if (fileNameArray != null)
  2230. {
  2231. if (fileNameArray.Length > 10)
  2232. {
  2233. //Some users need to be protected against themselves!
  2234. MessageBox.Show(this, _droppingFilesBlocked.Text);
  2235. return;
  2236. }
  2237. foreach (object fileNameObject in fileNameArray)
  2238. {
  2239. var fileName = fileNameObject as string;
  2240. if (!string.IsNullOrEmpty(fileName) && fileName.EndsWith(".patch", StringComparison.InvariantCultureIgnoreCase))
  2241. {
  2242. //Start apply patch dialog for each dropped patch file...
  2243. UICommands.StartApplyPatchDialog(this, fileName);
  2244. }
  2245. }
  2246. }
  2247. }
  2248. static void Revisions_DragEnter(object sender, DragEventArgs e)
  2249. {
  2250. var fileNameArray = e.Data.GetData(DataFormats.FileDrop) as Array;
  2251. if (fileNameArray != null)
  2252. {
  2253. foreach (object fileNameObject in fileNameArray)
  2254. {
  2255. var fileName = fileNameObject as string;
  2256. if (!string.IsNullOrEmpty(fileName) && fileName.EndsWith(".patch", StringComparison.InvariantCultureIgnoreCase))
  2257. {
  2258. //Allow drop (copy, not move) patch files
  2259. e.Effect = DragDropEffects.Copy;
  2260. }
  2261. else
  2262. {
  2263. //When a non-patch file is dragged, do not allow it
  2264. e.Effect = DragDropEffects.None;
  2265. return;
  2266. }
  2267. }
  2268. }
  2269. }
  2270. #endregion
  2271. internal void ShowGitNotes_ToolStripMenuItemClick(object sender, EventArgs e)
  2272. {
  2273. AppSettings.ShowGitNotes = !AppSettings.ShowGitNotes;
  2274. ForceRefreshRevisions();
  2275. }
  2276. internal void ShowMergeCommits_ToolStripMenuItemClick(object sender, EventArgs e)
  2277. {
  2278. AppSettings.ShowMergeCommits = !showMergeCommitsToolStripMenuItem.Checked;
  2279. showMergeCommitsToolStripMenuItem.Checked = AppSettings.ShowMergeCommits;
  2280. // hide revision graph when hiding merge commits, reasons:
  2281. // 1, revison graph is no longer relevant, as we are not sohwing all commits
  2282. // 2, performance hit when both revision graph and no merge commits are enabled
  2283. if (IsGraphLayout() && !AppSettings.ShowMergeCommits)
  2284. {
  2285. ToggleRevisionGraph();
  2286. SetRevisionsLayout();
  2287. }
  2288. ForceRefreshRevisions();
  2289. }
  2290. internal void ShowFirstParent_ToolStripMenuItemClick(object sender, EventArgs e)
  2291. {
  2292. AppSettings.ShowFirstParent = !AppSettings.ShowFirstParent;
  2293. var handler = ShowFirstParentsToggled;
  2294. if (handler != null)
  2295. handler(this, e);
  2296. ForceRefreshRevisions();
  2297. }
  2298. public void OnModuleChanged(object sender, GitModuleEventArgs e)
  2299. {
  2300. var handler = GitModuleChanged;
  2301. if (handler != null)
  2302. handler(this, e);
  2303. }
  2304. private void InitRepository_Click(object sender, EventArgs e)
  2305. {
  2306. UICommands.StartInitializeDialog(this, Module.WorkingDir, OnModuleChanged);
  2307. }
  2308. private void CloneRepository_Click(object sender, EventArgs e)
  2309. {
  2310. if (UICommands.StartCloneDialog(this, null, OnModuleChanged))
  2311. ForceRefreshRevisions();
  2312. }
  2313. internal void ShowRevisionGraph_ToolStripMenuItemClick(object sender, EventArgs e)
  2314. {
  2315. ToggleRevisionGraph();
  2316. SetRevisionsLayout();
  2317. _revisionGridMenuCommands.TriggerMenuChanged();
  2318. // must show MergeCommits when showing revision graph
  2319. if (!AppSettings.ShowMergeCommits && IsGraphLayout())
  2320. {
  2321. AppSettings.ShowMergeCommits = true;
  2322. showMergeCommitsToolStripMenuItem.Checked = true;
  2323. ForceRefreshRevisions();
  2324. }
  2325. else
  2326. Refresh();
  2327. }
  2328. private void ToggleRevisionGraph()
  2329. {
  2330. if (AppSettings.RevisionGraphLayout == (int)RevisionGridLayout.Small)
  2331. AppSettings.RevisionGraphLayout = (int)RevisionGridLayout.SmallWithGraph;
  2332. else if (AppSettings.RevisionGraphLayout == (int)RevisionGridLayout.Card)
  2333. AppSettings.RevisionGraphLayout = (int)RevisionGridLayout.CardWithGraph;
  2334. else if (AppSettings.RevisionGraphLayout == (int)RevisionGridLayout.LargeCard)
  2335. AppSettings.RevisionGraphLayout = (int)RevisionGridLayout.LargeCardWithGraph;
  2336. else if (AppSettings.RevisionGraphLayout == (int)RevisionGridLayout.SmallWithGraph)
  2337. AppSettings.RevisionGraphLayout = (int)RevisionGridLayout.Small;
  2338. else if (AppSettings.RevisionGraphLayout == (int)RevisionGridLayout.CardWithGraph)
  2339. AppSettings.RevisionGraphLayout = (int)RevisionGridLayout.Card;
  2340. else if (AppSettings.RevisionGraphLayout == (int)RevisionGridLayout.LargeCardWithGraph)
  2341. AppSettings.RevisionGraphLayout = (int)RevisionGridLayout.LargeCard;
  2342. else if (AppSettings.RevisionGraphLayout == (int)RevisionGridLayout.FilledBranchesSmall)
  2343. AppSettings.RevisionGraphLayout = (int)RevisionGridLayout.FilledBranchesSmallWithGraph;
  2344. else if (AppSettings.RevisionGraphLayout == (int)RevisionGridLayout.FilledBranchesSmallWithGraph)
  2345. AppSettings.RevisionGraphLayout = (int)RevisionGridLayout.FilledBranchesSmall;
  2346. }
  2347. internal void ShowTags_ToolStripMenuItemClick(object sender, EventArgs e)
  2348. {
  2349. AppSettings.ShowTags = !AppSettings.ShowTags;
  2350. _revisionGridMenuCommands.TriggerMenuChanged();
  2351. Refresh();
  2352. }
  2353. internal void ShowIds_ToolStripMenuItemClick(object sender, EventArgs e)
  2354. {
  2355. AppSettings.ShowIds = !AppSettings.ShowIds;
  2356. Revisions.IdColumn.Visible = AppSettings.ShowIds;
  2357. _revisionGridMenuCommands.TriggerMenuChanged();
  2358. Refresh();
  2359. }
  2360. public void ToggleRevisionCardLayout()
  2361. {
  2362. var layouts = new List<RevisionGridLayout>((RevisionGridLayout[])Enum.GetValues(typeof(RevisionGridLayout)));
  2363. layouts.Sort();
  2364. var maxLayout = (int)layouts[layouts.Count - 1];
  2365. int nextLayout = AppSettings.RevisionGraphLayout + 1;
  2366. if (nextLayout > maxLayout)
  2367. nextLayout = 1;
  2368. SetRevisionsLayout((RevisionGridLayout)nextLayout);
  2369. }
  2370. public void SetRevisionsLayout(RevisionGridLayout revisionGridLayout)
  2371. {
  2372. AppSettings.RevisionGraphLayout = (int)revisionGridLayout;
  2373. SetRevisionsLayout();
  2374. }
  2375. private void SetRevisionsLayout()
  2376. {
  2377. _layout = Enum.IsDefined(typeof(RevisionGridLayout), AppSettings.RevisionGraphLayout)
  2378. ? (RevisionGridLayout)AppSettings.RevisionGraphLayout
  2379. : RevisionGridLayout.SmallWithGraph;
  2380. IsCardLayout();
  2381. NormalFont = AppSettings.Font;// new Font(Settings.Font.Name, Settings.Font.Size + 2); // SystemFonts.DefaultFont.FontFamily, SystemFonts.DefaultFont.Size + 2);
  2382. SetAuthoredRevisionsBrush();
  2383. if (IsCardLayout())
  2384. {
  2385. if (AppSettings.RevisionGraphLayout == (int)RevisionGridLayout.Card
  2386. || AppSettings.RevisionGraphLayout == (int)RevisionGridLayout.CardWithGraph)
  2387. {
  2388. _rowHeigth = 45;
  2389. }
  2390. else
  2391. {
  2392. _rowHeigth = 70;
  2393. }
  2394. if (_filledItemBrush == null)
  2395. {
  2396. _filledItemBrush = new LinearGradientBrush(new Rectangle(0, 0, _rowHeigth, _rowHeigth),
  2397. Revisions.RowTemplate.DefaultCellStyle.SelectionBackColor,
  2398. Color.LightBlue, 90, false);
  2399. }
  2400. _selectedItemBrush = _filledItemBrush;
  2401. Revisions.ShowAuthor(!IsCardLayout());
  2402. Revisions.SetDimensions(NodeDimension, LaneWidth, LaneLineWidth, _rowHeigth, _selectedItemBrush);
  2403. }
  2404. else
  2405. {
  2406. if (IsFilledBranchesLayout())
  2407. {
  2408. using (var graphics = Graphics.FromHwnd(Handle))
  2409. {
  2410. _rowHeigth = (int)graphics.MeasureString("By", NormalFont).Height + 9;
  2411. }
  2412. _selectedItemBrush = SystemBrushes.Highlight;
  2413. }
  2414. else
  2415. {
  2416. _rowHeigth = 25;
  2417. if (_filledItemBrush == null)
  2418. {
  2419. _filledItemBrush = new LinearGradientBrush(new Rectangle(0, 0, _rowHeigth, _rowHeigth),
  2420. Revisions.RowTemplate.DefaultCellStyle.SelectionBackColor,
  2421. Color.LightBlue, 90, false);
  2422. }
  2423. _selectedItemBrush = _filledItemBrush;
  2424. }
  2425. Revisions.ShowAuthor(!IsCardLayout());
  2426. Revisions.SetDimensions(NodeDimension, LaneWidth, LaneLineWidth, _rowHeigth, _selectedItemBrush);
  2427. }
  2428. //Hide graph column when there it is disabled OR when a filter is active
  2429. //allowing for special case when history of a single file is being displayed
  2430. if (!IsGraphLayout() || (ShouldHideGraph(false) && !AllowGraphWithFilter))
  2431. {
  2432. Revisions.HideRevisionGraph();
  2433. }
  2434. else
  2435. {
  2436. Revisions.ShowRevisionGraph();
  2437. }
  2438. }
  2439. private void SetAuthoredRevisionsBrush()
  2440. {
  2441. if (_authoredRevisionsBrush != null && _authoredRevisionsBrush.Color != AppSettings.AuthoredRevisionsColor)
  2442. {
  2443. _authoredRevisionsBrush.Dispose();
  2444. _authoredRevisionsBrush = null;
  2445. }
  2446. if (_authoredRevisionsBrush == null)
  2447. {
  2448. _authoredRevisionsBrush = new SolidBrush(AppSettings.AuthoredRevisionsColor);
  2449. }
  2450. }
  2451. private bool IsFilledBranchesLayout()
  2452. {
  2453. return _layout == RevisionGridLayout.FilledBranchesSmall || _layout == RevisionGridLayout.FilledBranchesSmallWithGraph;
  2454. }
  2455. private bool IsCardLayout()
  2456. {
  2457. return _layout == RevisionGridLayout.Card
  2458. || _layout == RevisionGridLayout.CardWithGraph
  2459. || _layout == RevisionGridLayout.LargeCard
  2460. || _layout == RevisionGridLayout.LargeCardWithGraph;
  2461. }
  2462. internal bool IsGraphLayout()
  2463. {
  2464. return _layout == RevisionGridLayout.SmallWithGraph
  2465. || _layout == RevisionGridLayout.CardWithGraph
  2466. || _layout == RevisionGridLayout.LargeCardWithGraph
  2467. || _layout == RevisionGridLayout.FilledBranchesSmallWithGraph;
  2468. }
  2469. #region Hotkey commands
  2470. public const string HotkeySettingsName = "RevisionGrid";
  2471. internal enum Commands
  2472. {
  2473. ToggleRevisionGraph,
  2474. RevisionFilter,
  2475. ToggleAuthorDateCommitDate,
  2476. ToggleOrderRevisionsByDate,
  2477. ToggleShowRelativeDate,
  2478. ToggleDrawNonRelativesGray,
  2479. ToggleShowGitNotes,
  2480. ToggleRevisionCardLayout,
  2481. ToggleShowMergeCommits,
  2482. ShowAllBranches,
  2483. ShowCurrentBranchOnly,
  2484. ShowFilteredBranches,
  2485. ShowRemoteBranches,
  2486. ShowFirstParent,
  2487. GoToParent,
  2488. GoToChild,
  2489. ToggleHighlightSelectedBranch,
  2490. NextQuickSearch,
  2491. PrevQuickSearch,
  2492. SelectCurrentRevision,
  2493. GoToCommit,
  2494. NavigateBackward,
  2495. NavigateForward,
  2496. SelectAsBaseToCompare,
  2497. CompareToBase
  2498. }
  2499. protected override bool ExecuteCommand(int cmd)
  2500. {
  2501. Commands command = (Commands)cmd;
  2502. switch (command)
  2503. {
  2504. case Commands.ToggleRevisionGraph: ShowRevisionGraph_ToolStripMenuItemClick(null, null); break;
  2505. case Commands.RevisionFilter: FilterToolStripMenuItemClick(null, null); break;
  2506. case Commands.ToggleAuthorDateCommitDate: ShowAuthorDate_ToolStripMenuItemClick(null, null); break;
  2507. case Commands.ToggleOrderRevisionsByDate: OrderRevisionsByDate_ToolStripMenuItemClick(null, null); break;
  2508. case Commands.ToggleShowRelativeDate: ShowRelativeDate_ToolStripMenuItemClick(null, null); break;
  2509. case Commands.ToggleDrawNonRelativesGray: DrawNonrelativesGray_ToolStripMenuItemClick(null, null); break;
  2510. case Commands.ToggleShowGitNotes: ShowGitNotes_ToolStripMenuItemClick(null, null); break;
  2511. case Commands.ToggleRevisionCardLayout: ToggleRevisionCardLayout(); break;
  2512. case Commands.ToggleShowMergeCommits: ShowMergeCommits_ToolStripMenuItemClick(null, null); break;
  2513. case Commands.ShowAllBranches: ShowAllBranches_ToolStripMenuItemClick(null, null); break;
  2514. case Commands.ShowCurrentBranchOnly: ShowCurrentBranchOnly_ToolStripMenuItemClick(null, null); break;
  2515. case Commands.ShowFilteredBranches: ShowFilteredBranches_ToolStripMenuItemClick(null, null); break;
  2516. case Commands.ShowRemoteBranches: ShowRemoteBranches_ToolStripMenuItemClick(null, null); break;
  2517. case Commands.ShowFirstParent: ShowFirstParent_ToolStripMenuItemClick(null, null); break;
  2518. case Commands.SelectCurrentRevision: SetSelectedRevision(new GitRevision(Module, CurrentCheckout)); break;
  2519. case Commands.GoToCommit: _revisionGridMenuCommands.GotoCommitExcecute(); break;
  2520. case Commands.GoToParent: goToParentToolStripMenuItem_Click(null, null); break;
  2521. case Commands.GoToChild: goToChildToolStripMenuItem_Click(null, null); break;
  2522. case Commands.ToggleHighlightSelectedBranch: ToggleHighlightSelectedBranch(); break;
  2523. case Commands.NextQuickSearch: NextQuickSearch(true); break;
  2524. case Commands.PrevQuickSearch: NextQuickSearch(false); break;
  2525. case Commands.NavigateBackward: NavigateBackward(); break;
  2526. case Commands.NavigateForward: NavigateForward(); break;
  2527. case Commands.SelectAsBaseToCompare: selectAsBaseToolStripMenuItem_Click(null, null); break;
  2528. case Commands.CompareToBase: compareToBaseToolStripMenuItem_Click(null, null); break;
  2529. default:
  2530. {
  2531. bool result = base.ExecuteCommand(cmd);
  2532. RefreshRevisions();
  2533. return result;
  2534. }
  2535. }
  2536. return true;
  2537. }
  2538. #endregion
  2539. internal bool ExecuteCommand(Commands cmd)
  2540. {
  2541. return ExecuteCommand((int)cmd);
  2542. }
  2543. private void NextQuickSearch(bool down)
  2544. {
  2545. var curIndex = -1;
  2546. if (Revisions.SelectedRows.Count > 0)
  2547. curIndex = Revisions.SelectedRows[0].Index;
  2548. RestartQuickSearchTimer();
  2549. bool reverse = !down;
  2550. var nextIndex = 0;
  2551. if (curIndex >= 0)
  2552. nextIndex = reverse ? curIndex - 1 : curIndex + 1;
  2553. _quickSearchString = _lastQuickSearchString;
  2554. FindNextMatch(nextIndex, _quickSearchString, reverse);
  2555. ShowQuickSearchString();
  2556. }
  2557. private void ToggleHighlightSelectedBranch()
  2558. {
  2559. if (_revisionGraphCommand != null)
  2560. {
  2561. MessageBox.Show(_cannotHighlightSelectedBranch.Text);
  2562. return;
  2563. }
  2564. HighlightSelectedBranch();
  2565. }
  2566. public void HighlightSelectedBranch()
  2567. {
  2568. var revisions = GetSelectedRevisions();
  2569. if (revisions.Count > 0)
  2570. {
  2571. HighlightBranch(revisions[0].Guid);
  2572. Refresh();
  2573. }
  2574. }
  2575. private void deleteBranchTagToolStripMenuItem_Click(object sender, EventArgs e)
  2576. {
  2577. ToolStripMenuItem item = sender as ToolStripMenuItem;
  2578. if (item != null)
  2579. {
  2580. if (item.DropDown != null && item.DropDown.Items.Count == 1)
  2581. item.DropDown.Items[0].PerformClick();
  2582. }
  2583. }
  2584. private void goToParentToolStripMenuItem_Click(object sender, EventArgs e)
  2585. {
  2586. var r = GetRevision(LastRowIndex);
  2587. if (r != null)
  2588. {
  2589. if (_parentChildNavigationHistory.HasPreviousParent)
  2590. _parentChildNavigationHistory.NavigateToPreviousParent(r.Guid);
  2591. else if (r.HasParent())
  2592. _parentChildNavigationHistory.NavigateToParent(r.Guid, r.ParentGuids[0]);
  2593. }
  2594. }
  2595. private void goToChildToolStripMenuItem_Click(object sender, EventArgs e)
  2596. {
  2597. var r = GetRevision(LastRowIndex);
  2598. if (r != null)
  2599. {
  2600. var children = GetRevisionChildren(r.Guid);
  2601. if (_parentChildNavigationHistory.HasPreviousChild)
  2602. _parentChildNavigationHistory.NavigateToPreviousChild(r.Guid);
  2603. else if (children.Any())
  2604. _parentChildNavigationHistory.NavigateToChild(r.Guid, children[0]);
  2605. }
  2606. }
  2607. private void copyToClipboardToolStripMenuItem_DropDownOpened(object sender, EventArgs e)
  2608. {
  2609. var r = GetRevision(LastRowIndex);
  2610. if (r != null)
  2611. {
  2612. CopyToClipboardMenuHelper.AddOrUpdateTextPostfix(hashCopyToolStripMenuItem, CopyToClipboardMenuHelper.StrLimitWithElipses(r.Guid, 15));
  2613. CopyToClipboardMenuHelper.AddOrUpdateTextPostfix(messageCopyToolStripMenuItem, CopyToClipboardMenuHelper.StrLimitWithElipses(r.Subject, 30));
  2614. CopyToClipboardMenuHelper.AddOrUpdateTextPostfix(authorCopyToolStripMenuItem, r.Author);
  2615. CopyToClipboardMenuHelper.AddOrUpdateTextPostfix(dateCopyToolStripMenuItem, r.CommitDate.ToString());
  2616. }
  2617. }
  2618. public void GoToRef(string refName, bool showNoRevisionMsg)
  2619. {
  2620. string revisionGuid = Module.RevParse(refName);
  2621. if (!string.IsNullOrEmpty(revisionGuid))
  2622. {
  2623. SetSelectedRevision(new GitRevision(Module, revisionGuid));
  2624. }
  2625. else if (showNoRevisionMsg)
  2626. {
  2627. MessageBox.Show((ParentForm as IWin32Window) ?? this, _noRevisionFoundError.Text);
  2628. }
  2629. }
  2630. /// <summary>
  2631. /// duplicated from GitExtensionsForm
  2632. /// </summary>
  2633. /// <param name="commandCode"></param>
  2634. /// <returns></returns>
  2635. private Keys GetShortcutKeys(int commandCode)
  2636. {
  2637. var hotkey = GetHotkeyCommand(commandCode);
  2638. return hotkey == null ? Keys.None : hotkey.KeyData;
  2639. }
  2640. internal Keys GetShortcutKeys(Commands cmd)
  2641. {
  2642. return GetShortcutKeys((int)cmd);
  2643. }
  2644. /// <summary>
  2645. /// duplicated from GitExtensionsForm
  2646. /// </summary>
  2647. /// <param name="commandCode"></param>
  2648. /// <returns></returns>
  2649. private HotkeyCommand GetHotkeyCommand(int commandCode)
  2650. {
  2651. if (Hotkeys == null)
  2652. return null;
  2653. return Hotkeys.FirstOrDefault(h => h.CommandCode == commandCode);
  2654. }
  2655. internal RevisionGridMenuCommands MenuCommands { get { return _revisionGridMenuCommands; } }
  2656. private void CompareToBranchToolStripMenuItem_Click(object sender, EventArgs e)
  2657. {
  2658. var headCommit = this.GetSelectedRevisions().First();
  2659. using (var form = new FormCompareToBranch(UICommands, headCommit.Guid))
  2660. {
  2661. if (form.ShowDialog(this) == DialogResult.OK)
  2662. {
  2663. var baseCommit = Module.RevParse(form.BranchName);
  2664. using (var diffForm = new FormDiff(UICommands, this, baseCommit, headCommit.Guid,
  2665. form.BranchName, headCommit.Subject))
  2666. {
  2667. diffForm.ShowDialog(this);
  2668. }
  2669. }
  2670. }
  2671. }
  2672. private void CompareWithCurrentBranchToolStripMenuItem_Click(object sender, EventArgs e)
  2673. {
  2674. var baseCommit = this.GetSelectedRevisions().First();
  2675. var headBranch = Module.GetSelectedBranch();
  2676. var headBranchName = Module.RevParse(headBranch);
  2677. using (var diffForm = new FormDiff(UICommands, this, baseCommit.Guid, headBranchName,
  2678. baseCommit.Subject, headBranch))
  2679. {
  2680. diffForm.ShowDialog(this);
  2681. }
  2682. }
  2683. private void selectAsBaseToolStripMenuItem_Click(object sender, EventArgs e)
  2684. {
  2685. _baseCommitToCompare = GetSelectedRevisions().First();
  2686. compareToBaseToolStripMenuItem.Enabled = true;
  2687. }
  2688. private void compareToBaseToolStripMenuItem_Click(object sender, EventArgs e)
  2689. {
  2690. var headCommit = GetSelectedRevisions().First();
  2691. using (var diffForm = new FormDiff(UICommands, this, _baseCommitToCompare.Guid, headCommit.Guid,
  2692. _baseCommitToCompare.Subject, headCommit.Subject))
  2693. {
  2694. diffForm.ShowDialog(this);
  2695. }
  2696. }
  2697. private void getHelpOnHowToUseTheseFeaturesToolStripMenuItem_Click(object sender, EventArgs e)
  2698. {
  2699. OpenManual();
  2700. }
  2701. private void OpenManual()
  2702. {
  2703. string url = UserManual.UserManual.UrlFor("modify_history", "using-autosquash-rebase-feature");
  2704. OsShellUtil.OpenUrlInDefaultBrowser(url);
  2705. }
  2706. }
  2707. }