PageRenderTime 48ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/GitUI/UserControls/FileStatusList.cs

https://github.com/vbjay/gitextensions
C# | 766 lines | 658 code | 90 blank | 18 comment | 133 complexity | 18672c68d7f0f0063c586c2e92fa0011 MD5 | raw file
Possible License(s): GPL-3.0, GPL-2.0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections.Specialized;
  4. using System.ComponentModel;
  5. using System.Drawing;
  6. using System.IO;
  7. using System.Linq;
  8. using System.Reactive.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 GitUI.Properties;
  15. using GitUI.UserControls;
  16. using ResourceManager;
  17. namespace GitUI
  18. {
  19. using GitItemsWithParents = IDictionary<string, IList<GitItemStatus>>;
  20. public sealed partial class FileStatusList : GitModuleControl
  21. {
  22. private readonly TranslationString _UnsupportedMultiselectAction =
  23. new TranslationString("Operation not supported");
  24. private readonly TranslationString _DiffWithParent =
  25. new TranslationString("Diff with parent");
  26. private readonly IDisposable selectedIndexChangeSubscription;
  27. private static readonly TimeSpan SelectedIndexChangeThrottleDuration = TimeSpan.FromMilliseconds(50);
  28. private const int ImageSize = 16;
  29. public FileStatusList()
  30. {
  31. InitializeComponent(); Translate();
  32. selectedIndexChangeSubscription = Observable.FromEventPattern(
  33. h => FileStatusListView.SelectedIndexChanged += h,
  34. h => FileStatusListView.SelectedIndexChanged -= h)
  35. .Throttle(SelectedIndexChangeThrottleDuration)
  36. .ObserveOn(SynchronizationContext.Current)
  37. .Subscribe(_ => FileStatusListView_SelectedIndexChanged());
  38. SelectFirstItemOnSetItems = true;
  39. _noDiffFilesChangesDefaultText = NoFiles.Text;
  40. #if !__MonoCS__ // TODO Drag'n'Drop doesn't work on Mono/Linux
  41. FileStatusListView.MouseMove += FileStatusListView_MouseMove;
  42. FileStatusListView.MouseDown += FileStatusListView_MouseDown;
  43. #endif
  44. if (_images == null)
  45. {
  46. _images = new ImageList();
  47. _images.Images.Add(Resources.Removed); // 0
  48. _images.Images.Add(Resources.Added); // 1
  49. _images.Images.Add(Resources.Modified); // 2
  50. _images.Images.Add(Resources.Renamed); // 3
  51. _images.Images.Add(Resources.Copied); // 4
  52. _images.Images.Add(Resources.IconSubmoduleDirty); // 5
  53. _images.Images.Add(Resources.IconSubmoduleRevisionUp); // 6
  54. _images.Images.Add(Resources.IconSubmoduleRevisionUpDirty); // 7
  55. _images.Images.Add(Resources.IconSubmoduleRevisionDown); // 8
  56. _images.Images.Add(Resources.IconSubmoduleRevisionDownDirty); // 9
  57. _images.Images.Add(Resources.IconSubmoduleRevisionSemiUp); // 10
  58. _images.Images.Add(Resources.IconSubmoduleRevisionSemiUpDirty); // 11
  59. _images.Images.Add(Resources.IconSubmoduleRevisionSemiDown); // 12
  60. _images.Images.Add(Resources.IconSubmoduleRevisionSemiDownDirty); // 13
  61. _images.Images.Add(Resources.IconFileStatusUnknown); // 14
  62. }
  63. FileStatusListView.SmallImageList = _images;
  64. FileStatusListView.LargeImageList = _images;
  65. NoFiles.Visible = false;
  66. NoFiles.Font = new Font(SystemFonts.MessageBoxFont, FontStyle.Italic);
  67. }
  68. protected override void DisposeCustomResources()
  69. {
  70. selectedIndexChangeSubscription.Dispose();
  71. }
  72. private static ImageList _images;
  73. private readonly string _noDiffFilesChangesDefaultText;
  74. public void SetNoFilesText(string text)
  75. {
  76. NoFiles.Text = text;
  77. }
  78. public string GetNoFilesText()
  79. {
  80. return NoFiles.Text;
  81. }
  82. public override bool Focused
  83. {
  84. get
  85. {
  86. return FileStatusListView.Focused;
  87. }
  88. }
  89. public new void Focus()
  90. {
  91. if (FileStatusListView.Items.Count > 0)
  92. {
  93. if (SelectedItem == null)
  94. SelectedIndex = 0;
  95. FileStatusListView.Focus();
  96. }
  97. }
  98. public void BeginUpdate()
  99. {
  100. FileStatusListView.BeginUpdate();
  101. }
  102. public void EndUpdate()
  103. {
  104. FileStatusListView.EndUpdate();
  105. }
  106. private string GetItemText(Graphics graphics, GitItemStatus gitItemStatus)
  107. {
  108. var pathFormatter = new PathFormatter(graphics, FileStatusListView.Font);
  109. return pathFormatter.FormatTextForDrawing(FileStatusListView.ClientSize.Width - ImageSize,
  110. gitItemStatus.Name, gitItemStatus.OldName);
  111. }
  112. private void FileStatusListView_DrawItem(object sender, DrawListViewItemEventArgs e)
  113. {
  114. if (e.Bounds.Height <= 0 || e.Bounds.Width <= 0 || e.ItemIndex < 0)
  115. return;
  116. e.DrawBackground();
  117. Color color;
  118. if (e.Item.Selected)
  119. {
  120. e.Graphics.FillRectangle(SystemBrushes.Highlight, e.Bounds);
  121. color = SystemColors.HighlightText;
  122. }
  123. else
  124. color = SystemColors.WindowText;
  125. e.DrawFocusRectangle();
  126. e.Graphics.FillRectangle(Brushes.White, e.Bounds.Left, e.Bounds.Top, ImageSize, e.Bounds.Height);
  127. int centeredImageTop = e.Bounds.Top;
  128. if ((e.Bounds.Height - ImageSize) > 1)
  129. centeredImageTop = e.Bounds.Top + ((e.Bounds.Height - ImageSize) / 2);
  130. var image = e.Item.ImageList.Images[e.Item.ImageIndex];
  131. if (image != null)
  132. e.Graphics.DrawImage(image, e.Bounds.Left, centeredImageTop, ImageSize, ImageSize);
  133. GitItemStatus gitItemStatus = (GitItemStatus)e.Item.Tag;
  134. string text = GetItemText(e.Graphics, gitItemStatus);
  135. if (gitItemStatus.IsSubmodule && gitItemStatus.SubmoduleStatus != null && gitItemStatus.SubmoduleStatus.IsCompleted)
  136. text += gitItemStatus.SubmoduleStatus.Result.AddedAndRemovedString();
  137. e.Graphics.DrawString(text, e.Item.ListView.Font,
  138. new SolidBrush(color), e.Bounds.Left + ImageSize, e.Bounds.Top);
  139. }
  140. #if !__MonoCS__ // TODO Drag'n'Drop doesnt work on Mono/Linux
  141. void FileStatusListView_MouseDown(object sender, MouseEventArgs e)
  142. {
  143. //SELECT
  144. if (e.Button == MouseButtons.Right)
  145. {
  146. var hover = FileStatusListView.HitTest(e.Location);
  147. if (hover.Item != null && !hover.Item.Selected)
  148. {
  149. ClearSelected();
  150. hover.Item.Selected = true;
  151. }
  152. }
  153. //DRAG
  154. if (e.Button == MouseButtons.Left)
  155. {
  156. if (SelectedItems.Any())
  157. {
  158. // Remember the point where the mouse down occurred.
  159. // The DragSize indicates the size that the mouse can move
  160. // before a drag event should be started.
  161. Size dragSize = SystemInformation.DragSize;
  162. // Create a rectangle using the DragSize, with the mouse position being
  163. // at the center of the rectangle.
  164. dragBoxFromMouseDown = new Rectangle(new Point(e.X - (dragSize.Width / 2),
  165. e.Y - (dragSize.Height / 2)),
  166. dragSize);
  167. }
  168. else
  169. // Reset the rectangle if the mouse is not over an item in the ListView.
  170. dragBoxFromMouseDown = Rectangle.Empty;
  171. }
  172. }
  173. #endif
  174. public override ContextMenuStrip ContextMenuStrip
  175. {
  176. get
  177. {
  178. return FileStatusListView.ContextMenuStrip;
  179. }
  180. set
  181. {
  182. FileStatusListView.ContextMenuStrip = value;
  183. }
  184. }
  185. public override ContextMenu ContextMenu
  186. {
  187. get
  188. {
  189. return FileStatusListView.ContextMenu;
  190. }
  191. set
  192. {
  193. FileStatusListView.ContextMenu = value;
  194. }
  195. }
  196. #if !__MonoCS__ // TODO Drag'n'Drop doesnt work on Mono/Linux
  197. private Rectangle dragBoxFromMouseDown;
  198. void FileStatusListView_MouseMove(object sender, MouseEventArgs e)
  199. {
  200. ListView listView = sender as ListView;
  201. //DRAG
  202. // If the mouse moves outside the rectangle, start the drag.
  203. if (dragBoxFromMouseDown != Rectangle.Empty &&
  204. !dragBoxFromMouseDown.Contains(e.X, e.Y))
  205. {
  206. if (SelectedItems.Any())
  207. {
  208. StringCollection fileList = new StringCollection();
  209. foreach (GitItemStatus item in SelectedItems)
  210. {
  211. string fileName = Path.Combine(Module.WorkingDir, item.Name);
  212. fileList.Add(fileName.Replace('/', '\\'));
  213. }
  214. DataObject obj = new DataObject();
  215. obj.SetFileDropList(fileList);
  216. // Proceed with the drag and drop, passing in the list item.
  217. DoDragDrop(obj, DragDropEffects.Copy);
  218. dragBoxFromMouseDown = Rectangle.Empty;
  219. }
  220. }
  221. //TOOLTIP
  222. if (listView != null)
  223. {
  224. var point = new Point(e.X, e.Y);
  225. var hover = listView.HitTest(point);
  226. if (hover.Item != null)
  227. {
  228. var gitItemStatus = (GitItemStatus)hover.Item.Tag;
  229. string text;
  230. if (gitItemStatus.IsRenamed || gitItemStatus.IsCopied)
  231. text = string.Concat(gitItemStatus.Name, " (", gitItemStatus.OldName, ")");
  232. else
  233. text = gitItemStatus.Name;
  234. float fTextWidth = listView.CreateGraphics().MeasureString(text, listView.Font).Width + 17;
  235. //Use width-itemheight because the icon drawn in front of the text is the itemheight
  236. if (fTextWidth > (FileStatusListView.Width - FileStatusListView.GetItemRect(hover.Item.Index).Height))
  237. {
  238. if (!hover.Item.ToolTipText.Equals(gitItemStatus.ToString()))
  239. hover.Item.ToolTipText = gitItemStatus.ToString();
  240. }
  241. else
  242. hover.Item.ToolTipText = "";
  243. }
  244. }
  245. }
  246. #endif
  247. [Browsable(false)]
  248. public IEnumerable<GitItemStatus> AllItems
  249. {
  250. get
  251. {
  252. return (FileStatusListView.Items.Cast<ListViewItem>().
  253. Select(selectedItem => (GitItemStatus) selectedItem.Tag));
  254. }
  255. }
  256. [Browsable(false)]
  257. public IEnumerable<GitItemStatus> SelectedItems
  258. {
  259. get
  260. {
  261. return FileStatusListView.SelectedItems.Cast<ListViewItem>().
  262. Select(i => (GitItemStatus)i.Tag);
  263. }
  264. set
  265. {
  266. ClearSelected();
  267. if (value == null)
  268. return;
  269. foreach (var item in FileStatusListView.Items.Cast<ListViewItem>()
  270. .Where(i => value.Contains((GitItemStatus)i.Tag)))
  271. {
  272. item.Selected = true;
  273. }
  274. var first = FileStatusListView.SelectedItems.Cast<ListViewItem>().FirstOrDefault(x => x.Selected);
  275. if (first != null)
  276. first.EnsureVisible();
  277. StoreNextIndexToSelect();
  278. }
  279. }
  280. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  281. [Browsable(false)]
  282. public GitItemStatus SelectedItem
  283. {
  284. get
  285. {
  286. if (FileStatusListView.SelectedItems.Count > 0)
  287. {
  288. ListViewItem item = FileStatusListView.SelectedItems[0];
  289. return (GitItemStatus) item.Tag;
  290. }
  291. return null;
  292. }
  293. set
  294. {
  295. ClearSelected();
  296. if (value == null)
  297. return;
  298. foreach (ListViewItem item in FileStatusListView.Items)
  299. if (item.Tag == value)
  300. {
  301. item.Selected = true;
  302. item.EnsureVisible();
  303. return;
  304. }
  305. }
  306. }
  307. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  308. [Browsable(false)]
  309. public string SelectedItemParent
  310. {
  311. get
  312. {
  313. foreach (ListViewItem item in FileStatusListView.SelectedItems)
  314. return item.Group != null ? (string)item.Group.Tag : null;
  315. return null;
  316. }
  317. }
  318. public void ClearSelected()
  319. {
  320. foreach (ListViewItem item in FileStatusListView.SelectedItems)
  321. item.Selected = false;
  322. }
  323. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  324. [Browsable(false)]
  325. public int SelectedIndex
  326. {
  327. get
  328. {
  329. foreach (int i in FileStatusListView.SelectedIndices)
  330. return i;
  331. return -1;
  332. }
  333. set
  334. {
  335. ClearSelected();
  336. if (value >= 0)
  337. {
  338. FileStatusListView.Items[value].Selected = true;
  339. FileStatusListView.Items[value].Focused = true;
  340. FileStatusListView.Items[value].EnsureVisible();
  341. }
  342. }
  343. }
  344. private int _nextIndexToSelect = -1;
  345. public void StoreNextIndexToSelect()
  346. {
  347. _nextIndexToSelect = -1;
  348. foreach (int idx in FileStatusListView.SelectedIndices)
  349. if (idx > _nextIndexToSelect)
  350. _nextIndexToSelect = idx;
  351. _nextIndexToSelect = _nextIndexToSelect - FileStatusListView.SelectedIndices.Count + 1;
  352. }
  353. public void SelectStoredNextIndex(int defaultIndex = -1)
  354. {
  355. _nextIndexToSelect = Math.Min(_nextIndexToSelect, FileStatusListView.Items.Count - 1);
  356. if (_nextIndexToSelect < 0 && defaultIndex > -1)
  357. _nextIndexToSelect = Math.Min(defaultIndex, FileStatusListView.Items.Count - 1);
  358. if (_nextIndexToSelect > -1)
  359. SelectedIndex = _nextIndexToSelect;
  360. _nextIndexToSelect = -1;
  361. }
  362. public event EventHandler SelectedIndexChanged;
  363. public event EventHandler DataSourceChanged;
  364. public new event EventHandler DoubleClick;
  365. public new event KeyEventHandler KeyDown;
  366. void FileStatusListView_DoubleClick(object sender, EventArgs e)
  367. {
  368. if (DoubleClick == null)
  369. UICommands.StartFileHistoryDialog(this, SelectedItem.Name, Revision);
  370. else
  371. DoubleClick(sender, e);
  372. }
  373. void FileStatusListView_SelectedIndexChanged()
  374. {
  375. if (SelectedIndexChanged != null)
  376. SelectedIndexChanged(this, EventArgs.Empty);
  377. }
  378. private static int GetItemImageIndex(GitItemStatus gitItemStatus)
  379. {
  380. if (gitItemStatus.IsDeleted)
  381. return 0;
  382. if (gitItemStatus.IsNew || !gitItemStatus.IsTracked)
  383. return 1;
  384. if (gitItemStatus.IsChanged || gitItemStatus.IsConflict)
  385. {
  386. if (!gitItemStatus.IsSubmodule || gitItemStatus.SubmoduleStatus == null ||
  387. !gitItemStatus.SubmoduleStatus.IsCompleted)
  388. return 2;
  389. var status = gitItemStatus.SubmoduleStatus.Result;
  390. if (status == null)
  391. return 2;
  392. if (status.Status == SubmoduleStatus.FastForward)
  393. return 6 + (status.IsDirty ? 1 : 0);
  394. if (status.Status == SubmoduleStatus.Rewind)
  395. return 8 + (status.IsDirty ? 1 : 0);
  396. if (status.Status == SubmoduleStatus.NewerTime)
  397. return 10 + (status.IsDirty ? 1 : 0);
  398. if (status.Status == SubmoduleStatus.OlderTime)
  399. return 12 + (status.IsDirty ? 1 : 0);
  400. return !status.IsDirty ? 2 : 5;
  401. }
  402. if (gitItemStatus.IsRenamed)
  403. return 3;
  404. if (gitItemStatus.IsCopied)
  405. return 4;
  406. return 14;//icon unknown
  407. }
  408. [Browsable(false)]
  409. [DefaultValue(true)]
  410. public bool IsEmpty
  411. {
  412. get { return GitItemStatuses == null || !GitItemStatuses.Any(); }
  413. }
  414. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  415. [Browsable(false)]
  416. public IList<GitItemStatus> GitItemStatuses
  417. {
  418. get
  419. {
  420. var result = new List<GitItemStatus>();
  421. var data = GitItemStatusesWithParents;
  422. if (data != null)
  423. foreach (var plist in data.Values)
  424. result.AddAll(plist);
  425. return result;
  426. }
  427. set
  428. {
  429. if (value == null)
  430. GitItemStatusesWithParents = null;
  431. else
  432. SetGitItemStatuses(null, value);
  433. }
  434. }
  435. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  436. [Browsable(false)]
  437. public string GitFirstParent
  438. {
  439. get
  440. {
  441. var data = GitItemStatusesWithParents;
  442. if (data != null && data.Count > 0)
  443. return data.ElementAt(0).Key;
  444. return null;
  445. }
  446. }
  447. public void SetGitItemStatuses(string parentRev, IList<GitItemStatus> items)
  448. {
  449. var dictionary = new Dictionary<string, IList<GitItemStatus>> {{parentRev ?? "", items}};
  450. GitItemStatusesWithParents = dictionary;
  451. }
  452. private GitItemsWithParents _itemsDictionary = new Dictionary<string, IList<GitItemStatus>>();
  453. private bool _itemsChanging = false;
  454. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  455. [Browsable(false)]
  456. public GitItemsWithParents GitItemStatusesWithParents
  457. {
  458. get
  459. {
  460. return _itemsDictionary;
  461. }
  462. set
  463. {
  464. _itemsChanging = true;
  465. if (value == null || !value.Any())
  466. NoFiles.Visible = true;
  467. else
  468. NoFiles.Visible = false;
  469. bool empty = FileStatusListView.Items.Count == 0;
  470. FileStatusListView.ShowGroups = value != null && value.Count > 1;
  471. FileStatusListView.Groups.Clear();
  472. FileStatusListView.Items.Clear();
  473. _itemsDictionary = new Dictionary<string, IList<GitItemStatus>>();
  474. if (value == null || value.All(pair => pair.Value.Count == 0))
  475. {
  476. if (!empty)
  477. {
  478. //bug in the ListView control where supplying an empty list will not trigger a SelectedIndexChanged event, so we force it to trigger
  479. FileStatusListView_SelectedIndexChanged();
  480. }
  481. return;
  482. }
  483. FileStatusListView.BeginUpdate();
  484. var list = new List<ListViewItem>();
  485. foreach (var pair in value)
  486. {
  487. ListViewGroup group = null;
  488. if (!String.IsNullOrEmpty(pair.Key))
  489. {
  490. string shortHash = pair.Key.Length > 8 ? pair.Key.Substring(0, 8) : pair.Key;
  491. group = new ListViewGroup(_DiffWithParent.Text + " " + shortHash);
  492. group.Tag = pair.Key;
  493. FileStatusListView.Groups.Add(group);
  494. }
  495. foreach (var item in pair.Value)
  496. {
  497. var listItem = new ListViewItem(item.Name, group);
  498. listItem.ImageIndex = GetItemImageIndex(item);
  499. if (item.SubmoduleStatus != null && !item.SubmoduleStatus.IsCompleted)
  500. {
  501. var capturedItem = item;
  502. item.SubmoduleStatus.ContinueWith((task) => listItem.ImageIndex = GetItemImageIndex(capturedItem),
  503. CancellationToken.None,
  504. TaskContinuationOptions.OnlyOnRanToCompletion,
  505. TaskScheduler.FromCurrentSynchronizationContext());
  506. }
  507. listItem.Tag = item;
  508. list.Add(listItem);
  509. };
  510. }
  511. FileStatusListView.Items.AddRange(list.ToArray());
  512. _itemsChanging = false;
  513. FileStatusListView_SizeChanged(null, null);
  514. foreach (ListViewItem item in FileStatusListView.Items)
  515. {
  516. string parentRev = item.Group != null ? item.Group.Tag as string : "";
  517. if (!_itemsDictionary.ContainsKey(parentRev))
  518. _itemsDictionary.Add(parentRev, new List<GitItemStatus>());
  519. _itemsDictionary[parentRev].Add((GitItemStatus)item.Tag);
  520. }
  521. FileStatusListView.EndUpdate();
  522. FileStatusListView.SetGroupState(ListViewGroupState.Collapsible);
  523. if (DataSourceChanged != null)
  524. DataSourceChanged(this, new EventArgs());
  525. if (SelectFirstItemOnSetItems)
  526. SelectFirstVisibleItem();
  527. }
  528. }
  529. [DefaultValue(true)]
  530. public bool SelectFirstItemOnSetItems { get; set; }
  531. public void SelectFirstVisibleItem()
  532. {
  533. if (FileStatusListView.Items.Count == 0)
  534. return;
  535. var group = FileStatusListView.Groups.Cast<ListViewGroup>().
  536. FirstOrDefault(gr => gr.Items.Count > 0);
  537. if (group != null)
  538. {
  539. ListViewItem sortedFirstGroupItem = FileStatusListView.Items.Cast<ListViewItem>().
  540. FirstOrDefault(item => item.Group == group);
  541. if (sortedFirstGroupItem != null)
  542. sortedFirstGroupItem.Selected = true;
  543. }
  544. else if (FileStatusListView.Items.Count > 0)
  545. FileStatusListView.Items[0].Selected = true;
  546. }
  547. /// <summary>
  548. /// Gets or sets the revision.
  549. /// </summary>
  550. /// <value>The revision.</value>
  551. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  552. [Browsable(false)]
  553. public GitRevision Revision { get; set; }
  554. private void FileStatusListView_SizeChanged(object sender, EventArgs e)
  555. {
  556. if (_itemsChanging)
  557. return;
  558. NoFiles.Location = new Point(5, 5);
  559. NoFiles.Size = new Size(Size.Width - 10, Size.Height - 10);
  560. Refresh();
  561. FileStatusListView.BeginUpdate();
  562. FileStatusListView.AutoResizeColumn(0,
  563. ColumnHeaderAutoResizeStyle.HeaderSize);
  564. FileStatusListView.EndUpdate();
  565. }
  566. private void FileStatusListView_KeyDown(object sender, KeyEventArgs e)
  567. {
  568. switch (e.KeyCode)
  569. {
  570. case Keys.A:
  571. {
  572. if (!e.Control)
  573. break;
  574. FileStatusListView.BeginUpdate();
  575. try
  576. {
  577. for (var i = 0; i < FileStatusListView.Items.Count; i++)
  578. FileStatusListView.Items[i].Selected = true;
  579. e.Handled = true;
  580. }
  581. finally
  582. {
  583. FileStatusListView.EndUpdate();
  584. }
  585. break;
  586. }
  587. default:
  588. if (KeyDown != null)
  589. KeyDown(sender, e);
  590. break;
  591. }
  592. }
  593. public int SetSelectionFilter(string filter)
  594. {
  595. return FilterFiles(RegexFor(filter));
  596. }
  597. private static Regex RegexFor(string value)
  598. {
  599. return string.IsNullOrEmpty(value)
  600. ? new Regex("^$", RegexOptions.Compiled)
  601. : new Regex(value, RegexOptions.Compiled);
  602. }
  603. private int FilterFiles(Regex filter)
  604. {
  605. try
  606. {
  607. SuspendLayout();
  608. var items = AllItems;
  609. int i = 0;
  610. foreach (var item in items)
  611. {
  612. FileStatusListView.Items[i].Selected = filter.IsMatch(item.Name);
  613. i++;
  614. }
  615. return FileStatusListView.SelectedIndices.Count;
  616. }
  617. finally
  618. {
  619. ResumeLayout(true);
  620. }
  621. }
  622. public void SetDiffs(List<GitRevision> revisions)
  623. {
  624. switch (revisions.Count)
  625. {
  626. case 0:
  627. NoFiles.Text = _noDiffFilesChangesDefaultText;
  628. GitItemStatuses = null;
  629. break;
  630. case 1: // diff "parent" --> "selected revision"
  631. SetDiff(revisions[0]);
  632. break;
  633. case 2: // diff "first clicked revision" --> "second clicked revision"
  634. NoFiles.Text = _noDiffFilesChangesDefaultText;
  635. bool artificialRevSelected = revisions[0].IsArtificial() || revisions[1].IsArtificial();
  636. if (artificialRevSelected)
  637. {
  638. NoFiles.Text = _UnsupportedMultiselectAction.Text;
  639. GitItemStatuses = null;
  640. }
  641. else
  642. SetGitItemStatuses(revisions[1].Guid, Module.GetDiffFilesWithSubmodulesStatus(revisions[0].Guid, revisions[1].Guid));
  643. break;
  644. default: // more than 2 revisions selected => no diff
  645. NoFiles.Text = _UnsupportedMultiselectAction.Text;
  646. GitItemStatuses = null;
  647. break;
  648. }
  649. }
  650. public void SetDiff(GitRevision revision)
  651. {
  652. NoFiles.Text = _noDiffFilesChangesDefaultText;
  653. Revision = revision;
  654. if (revision == null)
  655. GitItemStatuses = null;
  656. else if (revision.ParentGuids == null || revision.ParentGuids.Length == 0)
  657. GitItemStatuses = Module.GetTreeFiles(revision.TreeGuid, true);
  658. else
  659. {
  660. if (revision.Guid == GitRevision.UnstagedGuid) //working directory changes
  661. GitItemStatuses = Module.GetUnstagedFilesWithSubmodulesStatus();
  662. else if (revision.Guid == GitRevision.IndexGuid) //index
  663. GitItemStatuses = Module.GetStagedFilesWithSubmodulesStatus();
  664. else
  665. {
  666. GitItemsWithParents dictionary = new Dictionary<string, IList<GitItemStatus>>();
  667. foreach (var parentRev in revision.ParentGuids)
  668. {
  669. dictionary.Add(parentRev, Module.GetDiffFilesWithSubmodulesStatus(revision.Guid, parentRev));
  670. }
  671. GitItemStatusesWithParents = dictionary;
  672. }
  673. }
  674. }
  675. }
  676. }