PageRenderTime 61ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/GitUI/FormBrowse.cs

https://github.com/eisnerd/gitextensions
C# | 2484 lines | 2357 code | 91 blank | 36 comment | 76 complexity | a754b2455a0e0d098630f5d2bdcf37ed 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.Diagnostics;
  5. using System.Drawing;
  6. using System.IO;
  7. using System.Linq;
  8. using System.Text;
  9. using System.Threading;
  10. using System.Windows.Forms;
  11. using GitCommands;
  12. using GitCommands.Repository;
  13. using GitUI.Hotkey;
  14. using GitUI.Plugin;
  15. using GitUI.RepoHosting;
  16. using GitUI.Script;
  17. using GitUI.Statistics;
  18. using GitUIPluginInterfaces;
  19. using ICSharpCode.TextEditor.Util;
  20. #if !__MonoCS__
  21. using Microsoft.WindowsAPICodePack.Taskbar;
  22. #endif
  23. using ResourceManager.Translation;
  24. namespace GitUI
  25. {
  26. public partial class FormBrowse : GitExtensionsForm
  27. {
  28. #region Translation
  29. private readonly TranslationString _stashCount =
  30. new TranslationString("{0} saved {1}");
  31. private readonly TranslationString _stashPlural =
  32. new TranslationString("stashes");
  33. private readonly TranslationString _stashSingular =
  34. new TranslationString("stash");
  35. private readonly TranslationString _warningMiddleOfBisect =
  36. new TranslationString("Your are in the middle of a bisect");
  37. private readonly TranslationString _warningMiddleOfRebase =
  38. new TranslationString("You are in the middle of a rebase");
  39. private readonly TranslationString _warningMiddleOfPatchApply =
  40. new TranslationString("You are in the middle of a patch apply");
  41. private readonly TranslationString _hintUnresolvedMergeConflicts =
  42. new TranslationString("There are unresolved merge conflicts!");
  43. private static readonly TranslationString _noBranchTitle =
  44. new TranslationString("no branch");
  45. private readonly TranslationString _noSubmodulesPresent =
  46. new TranslationString("No submodules");
  47. private readonly TranslationString _saveFileFilterCurrentFormat =
  48. new TranslationString("Current format");
  49. private readonly TranslationString _saveFileFilterAllFiles =
  50. new TranslationString("All files");
  51. private readonly TranslationString _indexLockDeleted =
  52. new TranslationString("index.lock deleted.");
  53. private readonly TranslationString _indexLockNotFound =
  54. new TranslationString("index.lock not found at:");
  55. private readonly TranslationString _errorCaption =
  56. new TranslationString("Error");
  57. private readonly TranslationString _noReposHostPluginLoaded =
  58. new TranslationString("No repository host plugin loaded.");
  59. private readonly TranslationString _noReposHostFound =
  60. new TranslationString("Could not find any relevant repository hosts for the currently open repository.");
  61. private readonly TranslationString _noRevisionFoundError =
  62. new TranslationString("No revision found.");
  63. private readonly TranslationString _configureWorkingDirMenu =
  64. new TranslationString("Configure this menu");
  65. private readonly TranslationString _UnsupportedMultiselectAction =
  66. new TranslationString("Operation not supported");
  67. #endregion
  68. private string _NoDiffFilesChangesText;
  69. private readonly SynchronizationContext syncContext;
  70. private readonly IndexWatcher _indexWatcher = new IndexWatcher();
  71. private Dashboard _dashboard;
  72. private ToolStripItem _rebase;
  73. private ToolStripItem _bisect;
  74. private ToolStripItem _warning;
  75. #if !__MonoCS__
  76. private ThumbnailToolBarButton _commitButton;
  77. private ThumbnailToolBarButton _pushButton;
  78. private ThumbnailToolBarButton _pullButton;
  79. private bool _toolbarButtonsCreated;
  80. #endif
  81. private bool _dontUpdateOnIndexChange;
  82. private ToolStripGitStatus _toolStripGitStatus;
  83. private FilterRevisionsHelper filterRevisionsHelper;
  84. private FilterBranchHelper _FilterBranchHelper;
  85. public FormBrowse(string filter)
  86. {
  87. syncContext = SynchronizationContext.Current;
  88. InitializeComponent();
  89. filterRevisionsHelper = new FilterRevisionsHelper(toolStripTextBoxFilter, toolStripDropDownButton1, RevisionGrid, toolStripLabel2, this);
  90. _FilterBranchHelper = new FilterBranchHelper(toolStripBranches, toolStripDropDownButton2, RevisionGrid);
  91. Translate();
  92. _NoDiffFilesChangesText = DiffFiles.GetNoFilesText();
  93. #if !__MonoCS__
  94. if (Settings.RunningOnWindows() && TaskbarManager.IsPlatformSupported)
  95. {
  96. TaskbarManager.Instance.ApplicationId = "HenkWesthuis.GitExtensions";
  97. }
  98. #endif
  99. if (Settings.ShowGitStatusInBrowseToolbar)
  100. {
  101. _toolStripGitStatus = new ToolStripGitStatus
  102. {
  103. ImageTransparentColor = System.Drawing.Color.Magenta
  104. };
  105. _toolStripGitStatus.Click += StatusClick;
  106. ToolStrip.Items.Insert(ToolStrip.Items.IndexOf(toolStripButton1), _toolStripGitStatus);
  107. ToolStrip.Items.Remove(toolStripButton1);
  108. _toolStripGitStatus.CommitTranslatedString = toolStripButton1.Text;
  109. }
  110. RevisionGrid.SelectionChanged += RevisionGridSelectionChanged;
  111. DiffText.ExtraDiffArgumentsChanged += DiffTextExtraDiffArgumentsChanged;
  112. filterRevisionsHelper.SetFilter(filter);
  113. DiffText.SetFileLoader(getNextPatchFile);
  114. GitTree.ImageList = new ImageList();
  115. GitTree.ImageList.Images.Add(Properties.Resources.New); //File
  116. GitTree.ImageList.Images.Add(Properties.Resources.Folder); //Folder
  117. GitTree.ImageList.Images.Add(Properties.Resources.Submodule); //Submodule
  118. GitTree.MouseDown += GitTree_MouseDown;
  119. GitTree.MouseMove += GitTree_MouseMove;
  120. this.HotkeysEnabled = true;
  121. this.Hotkeys = HotkeySettingsManager.LoadHotkeys(HotkeySettingsName);
  122. this.toolPanel.SplitterDistance = this.ToolStrip.Height;
  123. this._dontUpdateOnIndexChange = false;
  124. Settings.WorkingDirChanged += (a, b, c) => RefreshPullIcon();
  125. RefreshPullIcon();
  126. dontSetAsDefaultToolStripMenuItem.Checked = Settings.DonSetAsLastPullAction;
  127. GitUICommands.Instance.BrowseInitialize += (a, b) => Initialize();
  128. }
  129. private void ShowDashboard()
  130. {
  131. if (_dashboard == null)
  132. {
  133. _dashboard = new Dashboard();
  134. _dashboard.WorkingDirChanged += DashboardWorkingDirChanged;
  135. toolPanel.Panel2.Controls.Add(_dashboard);
  136. _dashboard.Dock = DockStyle.Fill;
  137. }
  138. else
  139. _dashboard.Refresh();
  140. _dashboard.Visible = true;
  141. _dashboard.BringToFront();
  142. _dashboard.ShowRecentRepositories();
  143. }
  144. private void HideDashboard()
  145. {
  146. if (_dashboard != null)
  147. _dashboard.Visible = false;
  148. }
  149. private void DashboardWorkingDirChanged(object sender, EventArgs e)
  150. {
  151. WorkingDirChanged(false);
  152. }
  153. private void GitTree_AfterSelect(object sender, TreeViewEventArgs e)
  154. {
  155. var item = e.Node.Tag as GitItem;
  156. if (item == null)
  157. return;
  158. if (item.IsBlob)
  159. FileText.ViewGitItem(item.FileName, item.Guid);
  160. else
  161. FileText.ViewText("", "");
  162. }
  163. private void BrowseLoad(object sender, EventArgs e)
  164. {
  165. RevisionGrid.Load();
  166. RestorePosition("browse");
  167. Cursor.Current = Cursors.WaitCursor;
  168. InternalInitialize(false);
  169. RevisionGrid.Focus();
  170. RevisionGrid.ActionOnRepositoryPerformed += ActionOnRepositoryPerformed;
  171. IndexWatcher.Reset();
  172. IndexWatcher.Changed += _indexWatcher_Changed;
  173. Cursor.Current = Cursors.Default;
  174. try
  175. {
  176. if (Settings.PlaySpecialStartupSound)
  177. {
  178. new System.Media.SoundPlayer(Properties.Resources.cow_moo).Play();
  179. }
  180. }
  181. catch // This code is just for fun, we do not want the program to crash because of it.
  182. {
  183. }
  184. }
  185. void _indexWatcher_Changed(bool indexChanged)
  186. {
  187. syncContext.Post(o =>
  188. {
  189. RefreshButton.Image = indexChanged && Settings.UseFastChecks && Settings.Module.ValidWorkingDir()
  190. ? GitUI.Properties.Resources.arrow_refresh_dirty
  191. : GitUI.Properties.Resources.arrow_refresh;
  192. }, this);
  193. }
  194. private bool pluginsLoaded;
  195. private void LoadPluginsInPluginMenu()
  196. {
  197. if (!pluginsLoaded)
  198. {
  199. foreach (var plugin in LoadedPlugins.Plugins)
  200. {
  201. var item = new ToolStripMenuItem { Text = plugin.Description, Tag = plugin };
  202. item.Click += ItemClick;
  203. pluginsToolStripMenuItem.DropDownItems.Add(item);
  204. }
  205. pluginsLoaded = true;
  206. UpdatePluginMenu(Settings.Module.ValidWorkingDir());
  207. }
  208. }
  209. /// <summary>
  210. /// Execute plugin
  211. /// </summary>
  212. private void ItemClick(object sender, EventArgs e)
  213. {
  214. var menuItem = sender as ToolStripMenuItem;
  215. if (menuItem == null)
  216. return;
  217. var plugin = menuItem.Tag as IGitPlugin;
  218. if (plugin == null)
  219. return;
  220. var eventArgs = new GitUIEventArgs(this, GitUICommands.Instance);
  221. string workingDirBefore = Settings.WorkingDir;
  222. bool refresh = plugin.Execute(eventArgs);
  223. if (workingDirBefore != Settings.WorkingDir)
  224. WorkingDirChanged(false);
  225. else if (refresh)
  226. RefreshToolStripMenuItemClick(null, null);
  227. }
  228. private void UpdatePluginMenu(bool validWorkingDir)
  229. {
  230. foreach (ToolStripItem item in pluginsToolStripMenuItem.DropDownItems)
  231. {
  232. var plugin = item.Tag as IGitPluginForRepository;
  233. item.Enabled = plugin == null || validWorkingDir;
  234. }
  235. }
  236. private void ActionOnRepositoryPerformed(object sender, EventArgs e)
  237. {
  238. InternalInitialize(false);
  239. }
  240. protected void Initialize()
  241. {
  242. try
  243. {
  244. InternalInitialize(true);
  245. }
  246. catch (Exception exception)
  247. {
  248. MessageBox.Show(this, exception.Message, _errorCaption.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
  249. }
  250. }
  251. private void InternalInitialize(bool hard)
  252. {
  253. Cursor.Current = Cursors.WaitCursor;
  254. GitUICommands.Instance.RaisePreBrowseInitialize(this);
  255. bool validWorkingDir = Settings.Module.ValidWorkingDir();
  256. bool hasWorkingDir = !string.IsNullOrEmpty(Settings.WorkingDir);
  257. branchSelect.Text = validWorkingDir ? Settings.Module.GetSelectedBranch() : "";
  258. if (hasWorkingDir)
  259. HideDashboard();
  260. else
  261. ShowDashboard();
  262. CommitInfoTabControl.Visible = validWorkingDir;
  263. fileExplorerToolStripMenuItem.Enabled = validWorkingDir;
  264. commandsToolStripMenuItem.Enabled = validWorkingDir;
  265. manageRemoteRepositoriesToolStripMenuItem1.Enabled = validWorkingDir;
  266. branchSelect.Enabled = validWorkingDir;
  267. toolStripButton1.Enabled = validWorkingDir;
  268. if (_toolStripGitStatus != null)
  269. _toolStripGitStatus.Enabled = validWorkingDir;
  270. toolStripButtonPull.Enabled = validWorkingDir;
  271. toolStripButtonPush.Enabled = validWorkingDir;
  272. submodulesToolStripMenuItem.Enabled = validWorkingDir;
  273. UpdatePluginMenu(validWorkingDir);
  274. gitMaintenanceToolStripMenuItem.Enabled = validWorkingDir;
  275. editgitignoreToolStripMenuItem1.Enabled = validWorkingDir;
  276. editgitattributesToolStripMenuItem.Enabled = validWorkingDir;
  277. editmailmapToolStripMenuItem.Enabled = validWorkingDir;
  278. toolStripSplitStash.Enabled = validWorkingDir;
  279. commitcountPerUserToolStripMenuItem.Enabled = validWorkingDir;
  280. _createPullRequestsToolStripMenuItem.Enabled = validWorkingDir;
  281. _viewPullRequestsToolStripMenuItem.Enabled = validWorkingDir;
  282. //Only show "Repository hosts" menu item when there is at least 1 repository host plugin loaded
  283. _repositoryHostsToolStripMenuItem.Visible = RepoHosts.GitHosters.Count > 0;
  284. if (RepoHosts.GitHosters.Count == 1)
  285. _repositoryHostsToolStripMenuItem.Text = RepoHosts.GitHosters[0].Description;
  286. _FilterBranchHelper.InitToolStripBranchFilter();
  287. if (hard)
  288. ShowRevisions();
  289. RefreshWorkingDirCombo();
  290. Text = GenerateWindowTitle(Settings.WorkingDir, validWorkingDir, branchSelect.Text);
  291. DiffText.Font = Settings.DiffFont;
  292. UpdateJumplist(validWorkingDir);
  293. CheckForMergeConflicts();
  294. UpdateStashCount();
  295. // load custom user menu
  296. LoadUserMenu();
  297. GitUICommands.Instance.RaisePostBrowseInitialize(this);
  298. Cursor.Current = Cursors.Default;
  299. }
  300. private void RefreshWorkingDirCombo()
  301. {
  302. if (Settings.RecentReposComboMinWidth > 0)
  303. {
  304. _NO_TRANSLATE_Workingdir.AutoSize = false;
  305. _NO_TRANSLATE_Workingdir.Width = Settings.RecentReposComboMinWidth;
  306. }
  307. else
  308. _NO_TRANSLATE_Workingdir.AutoSize = true;
  309. Repository r = null;
  310. if (Repositories.RepositoryHistory.Repositories.Count > 0)
  311. r = Repositories.RepositoryHistory.Repositories[0];
  312. List<RecentRepoInfo> mostRecentRepos = new List<RecentRepoInfo>();
  313. if (r == null || !r.Path.Equals(Settings.WorkingDir, StringComparison.InvariantCultureIgnoreCase))
  314. Repositories.AddMostRecentRepository(Settings.WorkingDir);
  315. using (var graphics = CreateGraphics())
  316. {
  317. var splitter = new RecentRepoSplitter
  318. {
  319. measureFont = _NO_TRANSLATE_Workingdir.Font,
  320. graphics = graphics
  321. };
  322. splitter.SplitRecentRepos(Repositories.RepositoryHistory.Repositories, mostRecentRepos, mostRecentRepos);
  323. }
  324. RecentRepoInfo ri = mostRecentRepos.Find((e) => e.Repo.Path.Equals(Settings.WorkingDir, StringComparison.InvariantCultureIgnoreCase));
  325. if (ri == null)
  326. _NO_TRANSLATE_Workingdir.Text = Settings.WorkingDir;
  327. else
  328. _NO_TRANSLATE_Workingdir.Text = ri.Caption;
  329. }
  330. /// <summary>
  331. /// Returns a short name for repository.
  332. /// If the repository contains a description it is returned,
  333. /// otherwise the last part of path is returned.
  334. /// </summary>
  335. /// <param name="repositoryDir">Path to repository.</param>
  336. /// <returns>Short name for repository</returns>
  337. private static String GetRepositoryShortName(string repositoryDir)
  338. {
  339. DirectoryInfo dirInfo = new DirectoryInfo(repositoryDir);
  340. if (dirInfo.Exists)
  341. {
  342. string desc = ReadRepositoryDescription(repositoryDir);
  343. if (desc.IsNullOrEmpty())
  344. {
  345. desc = Repositories.RepositoryHistory.Repositories
  346. .Where(repo => repo.Path.Equals(repositoryDir, StringComparison.CurrentCultureIgnoreCase)).Select(repo => repo.Title)
  347. .FirstOrDefault();
  348. }
  349. return desc ?? dirInfo.Name;
  350. }
  351. return dirInfo.Name;
  352. }
  353. private void LoadUserMenu()
  354. {
  355. var scripts = ScriptManager.GetScripts().Where(script => script.Enabled
  356. && script.OnEvent == ScriptEvent.ShowInUserMenuBar).ToList();
  357. for (int i = ToolStrip.Items.Count - 1; i >= 0; i--)
  358. if (ToolStrip.Items[i].Tag != null &&
  359. ToolStrip.Items[i].Tag as String == "userscript")
  360. ToolStrip.Items.RemoveAt(i);
  361. if (scripts.Count == 0)
  362. return;
  363. ToolStripSeparator toolstripseparator = new ToolStripSeparator();
  364. toolstripseparator.Tag = "userscript";
  365. ToolStrip.Items.Add(toolstripseparator);
  366. foreach (ScriptInfo scriptInfo in scripts)
  367. {
  368. ToolStripButton tempButton = new ToolStripButton();
  369. //store scriptname
  370. tempButton.Text = scriptInfo.Name;
  371. tempButton.Tag = "userscript";
  372. //add handler
  373. tempButton.Click += UserMenu_Click;
  374. tempButton.Enabled = true;
  375. tempButton.Visible = true;
  376. //tempButton.Image = GitUI.Properties.Resources.bug;
  377. //scriptInfo.Icon = "Cow";
  378. tempButton.Image = scriptInfo.GetIcon();
  379. tempButton.DisplayStyle = ToolStripItemDisplayStyle.ImageAndText;
  380. //add to toolstrip
  381. ToolStrip.Items.Add(tempButton);
  382. }
  383. }
  384. private void UserMenu_Click(object sender, EventArgs e)
  385. {
  386. ScriptRunner.RunScript(((ToolStripButton)sender).Text, null);
  387. RevisionGrid.RefreshRevisions();
  388. }
  389. private void UpdateJumplist(bool validWorkingDir)
  390. {
  391. #if !__MonoCS__
  392. if (Settings.RunningOnWindows() && TaskbarManager.IsPlatformSupported)
  393. {
  394. //Call this method using reflection. This is a workaround to *not* reference WPF libraries, becuase of how the WindowsAPICodePack was implimented.
  395. TaskbarManager.Instance.GetType().InvokeMember("SetApplicationIdForSpecificWindow", System.Reflection.BindingFlags.InvokeMethod, null, TaskbarManager.Instance, new object[] { Handle, "GitExtensions" });
  396. if (validWorkingDir)
  397. {
  398. string repositoryDescription = GetRepositoryShortName(Settings.WorkingDir);
  399. string baseFolder = Path.Combine(Settings.ApplicationDataPath, "Recent");
  400. if (!Directory.Exists(baseFolder))
  401. {
  402. Directory.CreateDirectory(baseFolder);
  403. }
  404. //Remove InvalidPathChars
  405. StringBuilder sb = new StringBuilder(repositoryDescription);
  406. foreach (char c in Path.GetInvalidFileNameChars())
  407. {
  408. sb.Replace(c, '_');
  409. }
  410. string path = Path.Combine(baseFolder, String.Format("{0}.{1}", sb, "gitext"));
  411. File.WriteAllText(path, Settings.WorkingDir);
  412. JumpList.AddToRecent(path);
  413. }
  414. CreateOrUpdateTaskBarButtons(validWorkingDir);
  415. }
  416. #endif
  417. }
  418. private void CreateOrUpdateTaskBarButtons(bool validRepo)
  419. {
  420. #if !__MonoCS__
  421. if (Settings.RunningOnWindows() && TaskbarManager.IsPlatformSupported)
  422. {
  423. if (!_toolbarButtonsCreated)
  424. {
  425. _commitButton = new ThumbnailToolBarButton(MakeIcon(toolStripButton1.Image, 48, true), toolStripButton1.Text);
  426. _commitButton.Click += ToolStripButton1Click;
  427. _pushButton = new ThumbnailToolBarButton(MakeIcon(toolStripButtonPush.Image, 48, true), toolStripButtonPush.Text);
  428. _pushButton.Click += PushToolStripMenuItemClick;
  429. _pullButton = new ThumbnailToolBarButton(MakeIcon(toolStripButtonPull.Image, 48, true), toolStripButtonPull.Text);
  430. _pullButton.Click += PullToolStripMenuItemClick;
  431. _toolbarButtonsCreated = true;
  432. ThumbnailToolBarButton[] buttons = new[] { _commitButton, _pullButton, _pushButton };
  433. //Call this method using reflection. This is a workaround to *not* reference WPF libraries, becuase of how the WindowsAPICodePack was implimented.
  434. TaskbarManager.Instance.ThumbnailToolBars.GetType().InvokeMember("AddButtons", System.Reflection.BindingFlags.InvokeMethod, null, TaskbarManager.Instance.ThumbnailToolBars,
  435. new object[] { Handle, buttons });
  436. }
  437. _commitButton.Enabled = validRepo;
  438. _pushButton.Enabled = validRepo;
  439. _pullButton.Enabled = validRepo;
  440. }
  441. #endif
  442. }
  443. /// <summary>
  444. /// Converts an image into an icon. This was taken off of the interwebs.
  445. /// It's on a billion different sites and forum posts, so I would say its creative commons by now. -tekmaven
  446. /// </summary>
  447. /// <param name="img">The image that shall become an icon</param>
  448. /// <param name="size">The width and height of the icon. Standard
  449. /// sizes are 16x16, 32x32, 48x48, 64x64.</param>
  450. /// <param name="keepAspectRatio">Whether the image should be squashed into a
  451. /// square or whether whitespace should be put around it.</param>
  452. /// <returns>An icon!!</returns>
  453. private static Icon MakeIcon(Image img, int size, bool keepAspectRatio)
  454. {
  455. Bitmap square = new Bitmap(size, size); // create new bitmap
  456. Graphics g = Graphics.FromImage(square); // allow drawing to it
  457. int x, y, w, h; // dimensions for new image
  458. if (!keepAspectRatio || img.Height == img.Width)
  459. {
  460. // just fill the square
  461. x = y = 0; // set x and y to 0
  462. w = h = size; // set width and height to size
  463. }
  464. else
  465. {
  466. // work out the aspect ratio
  467. float r = (float)img.Width / (float)img.Height;
  468. // set dimensions accordingly to fit inside size^2 square
  469. if (r > 1)
  470. { // w is bigger, so divide h by r
  471. w = size;
  472. h = (int)((float)size / r);
  473. x = 0; y = (size - h) / 2; // center the image
  474. }
  475. else
  476. { // h is bigger, so multiply w by r
  477. w = (int)((float)size * r);
  478. h = size;
  479. y = 0; x = (size - w) / 2; // center the image
  480. }
  481. }
  482. // make the image shrink nicely by using HighQualityBicubic mode
  483. g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
  484. g.DrawImage(img, x, y, w, h); // draw image with specified dimensions
  485. g.Flush(); // make sure all drawing operations complete before we get the icon
  486. // following line would work directly on any image, but then
  487. // it wouldn't look as nice.
  488. return Icon.FromHandle(square.GetHicon());
  489. }
  490. private void UpdateStashCount()
  491. {
  492. if (Settings.ShowStashCount)
  493. {
  494. int stashCount = Settings.Module.GetStashes().Count;
  495. toolStripSplitStash.Text = string.Format(_stashCount.Text, stashCount,
  496. stashCount != 1 ? _stashPlural.Text : _stashSingular.Text);
  497. }
  498. else
  499. {
  500. toolStripSplitStash.Text = string.Empty;
  501. }
  502. }
  503. private void CheckForMergeConflicts()
  504. {
  505. bool validWorkingDir = Settings.Module.ValidWorkingDir();
  506. if (validWorkingDir && Settings.Module.InTheMiddleOfBisect())
  507. {
  508. if (_bisect == null)
  509. {
  510. _bisect = new WarningToolStripItem { Text = _warningMiddleOfBisect.Text };
  511. _bisect.Click += BisectClick;
  512. statusStrip.Items.Add(_bisect);
  513. }
  514. }
  515. else
  516. {
  517. if (_bisect != null)
  518. {
  519. _bisect.Click -= BisectClick;
  520. statusStrip.Items.Remove(_bisect);
  521. _bisect = null;
  522. }
  523. }
  524. if (validWorkingDir &&
  525. (Settings.Module.InTheMiddleOfRebase() || Settings.Module.InTheMiddleOfPatch()))
  526. {
  527. if (_rebase == null)
  528. {
  529. _rebase = new WarningToolStripItem
  530. {
  531. Text = Settings.Module.InTheMiddleOfRebase()
  532. ? _warningMiddleOfRebase.Text
  533. : _warningMiddleOfPatchApply.Text
  534. };
  535. _rebase.Click += RebaseClick;
  536. statusStrip.Items.Add(_rebase);
  537. }
  538. }
  539. else
  540. {
  541. if (_rebase != null)
  542. {
  543. _rebase.Click -= RebaseClick;
  544. statusStrip.Items.Remove(_rebase);
  545. _rebase = null;
  546. }
  547. }
  548. if (validWorkingDir && Settings.Module.InTheMiddleOfConflictedMerge() &&
  549. !Directory.Exists(Settings.Module.GetGitDirectory() + "rebase-apply\\"))
  550. {
  551. if (_warning == null)
  552. {
  553. _warning = new WarningToolStripItem { Text = _hintUnresolvedMergeConflicts.Text };
  554. _warning.Click += WarningClick;
  555. statusStrip.Items.Add(_warning);
  556. }
  557. }
  558. else
  559. {
  560. if (_warning != null)
  561. {
  562. _warning.Click -= WarningClick;
  563. statusStrip.Items.Remove(_warning);
  564. _warning = null;
  565. }
  566. }
  567. //Only show status strip when there are status items on it.
  568. //There is always a close (x) button, do not count first item.
  569. if (statusStrip.Items.Count > 1)
  570. statusStrip.Show();
  571. else
  572. statusStrip.Hide();
  573. }
  574. /// <summary>
  575. /// Generates main window title according to given repository.
  576. /// </summary>
  577. /// <param name="workingDir">Path to repository.</param>
  578. /// <param name="isWorkingDirValid">If the given path contains valid repository.</param>
  579. /// <param name="branchName">Current branch name.</param>
  580. private static string GenerateWindowTitle(string workingDir, bool isWorkingDirValid, string branchName)
  581. {
  582. #if DEBUG
  583. const string defaultTitle = "Git Extensions -> DEBUG <-";
  584. const string repositoryTitleFormat = "{0} ({1}) - Git Extensions -> DEBUG <-";
  585. #else
  586. const string defaultTitle = "Git Extensions";
  587. const string repositoryTitleFormat = "{0} ({1}) - Git Extensions";
  588. #endif
  589. if (!isWorkingDirValid)
  590. return defaultTitle;
  591. string repositoryDescription = GetRepositoryShortName(workingDir);
  592. if (string.IsNullOrEmpty(branchName))
  593. branchName = _noBranchTitle.Text;
  594. return string.Format(repositoryTitleFormat, repositoryDescription, branchName.Trim('(', ')'));
  595. }
  596. /// <summary>
  597. /// Reads repository description's first line from ".git\description" file.
  598. /// </summary>
  599. /// <param name="workingDir">Path to repository.</param>
  600. /// <returns>If the repository has description, returns that description, else returns <c>null</c>.</returns>
  601. private static string ReadRepositoryDescription(string workingDir)
  602. {
  603. const string repositoryDescriptionFileName = "description";
  604. const string defaultDescription = "Unnamed repository; edit this file 'description' to name the repository.";
  605. var repositoryPath = GitModule.GetGitDirectory(workingDir);
  606. var repositoryDescriptionFilePath = Path.Combine(repositoryPath, repositoryDescriptionFileName);
  607. if (!File.Exists(repositoryDescriptionFilePath))
  608. return null;
  609. try
  610. {
  611. var repositoryDescription = File.ReadAllLines(repositoryDescriptionFilePath).FirstOrDefault();
  612. return string.Equals(repositoryDescription, defaultDescription, StringComparison.CurrentCulture)
  613. ? null
  614. : repositoryDescription;
  615. }
  616. catch (IOException)
  617. {
  618. return null;
  619. }
  620. }
  621. private void RebaseClick(object sender, EventArgs e)
  622. {
  623. if (Settings.Module.InTheMiddleOfRebase())
  624. GitUICommands.Instance.StartRebaseDialog(this, null);
  625. else
  626. GitUICommands.Instance.StartApplyPatchDialog(this);
  627. Initialize();
  628. }
  629. private void ShowRevisions()
  630. {
  631. if (IndexWatcher.IndexChanged)
  632. {
  633. RevisionGrid.RefreshRevisions();
  634. FillFileTree();
  635. FillDiff();
  636. FillCommitInfo();
  637. }
  638. IndexWatcher.Reset();
  639. }
  640. //store strings to not keep references to nodes
  641. private readonly Stack<string> lastSelectedNodes = new Stack<string>();
  642. private void FillFileTree()
  643. {
  644. if (CommitInfoTabControl.SelectedTab != Tree)
  645. return;
  646. try
  647. {
  648. GitTree.SuspendLayout();
  649. // Save state only when there is selected node
  650. if (GitTree.SelectedNode != null)
  651. {
  652. TreeNode node = GitTree.SelectedNode;
  653. FileText.SaveCurrentScrollPos();
  654. lastSelectedNodes.Clear();
  655. while (node != null)
  656. {
  657. lastSelectedNodes.Push(node.Text);
  658. node = node.Parent;
  659. }
  660. }
  661. // Refresh tree
  662. GitTree.Nodes.Clear();
  663. //restore selected file and scroll position when new selection is done
  664. if (RevisionGrid.GetSelectedRevisions().Count > 0)
  665. {
  666. LoadInTree(RevisionGrid.GetSelectedRevisions()[0].SubItems, GitTree.Nodes);
  667. //GitTree.Sort();
  668. TreeNode lastMatchedNode = null;
  669. // Load state
  670. var currenNodes = GitTree.Nodes;
  671. TreeNode matchedNode = null;
  672. while (lastSelectedNodes.Count > 0 && currenNodes != null)
  673. {
  674. var next = lastSelectedNodes.Pop();
  675. foreach (TreeNode node in currenNodes)
  676. {
  677. if (node.Text != next && next.Length != 40)
  678. continue;
  679. node.Expand();
  680. matchedNode = node;
  681. break;
  682. }
  683. if (matchedNode == null)
  684. currenNodes = null;
  685. else
  686. {
  687. lastMatchedNode = matchedNode;
  688. currenNodes = matchedNode.Nodes;
  689. }
  690. }
  691. //if there is no exact match, don't restore scroll position
  692. if (lastMatchedNode != matchedNode)
  693. FileText.ResetCurrentScrollPos();
  694. GitTree.SelectedNode = lastMatchedNode;
  695. }
  696. if (GitTree.SelectedNode == null)
  697. {
  698. FileText.ViewText("", "");
  699. }
  700. }
  701. finally
  702. {
  703. GitTree.ResumeLayout();
  704. }
  705. }
  706. private void FillDiff()
  707. {
  708. if (CommitInfoTabControl.SelectedTab != Diff)
  709. return;
  710. var revisions = RevisionGrid.GetSelectedRevisions();
  711. DiffText.SaveCurrentScrollPos();
  712. DiffFiles.SetNoFilesText(_NoDiffFilesChangesText);
  713. switch (revisions.Count)
  714. {
  715. case 2:
  716. bool artificialRevSelected = revisions[0].IsArtificial() || revisions[1].IsArtificial();
  717. if (artificialRevSelected)
  718. {
  719. DiffFiles.SetNoFilesText(_UnsupportedMultiselectAction.Text);
  720. DiffFiles.GitItemStatuses = null;
  721. }
  722. else
  723. DiffFiles.GitItemStatuses =
  724. Settings.Module.GetDiffFiles(revisions[0].Guid, revisions[1].Guid);
  725. break;
  726. case 0:
  727. DiffFiles.GitItemStatuses = null;
  728. return;
  729. default:
  730. var revision = revisions[0];
  731. DiffFiles.Revision = revision;
  732. if (revision == null)
  733. DiffFiles.GitItemStatuses = null;
  734. else if (revision.ParentGuids == null || revision.ParentGuids.Length == 0)
  735. DiffFiles.GitItemStatuses = Settings.Module.GetTreeFiles(revision.TreeGuid, true);
  736. else
  737. {
  738. if (revision.Guid == GitRevision.UncommittedWorkingDirGuid) //working dir changes
  739. DiffFiles.GitItemStatuses = Settings.Module.GetUnstagedFiles();
  740. else if (revision.Guid == GitRevision.IndexGuid) //index
  741. DiffFiles.GitItemStatuses = Settings.Module.GetStagedFiles();
  742. else
  743. DiffFiles.GitItemStatuses = Settings.Module.GetDiffFiles(revision.Guid, revision.ParentGuids[0]);
  744. }
  745. break;
  746. }
  747. }
  748. private void FillCommitInfo()
  749. {
  750. if (CommitInfoTabControl.SelectedTab != CommitInfo)
  751. return;
  752. if (RevisionGrid.GetSelectedRevisions().Count == 0)
  753. return;
  754. var revision = RevisionGrid.GetSelectedRevisions()[0];
  755. if (revision != null)
  756. RevisionInfo.SetRevision(revision.Guid);
  757. }
  758. public void FileHistoryOnClick(object sender, EventArgs e)
  759. {
  760. var item = GitTree.SelectedNode.Tag as GitItem;
  761. if (item == null)
  762. return;
  763. if (item.IsBlob || item.IsTree)
  764. {
  765. IList<GitRevision> revisions = RevisionGrid.GetSelectedRevisions();
  766. if (revisions.Count == 0)
  767. GitUICommands.Instance.StartFileHistoryDialog(this, item.FileName);
  768. else
  769. GitUICommands.Instance.StartFileHistoryDialog(this, item.FileName, revisions[0], false, false);
  770. }
  771. }
  772. public void FindFileOnClick(object sender, EventArgs e)
  773. {
  774. var searchWindow = new SearchWindow<string>(FindFileMatches)
  775. {
  776. Owner = this
  777. };
  778. searchWindow.ShowDialog(this);
  779. string selectedItem = searchWindow.SelectedItem;
  780. if (string.IsNullOrEmpty(selectedItem))
  781. {
  782. return;
  783. }
  784. string[] items = selectedItem.Split(new[] { '/' });
  785. TreeNodeCollection nodes = GitTree.Nodes;
  786. for (int i = 0; i < items.Length - 1; i++)
  787. {
  788. TreeNode selectedNode = Find(nodes, items[i]);
  789. if (selectedNode == null)
  790. {
  791. return; //Item does not exist in the tree
  792. }
  793. selectedNode.Expand();
  794. nodes = selectedNode.Nodes;
  795. }
  796. var lastItem = Find(nodes, items[items.Length - 1]);
  797. if (lastItem != null)
  798. {
  799. GitTree.SelectedNode = lastItem;
  800. }
  801. }
  802. private static TreeNode Find(TreeNodeCollection nodes, string label)
  803. {
  804. for (int i = 0; i < nodes.Count; i++)
  805. {
  806. if (nodes[i].Text == label)
  807. {
  808. return nodes[i];
  809. }
  810. }
  811. return null;
  812. }
  813. private IList<string> FindFileMatches(string name)
  814. {
  815. var candidates = Settings.Module.GetFullTree(RevisionGrid.GetSelectedRevisions()[0].TreeGuid);
  816. string nameAsLower = name.ToLower();
  817. return candidates.Where(fileName => fileName.ToLower().Contains(nameAsLower)).ToList();
  818. }
  819. public void OpenWithOnClick(object sender, EventArgs e)
  820. {
  821. var gitItem = GitTree.SelectedNode.Tag as GitItem;
  822. if (gitItem == null || !gitItem.IsBlob)
  823. return;
  824. var fileName = gitItem.FileName;
  825. if (fileName.Contains("\\") && fileName.LastIndexOf("\\") < fileName.Length)
  826. fileName = fileName.Substring(fileName.LastIndexOf('\\') + 1);
  827. if (fileName.Contains("/") && fileName.LastIndexOf("/") < fileName.Length)
  828. fileName = fileName.Substring(fileName.LastIndexOf('/') + 1);
  829. fileName = (Path.GetTempPath() + fileName).Replace(Settings.PathSeparatorWrong, Settings.PathSeparator);
  830. Settings.Module.SaveBlobAs(fileName, gitItem.Guid);
  831. OpenWith.OpenAs(fileName);
  832. }
  833. private void FileTreeContextMenu_Opening(object sender, System.ComponentModel.CancelEventArgs e)
  834. {
  835. var gitItem = (GitTree.SelectedNode != null) ? GitTree.SelectedNode.Tag as GitItem : null;
  836. var enableItems = gitItem != null && gitItem.IsBlob;
  837. saveAsToolStripMenuItem.Enabled = enableItems;
  838. openFileToolStripMenuItem.Enabled = enableItems;
  839. openFileWithToolStripMenuItem.Enabled = enableItems;
  840. openWithToolStripMenuItem.Enabled = enableItems;
  841. copyFilenameToClipboardToolStripMenuItem.Enabled = enableItems;
  842. fileHistoryToolStripMenuItem.Enabled = enableItems;
  843. editCheckedOutFileToolStripMenuItem.Enabled = enableItems;
  844. }
  845. public void OpenOnClick(object sender, EventArgs e)
  846. {
  847. try
  848. {
  849. var gitItem = GitTree.SelectedNode.Tag as GitItem;
  850. if (gitItem == null || !gitItem.IsBlob)
  851. return;
  852. var fileName = gitItem.FileName;
  853. if (fileName.Contains("\\") && fileName.LastIndexOf("\\") < fileName.Length)
  854. fileName = fileName.Substring(fileName.LastIndexOf('\\') + 1);
  855. if (fileName.Contains("/") && fileName.LastIndexOf("/") < fileName.Length)
  856. fileName = fileName.Substring(fileName.LastIndexOf('/') + 1);
  857. fileName = (Path.GetTempPath() + fileName).Replace(Settings.PathSeparatorWrong, Settings.PathSeparator);
  858. Settings.Module.SaveBlobAs(fileName, (gitItem).Guid);
  859. Process.Start(fileName);
  860. }
  861. catch (Exception ex)
  862. {
  863. MessageBox.Show(this, ex.Message);
  864. }
  865. }
  866. protected void LoadInTree(List<IGitItem> items, TreeNodeCollection node)
  867. {
  868. items.Sort(new GitFileTreeComparer());
  869. foreach (var item in items)
  870. {
  871. var subNode = node.Add(item.Name);
  872. subNode.Tag = item;
  873. var gitItem = item as GitItem;
  874. if (gitItem == null)
  875. subNode.Nodes.Add(new TreeNode());
  876. else
  877. {
  878. if (gitItem.IsTree)
  879. {
  880. subNode.ImageIndex = 1;
  881. subNode.SelectedImageIndex = 1;
  882. subNode.Nodes.Add(new TreeNode());
  883. }
  884. else
  885. if (gitItem.IsCommit)
  886. {
  887. subNode.ImageIndex = 2;
  888. subNode.SelectedImageIndex = 2;
  889. subNode.Text = item.Name + " (Submodule)";
  890. }
  891. }
  892. }
  893. }
  894. private void RevisionGridSelectionChanged(object sender, EventArgs e)
  895. {
  896. try
  897. {
  898. var revisions = RevisionGrid.GetSelectedRevisions();
  899. if (revisions.Count > 0 &&
  900. (revisions[0].Guid == GitRevision.UncommittedWorkingDirGuid ||
  901. revisions[0].Guid == GitRevision.IndexGuid))
  902. {
  903. CommitInfoTabControl.RemoveIfExists(CommitInfo);
  904. CommitInfoTabControl.RemoveIfExists(Tree);
  905. }
  906. else
  907. {
  908. CommitInfoTabControl.InsertIfNotExists(0, CommitInfo);
  909. CommitInfoTabControl.InsertIfNotExists(1, Tree);
  910. }
  911. FillFileTree();
  912. FillDiff();
  913. FillCommitInfo();
  914. }
  915. catch (Exception ex)
  916. {
  917. Trace.WriteLine(ex.Message);
  918. }
  919. }
  920. private void OpenToolStripMenuItemClick(object sender, EventArgs e)
  921. {
  922. if (new Open().ShowDialog(this) == DialogResult.OK)
  923. {
  924. WorkingDirChanged(false);
  925. }
  926. }
  927. private void CheckoutToolStripMenuItemClick(object sender, EventArgs e)
  928. {
  929. if (GitUICommands.Instance.StartCheckoutRevisionDialog(this))
  930. Initialize();
  931. }
  932. private void GitTreeDoubleClick(object sender, EventArgs e)
  933. {
  934. if (GitTree.SelectedNode == null || !(GitTree.SelectedNode.Tag is IGitItem))
  935. return;
  936. var item = GitTree.SelectedNode.Tag as GitItem;
  937. if (item == null)
  938. return;
  939. if (!item.IsBlob)
  940. return;
  941. if (GitUICommands.Instance.StartFileHistoryDialog(this, item.FileName, null))
  942. Initialize();
  943. }
  944. private void ViewDiffToolStripMenuItemClick(object sender, EventArgs e)
  945. {
  946. if (GitUICommands.Instance.StartCompareRevisionsDialog(this))
  947. Initialize();
  948. }
  949. private void CloneToolStripMenuItemClick(object sender, EventArgs e)
  950. {
  951. if (GitUICommands.Instance.StartCloneDialog(this))
  952. Initialize();
  953. }
  954. private void CommitToolStripMenuItemClick(object sender, EventArgs e)
  955. {
  956. GitUICommands.Instance.StartCommitDialog(Initialize, this);
  957. }
  958. private void InitNewRepositoryToolStripMenuItemClick(object sender, EventArgs e)
  959. {
  960. if (GitUICommands.Instance.StartInitializeDialog(this))
  961. Initialize();
  962. }
  963. private void PushToolStripMenuItemClick(object sender, EventArgs e)
  964. {
  965. bool bSilent = (ModifierKeys & Keys.Shift) != 0;
  966. if (GitUICommands.Instance.StartPushDialog(this, bSilent))
  967. Initialize();
  968. }
  969. private void PullToolStripMenuItemClick(object sender, EventArgs e)
  970. {
  971. bool bSilent;
  972. if (sender == toolStripButtonPull || sender == pullToolStripMenuItem)
  973. {
  974. if (Settings.LastPullAction == Settings.PullAction.None)
  975. {
  976. bSilent = (ModifierKeys & Keys.Shift) != 0;
  977. }
  978. else
  979. {
  980. bSilent = true;
  981. Settings.LastPullActionToPullMerge();
  982. }
  983. }
  984. else
  985. {
  986. bSilent = sender != pullToolStripMenuItem1;
  987. RefreshPullIcon();
  988. Settings.LastPullActionToPullMerge();
  989. }
  990. if (GitUICommands.Instance.StartPullDialog(this, bSilent))
  991. Initialize();
  992. }
  993. private void RefreshToolStripMenuItemClick(object sender, EventArgs e)
  994. {
  995. if (_dashboard != null)
  996. {
  997. _dashboard.Refresh();
  998. }
  999. if (_dashboard == null || !_dashboard.Visible)
  1000. {
  1001. RevisionGrid.ForceRefreshRevisions();
  1002. InternalInitialize(false);
  1003. IndexWatcher.Reset();
  1004. }
  1005. }
  1006. private void AboutToolStripMenuItemClick(object sender, EventArgs e)
  1007. {
  1008. new AboutBox().ShowDialog(this);
  1009. }
  1010. private void PatchToolStripMenuItemClick(object sender, EventArgs e)
  1011. {
  1012. if (GitUICommands.Instance.StartViewPatchDialog(this))
  1013. Initialize();
  1014. }
  1015. private void ApplyPatchToolStripMenuItemClick(object sender, EventArgs e)
  1016. {
  1017. if (GitUICommands.Instance.StartApplyPatchDialog(this))
  1018. Initialize();
  1019. }
  1020. private void GitBashToolStripMenuItemClick1(object sender, EventArgs e)
  1021. {
  1022. Settings.Module.RunBash();
  1023. }
  1024. private void GitGuiToolStripMenuItemClick(object sender, EventArgs e)
  1025. {
  1026. Settings.Module.RunGui();
  1027. }
  1028. private void FormatPatchToolStripMenuItemClick(object sender, EventArgs e)
  1029. {
  1030. if (GitUICommands.Instance.StartFormatPatchDialog(this))
  1031. Initialize();
  1032. }
  1033. private void GitcommandLogToolStripMenuItemClick(object sender, EventArgs e)
  1034. {
  1035. GitLogForm.ShowOrActivate(this);
  1036. }
  1037. private void CheckoutBranchToolStripMenuItemClick(object sender, EventArgs e)
  1038. {
  1039. if (GitUICommands.Instance.StartCheckoutBranchDialog(this))
  1040. Initialize();
  1041. }
  1042. private void StashToolStripMenuItemClick(object sender, EventArgs e)
  1043. {
  1044. if (GitUICommands.Instance.StartStashDialog(this))
  1045. Initialize();
  1046. }
  1047. private void RunMergetoolToolStripMenuItemClick(object sender, EventArgs e)
  1048. {
  1049. if (GitUICommands.Instance.StartResolveConflictsDialog(this))
  1050. Initialize();
  1051. }
  1052. private void WarningClick(object sender, EventArgs e)
  1053. {
  1054. if (GitUICommands.Instance.StartResolveConflictsDialog(this))
  1055. Initialize();
  1056. }
  1057. private void WorkingdirClick(object sender, EventArgs e)
  1058. {
  1059. _NO_TRANSLATE_Workingdir.ShowDropDown();
  1060. }
  1061. private void CurrentBranchClick(object sender, EventArgs e)
  1062. {
  1063. branchSelect.ShowDropDown();
  1064. }
  1065. private void DeleteBranchToolStripMenuItemClick(object sender, EventArgs e)
  1066. {
  1067. if (GitUICommands.Instance.StartDeleteBranchDialog(this, null))
  1068. Initialize();
  1069. }
  1070. private void CherryPickToolStripMenuItemClick(object sender, EventArgs e)
  1071. {
  1072. if (GitUICommands.Instance.StartCherryPickDialog(this))
  1073. Initialize();
  1074. }
  1075. private void MergeBranchToolStripMenuItemClick(object sender, EventArgs e)
  1076. {
  1077. if (GitUICommands.Instance.StartMergeBranchDialog(this, null))
  1078. Initialize();
  1079. }
  1080. private void ToolStripButton1Click(object sender, EventArgs e)
  1081. {
  1082. CommitToolStripMenuItemClick(sender, e);
  1083. }
  1084. private void SettingsClick(object sender, EventArgs e)
  1085. {
  1086. SettingsToolStripMenuItem2Click(sender, e);
  1087. }
  1088. private void TagToolStripMenuItemClick(object sender, EventArgs e)
  1089. {
  1090. if (GitUICommands.Instance.StartCreateTagDialog(this))
  1091. Initialize();
  1092. }
  1093. private void RefreshButtonClick(object sender, EventArgs e)
  1094. {
  1095. RefreshToolStripMenuItemClick(sender, e);
  1096. }
  1097. private void CommitcountPerUserToolStripMenuItemClick(object sender, EventArgs e)
  1098. {
  1099. new FormCommitCount().ShowDialog(this);
  1100. }
  1101. private void KGitToolStripMenuItemClick(object sender, EventArgs e)
  1102. {
  1103. Settings.Module.RunGitK();
  1104. }
  1105. private void DonateToolStripMenuItemClick(object sender, EventArgs e)
  1106. {
  1107. new FormDonate().ShowDialog(this);
  1108. }
  1109. private void DeleteTagToolStripMenuItemClick(object sender, EventArgs e)
  1110. {
  1111. if (GitUICommands.Instance.StartDeleteTagDialog(this))
  1112. Initialize();
  1113. }
  1114. private void FormBrowseFormClosing(object sender, FormClosingEventArgs e)
  1115. {
  1116. SaveUserMenuPosition();
  1117. SavePosition("browse");
  1118. }
  1119. private void SaveUserMenuPosition()
  1120. {
  1121. GitCommands.Settings.UserMenuLocationX = UserMenuToolStrip.Location.X;
  1122. GitCommands.Settings.UserMenuLocationY = UserMenuToolStrip.Location.Y;
  1123. }
  1124. private void EditGitignoreToolStripMenuItem1Click(object sender, EventArgs e)
  1125. {
  1126. if (GitUICommands.Instance.StartEditGitIgnoreDialog(this))
  1127. Initialize();
  1128. }
  1129. private void SettingsToolStripMenuItem2Click(object sender, EventArgs e)
  1130. {
  1131. var translation = Settings.Translation;
  1132. GitUICommands.Instance.StartSettingsDialog(this);
  1133. if (translation != Settings.Translation)
  1134. Translate();
  1135. this.Hotkeys = HotkeySettingsManager.LoadHotkeys(HotkeySettingsName);
  1136. Initialize();
  1137. RevisionGrid.ReloadHotkeys();
  1138. RevisionGrid.ReloadTranslation();
  1139. }
  1140. private void ArchiveToolStripMenuItemClick(object sender, EventArgs e)
  1141. {
  1142. if (GitUICommands.Instance.StartArchiveDialog(this))
  1143. Initialize();
  1144. }
  1145. private void EditMailMapToolStripMenuItemClick(object sender, EventArgs e)
  1146. {
  1147. if (GitUICommands.Instance.StartMailMapDialog(this))
  1148. Initialize();
  1149. }
  1150. private void CompressGitDatabaseToolStripMenuItemClick(object sender, EventArgs e)
  1151. {
  1152. FormProcess.ShowDialog(this, "gc");
  1153. }
  1154. private void VerifyGitDatabaseToolStripMenuItemClick(object sender, EventArgs e)
  1155. {
  1156. if (GitUICommands.Instance.StartVerifyDatabaseDialog(this))
  1157. Initialize();
  1158. }
  1159. private void ManageRemoteRepositoriesToolStripMenuItemClick(object sender, EventArgs e)
  1160. {
  1161. if (GitUICommands.Instance.StartRemotesDialog(this))
  1162. Initialize();
  1163. }
  1164. private void RebaseToolStripMenuItemClick(object sender, EventArgs e)
  1165. {
  1166. if (GitUICommands.Instance.StartRebaseDialog(this, null))
  1167. Initialize();
  1168. }
  1169. private void StartAuthenticationAgentToolStripMenuItemClick(object sender, EventArgs e)
  1170. {
  1171. Settings.Module.StartExternalCommand(Settings.Pageant, "");
  1172. }
  1173. private void GenerateOrImportKeyToolStripMenuItemClick(object sender, EventArgs e)
  1174. {
  1175. Settings.Module.StartExternalCommand(Settings.Puttygen, "");
  1176. }
  1177. private void TabControl1SelectedIndexChanged(object sender, EventArgs e)
  1178. {
  1179. FillFileTree();
  1180. FillDiff();
  1181. FillCommitInfo();
  1182. }
  1183. private void DiffFilesSelectedIndexChanged(object sender, EventArgs e)
  1184. {
  1185. if (!_dontUpdateOnIndexChange)
  1186. ShowSelectedFileDiff();
  1187. }
  1188. private void ShowSelectedFileDiff()
  1189. {
  1190. if (DiffFiles.SelectedItem == null)
  1191. {
  1192. DiffText.ViewPatch("");
  1193. return;
  1194. }
  1195. GitItemStatus selectedItem = DiffFiles.SelectedItem;
  1196. DiffText.ViewPatch(RevisionGrid, selectedItem, String.Empty);
  1197. }
  1198. private void ChangelogToolStripMenuItemClick(object sender, EventArgs e)
  1199. {
  1200. new FormChangeLog().ShowDialog(this);
  1201. }
  1202. private void DiffFilesDoubleClick(object sender, EventArgs e)
  1203. {
  1204. if (DiffFiles.SelectedItem == null)
  1205. return;
  1206. if (GitUICommands.Instance.StartFileHistoryDialog(this, (DiffFiles.SelectedItem).Name))
  1207. Initialize();
  1208. }
  1209. private void ToolStripButtonPushClick(object sender, EventArgs e)
  1210. {
  1211. PushToolStripMenuItemClick(sender, e);
  1212. }
  1213. private void ManageSubmodulesToolStripMenuItemClick(object sender, EventArgs e)
  1214. {
  1215. if (GitUICommands.Instance.StartSubmodulesDialog(this))
  1216. Initialize();
  1217. }
  1218. private void UpdateAllSubmodulesToolStripMenuItemClick(object sender, EventArgs e)
  1219. {
  1220. if (GitUICommands.Instance.StartUpdateSubmodulesDialog(this))
  1221. Initialize();
  1222. }
  1223. private void SynchronizeAllSubmodulesToolStripMenuItemClick(object sender, EventArgs e)
  1224. {
  1225. if (GitUICommands.Instance.StartSyncSubmodulesDialog(this))
  1226. Initialize();
  1227. }
  1228. private void ToolStripSplitStashButtonClick(object sender, EventArgs e)
  1229. {
  1230. if (GitUICommands.Instance.StartStashDialog(this))
  1231. Initialize();
  1232. }
  1233. private void StashChangesToolStripMenuItemClick(object sender, EventArgs e)
  1234. {
  1235. var arguments = GitCommandHelpers.StashSaveCmd(Settings.IncludeUntrackedFilesInManualStash);
  1236. FormProcess.ShowDialog(this, arguments);
  1237. Initialize();
  1238. }
  1239. private void StashPopToolStripMenuItemClick(object sender, EventArgs e)
  1240. {
  1241. FormProcess.ShowDialog(this, "stash pop");
  1242. Initialize();
  1243. MergeConflictHandler.HandleMergeConflicts(this, false);
  1244. }
  1245. private void ViewStashToolStripMenuItemClick(object sender, EventArgs e)
  1246. {
  1247. if (GitUICommands.Instance.StartStashDialog(this))
  1248. Initialize();
  1249. }
  1250. private void OpenSubmoduleToolStripMenuItemDropDownOpening(object sender, EventArgs e)
  1251. {
  1252. LoadSubmodulesIntoDropDownMenu();
  1253. }
  1254. private void LoadSubmodulesIntoDropDownMenu()
  1255. {
  1256. Cursor.Current = Cursors.WaitCursor;
  1257. RemoveSubmoduleButtons();
  1258. foreach (var submodule in Settings.Module.GetSubmodulesNames().OrderBy(submoduleName => submoduleName))
  1259. {
  1260. var submenu = new ToolStripMenuItem(submodule);
  1261. submenu.Click += SubmoduleToolStripButtonClick;
  1262. submenu.Width = 200;
  1263. openSubmoduleToolStripMenuItem.DropDownItems.Add(submenu);
  1264. }
  1265. if (openSubmoduleToolStripMenuItem.DropDownItems.Count == 0)
  1266. openSubmoduleToolStripMenuItem.DropDownItems.Add(_noSubmodulesPresent.Text);
  1267. Cursor.Current = Cursors.Default;
  1268. }
  1269. private void RemoveSubmoduleButtons()
  1270. {
  1271. foreach (var item in openSubmoduleToolStripMenuItem.DropDownItems)
  1272. {
  1273. var toolStripButton = item as ToolStripMenuItem;
  1274. if (toolStripButton != null)
  1275. toolStripButton.Click -= SubmoduleToolStripButtonClick;
  1276. }
  1277. openSubmoduleToolStripMenuItem.DropDownItems.Clear();
  1278. }
  1279. private void SubmoduleToolStripButtonClick(object sender, EventArgs e)
  1280. {
  1281. var button = sender as ToolStripMenuItem;
  1282. if (button == null)
  1283. return;
  1284. string dir = Settings.WorkingDir + Settings.Module.GetSubmoduleLocalPath(button.Text);
  1285. Settings.WorkingDir = Path.GetFullPath(dir); // fix slashes
  1286. if (Settings.Module.ValidWorkingDir())
  1287. Repositories.AddMostRecentRepository(Settings.WorkingDir);
  1288. InternalInitialize(true);
  1289. }
  1290. private void ExitToolStripMenuItemClick(object sender, EventArgs e)
  1291. {
  1292. Close();
  1293. }
  1294. private void FileToolStripMenuItemDropDownOpening(object sender, EventArgs e)
  1295. {
  1296. recentToolStripMenuItem.DropDownItems.Clear();
  1297. foreach (var historyItem in Repositories.RepositoryHistory.Repositories)
  1298. {
  1299. if (string.IsNullOrEmpty(historyItem.Path))
  1300. continue;
  1301. var historyItemMenu = new ToolStripMenuItem(historyItem.Path);
  1302. historyItemMenu.Click += HistoryItemMenuClick;
  1303. historyItemMenu.Width = 225;
  1304. recentToolStripMenuItem.DropDownItems.Add(historyItemMenu);
  1305. }
  1306. }
  1307. private void HistoryItemMenuClick(object sender, EventArgs e)
  1308. {
  1309. var button = sender as ToolStripMenuItem;
  1310. if (button == null)
  1311. return;
  1312. Settings.WorkingDir = button.Text;
  1313. InternalInitialize(true);
  1314. }
  1315. private void SettingsToolStripMenuItemClick(object sender, EventArgs e)
  1316. {
  1317. GitUICommands.Instance.StartPluginSettingsDialog(this);
  1318. }
  1319. private void CloseToolStripMenuItemClick(object sender, EventArgs e)
  1320. {
  1321. Settings.WorkingDir = "";
  1322. WorkingDirChanged(false);
  1323. }
  1324. public override void CancelButtonClick(object sender, EventArgs e)
  1325. {
  1326. if (string.IsNullOrEmpty(Settings.WorkingDir))
  1327. {
  1328. Close();
  1329. return;
  1330. }
  1331. Settings.WorkingDir = "";
  1332. WorkingDirChanged(false);
  1333. }
  1334. private void GitTreeMouseDown(object sender, MouseEventArgs e)
  1335. {
  1336. if (e.Button == MouseButtons.Right)
  1337. GitTree.SelectedNode = GitTree.GetNodeAt(e.X, e.Y);
  1338. }
  1339. private void UserManualToolStripMenuItemClick(object sender, EventArgs e)
  1340. {
  1341. try
  1342. {
  1343. Process.Start(Settings.GetInstallDir() + "\\GitExtensionsUserManual.pdf");
  1344. }
  1345. catch (Exception ex)
  1346. {
  1347. MessageBox.Show(this, ex.Message);
  1348. }
  1349. }
  1350. private void DiffTextExtraDiffArgumentsChanged(object sender, EventArgs e)
  1351. {
  1352. ShowSelectedFileDiff();
  1353. }
  1354. private void CleanupToolStripMenuItemClick(object sender, EventArgs e)
  1355. {
  1356. new FormCleanupRepository().ShowDialog(this);
  1357. }
  1358. private void openWithDifftoolToolStripMenuItem_Click(object sender, EventArgs e)
  1359. {
  1360. if (DiffFiles.SelectedItem == null)
  1361. return;
  1362. var selectedItem = (DiffFiles.SelectedItem).Name;
  1363. GitUIExtensions.DiffWithRevisionKind diffKind;
  1364. if (sender == diffBaseLocalToolStripMenuItem)
  1365. diffKind = GitUIExtensions.DiffWithRevisionKind.DiffBaseLocal;
  1366. else if (sender == difftoolRemoteLocalToolStripMenuItem)
  1367. diffKind = GitUIExtensions.DiffWithRevisionKind.DiffRemoteLocal;
  1368. else
  1369. diffKind = GitUIExtensions.DiffWithRevisionKind.DiffAsSelected;
  1370. RevisionGrid.OpenWithDifftool(selectedItem, diffKind);
  1371. }
  1372. private void AddWorkingdirDropDownItem(Repository repo, string caption)
  1373. {
  1374. ToolStripMenuItem toolStripItem = new ToolStripMenuItem(caption);
  1375. _NO_TRANSLATE_Workingdir.DropDownItems.Add(toolStripItem);
  1376. toolStripItem.Click += (hs, he) => SetWorkingDir(repo.Path);
  1377. if (repo.Title != null || !repo.Path.Equals(caption))
  1378. toolStripItem.ToolTipText = repo.Path;
  1379. }
  1380. private void WorkingdirDropDownOpening(object sender, EventArgs e)
  1381. {
  1382. _NO_TRANSLATE_Workingdir.DropDownItems.Clear();
  1383. List<RecentRepoInfo> mostRecentRepos = new List<RecentRepoInfo>();
  1384. List<RecentRepoInfo> lessRecentRepos = new List<RecentRepoInfo>();
  1385. using (var graphics = CreateGraphics())
  1386. {
  1387. var splitter = new RecentRepoSplitter
  1388. {
  1389. measureFont = _NO_TRANSLATE_Workingdir.Font,
  1390. graphics = graphics
  1391. };
  1392. splitter.SplitRecentRepos(Repositories.RepositoryHistory.Repositories, mostRecentRepos, lessRecentRepos);
  1393. }
  1394. foreach (RecentRepoInfo repo in mostRecentRepos)
  1395. AddWorkingdirDropDownItem(repo.Repo, repo.Caption);
  1396. if (lessRecentRepos.Count > 0)
  1397. {
  1398. if (mostRecentRepos.Count > 0 && (Settings.SortMostRecentRepos || Settings.SortLessRecentRepos))
  1399. _NO_TRANSLATE_Workingdir.DropDownItems.Add(new ToolStripSeparator());
  1400. foreach (RecentRepoInfo repo in lessRecentRepos)
  1401. AddWorkingdirDropDownItem(repo.Repo, repo.Caption);
  1402. }
  1403. _NO_TRANSLATE_Workingdir.DropDownItems.Add(new ToolStripSeparator());
  1404. ToolStripMenuItem toolStripItem = new ToolStripMenuItem(openToolStripMenuItem.Text);
  1405. toolStripItem.ShortcutKeys = openToolStripMenuItem.ShortcutKeys;
  1406. _NO_TRANSLATE_Workingdir.DropDownItems.Add(toolStripItem);
  1407. toolStripItem.Click += (hs, he) => OpenToolStripMenuItemClick(hs, he);
  1408. toolStripItem = new ToolStripMenuItem(_configureWorkingDirMenu.Text);
  1409. _NO_TRANSLATE_Workingdir.DropDownItems.Add(toolStripItem);
  1410. toolStripItem.Click += (hs, he) =>
  1411. {
  1412. new FormRecentReposSettings().ShowDialog(this);
  1413. RefreshWorkingDirCombo();
  1414. };
  1415. }
  1416. private void SetWorkingDir(string path)
  1417. {
  1418. Settings.WorkingDir = path;
  1419. Repositories.AddMostRecentRepository(Settings.WorkingDir);
  1420. InternalInitialize(true);
  1421. }
  1422. private void TranslateToolStripMenuItemClick(object sender, EventArgs e)
  1423. {
  1424. new FormTranslate().ShowDialog(this);
  1425. }
  1426. private void FileExplorerToolStripMenuItemClick(object sender, EventArgs e)
  1427. {
  1428. try
  1429. {
  1430. Process.Start(Settings.WorkingDir);
  1431. }
  1432. catch (Exception ex)
  1433. {
  1434. MessageBox.Show(this, ex.Message);
  1435. }
  1436. }
  1437. private void StatusClick(object sender, EventArgs e)
  1438. {
  1439. // TODO: Replace with a status page?
  1440. CommitToolStripMenuItemClick(sender, e);
  1441. }
  1442. public void SaveAsOnClick(object sender, EventArgs e)
  1443. {
  1444. var item = GitTree.SelectedNode.Tag as GitItem;
  1445. if (item == null)
  1446. return;
  1447. if (!item.IsBlob)
  1448. return;
  1449. var fullName = Settings.WorkingDir + item.FileName;
  1450. var fileDialog =
  1451. new SaveFileDialog
  1452. {
  1453. InitialDirectory = Path.GetDirectoryName(fullName),
  1454. FileName = Path.GetFileName(fullName),
  1455. DefaultExt = GitCommandHelpers.GetFileExtension(fullName),
  1456. AddExtension = true
  1457. };
  1458. fileDialog.Filter =
  1459. _saveFileFilterCurrentFormat.Text + " (*." +
  1460. GitCommandHelpers.GetFileExtension(fileDialog.FileName) + ")|*." +
  1461. GitCommandHelpers.GetFileExtension(fileDialog.FileName) +
  1462. "|" + _saveFileFilterAllFiles.Text + " (*.*)|*.*";
  1463. if (fileDialog.ShowDialog(this) == DialogResult.OK)
  1464. {
  1465. Settings.Module.SaveBlobAs(fileDialog.FileName, item.Guid);
  1466. }
  1467. }
  1468. private void GitTreeBeforeExpand(object sender, TreeViewCancelEventArgs e)
  1469. {
  1470. if (e.Node.IsExpanded)
  1471. return;
  1472. var item = (IGitItem)e.Node.Tag;
  1473. e.Node.Nodes.Clear();
  1474. LoadInTree(item.SubItems, e.Node.Nodes);
  1475. }
  1476. private void BranchToolStripMenuItemClick(object sender, EventArgs e)
  1477. {
  1478. if (GitUICommands.Instance.StartCreateBranchDialog(this))
  1479. Initialize();
  1480. }
  1481. private void RevisionGridDoubleClick(object sender, EventArgs e)
  1482. {
  1483. GitUICommands.Instance.StartCompareRevisionsDialog(this);
  1484. }
  1485. private void GitBashClick(object sender, EventArgs e)
  1486. {
  1487. GitBashToolStripMenuItemClick1(sender, e);
  1488. }
  1489. private void ToolStripButtonPullClick(object sender, EventArgs e)
  1490. {
  1491. PullToolStripMenuItemClick(sender, e);
  1492. }
  1493. private void editgitattributesToolStripMenuItem_Click(object sender, EventArgs e)
  1494. {
  1495. if (GitUICommands.Instance.StartEditGitAttributesDialog(this))
  1496. Initialize();
  1497. }
  1498. private void copyFilenameToClipboardToolStripMenuItem_Click(object sender, EventArgs e)
  1499. {
  1500. var gitItem = GitTree.SelectedNode.Tag as GitItem;
  1501. if (gitItem == null)
  1502. return;
  1503. var fileName = Settings.WorkingDir + (gitItem).FileName;
  1504. Clipboard.SetText(fileName.Replace('/', '\\'));
  1505. }
  1506. private void copyFilenameToClipboardToolStripMenuItem1_Click(object sender, EventArgs e)
  1507. {
  1508. if (DiffFiles.SelectedItems.Count == 0)
  1509. return;
  1510. var fileNames = new StringBuilder();
  1511. foreach (var item in DiffFiles.SelectedItems)
  1512. {
  1513. //Only use appendline when multiple items are selected.
  1514. //This to make it easier to use the text from clipboard when 1 file is selected.
  1515. if (fileNames.Length > 0)
  1516. fileNames.AppendLine();
  1517. fileNames.Append((Settings.WorkingDir + item.Name).Replace(Settings.PathSeparatorWrong, Settings.PathSeparator));
  1518. }
  1519. Clipboard.SetText(fileNames.ToString());
  1520. }
  1521. private void deleteIndexlockToolStripMenuItem_Click(object sender, EventArgs e)
  1522. {
  1523. string fileName = Path.Combine(Settings.Module.WorkingDirGitDir(), "index.lock");
  1524. if (File.Exists(fileName))
  1525. {
  1526. File.Delete(fileName);
  1527. MessageBox.Show(this, _indexLockDeleted.Text);
  1528. }
  1529. else
  1530. MessageBox.Show(this, _indexLockNotFound.Text + " " + fileName);
  1531. }
  1532. private void saveAsToolStripMenuItem1_Click(object sender, EventArgs e)
  1533. {
  1534. IList<GitRevision> revisions = RevisionGrid.GetSelectedRevisions();
  1535. if (revisions.Count == 0)
  1536. return;
  1537. if (DiffFiles.SelectedItem == null)
  1538. return;
  1539. GitItemStatus item = DiffFiles.SelectedItem;
  1540. var fullName = Settings.WorkingDir + item.Name;
  1541. var fileDialog =
  1542. new SaveFileDialog
  1543. {
  1544. InitialDirectory = Path.GetDirectoryName(fullName),
  1545. FileName = Path.GetFileName(fullName),
  1546. DefaultExt = GitCommandHelpers.GetFileExtension(fullName),
  1547. AddExtension = true
  1548. };
  1549. fileDialog.Filter =
  1550. _saveFileFilterCurrentFormat.Text + " (*." +
  1551. fileDialog.DefaultExt + ")|*." +
  1552. fileDialog.DefaultExt +
  1553. "|" + _saveFileFilterAllFiles.Text + " (*.*)|*.*";
  1554. if (fileDialog.ShowDialog(this) == DialogResult.OK)
  1555. {
  1556. Settings.Module.SaveBlobAs(fileDialog.FileName, string.Format("{0}:\"{1}\"", revisions[0].Guid, item.Name));
  1557. }
  1558. }
  1559. private void toolStripStatusLabel1_Click(object sender, EventArgs e)
  1560. {
  1561. statusStrip.Hide();
  1562. }
  1563. private void openWithToolStripMenuItem_Click(object sender, EventArgs e)
  1564. {
  1565. var item = GitTree.SelectedNode.Tag;
  1566. var gitItem = item as GitItem;
  1567. if (gitItem == null || !(gitItem).IsBlob)
  1568. return;
  1569. var fileName = Settings.WorkingDir + (gitItem).FileName;
  1570. OpenWith.OpenAs(fileName.Replace(Settings.PathSeparatorWrong, Settings.PathSeparator));
  1571. }
  1572. private void pluginsToolStripMenuItem_DropDownOpening(object sender, EventArgs e)
  1573. {
  1574. LoadPluginsInPluginMenu();
  1575. }
  1576. private void BisectClick(object sender, EventArgs e)
  1577. {
  1578. new FormBisect(RevisionGrid).ShowDialog(this);
  1579. Initialize();
  1580. }
  1581. private void fileHistoryDiffToolstripMenuItem_Click(object sender, EventArgs e)
  1582. {
  1583. GitItemStatus item = DiffFiles.SelectedItem;
  1584. if (item.IsTracked)
  1585. {
  1586. IList<GitRevision> revisions = RevisionGrid.GetSelectedRevisions();
  1587. if (revisions.Count == 0)
  1588. GitUICommands.Instance.StartFileHistoryDialog(this, item.Name);
  1589. else
  1590. GitUICommands.Instance.StartFileHistoryDialog(this, item.Name, revisions[0], false);
  1591. }
  1592. }
  1593. private void CurrentBranchDropDownOpening(object sender, EventArgs e)
  1594. {
  1595. branchSelect.DropDownItems.Clear();
  1596. foreach (var branch in Settings.Module.GetHeads(false))
  1597. {
  1598. var toolStripItem = branchSelect.DropDownItems.Add(branch.Name);
  1599. toolStripItem.Click += BranchSelectToolStripItem_Click;
  1600. }
  1601. branchSelect.DropDownItems.Add(new ToolStripSeparator());
  1602. ToolStripMenuItem item = new ToolStripMenuItem(checkoutBranchToolStripMenuItem.Text);
  1603. item.ShortcutKeys = checkoutBranchToolStripMenuItem.ShortcutKeys;
  1604. item.ShortcutKeyDisplayString = checkoutBranchToolStripMenuItem.ShortcutKeyDisplayString;
  1605. branchSelect.DropDownItems.Add(item);
  1606. item.Click += (hs, he) => CheckoutBranchToolStripMenuItemClick(hs, he);
  1607. }
  1608. void BranchSelectToolStripItem_Click(object sender, EventArgs e)
  1609. {
  1610. var toolStripItem = (ToolStripItem)sender;
  1611. var command = GitCommandHelpers.CheckoutCmd(toolStripItem.Text);
  1612. FormProcess.ShowDialog(this, command);
  1613. Initialize();
  1614. }
  1615. private void _forkCloneMenuItem_Click(object sender, EventArgs e)
  1616. {
  1617. if (RepoHosts.GitHosters.Count > 0)
  1618. {
  1619. GitUICommands.Instance.StartCloneForkFromHoster(this, RepoHosts.GitHosters[0]); //FIXME: Works until we have > 1 repo hoster
  1620. Initialize();
  1621. }
  1622. else
  1623. {
  1624. MessageBox.Show(this, _noReposHostPluginLoaded.Text, _errorCaption.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
  1625. }
  1626. }
  1627. private void _viewPullRequestsToolStripMenuItem_Click(object sender, EventArgs e)
  1628. {
  1629. var repoHost = RepoHosts.TryGetGitHosterForCurrentWorkingDir();
  1630. if (repoHost == null)
  1631. {
  1632. MessageBox.Show(this, _noReposHostFound.Text, _errorCaption.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
  1633. return;
  1634. }
  1635. GitUICommands.Instance.StartPullRequestsDialog(this, repoHost);
  1636. Initialize();
  1637. }
  1638. private void _createPullRequestToolStripMenuItem_Click(object sender, EventArgs e)
  1639. {
  1640. var repoHost = RepoHosts.TryGetGitHosterForCurrentWorkingDir();
  1641. if (repoHost == null)
  1642. {
  1643. MessageBox.Show(this, _noReposHostFound.Text, _errorCaption.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
  1644. return;
  1645. }
  1646. GitUICommands.Instance.StartCreatePullRequest(this, repoHost);
  1647. Initialize();
  1648. }
  1649. #region Hotkey commands
  1650. public const string HotkeySettingsName = "Browse";
  1651. internal enum Commands
  1652. {
  1653. GitBash,
  1654. GitGui,
  1655. GitGitK,
  1656. FocusRevisionGrid,
  1657. FocusCommitInfo,
  1658. FocusFileTree,
  1659. FocusDiff,
  1660. Commit,
  1661. AddNotes,
  1662. FindFileInSelectedCommit,
  1663. SelectCurrentRevision,
  1664. CheckoutBranch,
  1665. QuickFetch,
  1666. QuickPull,
  1667. QuickPush,
  1668. RotateApplicationIcon,
  1669. }
  1670. private void AddNotes()
  1671. {
  1672. Settings.Module.EditNotes(RevisionGrid.GetSelectedRevisions().Count > 0 ? RevisionGrid.GetSelectedRevisions()[0].Guid : string.Empty);
  1673. FillCommitInfo();
  1674. }
  1675. private void FindFileInSelectedCommit()
  1676. {
  1677. CommitInfoTabControl.SelectedTab = Tree;
  1678. EnabledSplitViewLayout(true);
  1679. GitTree.Focus();
  1680. FindFileOnClick(null, null);
  1681. }
  1682. private void QuickFetch()
  1683. {
  1684. FormProcess.ShowDialog(this, Settings.Module.FetchCmd(string.Empty, string.Empty, string.Empty));
  1685. Initialize();
  1686. }
  1687. protected override bool ExecuteCommand(int cmd)
  1688. {
  1689. switch ((Commands)cmd)
  1690. {
  1691. case Commands.GitBash: Settings.Module.RunBash(); break;
  1692. case Commands.GitGui: Settings.Module.RunGui(); break;
  1693. case Commands.GitGitK: Settings.Module.RunGitK(); break;
  1694. case Commands.FocusRevisionGrid: RevisionGrid.Focus(); break;
  1695. case Commands.FocusCommitInfo: CommitInfoTabControl.SelectedTab = CommitInfo; break;
  1696. case Commands.FocusFileTree: CommitInfoTabControl.SelectedTab = Tree; GitTree.Focus(); break;
  1697. case Commands.FocusDiff: CommitInfoTabControl.SelectedTab = Diff; DiffFiles.Focus(); break;
  1698. case Commands.Commit: CommitToolStripMenuItemClick(null, null); break;
  1699. case Commands.AddNotes: AddNotes(); break;
  1700. case Commands.FindFileInSelectedCommit: FindFileInSelectedCommit(); break;
  1701. case Commands.SelectCurrentRevision: RevisionGrid.SetSelectedRevision(new GitRevision(RevisionGrid.CurrentCheckout)); break;
  1702. case Commands.CheckoutBranch: CheckoutBranchToolStripMenuItemClick(null, null); break;
  1703. case Commands.QuickFetch: QuickFetch(); break;
  1704. case Commands.QuickPull:
  1705. if (GitUICommands.Instance.StartPullDialog(this, true))
  1706. Initialize();
  1707. break;
  1708. case Commands.QuickPush:
  1709. if (GitUICommands.Instance.StartPushDialog(this, true))
  1710. Initialize();
  1711. break;
  1712. case Commands.RotateApplicationIcon: RotateApplicationIcon(); break;
  1713. default: ExecuteScriptCommand(cmd, Keys.None); break;
  1714. }
  1715. return true;
  1716. }
  1717. #endregion
  1718. private void goToToolStripMenuItem_Click(object sender, EventArgs e)
  1719. {
  1720. FormGoToCommit formGoToCommit = new FormGoToCommit();
  1721. if (formGoToCommit.ShowDialog(this) == DialogResult.OK)
  1722. {
  1723. string revisionGuid = formGoToCommit.GetRevision();
  1724. if (!string.IsNullOrEmpty(revisionGuid))
  1725. {
  1726. RevisionGrid.SetSelectedRevision(new GitRevision(revisionGuid));
  1727. }
  1728. else
  1729. {
  1730. MessageBox.Show(this, _noRevisionFoundError.Text);
  1731. }
  1732. }
  1733. }
  1734. private void toggleSplitViewLayout_Click(object sender, EventArgs e)
  1735. {
  1736. EnabledSplitViewLayout(MainSplitContainer.Panel2.Height == 0 && MainSplitContainer.Height > 0);
  1737. }
  1738. private void EnabledSplitViewLayout(bool enabled)
  1739. {
  1740. if (enabled)
  1741. MainSplitContainer.SplitterDistance = (MainSplitContainer.Height / 5) * 2;
  1742. else
  1743. MainSplitContainer.SplitterDistance = MainSplitContainer.Height;
  1744. }
  1745. private void editCheckedOutFileToolStripMenuItem_Click(object sender, EventArgs e)
  1746. {
  1747. var item = GitTree.SelectedNode.Tag;
  1748. var gitItem = item as GitItem;
  1749. if (gitItem == null || !gitItem.IsBlob)
  1750. return;
  1751. var fileName = Settings.WorkingDir + (gitItem).FileName;
  1752. new FormEditor(fileName).ShowDialog(this);
  1753. }
  1754. #region Git file tree drag-drop
  1755. private Rectangle gitTreeDragBoxFromMouseDown;
  1756. private void GitTree_MouseDown(object sender, MouseEventArgs e)
  1757. {
  1758. //DRAG
  1759. if (e.Button == MouseButtons.Left)
  1760. {
  1761. // Remember the point where the mouse down occurred.
  1762. // The DragSize indicates the size that the mouse can move
  1763. // before a drag event should be started.
  1764. Size dragSize = SystemInformation.DragSize;
  1765. // Create a rectangle using the DragSize, with the mouse position being
  1766. // at the center of the rectangle.
  1767. gitTreeDragBoxFromMouseDown = new Rectangle(new Point(e.X - (dragSize.Width / 2),
  1768. e.Y - (dragSize.Height / 2)),
  1769. dragSize);
  1770. }
  1771. }
  1772. void GitTree_MouseMove(object sender, MouseEventArgs e)
  1773. {
  1774. TreeView gitTree = (TreeView)sender;
  1775. //DRAG
  1776. // If the mouse moves outside the rectangle, start the drag.
  1777. if (gitTreeDragBoxFromMouseDown != Rectangle.Empty &&
  1778. !gitTreeDragBoxFromMouseDown.Contains(e.X, e.Y))
  1779. {
  1780. StringCollection fileList = new StringCollection();
  1781. //foreach (GitItemStatus item in SelectedItems)
  1782. if (gitTree.SelectedNode != null)
  1783. {
  1784. GitItem item = gitTree.SelectedNode.Tag as GitItem;
  1785. if (item != null)
  1786. {
  1787. string fileName = GitCommands.Settings.WorkingDir + item.FileName;
  1788. fileList.Add(fileName.Replace('/', '\\'));
  1789. }
  1790. DataObject obj = new DataObject();
  1791. obj.SetFileDropList(fileList);
  1792. // Proceed with the drag and drop, passing in the list item.
  1793. DoDragDrop(obj, DragDropEffects.Copy);
  1794. gitTreeDragBoxFromMouseDown = Rectangle.Empty;
  1795. }
  1796. }
  1797. }
  1798. #endregion
  1799. private int getNextIdx(int curIdx, int maxIdx, bool searchBackward)
  1800. {
  1801. if (searchBackward)
  1802. {
  1803. if (curIdx == 0)
  1804. {
  1805. curIdx = maxIdx;
  1806. }
  1807. else
  1808. {
  1809. curIdx--;
  1810. }
  1811. }
  1812. else
  1813. {
  1814. if (curIdx == maxIdx)
  1815. {
  1816. curIdx = 0;
  1817. }
  1818. else
  1819. {
  1820. curIdx++;
  1821. }
  1822. }
  1823. return curIdx;
  1824. }
  1825. private Tuple<int, string> getNextPatchFile(bool searchBackward)
  1826. {
  1827. var revisions = RevisionGrid.GetSelectedRevisions();
  1828. if (revisions.Count == 0)
  1829. return null;
  1830. int idx = DiffFiles.SelectedIndex;
  1831. if (idx == -1)
  1832. return new Tuple<int, string>(idx, null);
  1833. idx = getNextIdx(idx, DiffFiles.GitItemStatuses.Count - 1, searchBackward);
  1834. _dontUpdateOnIndexChange = true;
  1835. DiffFiles.SelectedIndex = idx;
  1836. _dontUpdateOnIndexChange = false;
  1837. return new Tuple<int, string>(idx, DiffText.GetSelectedPatch(RevisionGrid, DiffFiles.SelectedItem));
  1838. }
  1839. private void openContainingFolderToolStripMenuItem_Click(object sender, EventArgs e)
  1840. {
  1841. if (DiffFiles.SelectedItems.Count == 0)
  1842. return;
  1843. foreach (var item in DiffFiles.SelectedItems)
  1844. {
  1845. var fileNames = new StringBuilder();
  1846. fileNames.Append((Settings.WorkingDir + item.Name).Replace(Settings.PathSeparatorWrong, Settings.PathSeparator));
  1847. string filePath = fileNames.ToString();
  1848. if (File.Exists(filePath))
  1849. {
  1850. Process.Start("explorer.exe", "/select, " + filePath);
  1851. }
  1852. }
  1853. }
  1854. private void DiffContextMenu_Opening(object sender, System.ComponentModel.CancelEventArgs e)
  1855. {
  1856. bool artificialRevSelected;
  1857. IList<GitRevision> revisions = RevisionGrid.GetSelectedRevisions();
  1858. if (revisions.Count == 0)
  1859. artificialRevSelected = false;
  1860. else
  1861. artificialRevSelected = revisions[0].IsArtificial();
  1862. if (revisions.Count > 1)
  1863. artificialRevSelected = artificialRevSelected || revisions[revisions.Count - 1].IsArtificial();
  1864. foreach (var item in DiffFiles.SelectedItems)
  1865. {
  1866. var fileNames = new StringBuilder();
  1867. fileNames.Append((Settings.WorkingDir + item.Name).Replace(Settings.PathSeparatorWrong, Settings.PathSeparator));
  1868. if (File.Exists(fileNames.ToString()))
  1869. {
  1870. openContainingFolderToolStripMenuItem.Enabled = true;
  1871. diffBaseLocalToolStripMenuItem.Enabled = !artificialRevSelected;
  1872. difftoolRemoteLocalToolStripMenuItem.Enabled = !artificialRevSelected;
  1873. return;
  1874. }
  1875. }
  1876. openContainingFolderToolStripMenuItem.Enabled = false;
  1877. diffBaseLocalToolStripMenuItem.Enabled = false;
  1878. difftoolRemoteLocalToolStripMenuItem.Enabled = false;
  1879. }
  1880. protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
  1881. {
  1882. base.OnClosing(e);
  1883. if (_dashboard != null)
  1884. _dashboard.SaveSplitterPositions();
  1885. }
  1886. private void CloneSvnToolStripMenuItemClick(object sender, EventArgs e)
  1887. {
  1888. if (GitUICommands.Instance.StartSvnCloneDialog(this))
  1889. Initialize();
  1890. }
  1891. private void SvnRebaseToolStripMenuItem_Click(object sender, EventArgs e)
  1892. {
  1893. if (GitUICommands.Instance.StartSvnRebaseDialog(this))
  1894. Initialize();
  1895. }
  1896. private void SvnDcommitToolStripMenuItem_Click(object sender, EventArgs e)
  1897. {
  1898. if (GitUICommands.Instance.StartSvnDcommitDialog(this))
  1899. Initialize();
  1900. }
  1901. private void SvnFetchToolStripMenuItem_Click(object sender, EventArgs e)
  1902. {
  1903. if (GitUICommands.Instance.StartSvnFetchDialog(this))
  1904. Initialize();
  1905. }
  1906. private void expandAllStripMenuItem_Click(object sender, EventArgs e)
  1907. {
  1908. GitTree.ExpandAll();
  1909. }
  1910. private void collapseAllToolStripMenuItem_Click(object sender, EventArgs e)
  1911. {
  1912. GitTree.CollapseAll();
  1913. }
  1914. private void WorkingDirChanged(bool internalInitialize)
  1915. {
  1916. IndexWatcher.Clear();
  1917. RevisionGrid.ForceRefreshRevisions();
  1918. InternalInitialize(internalInitialize);
  1919. IndexWatcher.Reset();
  1920. }
  1921. private void DiffFiles_DataSourceChanged(object sender, EventArgs e)
  1922. {
  1923. if (DiffFiles.GitItemStatuses == null || DiffFiles.GitItemStatuses.Count == 0)
  1924. DiffText.ViewPatch(String.Empty);
  1925. }
  1926. private void blameToolStripMenuItem_Click(object sender, EventArgs e)
  1927. {
  1928. GitItemStatus item = DiffFiles.SelectedItem;
  1929. if (item.IsTracked)
  1930. {
  1931. IList<GitRevision> revisions = RevisionGrid.GetSelectedRevisions();
  1932. if (revisions.Count == 0)
  1933. GitUICommands.Instance.StartFileHistoryDialog(this, item.Name, null, false, true);
  1934. else
  1935. GitUICommands.Instance.StartFileHistoryDialog(this, item.Name, revisions[0], true, true);
  1936. }
  1937. }
  1938. private void blameToolStripMenuItem1_Click(object sender, EventArgs e)
  1939. {
  1940. var item = GitTree.SelectedNode.Tag as GitItem;
  1941. if (item == null)
  1942. return;
  1943. if (item.IsBlob || item.IsTree)
  1944. {
  1945. IList<GitRevision> revisions = RevisionGrid.GetSelectedRevisions();
  1946. if (revisions.Count == 0)
  1947. GitUICommands.Instance.StartFileHistoryDialog(this, item.FileName, null, false, true);
  1948. else
  1949. GitUICommands.Instance.StartFileHistoryDialog(this, item.FileName, revisions[0], true, true);
  1950. }
  1951. }
  1952. public override void AddTranslationItems(Translation translation)
  1953. {
  1954. base.AddTranslationItems(translation);
  1955. TranslationUtl.AddTranslationItemsFromFields(Name, filterRevisionsHelper, translation);
  1956. TranslationUtl.AddTranslationItemsFromFields(Name, _FilterBranchHelper, translation);
  1957. }
  1958. public override void TranslateItems(Translation translation)
  1959. {
  1960. base.TranslateItems(translation);
  1961. TranslationUtl.TranslateItemsFromFields(Name, filterRevisionsHelper, translation);
  1962. TranslationUtl.TranslateItemsFromFields(Name, _FilterBranchHelper, translation);
  1963. }
  1964. private IList<GitItemStatus> FindDiffFilesMatches(string name)
  1965. {
  1966. var candidates = DiffFiles.GitItemStatuses;
  1967. string nameAsLower = name.ToLower();
  1968. return candidates.Where(item =>
  1969. {
  1970. return item.Name != null && item.Name.ToLower().Contains(nameAsLower)
  1971. || item.OldName != null && item.OldName.ToLower().Contains(nameAsLower);
  1972. }
  1973. ).ToList();
  1974. }
  1975. private void findInDiffToolStripMenuItem_Click(object sender, EventArgs e)
  1976. {
  1977. var searchWindow = new SearchWindow<GitItemStatus>(FindDiffFilesMatches)
  1978. {
  1979. Owner = this
  1980. };
  1981. searchWindow.ShowDialog(this);
  1982. GitItemStatus selectedItem = searchWindow.SelectedItem;
  1983. if (selectedItem != null)
  1984. {
  1985. DiffFiles.SelectedItem = selectedItem;
  1986. }
  1987. }
  1988. private void dontSetAsDefaultToolStripMenuItem_Click(object sender, EventArgs e)
  1989. {
  1990. Settings.DonSetAsLastPullAction = !dontSetAsDefaultToolStripMenuItem.Checked;
  1991. dontSetAsDefaultToolStripMenuItem.Checked = Settings.DonSetAsLastPullAction;
  1992. }
  1993. private void mergeToolStripMenuItem_Click(object sender, EventArgs e)
  1994. {
  1995. Settings.LastPullAction = Settings.PullAction.Merge;
  1996. PullToolStripMenuItemClick(sender, e);
  1997. }
  1998. private void rebaseToolStripMenuItem1_Click(object sender, EventArgs e)
  1999. {
  2000. Settings.LastPullAction = Settings.PullAction.Rebase;
  2001. PullToolStripMenuItemClick(sender, e);
  2002. }
  2003. private void fetchToolStripMenuItem_Click(object sender, EventArgs e)
  2004. {
  2005. Settings.LastPullAction = Settings.PullAction.Fetch;
  2006. PullToolStripMenuItemClick(sender, e);
  2007. }
  2008. private void pullToolStripMenuItem1_Click(object sender, EventArgs e)
  2009. {
  2010. if (!Settings.DonSetAsLastPullAction)
  2011. Settings.LastPullAction = Settings.PullAction.None;
  2012. PullToolStripMenuItemClick(sender, e);
  2013. }
  2014. private void RefreshPullIcon()
  2015. {
  2016. switch (Settings.LastPullAction)
  2017. {
  2018. case Settings.PullAction.Fetch:
  2019. toolStripButtonPull.Image = Properties.Resources.PullFetch;
  2020. toolStripButtonPull.ToolTipText = "Pull - fetch";
  2021. break;
  2022. case Settings.PullAction.FetchAll:
  2023. toolStripButtonPull.Image = Properties.Resources.PullFetchAll;
  2024. toolStripButtonPull.ToolTipText = "Pull - fetch all";
  2025. break;
  2026. case Settings.PullAction.Merge:
  2027. toolStripButtonPull.Image = Properties.Resources.PullMerge;
  2028. toolStripButtonPull.ToolTipText = "Pull - merge";
  2029. break;
  2030. case Settings.PullAction.Rebase:
  2031. toolStripButtonPull.Image = Properties.Resources.PullRebase;
  2032. toolStripButtonPull.ToolTipText = "Pull - rebase";
  2033. break;
  2034. default:
  2035. toolStripButtonPull.Image = Properties.Resources._4;
  2036. toolStripButtonPull.ToolTipText = "Open pull dialog";
  2037. break;
  2038. }
  2039. }
  2040. private void fetchAllToolStripMenuItem_Click(object sender, EventArgs e)
  2041. {
  2042. if (!Settings.DonSetAsLastPullAction)
  2043. Settings.LastPullAction = Settings.PullAction.FetchAll;
  2044. RefreshPullIcon();
  2045. bool pullCompelted;
  2046. ConfigureFormPull configProc = (formPull) => formPull.SetForFetchAll();
  2047. if (GitUICommands.Instance.StartPullDialog(this, true, out pullCompelted, configProc))
  2048. Initialize();
  2049. }
  2050. private void resetFileToRemoteToolStripMenuItem_Click(object sender, EventArgs e)
  2051. {
  2052. IList<GitRevision> revisions = RevisionGrid.GetSelectedRevisions();
  2053. if (revisions.Count == 0)
  2054. return;
  2055. if (DiffFiles.SelectedItems.Count == 0)
  2056. return;
  2057. var files = DiffFiles.SelectedItems.Select(item => item.Name);
  2058. Settings.Module.CheckoutFiles(files, revisions[0].Guid, false);
  2059. }
  2060. private void resetFileToBaseToolStripMenuItem_Click(object sender, EventArgs e)
  2061. {
  2062. IList<GitRevision> revisions = RevisionGrid.GetSelectedRevisions();
  2063. if (revisions.Count == 0)
  2064. return;
  2065. if (!revisions[0].HasParent())
  2066. return;
  2067. if (DiffFiles.SelectedItems.Count == 0)
  2068. return;
  2069. var files = DiffFiles.SelectedItems.Select(item => item.Name);
  2070. Settings.Module.CheckoutFiles(files, revisions[0].Guid + "^", false);
  2071. }
  2072. private void _NO_TRANSLATE_Workingdir_MouseUp(object sender, MouseEventArgs e)
  2073. {
  2074. if (e.Button == MouseButtons.Right)
  2075. OpenToolStripMenuItemClick(sender, e);
  2076. }
  2077. private void branchSelect_MouseUp(object sender, MouseEventArgs e)
  2078. {
  2079. if (e.Button == MouseButtons.Right)
  2080. CheckoutBranchToolStripMenuItemClick(sender, e);
  2081. }
  2082. }
  2083. }