PageRenderTime 69ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/GitUI/CommandsDialogs/FormBrowse.cs

https://github.com/vbjay/gitextensions
C# | 3162 lines | 2883 code | 219 blank | 60 comment | 213 complexity | 0ccd660db8521343e8d6828aea17a64c 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.Net;
  9. using System.Reflection;
  10. using System.Text;
  11. using System.Threading;
  12. using System.Threading.Tasks;
  13. using System.Windows.Forms;
  14. using GitCommands;
  15. using GitCommands.Repository;
  16. using GitCommands.Utils;
  17. using GitUI.CommandsDialogs.BrowseDialog;
  18. using GitUI.CommandsDialogs.BrowseDialog.DashboardControl;
  19. using GitUI.Hotkey;
  20. using GitUI.Plugin;
  21. using GitUI.Properties;
  22. using GitUI.Script;
  23. using GitUIPluginInterfaces;
  24. using ResourceManager;
  25. using Settings = GitCommands.AppSettings;
  26. #if !__MonoCS__
  27. using Microsoft.WindowsAPICodePack.Taskbar;
  28. #endif
  29. namespace GitUI.CommandsDialogs
  30. {
  31. public partial class FormBrowse : GitModuleForm, IBrowseRepo
  32. {
  33. #region Translation
  34. private readonly TranslationString _stashCount =
  35. new TranslationString("{0} saved {1}");
  36. private readonly TranslationString _stashPlural =
  37. new TranslationString("stashes");
  38. private readonly TranslationString _stashSingular =
  39. new TranslationString("stash");
  40. private readonly TranslationString _warningMiddleOfBisect =
  41. new TranslationString("You are in the middle of a bisect");
  42. private readonly TranslationString _warningMiddleOfRebase =
  43. new TranslationString("You are in the middle of a rebase");
  44. private readonly TranslationString _warningMiddleOfPatchApply =
  45. new TranslationString("You are in the middle of a patch apply");
  46. private readonly TranslationString _hintUnresolvedMergeConflicts =
  47. new TranslationString("There are unresolved merge conflicts!");
  48. private readonly TranslationString _noBranchTitle =
  49. new TranslationString("no branch");
  50. private readonly TranslationString _noSubmodulesPresent =
  51. new TranslationString("No submodules");
  52. private readonly TranslationString _saveFileFilterCurrentFormat =
  53. new TranslationString("Current format");
  54. private readonly TranslationString _saveFileFilterAllFiles =
  55. new TranslationString("All files");
  56. private readonly TranslationString _indexLockDeleted =
  57. new TranslationString("index.lock deleted.");
  58. private readonly TranslationString _indexLockNotFound =
  59. new TranslationString("index.lock not found at:");
  60. private readonly TranslationString _errorCaption =
  61. new TranslationString("Error");
  62. private readonly TranslationString _noReposHostPluginLoaded =
  63. new TranslationString("No repository host plugin loaded.");
  64. private readonly TranslationString _noReposHostFound =
  65. new TranslationString("Could not find any relevant repository hosts for the currently open repository.");
  66. private readonly TranslationString _configureWorkingDirMenu =
  67. new TranslationString("Configure this menu");
  68. private readonly TranslationString directoryIsNotAValidRepositoryCaption =
  69. new TranslationString("Open");
  70. private readonly TranslationString directoryIsNotAValidRepository =
  71. new TranslationString("The selected item is not a valid git repository.\n\nDo you want to abort and remove it from the recent repositories list?");
  72. private readonly TranslationString _updateCurrentSubmodule =
  73. new TranslationString("Update current submodule");
  74. private readonly TranslationString _nodeNotFoundNextAvailableParentSelected =
  75. new TranslationString("Node not found. The next available parent node will be selected.");
  76. private readonly TranslationString _nodeNotFoundSelectionNotChanged =
  77. new TranslationString("Node not found. File tree selection was not changed.");
  78. #endregion
  79. private Dashboard _dashboard;
  80. private ToolStripItem _rebase;
  81. private ToolStripItem _bisect;
  82. private ToolStripItem _warning;
  83. #if !__MonoCS__
  84. private ThumbnailToolBarButton _commitButton;
  85. private ThumbnailToolBarButton _pushButton;
  86. private ThumbnailToolBarButton _pullButton;
  87. private bool _toolbarButtonsCreated;
  88. #endif
  89. private bool _dontUpdateOnIndexChange;
  90. private readonly ToolStripGitStatus _toolStripGitStatus;
  91. private readonly FilterRevisionsHelper _filterRevisionsHelper;
  92. private readonly FilterBranchHelper _filterBranchHelper;
  93. private const string DiffTabPageTitleBase = "Diff";
  94. private readonly FormBrowseMenus _formBrowseMenus;
  95. private readonly FormBrowseMenuCommands _formBrowseMenuCommands;
  96. /// <summary>
  97. /// For VS designer
  98. /// </summary>
  99. private FormBrowse()
  100. {
  101. InitializeComponent();
  102. Translate();
  103. }
  104. public FormBrowse(GitUICommands aCommands, string filter)
  105. : base(true, aCommands)
  106. {
  107. InitializeComponent();
  108. // set tab page images
  109. {
  110. var imageList = new ImageList();
  111. CommitInfoTabControl.ImageList = imageList;
  112. imageList.ColorDepth = ColorDepth.Depth8Bit;
  113. imageList.Images.Add(global::GitUI.Properties.Resources.IconCommit);
  114. imageList.Images.Add(global::GitUI.Properties.Resources.IconFileTree);
  115. imageList.Images.Add(global::GitUI.Properties.Resources.IconDiff);
  116. CommitInfoTabControl.TabPages[0].ImageIndex = 0;
  117. CommitInfoTabControl.TabPages[1].ImageIndex = 1;
  118. CommitInfoTabControl.TabPages[2].ImageIndex = 2;
  119. }
  120. RevisionGrid.UICommandsSource = this;
  121. Repositories.LoadRepositoryHistoryAsync();
  122. Task.Factory.StartNew(PluginLoader.Load)
  123. .ContinueWith((task) => RegisterPlugins(), TaskScheduler.FromCurrentSynchronizationContext());
  124. RevisionGrid.GitModuleChanged += SetGitModule;
  125. _filterRevisionsHelper = new FilterRevisionsHelper(toolStripTextBoxFilter, toolStripDropDownButton1, RevisionGrid, toolStripLabel2, this);
  126. _filterBranchHelper = new FilterBranchHelper(toolStripBranches, toolStripDropDownButton2, RevisionGrid);
  127. Translate();
  128. if (Settings.ShowGitStatusInBrowseToolbar)
  129. {
  130. _toolStripGitStatus = new ToolStripGitStatus
  131. {
  132. ImageTransparentColor = Color.Magenta
  133. };
  134. if (aCommands != null)
  135. _toolStripGitStatus.UICommandsSource = this;
  136. _toolStripGitStatus.Click += StatusClick;
  137. ToolStrip.Items.Insert(ToolStrip.Items.IndexOf(toolStripButton1), _toolStripGitStatus);
  138. ToolStrip.Items.Remove(toolStripButton1);
  139. _toolStripGitStatus.CommitTranslatedString = toolStripButton1.Text;
  140. }
  141. RevisionGrid.SelectionChanged += RevisionGridSelectionChanged;
  142. DiffText.ExtraDiffArgumentsChanged += DiffTextExtraDiffArgumentsChanged;
  143. _filterRevisionsHelper.SetFilter(filter);
  144. DiffText.SetFileLoader(getNextPatchFile);
  145. GitTree.ImageList = new ImageList();
  146. GitTree.ImageList.Images.Add(Properties.Resources.New); //File
  147. GitTree.ImageList.Images.Add(Properties.Resources.Folder); //Folder
  148. GitTree.ImageList.Images.Add(Properties.Resources.IconFolderSubmodule); //Submodule
  149. GitTree.MouseDown += GitTree_MouseDown;
  150. GitTree.MouseMove += GitTree_MouseMove;
  151. this.HotkeysEnabled = true;
  152. this.Hotkeys = HotkeySettingsManager.LoadHotkeys(HotkeySettingsName);
  153. this.toolPanel.SplitterDistance = this.ToolStrip.Height;
  154. this._dontUpdateOnIndexChange = false;
  155. GitUICommandsChanged += (a, oldcommands) =>
  156. {
  157. RefreshPullIcon();
  158. oldcommands.PostRepositoryChanged -= UICommands_PostRepositoryChanged;
  159. UICommands.PostRepositoryChanged += UICommands_PostRepositoryChanged;
  160. oldcommands.BrowseRepo = null;
  161. UICommands.BrowseRepo = this;
  162. };
  163. if (aCommands != null)
  164. {
  165. RefreshPullIcon();
  166. UICommands.PostRepositoryChanged += UICommands_PostRepositoryChanged;
  167. UICommands.BrowseRepo = this;
  168. }
  169. FillBuildReport(); // Ensure correct page visibility
  170. RevisionGrid.ShowBuildServerInfo = true;
  171. _formBrowseMenuCommands = new FormBrowseMenuCommands(this, RevisionGrid);
  172. _formBrowseMenus = new FormBrowseMenus(menuStrip1);
  173. RevisionGrid.MenuCommands.MenuChanged += (sender, e) => _formBrowseMenus.OnMenuCommandsPropertyChanged();
  174. }
  175. void UICommands_PostRepositoryChanged(object sender, GitUIBaseEventArgs e)
  176. {
  177. this.InvokeAsync(RefreshRevisions);
  178. }
  179. private void RefreshRevisions()
  180. {
  181. if (_dashboard == null || !_dashboard.Visible)
  182. {
  183. RevisionGrid.ForceRefreshRevisions();
  184. InternalInitialize(false);
  185. }
  186. }
  187. #region IBrowseRepo
  188. public void GoToRef(string refName, bool showNoRevisionMsg)
  189. {
  190. RevisionGrid.GoToRef(refName, showNoRevisionMsg);
  191. }
  192. #endregion
  193. private void ShowDashboard()
  194. {
  195. if (_dashboard == null)
  196. {
  197. _dashboard = new Dashboard();
  198. _dashboard.GitModuleChanged += SetGitModule;
  199. toolPanel.Panel2.Controls.Add(_dashboard);
  200. _dashboard.Dock = DockStyle.Fill;
  201. }
  202. else
  203. _dashboard.Refresh();
  204. _dashboard.Visible = true;
  205. _dashboard.BringToFront();
  206. _dashboard.ShowRecentRepositories();
  207. }
  208. private void HideDashboard()
  209. {
  210. if (_dashboard != null && _dashboard.Visible)
  211. _dashboard.Visible = false;
  212. }
  213. private void GitTree_AfterSelect(object sender, TreeViewEventArgs e)
  214. {
  215. var item = e.Node.Tag as GitItem;
  216. if (item == null)
  217. return;
  218. if (item.IsBlob)
  219. FileText.ViewGitItem(item.FileName, item.Guid);
  220. else if (item.IsCommit)
  221. FileText.ViewText(item.FileName,
  222. GitCommandHelpers.GetSubmoduleText(Module, item.FileName, item.Guid));
  223. else
  224. FileText.ViewText("", "");
  225. }
  226. private void BrowseLoad(object sender, EventArgs e)
  227. {
  228. #if !__MonoCS__
  229. if (EnvUtils.RunningOnWindows() && TaskbarManager.IsPlatformSupported)
  230. {
  231. TaskbarManager.Instance.ApplicationId = "GitExtensions";
  232. }
  233. #endif
  234. HideVariableMainMenuItems();
  235. RevisionGrid.Load();
  236. _filterBranchHelper.InitToolStripBranchFilter();
  237. Cursor.Current = Cursors.WaitCursor;
  238. InternalInitialize(false);
  239. RevisionGrid.Focus();
  240. RevisionGrid.IndexWatcher.Reset();
  241. RevisionGrid.IndexWatcher.Changed += _indexWatcher_Changed;
  242. Cursor.Current = Cursors.Default;
  243. try
  244. {
  245. if (Settings.PlaySpecialStartupSound)
  246. {
  247. using (var cowMoo = Resources.cow_moo)
  248. new System.Media.SoundPlayer(cowMoo).Play();
  249. }
  250. }
  251. catch // This code is just for fun, we do not want the program to crash because of it.
  252. {
  253. }
  254. }
  255. void _indexWatcher_Changed(bool indexChanged)
  256. {
  257. this.InvokeAsync(() =>
  258. {
  259. RefreshButton.Image = indexChanged && Settings.UseFastChecks && Module.IsValidGitWorkingDir()
  260. ? Resources.arrow_refresh_dirty
  261. : Resources.arrow_refresh;
  262. });
  263. }
  264. private bool _pluginsLoaded;
  265. private void LoadPluginsInPluginMenu()
  266. {
  267. if (_pluginsLoaded)
  268. return;
  269. foreach (var plugin in LoadedPlugins.Plugins)
  270. {
  271. var item = new ToolStripMenuItem { Text = plugin.Description, Tag = plugin };
  272. item.Click += ItemClick;
  273. pluginsToolStripMenuItem.DropDownItems.Insert(pluginsToolStripMenuItem.DropDownItems.Count - 2, item);
  274. }
  275. _pluginsLoaded = true;
  276. UpdatePluginMenu(Module.IsValidGitWorkingDir());
  277. }
  278. /// <summary>
  279. /// Execute plugin
  280. /// </summary>
  281. private void ItemClick(object sender, EventArgs e)
  282. {
  283. var menuItem = sender as ToolStripMenuItem;
  284. if (menuItem == null)
  285. return;
  286. var plugin = menuItem.Tag as IGitPlugin;
  287. if (plugin == null)
  288. return;
  289. var eventArgs = new GitUIEventArgs(this, UICommands);
  290. bool refresh = plugin.Execute(eventArgs);
  291. if (refresh)
  292. RefreshToolStripMenuItemClick(null, null);
  293. }
  294. private void UpdatePluginMenu(bool validWorkingDir)
  295. {
  296. foreach (ToolStripItem item in pluginsToolStripMenuItem.DropDownItems)
  297. {
  298. var plugin = item.Tag as IGitPluginForRepository;
  299. item.Enabled = plugin == null || validWorkingDir;
  300. }
  301. }
  302. private void RegisterPlugins()
  303. {
  304. foreach (var plugin in LoadedPlugins.Plugins)
  305. plugin.Register(UICommands);
  306. UICommands.RaisePostRegisterPlugin(this);
  307. }
  308. private void UnregisterPlugins()
  309. {
  310. foreach (var plugin in LoadedPlugins.Plugins)
  311. plugin.Unregister(UICommands);
  312. }
  313. /// <summary>
  314. /// to avoid showing menu items that should not be there during
  315. /// the transition from dashboard to repo browser and vice versa
  316. ///
  317. /// and reset hotkeys that are shared between mutual exclusive menu items
  318. /// </summary>
  319. private void HideVariableMainMenuItems()
  320. {
  321. dashboardToolStripMenuItem.Visible = false;
  322. repositoryToolStripMenuItem.Visible = false;
  323. commandsToolStripMenuItem.Visible = false;
  324. refreshToolStripMenuItem.ShortcutKeys = Keys.None;
  325. refreshDashboardToolStripMenuItem.ShortcutKeys = Keys.None;
  326. _repositoryHostsToolStripMenuItem.Visible = false;
  327. _formBrowseMenus.RemoveAdditionalMainMenuItems();
  328. menuStrip1.Refresh();
  329. }
  330. private void InternalInitialize(bool hard)
  331. {
  332. Cursor.Current = Cursors.WaitCursor;
  333. UICommands.RaisePreBrowseInitialize(this);
  334. // check for updates
  335. if (Settings.LastUpdateCheck.AddDays(7) < DateTime.Now)
  336. {
  337. Settings.LastUpdateCheck = DateTime.Now;
  338. using (var updateForm = new FormUpdates(Module.AppVersion))
  339. updateForm.SearchForUpdatesAndShow(Owner, false);
  340. }
  341. bool bareRepository = Module.IsBareRepository();
  342. bool validWorkingDir = Module.IsValidGitWorkingDir();
  343. bool hasWorkingDir = !string.IsNullOrEmpty(Module.WorkingDir);
  344. branchSelect.Text = validWorkingDir ? Module.GetSelectedBranch() : "";
  345. if (hasWorkingDir)
  346. HideDashboard();
  347. else
  348. ShowDashboard();
  349. toolStripButtonLevelUp.Enabled = hasWorkingDir && !bareRepository;
  350. CommitInfoTabControl.Visible = validWorkingDir;
  351. fileExplorerToolStripMenuItem.Enabled = validWorkingDir;
  352. manageRemoteRepositoriesToolStripMenuItem1.Enabled = validWorkingDir;
  353. branchSelect.Enabled = validWorkingDir;
  354. toolStripButton1.Enabled = validWorkingDir && !bareRepository;
  355. if (_toolStripGitStatus != null)
  356. _toolStripGitStatus.Enabled = validWorkingDir;
  357. toolStripButtonPull.Enabled = validWorkingDir;
  358. toolStripButtonPush.Enabled = validWorkingDir;
  359. dashboardToolStripMenuItem.Visible = !validWorkingDir;
  360. repositoryToolStripMenuItem.Visible = validWorkingDir;
  361. commandsToolStripMenuItem.Visible = validWorkingDir;
  362. if (validWorkingDir)
  363. {
  364. refreshToolStripMenuItem.ShortcutKeys = Keys.F5;
  365. }
  366. else
  367. {
  368. refreshDashboardToolStripMenuItem.ShortcutKeys = Keys.F5;
  369. }
  370. UpdatePluginMenu(validWorkingDir);
  371. gitMaintenanceToolStripMenuItem.Enabled = validWorkingDir;
  372. editgitignoreToolStripMenuItem1.Enabled = validWorkingDir;
  373. editgitattributesToolStripMenuItem.Enabled = validWorkingDir;
  374. editmailmapToolStripMenuItem.Enabled = validWorkingDir;
  375. toolStripSplitStash.Enabled = validWorkingDir && !bareRepository;
  376. commitcountPerUserToolStripMenuItem.Enabled = validWorkingDir;
  377. _createPullRequestsToolStripMenuItem.Enabled = validWorkingDir;
  378. _viewPullRequestsToolStripMenuItem.Enabled = validWorkingDir;
  379. //Only show "Repository hosts" menu item when there is at least 1 repository host plugin loaded
  380. _repositoryHostsToolStripMenuItem.Visible = RepoHosts.GitHosters.Count > 0;
  381. if (RepoHosts.GitHosters.Count == 1)
  382. _repositoryHostsToolStripMenuItem.Text = RepoHosts.GitHosters[0].Description;
  383. _filterBranchHelper.InitToolStripBranchFilter();
  384. if (repositoryToolStripMenuItem.Visible)
  385. {
  386. manageSubmodulesToolStripMenuItem.Enabled = !bareRepository;
  387. updateAllSubmodulesToolStripMenuItem.Enabled = !bareRepository;
  388. synchronizeAllSubmodulesToolStripMenuItem.Enabled = !bareRepository;
  389. editgitignoreToolStripMenuItem1.Enabled = !bareRepository;
  390. editgitattributesToolStripMenuItem.Enabled = !bareRepository;
  391. editmailmapToolStripMenuItem.Enabled = !bareRepository;
  392. }
  393. if (commandsToolStripMenuItem.Visible)
  394. {
  395. commitToolStripMenuItem.Enabled = !bareRepository;
  396. mergeToolStripMenuItem.Enabled = !bareRepository;
  397. rebaseToolStripMenuItem1.Enabled = !bareRepository;
  398. pullToolStripMenuItem1.Enabled = !bareRepository;
  399. resetToolStripMenuItem.Enabled = !bareRepository;
  400. cleanupToolStripMenuItem.Enabled = !bareRepository;
  401. stashToolStripMenuItem.Enabled = !bareRepository;
  402. checkoutBranchToolStripMenuItem.Enabled = !bareRepository;
  403. mergeBranchToolStripMenuItem.Enabled = !bareRepository;
  404. rebaseToolStripMenuItem.Enabled = !bareRepository;
  405. runMergetoolToolStripMenuItem.Enabled = !bareRepository;
  406. cherryPickToolStripMenuItem.Enabled = !bareRepository;
  407. checkoutToolStripMenuItem.Enabled = !bareRepository;
  408. bisectToolStripMenuItem.Enabled = !bareRepository;
  409. applyPatchToolStripMenuItem.Enabled = !bareRepository;
  410. SvnRebaseToolStripMenuItem.Enabled = !bareRepository;
  411. SvnDcommitToolStripMenuItem.Enabled = !bareRepository;
  412. }
  413. stashChangesToolStripMenuItem.Enabled = !bareRepository;
  414. gitGUIToolStripMenuItem.Enabled = !bareRepository;
  415. SetShortcutKeyDisplayStringsFromHotkeySettings();
  416. if (hard && hasWorkingDir)
  417. ShowRevisions();
  418. RefreshWorkingDirCombo();
  419. Text = GenerateWindowTitle(Module.WorkingDir, validWorkingDir, branchSelect.Text);
  420. DiffText.Font = Settings.DiffFont;
  421. UpdateJumplist(validWorkingDir);
  422. CheckForMergeConflicts();
  423. UpdateStashCount();
  424. UpdateSubmodulesList();
  425. // load custom user menu
  426. LoadUserMenu();
  427. if (validWorkingDir)
  428. {
  429. // add Navigate and View menu
  430. _formBrowseMenus.ResetMenuCommandSets();
  431. //// _formBrowseMenus.AddMenuCommandSet(MainMenuItem.NavigateMenu, _formBrowseMenuCommands.GetNavigateMenuCommands()); // not used at the moment
  432. _formBrowseMenus.AddMenuCommandSet(MainMenuItem.NavigateMenu, RevisionGrid.MenuCommands.GetNavigateMenuCommands());
  433. _formBrowseMenus.AddMenuCommandSet(MainMenuItem.ViewMenu, RevisionGrid.MenuCommands.GetViewMenuCommands());
  434. _formBrowseMenus.InsertAdditionalMainMenuItems(repositoryToolStripMenuItem);
  435. }
  436. UICommands.RaisePostBrowseInitialize(this);
  437. Cursor.Current = Cursors.Default;
  438. }
  439. internal Keys GetShortcutKeys(Commands cmd)
  440. {
  441. return GetShortcutKeys((int)cmd);
  442. }
  443. /// <summary>
  444. ///
  445. /// </summary>
  446. private void SetShortcutKeyDisplayStringsFromHotkeySettings()
  447. {
  448. gitBashToolStripMenuItem.ShortcutKeyDisplayString = GetShortcutKeys(Commands.GitBash).ToShortcutKeyDisplayString();
  449. commitToolStripMenuItem.ShortcutKeyDisplayString = GetShortcutKeys(Commands.Commit).ToShortcutKeyDisplayString();
  450. // TODO: add more
  451. }
  452. private void RefreshWorkingDirCombo()
  453. {
  454. Repository r = null;
  455. if (Repositories.RepositoryHistory.Repositories.Count > 0)
  456. r = Repositories.RepositoryHistory.Repositories[0];
  457. List<RecentRepoInfo> mostRecentRepos = new List<RecentRepoInfo>();
  458. if (r == null || !r.Path.Equals(Module.WorkingDir, StringComparison.InvariantCultureIgnoreCase))
  459. Repositories.AddMostRecentRepository(Module.WorkingDir);
  460. using (var graphics = CreateGraphics())
  461. {
  462. var splitter = new RecentRepoSplitter
  463. {
  464. measureFont = _NO_TRANSLATE_Workingdir.Font,
  465. graphics = graphics
  466. };
  467. splitter.SplitRecentRepos(Repositories.RepositoryHistory.Repositories, mostRecentRepos, mostRecentRepos);
  468. RecentRepoInfo ri = mostRecentRepos.Find((e) => e.Repo.Path.Equals(Module.WorkingDir, StringComparison.InvariantCultureIgnoreCase));
  469. if (ri == null)
  470. _NO_TRANSLATE_Workingdir.Text = Module.WorkingDir;
  471. else
  472. _NO_TRANSLATE_Workingdir.Text = ri.Caption;
  473. if (Settings.RecentReposComboMinWidth > 0)
  474. {
  475. _NO_TRANSLATE_Workingdir.AutoSize = false;
  476. var captionWidth = graphics.MeasureString(_NO_TRANSLATE_Workingdir.Text, _NO_TRANSLATE_Workingdir.Font).Width;
  477. captionWidth = captionWidth + _NO_TRANSLATE_Workingdir.DropDownButtonWidth + 5;
  478. _NO_TRANSLATE_Workingdir.Width = Math.Max(Settings.RecentReposComboMinWidth, (int)captionWidth);
  479. }
  480. else
  481. _NO_TRANSLATE_Workingdir.AutoSize = true;
  482. }
  483. }
  484. /// <summary>
  485. /// Returns a short name for repository.
  486. /// If the repository contains a description it is returned,
  487. /// otherwise the last part of path is returned.
  488. /// </summary>
  489. /// <param name="repositoryDir">Path to repository.</param>
  490. /// <returns>Short name for repository</returns>
  491. private static String GetRepositoryShortName(string repositoryDir)
  492. {
  493. DirectoryInfo dirInfo = new DirectoryInfo(repositoryDir);
  494. if (dirInfo.Exists)
  495. {
  496. string desc = ReadRepositoryDescription(repositoryDir);
  497. if (desc.IsNullOrEmpty())
  498. {
  499. desc = Repositories.RepositoryHistory.Repositories
  500. .Where(repo => repo.Path.Equals(repositoryDir, StringComparison.CurrentCultureIgnoreCase)).Select(repo => repo.Title)
  501. .FirstOrDefault();
  502. }
  503. return desc ?? dirInfo.Name;
  504. }
  505. return dirInfo.Name;
  506. }
  507. private void LoadUserMenu()
  508. {
  509. var scripts = ScriptManager.GetScripts().Where(script => script.Enabled
  510. && script.OnEvent == ScriptEvent.ShowInUserMenuBar).ToList();
  511. for (int i = ToolStrip.Items.Count - 1; i >= 0; i--)
  512. if (ToolStrip.Items[i].Tag != null &&
  513. ToolStrip.Items[i].Tag as String == "userscript")
  514. ToolStrip.Items.RemoveAt(i);
  515. if (scripts.Count == 0)
  516. return;
  517. ToolStripSeparator toolstripseparator = new ToolStripSeparator();
  518. toolstripseparator.Tag = "userscript";
  519. ToolStrip.Items.Add(toolstripseparator);
  520. foreach (ScriptInfo scriptInfo in scripts)
  521. {
  522. ToolStripButton tempButton = new ToolStripButton();
  523. //store scriptname
  524. tempButton.Text = scriptInfo.Name;
  525. tempButton.Tag = "userscript";
  526. //add handler
  527. tempButton.Click += UserMenu_Click;
  528. tempButton.Enabled = true;
  529. tempButton.Visible = true;
  530. //tempButton.Image = GitUI.Properties.Resources.bug;
  531. //scriptInfo.Icon = "Cow";
  532. tempButton.Image = scriptInfo.GetIcon();
  533. tempButton.DisplayStyle = ToolStripItemDisplayStyle.ImageAndText;
  534. //add to toolstrip
  535. ToolStrip.Items.Add(tempButton);
  536. }
  537. }
  538. private void UserMenu_Click(object sender, EventArgs e)
  539. {
  540. if (ScriptRunner.RunScript(this, Module, ((ToolStripButton)sender).Text, this.RevisionGrid))
  541. RevisionGrid.RefreshRevisions();
  542. }
  543. private void UpdateJumplist(bool validWorkingDir)
  544. {
  545. #if !__MonoCS__
  546. if (EnvUtils.RunningOnWindows() && TaskbarManager.IsPlatformSupported)
  547. {
  548. if (validWorkingDir)
  549. {
  550. string repositoryDescription = GetRepositoryShortName(Module.WorkingDir);
  551. string baseFolder = Path.Combine(Settings.ApplicationDataPath.Value, "Recent");
  552. if (!Directory.Exists(baseFolder))
  553. {
  554. Directory.CreateDirectory(baseFolder);
  555. }
  556. //Remove InvalidPathChars
  557. StringBuilder sb = new StringBuilder(repositoryDescription);
  558. foreach (char c in Path.GetInvalidFileNameChars())
  559. {
  560. sb.Replace(c, '_');
  561. }
  562. string path = Path.Combine(baseFolder, String.Format("{0}.{1}", sb, "gitext"));
  563. File.WriteAllText(path, Module.WorkingDir);
  564. JumpList.AddToRecent(path);
  565. var JList = JumpList.CreateJumpListForIndividualWindow(TaskbarManager.Instance.ApplicationId, Handle);
  566. JList.ClearAllUserTasks();
  567. //to control which category Recent/Frequent is displayed
  568. JList.KnownCategoryToDisplay = JumpListKnownCategoryType.Recent;
  569. JList.Refresh();
  570. }
  571. CreateOrUpdateTaskBarButtons(validWorkingDir);
  572. }
  573. #endif
  574. }
  575. #if !__MonoCS__
  576. private void CreateOrUpdateTaskBarButtons(bool validRepo)
  577. {
  578. if (EnvUtils.RunningOnWindows() && TaskbarManager.IsPlatformSupported)
  579. {
  580. if (!_toolbarButtonsCreated)
  581. {
  582. _commitButton = new ThumbnailToolBarButton(MakeIcon(toolStripButton1.Image, 48, true), toolStripButton1.Text);
  583. _commitButton.Click += ToolStripButton1Click;
  584. _pushButton = new ThumbnailToolBarButton(MakeIcon(toolStripButtonPush.Image, 48, true), toolStripButtonPush.Text);
  585. _pushButton.Click += PushToolStripMenuItemClick;
  586. _pullButton = new ThumbnailToolBarButton(MakeIcon(toolStripButtonPull.Image, 48, true), toolStripButtonPull.Text);
  587. _pullButton.Click += PullToolStripMenuItemClick;
  588. _toolbarButtonsCreated = true;
  589. ThumbnailToolBarButton[] buttons = new[] { _commitButton, _pullButton, _pushButton };
  590. //Call this method using reflection. This is a workaround to *not* reference WPF libraries, becuase of how the WindowsAPICodePack was implimented.
  591. TaskbarManager.Instance.ThumbnailToolBars.AddButtons(Handle, buttons);
  592. }
  593. _commitButton.Enabled = validRepo;
  594. _pushButton.Enabled = validRepo;
  595. _pullButton.Enabled = validRepo;
  596. }
  597. }
  598. #endif
  599. /// <summary>
  600. /// Converts an image into an icon. This was taken off of the interwebs.
  601. /// It's on a billion different sites and forum posts, so I would say its creative commons by now. -tekmaven
  602. /// </summary>
  603. /// <param name="img">The image that shall become an icon</param>
  604. /// <param name="size">The width and height of the icon. Standard
  605. /// sizes are 16x16, 32x32, 48x48, 64x64.</param>
  606. /// <param name="keepAspectRatio">Whether the image should be squashed into a
  607. /// square or whether whitespace should be put around it.</param>
  608. /// <returns>An icon!!</returns>
  609. private static Icon MakeIcon(Image img, int size, bool keepAspectRatio)
  610. {
  611. Bitmap square = new Bitmap(size, size); // create new bitmap
  612. Graphics g = Graphics.FromImage(square); // allow drawing to it
  613. int x, y, w, h; // dimensions for new image
  614. if (!keepAspectRatio || img.Height == img.Width)
  615. {
  616. // just fill the square
  617. x = y = 0; // set x and y to 0
  618. w = h = size; // set width and height to size
  619. }
  620. else
  621. {
  622. // work out the aspect ratio
  623. float r = (float)img.Width / (float)img.Height;
  624. // set dimensions accordingly to fit inside size^2 square
  625. if (r > 1)
  626. { // w is bigger, so divide h by r
  627. w = size;
  628. h = (int)((float)size / r);
  629. x = 0; y = (size - h) / 2; // center the image
  630. }
  631. else
  632. { // h is bigger, so multiply w by r
  633. w = (int)((float)size * r);
  634. h = size;
  635. y = 0; x = (size - w) / 2; // center the image
  636. }
  637. }
  638. // make the image shrink nicely by using HighQualityBicubic mode
  639. g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
  640. g.DrawImage(img, x, y, w, h); // draw image with specified dimensions
  641. g.Flush(); // make sure all drawing operations complete before we get the icon
  642. // following line would work directly on any image, but then
  643. // it wouldn't look as nice.
  644. return Icon.FromHandle(square.GetHicon());
  645. }
  646. private void UpdateStashCount()
  647. {
  648. if (Settings.ShowStashCount)
  649. {
  650. AsyncLoader.DoAsync(() => Module.GetStashes().Count,
  651. (result) => toolStripSplitStash.Text = string.Format(_stashCount.Text, result,
  652. result != 1 ? _stashPlural.Text : _stashSingular.Text));
  653. }
  654. else
  655. {
  656. toolStripSplitStash.Text = string.Empty;
  657. }
  658. }
  659. private void CheckForMergeConflicts()
  660. {
  661. bool validWorkingDir = Module.IsValidGitWorkingDir();
  662. if (validWorkingDir && Module.InTheMiddleOfBisect())
  663. {
  664. if (_bisect == null)
  665. {
  666. _bisect = new WarningToolStripItem { Text = _warningMiddleOfBisect.Text };
  667. _bisect.Click += BisectClick;
  668. statusStrip.Items.Add(_bisect);
  669. }
  670. }
  671. else
  672. {
  673. if (_bisect != null)
  674. {
  675. _bisect.Click -= BisectClick;
  676. statusStrip.Items.Remove(_bisect);
  677. _bisect = null;
  678. }
  679. }
  680. if (validWorkingDir &&
  681. (Module.InTheMiddleOfRebase() || Module.InTheMiddleOfPatch()))
  682. {
  683. if (_rebase == null)
  684. {
  685. _rebase = new WarningToolStripItem
  686. {
  687. Text = Module.InTheMiddleOfRebase()
  688. ? _warningMiddleOfRebase.Text
  689. : _warningMiddleOfPatchApply.Text
  690. };
  691. _rebase.Click += RebaseClick;
  692. statusStrip.Items.Add(_rebase);
  693. }
  694. }
  695. else
  696. {
  697. if (_rebase != null)
  698. {
  699. _rebase.Click -= RebaseClick;
  700. statusStrip.Items.Remove(_rebase);
  701. _rebase = null;
  702. }
  703. }
  704. if (validWorkingDir && Module.InTheMiddleOfConflictedMerge() &&
  705. !Directory.Exists(Module.GetGitDirectory() + "rebase-apply\\"))
  706. {
  707. if (_warning == null)
  708. {
  709. _warning = new WarningToolStripItem { Text = _hintUnresolvedMergeConflicts.Text };
  710. _warning.Click += WarningClick;
  711. statusStrip.Items.Add(_warning);
  712. }
  713. }
  714. else
  715. {
  716. if (_warning != null)
  717. {
  718. _warning.Click -= WarningClick;
  719. statusStrip.Items.Remove(_warning);
  720. _warning = null;
  721. }
  722. }
  723. //Only show status strip when there are status items on it.
  724. //There is always a close (x) button, do not count first item.
  725. if (statusStrip.Items.Count > 1)
  726. statusStrip.Show();
  727. else
  728. statusStrip.Hide();
  729. }
  730. /// <summary>
  731. /// Generates main window title according to given repository.
  732. /// </summary>
  733. /// <param name="workingDir">Path to repository.</param>
  734. /// <param name="isWorkingDirValid">If the given path contains valid repository.</param>
  735. /// <param name="branchName">Current branch name.</param>
  736. private string GenerateWindowTitle(string workingDir, bool isWorkingDirValid, string branchName)
  737. {
  738. #if DEBUG
  739. const string defaultTitle = "Git Extensions -> DEBUG <-";
  740. const string repositoryTitleFormat = "{0} ({1}) - Git Extensions -> DEBUG <-";
  741. #else
  742. const string defaultTitle = "Git Extensions";
  743. const string repositoryTitleFormat = "{0} ({1}) - Git Extensions";
  744. #endif
  745. if (!isWorkingDirValid)
  746. return defaultTitle;
  747. string repositoryDescription = GetRepositoryShortName(workingDir);
  748. if (string.IsNullOrEmpty(branchName))
  749. branchName = _noBranchTitle.Text;
  750. return string.Format(repositoryTitleFormat, repositoryDescription, branchName.Trim('(', ')'));
  751. }
  752. /// <summary>
  753. /// Reads repository description's first line from ".git\description" file.
  754. /// </summary>
  755. /// <param name="workingDir">Path to repository.</param>
  756. /// <returns>If the repository has description, returns that description, else returns <c>null</c>.</returns>
  757. private static string ReadRepositoryDescription(string workingDir)
  758. {
  759. const string repositoryDescriptionFileName = "description";
  760. const string defaultDescription = "Unnamed repository; edit this file 'description' to name the repository.";
  761. var repositoryPath = GitModule.GetGitDirectory(workingDir);
  762. var repositoryDescriptionFilePath = Path.Combine(repositoryPath, repositoryDescriptionFileName);
  763. if (!File.Exists(repositoryDescriptionFilePath))
  764. return null;
  765. try
  766. {
  767. var repositoryDescription = File.ReadLines(repositoryDescriptionFilePath).FirstOrDefault();
  768. return string.Equals(repositoryDescription, defaultDescription, StringComparison.CurrentCulture)
  769. ? null
  770. : repositoryDescription;
  771. }
  772. catch (IOException)
  773. {
  774. return null;
  775. }
  776. }
  777. private void RebaseClick(object sender, EventArgs e)
  778. {
  779. if (Module.InTheMiddleOfRebase())
  780. UICommands.StartRebaseDialog(this, null);
  781. else
  782. UICommands.StartApplyPatchDialog(this);
  783. }
  784. private void ShowRevisions()
  785. {
  786. if (RevisionGrid.IndexWatcher.IndexChanged)
  787. {
  788. RevisionGrid.RefreshRevisions();
  789. FillFileTree();
  790. FillDiff();
  791. FillCommitInfo();
  792. FillBuildReport();
  793. }
  794. RevisionGrid.IndexWatcher.Reset();
  795. }
  796. //store strings to not keep references to nodes
  797. private readonly Stack<string> lastSelectedNodes = new Stack<string>();
  798. private void FillFileTree()
  799. {
  800. if (CommitInfoTabControl.SelectedTab != TreeTabPage)
  801. return;
  802. if (selectedRevisionUpdatedTargets.HasFlag(UpdateTargets.FileTree))
  803. return;
  804. selectedRevisionUpdatedTargets |= UpdateTargets.FileTree;
  805. try
  806. {
  807. GitTree.SuspendLayout();
  808. // Save state only when there is selected node
  809. if (GitTree.SelectedNode != null)
  810. {
  811. TreeNode node = GitTree.SelectedNode;
  812. FileText.SaveCurrentScrollPos();
  813. lastSelectedNodes.Clear();
  814. while (node != null)
  815. {
  816. lastSelectedNodes.Push(node.Text);
  817. node = node.Parent;
  818. }
  819. }
  820. // Refresh tree
  821. GitTree.Nodes.Clear();
  822. //restore selected file and scroll position when new selection is done
  823. if (RevisionGrid.GetSelectedRevisions().Count > 0)
  824. {
  825. LoadInTree(RevisionGrid.GetSelectedRevisions()[0].SubItems, GitTree.Nodes);
  826. //GitTree.Sort();
  827. TreeNode lastMatchedNode = null;
  828. // Load state
  829. var currenNodes = GitTree.Nodes;
  830. TreeNode matchedNode = null;
  831. while (lastSelectedNodes.Count > 0 && currenNodes != null)
  832. {
  833. var next = lastSelectedNodes.Pop();
  834. foreach (TreeNode node in currenNodes)
  835. {
  836. if (node.Text != next && next.Length != 40)
  837. continue;
  838. node.Expand();
  839. matchedNode = node;
  840. break;
  841. }
  842. if (matchedNode == null)
  843. currenNodes = null;
  844. else
  845. {
  846. lastMatchedNode = matchedNode;
  847. currenNodes = matchedNode.Nodes;
  848. }
  849. }
  850. //if there is no exact match, don't restore scroll position
  851. if (lastMatchedNode != matchedNode)
  852. FileText.ResetCurrentScrollPos();
  853. GitTree.SelectedNode = lastMatchedNode;
  854. }
  855. if (GitTree.SelectedNode == null)
  856. {
  857. FileText.ViewText("", "");
  858. }
  859. }
  860. finally
  861. {
  862. GitTree.ResumeLayout();
  863. }
  864. }
  865. private void FillDiff()
  866. {
  867. DiffTabPage.Text = string.Format("{0}", DiffTabPageTitleBase);
  868. if (CommitInfoTabControl.SelectedTab != DiffTabPage)
  869. {
  870. return;
  871. }
  872. if (selectedRevisionUpdatedTargets.HasFlag(UpdateTargets.DiffList))
  873. return;
  874. selectedRevisionUpdatedTargets |= UpdateTargets.DiffList;
  875. var revisions = RevisionGrid.GetSelectedRevisions();
  876. DiffText.SaveCurrentScrollPos();
  877. DiffFiles.SetDiffs(revisions);
  878. switch (revisions.Count)
  879. {
  880. case 0:
  881. DiffTabPage.Text = string.Format("{0} (no selection)", DiffTabPageTitleBase);
  882. break;
  883. case 1: // diff "parent" --> "selected revision"
  884. var revision = revisions[0];
  885. if (revision != null && revision.ParentGuids != null && revision.ParentGuids.Length != 0)
  886. DiffTabPage.Text = string.Format("{0} (A: parent --> B: selection)", DiffTabPageTitleBase);
  887. break;
  888. case 2: // diff "first clicked revision" --> "second clicked revision"
  889. bool artificialRevSelected = revisions[0].IsArtificial() || revisions[1].IsArtificial();
  890. if (!artificialRevSelected)
  891. DiffTabPage.Text = string.Format("{0} (A: first --> B: second)", DiffTabPageTitleBase);
  892. break;
  893. default: // more than 2 revisions selected => no diff
  894. DiffTabPage.Text = string.Format("{0} (not supported)", DiffTabPageTitleBase);
  895. break;
  896. }
  897. }
  898. private void FillCommitInfo()
  899. {
  900. if (CommitInfoTabControl.SelectedTab != CommitInfoTabPage)
  901. return;
  902. if (selectedRevisionUpdatedTargets.HasFlag(UpdateTargets.CommitInfo))
  903. return;
  904. selectedRevisionUpdatedTargets |= UpdateTargets.CommitInfo;
  905. if (RevisionGrid.GetSelectedRevisions().Count == 0)
  906. return;
  907. var revision = RevisionGrid.GetSelectedRevisions()[0];
  908. var children = RevisionGrid.GetRevisionChildren(revision.Guid);
  909. RevisionInfo.SetRevisionWithChildren(revision, children);
  910. }
  911. private BuildReportTabPageExtension BuildReportTabPageExtension;
  912. private void FillBuildReport()
  913. {
  914. if(EnvUtils.IsMonoRuntime())
  915. return;
  916. var selectedRevisions = RevisionGrid.GetSelectedRevisions();
  917. var revision = selectedRevisions.Count == 1 ? selectedRevisions.Single() : null;
  918. if (BuildReportTabPageExtension == null)
  919. BuildReportTabPageExtension = new BuildReportTabPageExtension(CommitInfoTabControl);
  920. BuildReportTabPageExtension.FillBuildReport(revision);
  921. }
  922. public void fileHistoryItem_Click(object sender, EventArgs e)
  923. {
  924. var item = GitTree.SelectedNode.Tag as GitItem;
  925. if (item == null)
  926. return;
  927. IList<GitRevision> revisions = RevisionGrid.GetSelectedRevisions();
  928. if (revisions.Count == 0 || GitRevision.IsArtificial(revisions[0].Guid))
  929. UICommands.StartFileHistoryDialog(this, item.FileName);
  930. else
  931. UICommands.StartFileHistoryDialog(this, item.FileName, revisions[0], false, false);
  932. }
  933. private void blameMenuItem_Click(object sender, EventArgs e)
  934. {
  935. var item = GitTree.SelectedNode.Tag as GitItem;
  936. if (item == null)
  937. return;
  938. IList<GitRevision> revisions = RevisionGrid.GetSelectedRevisions();
  939. if (revisions.Count == 0 || GitRevision.IsArtificial(revisions[0].Guid))
  940. UICommands.StartFileHistoryDialog(this, item.FileName, null, false, true);
  941. else
  942. UICommands.StartFileHistoryDialog(this, item.FileName, revisions[0], true, true);
  943. }
  944. public void FindFileOnClick(object sender, EventArgs e)
  945. {
  946. string selectedItem;
  947. using (var searchWindow = new SearchWindow<string>(FindFileMatches)
  948. {
  949. Owner = this
  950. })
  951. {
  952. searchWindow.ShowDialog(this);
  953. selectedItem = searchWindow.SelectedItem;
  954. }
  955. if (string.IsNullOrEmpty(selectedItem))
  956. {
  957. return;
  958. }
  959. string[] items = selectedItem.Split(new[] { '/' });
  960. TreeNodeCollection nodes = GitTree.Nodes;
  961. for (int i = 0; i < items.Length - 1; i++)
  962. {
  963. TreeNode selectedNode = Find(nodes, items[i]);
  964. if (selectedNode == null)
  965. {
  966. return; //Item does not exist in the tree
  967. }
  968. selectedNode.Expand();
  969. nodes = selectedNode.Nodes;
  970. }
  971. var lastItem = Find(nodes, items[items.Length - 1]);
  972. if (lastItem != null)
  973. {
  974. GitTree.SelectedNode = lastItem;
  975. }
  976. }
  977. private static TreeNode Find(TreeNodeCollection nodes, string label)
  978. {
  979. for (int i = 0; i < nodes.Count; i++)
  980. {
  981. if (nodes[i].Text == label)
  982. {
  983. return nodes[i];
  984. }
  985. }
  986. return null;
  987. }
  988. private IList<string> FindFileMatches(string name)
  989. {
  990. var candidates = Module.GetFullTree(RevisionGrid.GetSelectedRevisions()[0].TreeGuid);
  991. string nameAsLower = name.ToLower();
  992. return candidates.Where(fileName => fileName.ToLower().Contains(nameAsLower)).ToList();
  993. }
  994. private string SaveSelectedItemToTempFile()
  995. {
  996. var gitItem = GitTree.SelectedNode.Tag as GitItem;
  997. if (gitItem == null || !gitItem.IsBlob)
  998. return null;
  999. var fileName = gitItem.FileName;
  1000. if (fileName.Contains("\\") && fileName.LastIndexOf("\\") < fileName.Length)
  1001. fileName = fileName.Substring(fileName.LastIndexOf('\\') + 1);
  1002. if (fileName.Contains("/") && fileName.LastIndexOf("/") < fileName.Length)
  1003. fileName = fileName.Substring(fileName.LastIndexOf('/') + 1);
  1004. fileName = (Path.GetTempPath() + fileName).ToNativePath();
  1005. Module.SaveBlobAs(fileName, gitItem.Guid);
  1006. return fileName;
  1007. }
  1008. public void OpenWithOnClick(object sender, EventArgs e)
  1009. {
  1010. var fileName = SaveSelectedItemToTempFile();
  1011. if (fileName != null)
  1012. OsShellUtil.OpenAs(fileName);
  1013. }
  1014. public void OpenOnClick(object sender, EventArgs e)
  1015. {
  1016. try
  1017. {
  1018. var fileName = SaveSelectedItemToTempFile();
  1019. if (fileName != null)
  1020. Process.Start(fileName);
  1021. }
  1022. catch (Exception ex)
  1023. {
  1024. MessageBox.Show(this, ex.Message);
  1025. }
  1026. }
  1027. private void FileTreeContextMenu_Opening(object sender, System.ComponentModel.CancelEventArgs e)
  1028. {
  1029. var gitItem = (GitTree.SelectedNode != null) ? GitTree.SelectedNode.Tag as GitItem : null;
  1030. var enableItems = gitItem != null && gitItem.IsBlob;
  1031. saveAsToolStripMenuItem.Enabled = enableItems;
  1032. openFileToolStripMenuItem.Enabled = enableItems;
  1033. openFileWithToolStripMenuItem.Enabled = enableItems;
  1034. openWithToolStripMenuItem.Enabled = enableItems;
  1035. copyFilenameToClipboardToolStripMenuItem.Enabled = FormBrowseUtil.IsFileOrDirectory(FormBrowseUtil.GetFullPathFromGitItem(Module, gitItem));
  1036. editCheckedOutFileToolStripMenuItem.Enabled = enableItems;
  1037. }
  1038. protected void LoadInTree(IEnumerable<IGitItem> items, TreeNodeCollection node)
  1039. {
  1040. var sortedItems = items.OrderBy(gi => gi, new GitFileTreeComparer());
  1041. foreach (var item in sortedItems)
  1042. {
  1043. var subNode = node.Add(item.Name);
  1044. subNode.Tag = item;
  1045. var gitItem = item as GitItem;
  1046. if (gitItem == null)
  1047. subNode.Nodes.Add(new TreeNode());
  1048. else
  1049. {
  1050. if (gitItem.IsTree)
  1051. {
  1052. subNode.ImageIndex = 1;
  1053. subNode.SelectedImageIndex = 1;
  1054. subNode.Nodes.Add(new TreeNode());
  1055. }
  1056. else
  1057. if (gitItem.IsCommit)
  1058. {
  1059. subNode.ImageIndex = 2;
  1060. subNode.SelectedImageIndex = 2;
  1061. subNode.Text = item.Name + " (Submodule)";
  1062. }
  1063. }
  1064. }
  1065. }
  1066. [Flags]
  1067. internal enum UpdateTargets
  1068. {
  1069. None = 1,
  1070. DiffList = 2,
  1071. FileTree = 4,
  1072. CommitInfo = 8
  1073. }
  1074. private UpdateTargets selectedRevisionUpdatedTargets = UpdateTargets.None;
  1075. private void RevisionGridSelectionChanged(object sender, EventArgs e)
  1076. {
  1077. try
  1078. {
  1079. selectedRevisionUpdatedTargets = UpdateTargets.None;
  1080. var revisions = RevisionGrid.GetSelectedRevisions();
  1081. if (revisions.Any() && GitRevision.IsArtificial(revisions[0].Guid))
  1082. {
  1083. CommitInfoTabControl.RemoveIfExists(CommitInfoTabPage);
  1084. CommitInfoTabControl.RemoveIfExists(TreeTabPage);
  1085. }
  1086. else
  1087. {
  1088. CommitInfoTabControl.InsertIfNotExists(0, CommitInfoTabPage);
  1089. CommitInfoTabControl.InsertIfNotExists(1, TreeTabPage);
  1090. }
  1091. //RevisionGrid.HighlightSelectedBranch();
  1092. FillFileTree();
  1093. FillDiff();
  1094. FillCommitInfo();
  1095. FillBuildReport();
  1096. }
  1097. catch (Exception ex)
  1098. {
  1099. Trace.WriteLine(ex.Message);
  1100. }
  1101. }
  1102. private void OpenToolStripMenuItemClick(object sender, EventArgs e)
  1103. {
  1104. GitModule module = FormOpenDirectory.OpenModule(this);
  1105. if (module != null)
  1106. SetGitModule(module);
  1107. }
  1108. private void CheckoutToolStripMenuItemClick(object sender, EventArgs e)
  1109. {
  1110. UICommands.StartCheckoutRevisionDialog(this);
  1111. }
  1112. private void GitTreeDoubleClick(object sender, EventArgs e)
  1113. {
  1114. if (GitTree.SelectedNode == null || !(GitTree.SelectedNode.Tag is IGitItem))
  1115. return;
  1116. var item = GitTree.SelectedNode.Tag as GitItem;
  1117. if (item == null)
  1118. return;
  1119. if (item.IsBlob)
  1120. {
  1121. UICommands.StartFileHistoryDialog(this, item.FileName, null);
  1122. }
  1123. else if (item.IsCommit)
  1124. {
  1125. Process process = new Process();
  1126. process.StartInfo.FileName = Application.ExecutablePath;
  1127. process.StartInfo.Arguments = "browse";
  1128. process.StartInfo.WorkingDirectory = Path.Combine(Module.WorkingDir, item.FileName.EnsureTrailingPathSeparator());
  1129. process.Start();
  1130. }
  1131. }
  1132. private void CloneToolStripMenuItemClick(object sender, EventArgs e)
  1133. {
  1134. UICommands.StartCloneDialog(this, string.Empty, false, SetGitModule);
  1135. }
  1136. private void CommitToolStripMenuItemClick(object sender, EventArgs e)
  1137. {
  1138. UICommands.StartCommitDialog(this);
  1139. }
  1140. private void InitNewRepositoryToolStripMenuItemClick(object sender, EventArgs e)
  1141. {
  1142. UICommands.StartInitializeDialog(this, SetGitModule);
  1143. }
  1144. private void PushToolStripMenuItemClick(object sender, EventArgs e)
  1145. {
  1146. bool bSilent = (ModifierKeys & Keys.Shift) != 0;
  1147. UICommands.StartPushDialog(this, bSilent);
  1148. }
  1149. private void PullToolStripMenuItemClick(object sender, EventArgs e)
  1150. {
  1151. bool bSilent;
  1152. if (sender == toolStripButtonPull || sender == pullToolStripMenuItem)
  1153. {
  1154. if (Module.LastPullAction == Settings.PullAction.None)
  1155. {
  1156. bSilent = (ModifierKeys & Keys.Shift) != 0;
  1157. }
  1158. else if (Module.LastPullAction == Settings.PullAction.FetchAll)
  1159. {
  1160. fetchAllToolStripMenuItem_Click(sender, e);
  1161. return;
  1162. }
  1163. else
  1164. {
  1165. bSilent = (sender == toolStripButtonPull);
  1166. Module.LastPullActionToFormPullAction();
  1167. }
  1168. }
  1169. else
  1170. {
  1171. bSilent = sender != pullToolStripMenuItem1;
  1172. RefreshPullIcon();
  1173. Module.LastPullActionToFormPullAction();
  1174. }
  1175. UICommands.StartPullDialog(this, bSilent);
  1176. }
  1177. private void RefreshToolStripMenuItemClick(object sender, EventArgs e)
  1178. {
  1179. RefreshRevisions();
  1180. }
  1181. private void RefreshDashboardToolStripMenuItemClick(object sender, EventArgs e)
  1182. {
  1183. _dashboard.Refresh();
  1184. }
  1185. private void AboutToolStripMenuItemClick(object sender, EventArgs e)
  1186. {
  1187. using (var frm = new AboutBox()) frm.ShowDialog(this);
  1188. }
  1189. private void PatchToolStripMenuItemClick(object sender, EventArgs e)
  1190. {
  1191. UICommands.StartViewPatchDialog(this);
  1192. }
  1193. private void ApplyPatchToolStripMenuItemClick(object sender, EventArgs e)
  1194. {
  1195. UICommands.StartApplyPatchDialog(this);
  1196. }
  1197. private void GitBashToolStripMenuItemClick1(object sender, EventArgs e)
  1198. {
  1199. Module.RunBash();
  1200. }
  1201. private void GitGuiToolStripMenuItemClick(object sender, EventArgs e)
  1202. {
  1203. Module.RunGui();
  1204. }
  1205. private void FormatPatchToolStripMenuItemClick(object sender, EventArgs e)
  1206. {
  1207. UICommands.StartFormatPatchDialog(this);
  1208. }
  1209. private void GitcommandLogToolStripMenuItemClick(object sender, EventArgs e)
  1210. {
  1211. FormGitLog.ShowOrActivate(this);
  1212. }
  1213. private void CheckoutBranchToolStripMenuItemClick(object sender, EventArgs e)
  1214. {
  1215. UICommands.StartCheckoutBranch(this);
  1216. }
  1217. private void StashToolStripMenuItemClick(object sender, EventArgs e)
  1218. {
  1219. UICommands.StartStashDialog(this);
  1220. }
  1221. private void ResetToolStripMenuItem_Click(object sender, EventArgs e)
  1222. {
  1223. UICommands.StartResetChangesDialog(this);
  1224. }
  1225. private void RunMergetoolToolStripMenuItemClick(object sender, EventArgs e)
  1226. {
  1227. UICommands.StartResolveConflictsDialog(this);
  1228. }
  1229. private void WarningClick(object sender, EventArgs e)
  1230. {
  1231. UICommands.StartResolveConflictsDialog(this);
  1232. }
  1233. private void WorkingdirClick(object sender, EventArgs e)
  1234. {
  1235. _NO_TRANSLATE_Workingdir.ShowDropDown();
  1236. }
  1237. private void CurrentBranchClick(object sender, EventArgs e)
  1238. {
  1239. branchSelect.ShowDropDown();
  1240. }
  1241. private void DeleteBranchToolStripMenuItemClick(object sender, EventArgs e)
  1242. {
  1243. UICommands.StartDeleteBranchDialog(this, null);
  1244. }
  1245. private void DeleteTagToolStripMenuItemClick(object sender, EventArgs e)
  1246. {
  1247. UICommands.StartDeleteTagDialog(this, null);
  1248. }
  1249. private void CherryPickToolStripMenuItemClick(object sender, EventArgs e)
  1250. {
  1251. var revisions = RevisionGrid.GetSelectedRevisions();
  1252. if (revisions.Count != 1)
  1253. {
  1254. MessageBox.Show("Select exactly one revision.");
  1255. return;
  1256. }
  1257. UICommands.StartCherryPickDialog(this, revisions.First());
  1258. }
  1259. private void MergeBranchToolStripMenuItemClick(object sender, EventArgs e)
  1260. {
  1261. UICommands.StartMergeBranchDialog(this, null);
  1262. }
  1263. private void ToolStripButton1Click(object sender, EventArgs e)
  1264. {
  1265. CommitToolStripMenuItemClick(sender, e);
  1266. }
  1267. private void SettingsClick(object sender, EventArgs e)
  1268. {
  1269. SettingsToolStripMenuItem2Click(sender, e);
  1270. }
  1271. private void TagToolStripMenuItemClick(object sender, EventArgs e)
  1272. {
  1273. UICommands.StartCreateTagDialog(this);
  1274. }
  1275. private void RefreshButtonClick(object sender, EventArgs e)
  1276. {
  1277. RefreshToolStripMenuItemClick(sender, e);
  1278. }
  1279. private void CommitcountPerUserToolStripMenuItemClick(object sender, EventArgs e)
  1280. {
  1281. using (var frm = new FormCommitCount(UICommands)) frm.ShowDialog(this);
  1282. }
  1283. private void KGitToolStripMenuItemClick(object sender, EventArgs e)
  1284. {
  1285. Module.RunGitK();
  1286. }
  1287. private void DonateToolStripMenuItemClick(object sender, EventArgs e)
  1288. {
  1289. using (var frm = new FormDonate()) frm.ShowDialog(this);
  1290. }
  1291. private void FormBrowseFormClosing(object sender, FormClosingEventArgs e)
  1292. {
  1293. SaveUserMenuPosition();
  1294. }
  1295. private void SaveUserMenuPosition()
  1296. {
  1297. GitCommands.AppSettings.UserMenuLocationX = UserMenuToolStrip.Location.X;
  1298. GitCommands.AppSettings.UserMenuLocationY = UserMenuToolStrip.Location.Y;
  1299. }
  1300. private void EditGitignoreToolStripMenuItem1Click(object sender, EventArgs e)
  1301. {
  1302. UICommands.StartEditGitIgnoreDialog(this);
  1303. }
  1304. private void SettingsToolStripMenuItem2Click(object sender, EventArgs e)
  1305. {
  1306. var translation = Settings.Translation;
  1307. UICommands.StartSettingsDialog(this);
  1308. if (translation != Settings.Translation)
  1309. Translate();
  1310. this.Hotkeys = HotkeySettingsManager.LoadHotkeys(HotkeySettingsName);
  1311. RevisionGrid.ReloadHotkeys();
  1312. RevisionGrid.ReloadTranslation();
  1313. }
  1314. private void ArchiveToolStripMenuItemClick(object sender, EventArgs e)
  1315. {
  1316. var revisions = RevisionGrid.GetSelectedRevisions();
  1317. if (revisions.Count > 2)
  1318. {
  1319. MessageBox.Show(this, "Select only one or two revisions. Abort.", "Archive revision");
  1320. return;
  1321. }
  1322. GitRevision mainRevision = revisions.First();
  1323. GitRevision diffRevision = null;
  1324. if (revisions.Count == 2)
  1325. diffRevision = revisions.Last();
  1326. UICommands.StartArchiveDialog(this, mainRevision, diffRevision);
  1327. }
  1328. private void EditMailMapToolStripMenuItemClick(object sender, EventArgs e)
  1329. {
  1330. UICommands.StartMailMapDialog(this);
  1331. }
  1332. private void EditLocalGitConfigToolStripMenuItemClick(object sender, EventArgs e)
  1333. {
  1334. var fileName = Path.Combine(Module.GetGitDirectory(), "config");
  1335. UICommands.StartFileEditorDialog(fileName, true);
  1336. }
  1337. private void CompressGitDatabaseToolStripMenuItemClick(object sender, EventArgs e)
  1338. {
  1339. FormProcess.ShowModeless(this, "gc");
  1340. }
  1341. private void VerifyGitDatabaseToolStripMenuItemClick(object sender, EventArgs e)
  1342. {
  1343. UICommands.StartVerifyDatabaseDialog(this);
  1344. }
  1345. private void ManageRemoteRepositoriesToolStripMenuItemClick(object sender, EventArgs e)
  1346. {
  1347. UICommands.StartRemotesDialog(this);
  1348. }
  1349. private void RebaseToolStripMenuItemClick(object sender, EventArgs e)
  1350. {
  1351. IList<GitRevision> revisions = RevisionGrid.GetSelectedRevisions();
  1352. if (2 == revisions.Count)
  1353. {
  1354. string to = null;
  1355. string from = null;
  1356. string currentBranch = Module.GetSelectedBranch();
  1357. string currentCheckout = RevisionGrid.CurrentCheckout;
  1358. if (revisions[0].Guid == currentCheckout)
  1359. {
  1360. from = revisions[1].Guid.Substring(0, 8);
  1361. to = currentBranch;
  1362. }
  1363. else if (revisions[1].Guid == currentCheckout)
  1364. {
  1365. from = revisions[0].Guid.Substring(0, 8);
  1366. to = currentBranch;
  1367. }
  1368. UICommands.StartRebaseDialog(this, from, to, null);
  1369. }
  1370. else
  1371. {
  1372. UICommands.StartRebaseDialog(this, null);
  1373. }
  1374. }
  1375. private void StartAuthenticationAgentToolStripMenuItemClick(object sender, EventArgs e)
  1376. {
  1377. Module.RunExternalCmdDetached(Settings.Pageant, "");
  1378. }
  1379. private void GenerateOrImportKeyToolStripMenuItemClick(object sender, EventArgs e)
  1380. {
  1381. Module.RunExternalCmdDetached(Settings.Puttygen, "");
  1382. }
  1383. private void TabControl1SelectedIndexChanged(object sender, EventArgs e)
  1384. {
  1385. FillFileTree();
  1386. FillDiff();
  1387. FillCommitInfo();
  1388. FillBuildReport();
  1389. }
  1390. private void DiffFilesSelectedIndexChanged(object sender, EventArgs e)
  1391. {
  1392. if (!_dontUpdateOnIndexChange)
  1393. ShowSelectedFileDiff();
  1394. }
  1395. private void ShowSelectedFileDiff()
  1396. {
  1397. if (DiffFiles.SelectedItem == null)
  1398. {
  1399. DiffText.ViewPatch("");
  1400. return;
  1401. }
  1402. IList<GitRevision> items = RevisionGrid.GetSelectedRevisions();
  1403. if (items.Count() == 1)
  1404. items.Add(new GitRevision(Module, DiffFiles.SelectedItemParent));
  1405. DiffText.ViewChanges(items, DiffFiles.SelectedItem, String.Empty);
  1406. }
  1407. private void ChangelogToolStripMenuItemClick(object sender, EventArgs e)
  1408. {
  1409. using (var frm = new FormChangeLog()) frm.ShowDialog(this);
  1410. }
  1411. private void DiffFilesDoubleClick(object sender, EventArgs e)
  1412. {
  1413. if (DiffFiles.SelectedItem == null)
  1414. return;
  1415. UICommands.StartFileHistoryDialog(this, (DiffFiles.SelectedItem).Name);
  1416. }
  1417. private void ToolStripButtonPushClick(object sender, EventArgs e)
  1418. {
  1419. PushToolStripMenuItemClick(sender, e);
  1420. }
  1421. private void ManageSubmodulesToolStripMenuItemClick(object sender, EventArgs e)
  1422. {
  1423. UICommands.StartSubmodulesDialog(this);
  1424. }
  1425. private void UpdateSubmoduleToolStripMenuItemClick(object sender, EventArgs e)
  1426. {
  1427. var submodule = (sender as ToolStripMenuItem).Tag as string;
  1428. FormProcess.ShowDialog(this, Module.SuperprojectModule,
  1429. GitCommandHelpers.SubmoduleUpdateCmd(submodule));
  1430. UICommands.RepoChangedNotifier.Notify();
  1431. }
  1432. private void UpdateAllSubmodulesToolStripMenuItemClick(object sender, EventArgs e)
  1433. {
  1434. UICommands.StartUpdateSubmodulesDialog(this);
  1435. }
  1436. private void SynchronizeAllSubmodulesToolStripMenuItemClick(object sender, EventArgs e)
  1437. {
  1438. UICommands.StartSyncSubmodulesDialog(this);
  1439. }
  1440. private void ToolStripSplitStashButtonClick(object sender, EventArgs e)
  1441. {
  1442. UICommands.StartStashDialog(this);
  1443. }
  1444. private void StashChangesToolStripMenuItemClick(object sender, EventArgs e)
  1445. {
  1446. UICommands.StashSave(this, AppSettings.IncludeUntrackedFilesInManualStash);
  1447. }
  1448. private void StashPopToolStripMenuItemClick(object sender, EventArgs e)
  1449. {
  1450. UICommands.StashPop(this);
  1451. }
  1452. private void ViewStashToolStripMenuItemClick(object sender, EventArgs e)
  1453. {
  1454. UICommands.StartStashDialog(this);
  1455. }
  1456. private void ExitToolStripMenuItemClick(object sender, EventArgs e)
  1457. {
  1458. Close();
  1459. }
  1460. private void FileToolStripMenuItemDropDownOpening(object sender, EventArgs e)
  1461. {
  1462. recentToolStripMenuItem.DropDownItems.Clear();
  1463. foreach (var historyItem in Repositories.RepositoryHistory.Repositories)
  1464. {
  1465. if (string.IsNullOrEmpty(historyItem.Path))
  1466. continue;
  1467. var historyItemMenu = new ToolStripMenuItem(historyItem.Path);
  1468. historyItemMenu.Click += HistoryItemMenuClick;
  1469. historyItemMenu.Width = 225;
  1470. recentToolStripMenuItem.DropDownItems.Add(historyItemMenu);
  1471. }
  1472. }
  1473. private void ChangeWorkingDir(string path)
  1474. {
  1475. GitModule module = new GitModule(path);
  1476. if (!module.IsValidGitWorkingDir())
  1477. {
  1478. DialogResult dialogResult = MessageBox.Show(this, directoryIsNotAValidRepository.Text,
  1479. directoryIsNotAValidRepositoryCaption.Text, MessageBoxButtons.YesNoCancel,
  1480. MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
  1481. if (dialogResult == DialogResult.Yes)
  1482. {
  1483. Repositories.RepositoryHistory.RemoveRecentRepository(path);
  1484. return;
  1485. }
  1486. else if (dialogResult == DialogResult.Cancel)
  1487. return;
  1488. }
  1489. SetGitModule(module);
  1490. }
  1491. private void HistoryItemMenuClick(object sender, EventArgs e)
  1492. {
  1493. var button = sender as ToolStripMenuItem;
  1494. if (button == null)
  1495. return;
  1496. ChangeWorkingDir(button.Text);
  1497. }
  1498. private void PluginSettingsToolStripMenuItemClick(object sender, EventArgs e)
  1499. {
  1500. UICommands.StartPluginSettingsDialog(this);
  1501. }
  1502. private void RepoSettingsToolStripMenuItemClick(object sender, EventArgs e)
  1503. {
  1504. UICommands.StartRepoSettingsDialog(this);
  1505. }
  1506. private void CloseToolStripMenuItemClick(object sender, EventArgs e)
  1507. {
  1508. SetWorkingDir("");
  1509. }
  1510. public override void CancelButtonClick(object sender, EventArgs e)
  1511. {
  1512. // If a filter is applied, clear it
  1513. if (RevisionGrid.FilterIsApplied(false))
  1514. {
  1515. // Clear filter
  1516. _filterRevisionsHelper.SetFilter(string.Empty);
  1517. }
  1518. // If a branch filter is applied by text or using the menus "Show current branch only"
  1519. else if (RevisionGrid.FilterIsApplied(true) || AppSettings.BranchFilterEnabled)
  1520. {
  1521. // Clear branch filter
  1522. _filterBranchHelper.SetBranchFilter(string.Empty, true);
  1523. // Execute the "Show all branches" menu option
  1524. RevisionGrid.ShowAllBranches_ToolStripMenuItemClick(sender, e);
  1525. }
  1526. }
  1527. private void GitTreeMouseDown(object sender, MouseEventArgs e)
  1528. {
  1529. if (e.Button == MouseButtons.Right)
  1530. GitTree.SelectedNode = GitTree.GetNodeAt(e.X, e.Y);
  1531. }
  1532. private void UserManualToolStripMenuItemClick(object sender, EventArgs e)
  1533. {
  1534. try
  1535. {
  1536. Process.Start(Path.Combine(Settings.GetInstallDir(), "GitExtensionsUserManual.pdf"));
  1537. }
  1538. catch (Exception ex)
  1539. {
  1540. MessageBox.Show(this, ex.Message);
  1541. }
  1542. }
  1543. private void DiffTextExtraDiffArgumentsChanged(object sender, EventArgs e)
  1544. {
  1545. ShowSelectedFileDiff();
  1546. }
  1547. private void CleanupToolStripMenuItemClick(object sender, EventArgs e)
  1548. {
  1549. UICommands.StartCleanupRepositoryDialog(this);
  1550. }
  1551. private void openWithDifftoolToolStripMenuItem_Click(object sender, EventArgs e)
  1552. {
  1553. if (DiffFiles.SelectedItem == null)
  1554. return;
  1555. var selectedItem = DiffFiles.SelectedItem;
  1556. GitUIExtensions.DiffWithRevisionKind diffKind;
  1557. if (sender == aLocalToolStripMenuItem)
  1558. diffKind = GitUIExtensions.DiffWithRevisionKind.DiffALocal;
  1559. else if (sender == bLocalToolStripMenuItem)
  1560. diffKind = GitUIExtensions.DiffWithRevisionKind.DiffBLocal;
  1561. else if (sender == parentOfALocalToolStripMenuItem)
  1562. diffKind = GitUIExtensions.DiffWithRevisionKind.DiffAParentLocal;
  1563. else if (sender == parentOfBLocalToolStripMenuItem)
  1564. diffKind = GitUIExtensions.DiffWithRevisionKind.DiffBParentLocal;
  1565. else
  1566. {
  1567. Debug.Assert(sender == aBToolStripMenuItem, "Not implemented DiffWithRevisionKind: " + sender);
  1568. diffKind = GitUIExtensions.DiffWithRevisionKind.DiffAB;
  1569. }
  1570. string parentGuid = RevisionGrid.GetSelectedRevisions().Count() == 1 ? DiffFiles.SelectedItemParent : null;
  1571. RevisionGrid.OpenWithDifftool(selectedItem.Name, selectedItem.OldName, diffKind, parentGuid);
  1572. }
  1573. private void AddWorkingdirDropDownItem(Repository repo, string caption)
  1574. {
  1575. ToolStripMenuItem toolStripItem = new ToolStripMenuItem(caption);
  1576. _NO_TRANSLATE_Workingdir.DropDownItems.Add(toolStripItem);
  1577. toolStripItem.Click += (hs, he) => ChangeWorkingDir(repo.Path);
  1578. if (repo.Title != null || !repo.Path.Equals(caption))
  1579. toolStripItem.ToolTipText = repo.Path;
  1580. }
  1581. private void WorkingdirDropDownOpening(object sender, EventArgs e)
  1582. {
  1583. _NO_TRANSLATE_Workingdir.DropDownItems.Clear();
  1584. List<RecentRepoInfo> mostRecentRepos = new List<RecentRepoInfo>();
  1585. List<RecentRepoInfo> lessRecentRepos = new List<RecentRepoInfo>();
  1586. using (var graphics = CreateGraphics())
  1587. {
  1588. var splitter = new RecentRepoSplitter
  1589. {
  1590. measureFont = _NO_TRANSLATE_Workingdir.Font,
  1591. graphics = graphics
  1592. };
  1593. splitter.SplitRecentRepos(Repositories.RepositoryHistory.Repositories, mostRecentRepos, lessRecentRepos);
  1594. }
  1595. foreach (RecentRepoInfo repo in mostRecentRepos)
  1596. AddWorkingdirDropDownItem(repo.Repo, repo.Caption);
  1597. if (lessRecentRepos.Count > 0)
  1598. {
  1599. if (mostRecentRepos.Count > 0 && (Settings.SortMostRecentRepos || Settings.SortLessRecentRepos))
  1600. _NO_TRANSLATE_Workingdir.DropDownItems.Add(new ToolStripSeparator());
  1601. foreach (RecentRepoInfo repo in lessRecentRepos)
  1602. AddWorkingdirDropDownItem(repo.Repo, repo.Caption);
  1603. }
  1604. _NO_TRANSLATE_Workingdir.DropDownItems.Add(new ToolStripSeparator());
  1605. ToolStripMenuItem toolStripItem = new ToolStripMenuItem(openToolStripMenuItem.Text);
  1606. toolStripItem.ShortcutKeys = openToolStripMenuItem.ShortcutKeys;
  1607. _NO_TRANSLATE_Workingdir.DropDownItems.Add(toolStripItem);
  1608. toolStripItem.Click += (hs, he) => OpenToolStripMenuItemClick(hs, he);
  1609. toolStripItem = new ToolStripMenuItem(_configureWorkingDirMenu.Text);
  1610. _NO_TRANSLATE_Workingdir.DropDownItems.Add(toolStripItem);
  1611. toolStripItem.Click += (hs, he) =>
  1612. {
  1613. using (var frm = new FormRecentReposSettings()) frm.ShowDialog(this);
  1614. RefreshWorkingDirCombo();
  1615. };
  1616. }
  1617. private void SetWorkingDir(string path)
  1618. {
  1619. SetGitModule(new GitModule(path));
  1620. }
  1621. private void SetGitModule(GitModule module)
  1622. {
  1623. HideVariableMainMenuItems();
  1624. UnregisterPlugins();
  1625. UICommands = new GitUICommands(module);
  1626. if (Module.IsValidGitWorkingDir())
  1627. {
  1628. Repositories.AddMostRecentRepository(Module.WorkingDir);
  1629. Settings.RecentWorkingDir = module.WorkingDir;
  1630. #if DEBUG
  1631. //Current encodings
  1632. Debug.WriteLine("Encodings for " + module.WorkingDir);
  1633. Debug.WriteLine("Files content encoding: " + module.FilesEncoding.EncodingName);
  1634. Debug.WriteLine("Commit encoding: " + module.CommitEncoding.EncodingName);
  1635. if (module.LogOutputEncoding.CodePage != module.CommitEncoding.CodePage)
  1636. Debug.WriteLine("Log output encoding: " + module.LogOutputEncoding.EncodingName);
  1637. #endif
  1638. }
  1639. HideDashboard();
  1640. UICommands.RepoChangedNotifier.Notify();
  1641. RevisionGrid.IndexWatcher.Reset();
  1642. RegisterPlugins();
  1643. }
  1644. private void TranslateToolStripMenuItemClick(object sender, EventArgs e)
  1645. {
  1646. Process.Start(Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "TranslationApp.exe"));
  1647. }
  1648. private void FileExplorerToolStripMenuItemClick(object sender, EventArgs e)
  1649. {
  1650. try
  1651. {
  1652. Process.Start(Module.WorkingDir);
  1653. }
  1654. catch (Exception ex)
  1655. {
  1656. MessageBox.Show(this, ex.Message);
  1657. }
  1658. }
  1659. private void StatusClick(object sender, EventArgs e)
  1660. {
  1661. // TODO: Replace with a status page?
  1662. CommitToolStripMenuItemClick(sender, e);
  1663. }
  1664. public void SaveAsOnClick(object sender, EventArgs e)
  1665. {
  1666. var item = GitTree.SelectedNode.Tag as GitItem;
  1667. if (item == null)
  1668. return;
  1669. if (!item.IsBlob)
  1670. return;
  1671. var fullName = Path.Combine(Module.WorkingDir, item.FileName);
  1672. using (var fileDialog =
  1673. new SaveFileDialog
  1674. {
  1675. InitialDirectory = Path.GetDirectoryName(fullName),
  1676. FileName = Path.GetFileName(fullName),
  1677. DefaultExt = GitCommandHelpers.GetFileExtension(fullName),
  1678. AddExtension = true
  1679. })
  1680. {
  1681. fileDialog.Filter =
  1682. _saveFileFilterCurrentFormat.Text + " (*." +
  1683. GitCommandHelpers.GetFileExtension(fileDialog.FileName) + ")|*." +
  1684. GitCommandHelpers.GetFileExtension(fileDialog.FileName) +
  1685. "|" + _saveFileFilterAllFiles.Text + " (*.*)|*.*";
  1686. if (fileDialog.ShowDialog(this) == DialogResult.OK)
  1687. {
  1688. Module.SaveBlobAs(fileDialog.FileName, item.Guid);
  1689. }
  1690. }
  1691. }
  1692. private void ResetToThisRevisionOnClick(object sender, EventArgs e)
  1693. {
  1694. IList<GitRevision> revisions = RevisionGrid.GetSelectedRevisions();
  1695. if (!revisions.Any() || revisions.Count != 1)
  1696. {
  1697. MessageBox.Show("Exactly one revision must be selected. Abort.");
  1698. return;
  1699. ////throw new ApplicationException("Exactly one revision must be selected"); // todo: unified exception handling?
  1700. }
  1701. if (MessageBox.Show("Really reset selected file / directory?", "Reset", MessageBoxButtons.OKCancel)
  1702. == System.Windows.Forms.DialogResult.OK)
  1703. {
  1704. var item = GitTree.SelectedNode.Tag as GitItem;
  1705. var files = new List<string> { item.FileName };
  1706. Module.CheckoutFiles(files, revisions.First().Guid, false);
  1707. }
  1708. }
  1709. private void GitTreeBeforeExpand(object sender, TreeViewCancelEventArgs e)
  1710. {
  1711. if (e.Node.IsExpanded)
  1712. return;
  1713. var item = (IGitItem)e.Node.Tag;
  1714. e.Node.Nodes.Clear();
  1715. LoadInTree(item.SubItems, e.Node.Nodes);
  1716. }
  1717. private void CreateBranchToolStripMenuItemClick(object sender, EventArgs e)
  1718. {
  1719. UICommands.StartCreateBranchDialog(this, RevisionGrid.GetSelectedRevisions().FirstOrDefault());
  1720. }
  1721. private void GitBashClick(object sender, EventArgs e)
  1722. {
  1723. GitBashToolStripMenuItemClick1(sender, e);
  1724. }
  1725. private void ToolStripButtonPullClick(object sender, EventArgs e)
  1726. {
  1727. PullToolStripMenuItemClick(sender, e);
  1728. }
  1729. private void editgitattributesToolStripMenuItem_Click(object sender, EventArgs e)
  1730. {
  1731. UICommands.StartEditGitAttributesDialog(this);
  1732. }
  1733. private void copyFilenameToClipboardToolStripMenuItem_Click(object sender, EventArgs e)
  1734. {
  1735. var gitItem = GitTree.SelectedNode.Tag as GitItem;
  1736. if (gitItem == null)
  1737. return;
  1738. var fileName = Path.Combine(Module.WorkingDir, (gitItem).FileName);
  1739. Clipboard.SetText(fileName.Replace('/', '\\'));
  1740. }
  1741. private void copyFilenameToClipboardToolStripMenuItem1_Click(object sender, EventArgs e)
  1742. {
  1743. if (!DiffFiles.SelectedItems.Any())
  1744. return;
  1745. var fileNames = new StringBuilder();
  1746. foreach (var item in DiffFiles.SelectedItems)
  1747. {
  1748. //Only use append line when multiple items are selected.
  1749. //This to make it easier to use the text from clipboard when 1 file is selected.
  1750. if (fileNames.Length > 0)
  1751. fileNames.AppendLine();
  1752. fileNames.Append(Path.Combine(Module.WorkingDir, item.Name).ToNativePath());
  1753. }
  1754. Clipboard.SetText(fileNames.ToString());
  1755. }
  1756. private void deleteIndexlockToolStripMenuItem_Click(object sender, EventArgs e)
  1757. {
  1758. string fileName = Path.Combine(Module.GetGitDirectory(), "index.lock");
  1759. if (File.Exists(fileName))
  1760. {
  1761. File.Delete(fileName);
  1762. MessageBox.Show(this, _indexLockDeleted.Text);
  1763. }
  1764. else
  1765. MessageBox.Show(this, _indexLockNotFound.Text + " " + fileName);
  1766. }
  1767. private void saveAsToolStripMenuItem1_Click(object sender, EventArgs e)
  1768. {
  1769. IList<GitRevision> revisions = RevisionGrid.GetSelectedRevisions();
  1770. if (revisions.Count == 0)
  1771. return;
  1772. if (DiffFiles.SelectedItem == null)
  1773. return;
  1774. GitItemStatus item = DiffFiles.SelectedItem;
  1775. var fullName = Path.Combine(Module.WorkingDir, item.Name);
  1776. using (var fileDialog =
  1777. new SaveFileDialog
  1778. {
  1779. InitialDirectory = Path.GetDirectoryName(fullName),
  1780. FileName = Path.GetFileName(fullName),
  1781. DefaultExt = GitCommandHelpers.GetFileExtension(fullName),
  1782. AddExtension = true
  1783. })
  1784. {
  1785. fileDialog.Filter =
  1786. _saveFileFilterCurrentFormat.Text + " (*." +
  1787. fileDialog.DefaultExt + ")|*." +
  1788. fileDialog.DefaultExt +
  1789. "|" + _saveFileFilterAllFiles.Text + " (*.*)|*.*";
  1790. if (fileDialog.ShowDialog(this) == DialogResult.OK)
  1791. {
  1792. Module.SaveBlobAs(fileDialog.FileName, string.Format("{0}:\"{1}\"", revisions[0].Guid, item.Name));
  1793. }
  1794. }
  1795. }
  1796. private void toolStripStatusLabel1_Click(object sender, EventArgs e)
  1797. {
  1798. statusStrip.Hide();
  1799. }
  1800. private void openWithToolStripMenuItem_Click(object sender, EventArgs e)
  1801. {
  1802. var item = GitTree.SelectedNode.Tag;
  1803. var gitItem = item as GitItem;
  1804. if (gitItem == null || !(gitItem).IsBlob)
  1805. return;
  1806. var fileName = Path.Combine(Module.WorkingDir, (gitItem).FileName);
  1807. OsShellUtil.OpenAs(fileName.ToNativePath());
  1808. }
  1809. private void pluginsToolStripMenuItem_DropDownOpening(object sender, EventArgs e)
  1810. {
  1811. LoadPluginsInPluginMenu();
  1812. }
  1813. private void BisectClick(object sender, EventArgs e)
  1814. {
  1815. using (var frm = new FormBisect(RevisionGrid)) frm.ShowDialog(this);
  1816. UICommands.RepoChangedNotifier.Notify();
  1817. }
  1818. private void fileHistoryDiffToolstripMenuItem_Click(object sender, EventArgs e)
  1819. {
  1820. GitItemStatus item = DiffFiles.SelectedItem;
  1821. if (item.IsTracked)
  1822. {
  1823. IList<GitRevision> revisions = RevisionGrid.GetSelectedRevisions();
  1824. if (revisions.Count == 0 || GitRevision.IsArtificial(revisions[0].Guid))
  1825. UICommands.StartFileHistoryDialog(this, item.Name);
  1826. else
  1827. UICommands.StartFileHistoryDialog(this, item.Name, revisions[0], false);
  1828. }
  1829. }
  1830. private void blameToolStripMenuItem_Click(object sender, EventArgs e)
  1831. {
  1832. GitItemStatus item = DiffFiles.SelectedItem;
  1833. if (item.IsTracked)
  1834. {
  1835. IList<GitRevision> revisions = RevisionGrid.GetSelectedRevisions();
  1836. if (revisions.Count == 0 || GitRevision.IsArtificial(revisions[0].Guid))
  1837. UICommands.StartFileHistoryDialog(this, item.Name, null, false, true);
  1838. else
  1839. UICommands.StartFileHistoryDialog(this, item.Name, revisions[0], true, true);
  1840. }
  1841. }
  1842. private void CurrentBranchDropDownOpening(object sender, EventArgs e)
  1843. {
  1844. branchSelect.DropDownItems.Clear();
  1845. ToolStripMenuItem item = new ToolStripMenuItem(checkoutBranchToolStripMenuItem.Text);
  1846. item.ShortcutKeys = checkoutBranchToolStripMenuItem.ShortcutKeys;
  1847. item.ShortcutKeyDisplayString = checkoutBranchToolStripMenuItem.ShortcutKeyDisplayString;
  1848. branchSelect.DropDownItems.Add(item);
  1849. item.Click += (hs, he) => CheckoutBranchToolStripMenuItemClick(hs, he);
  1850. branchSelect.DropDownItems.Add(new ToolStripSeparator());
  1851. foreach (var branch in Module.GetRefs(false))
  1852. {
  1853. var toolStripItem = branchSelect.DropDownItems.Add(branch.Name);
  1854. toolStripItem.Click += BranchSelectToolStripItem_Click;
  1855. //Make sure there are never more than 100 branches added to the menu
  1856. //GitExtensions will hang when the drop down is to large...
  1857. if (branchSelect.DropDownItems.Count > 100)
  1858. break;
  1859. }
  1860. }
  1861. void BranchSelectToolStripItem_Click(object sender, EventArgs e)
  1862. {
  1863. var toolStripItem = (ToolStripItem)sender;
  1864. UICommands.StartCheckoutBranch(this, toolStripItem.Text, false);
  1865. }
  1866. private void _forkCloneMenuItem_Click(object sender, EventArgs e)
  1867. {
  1868. if (RepoHosts.GitHosters.Count > 0)
  1869. {
  1870. UICommands.StartCloneForkFromHoster(this, RepoHosts.GitHosters[0], SetGitModule);
  1871. UICommands.RepoChangedNotifier.Notify();
  1872. }
  1873. else
  1874. {
  1875. MessageBox.Show(this, _noReposHostPluginLoaded.Text, _errorCaption.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
  1876. }
  1877. }
  1878. private void _viewPullRequestsToolStripMenuItem_Click(object sender, EventArgs e)
  1879. {
  1880. var repoHost = RepoHosts.TryGetGitHosterForModule(Module);
  1881. if (repoHost == null)
  1882. {
  1883. MessageBox.Show(this, _noReposHostFound.Text, _errorCaption.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
  1884. return;
  1885. }
  1886. UICommands.StartPullRequestsDialog(this, repoHost);
  1887. }
  1888. private void _createPullRequestToolStripMenuItem_Click(object sender, EventArgs e)
  1889. {
  1890. var repoHost = RepoHosts.TryGetGitHosterForModule(Module);
  1891. if (repoHost == null)
  1892. {
  1893. MessageBox.Show(this, _noReposHostFound.Text, _errorCaption.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
  1894. return;
  1895. }
  1896. UICommands.StartCreatePullRequest(this, repoHost);
  1897. }
  1898. #region Hotkey commands
  1899. public const string HotkeySettingsName = "Browse";
  1900. internal enum Commands
  1901. {
  1902. GitBash,
  1903. GitGui,
  1904. GitGitK,
  1905. FocusRevisionGrid,
  1906. FocusCommitInfo,
  1907. FocusFileTree,
  1908. FocusDiff,
  1909. Commit,
  1910. AddNotes,
  1911. FindFileInSelectedCommit,
  1912. CheckoutBranch,
  1913. QuickFetch,
  1914. QuickPull,
  1915. QuickPush,
  1916. RotateApplicationIcon,
  1917. CloseRepositry,
  1918. }
  1919. private void AddNotes()
  1920. {
  1921. Module.EditNotes(RevisionGrid.GetSelectedRevisions().Count > 0 ? RevisionGrid.GetSelectedRevisions()[0].Guid : string.Empty);
  1922. FillCommitInfo();
  1923. }
  1924. private void FindFileInSelectedCommit()
  1925. {
  1926. CommitInfoTabControl.SelectedTab = TreeTabPage;
  1927. EnabledSplitViewLayout(true);
  1928. GitTree.Focus();
  1929. FindFileOnClick(null, null);
  1930. }
  1931. private void QuickFetch()
  1932. {
  1933. FormProcess.ShowDialog(this, Module.FetchCmd(string.Empty, string.Empty, string.Empty));
  1934. UICommands.RepoChangedNotifier.Notify();
  1935. }
  1936. protected override bool ExecuteCommand(int cmd)
  1937. {
  1938. switch ((Commands)cmd)
  1939. {
  1940. case Commands.GitBash: Module.RunBash(); break;
  1941. case Commands.GitGui: Module.RunGui(); break;
  1942. case Commands.GitGitK: Module.RunGitK(); break;
  1943. case Commands.FocusRevisionGrid: RevisionGrid.Focus(); break;
  1944. case Commands.FocusCommitInfo: CommitInfoTabControl.SelectedTab = CommitInfoTabPage; break;
  1945. case Commands.FocusFileTree: CommitInfoTabControl.SelectedTab = TreeTabPage; GitTree.Focus(); break;
  1946. case Commands.FocusDiff: CommitInfoTabControl.SelectedTab = DiffTabPage; DiffFiles.Focus(); break;
  1947. case Commands.Commit: CommitToolStripMenuItemClick(null, null); break;
  1948. case Commands.AddNotes: AddNotes(); break;
  1949. case Commands.FindFileInSelectedCommit: FindFileInSelectedCommit(); break;
  1950. case Commands.CheckoutBranch: CheckoutBranchToolStripMenuItemClick(null, null); break;
  1951. case Commands.QuickFetch: QuickFetch(); break;
  1952. case Commands.QuickPull:
  1953. UICommands.StartPullDialog(this, true);
  1954. break;
  1955. case Commands.QuickPush:
  1956. UICommands.StartPushDialog(this, true);
  1957. break;
  1958. case Commands.RotateApplicationIcon: RotateApplicationIcon(); break;
  1959. case Commands.CloseRepositry: CloseToolStripMenuItemClick(null, null); break;
  1960. default: return base.ExecuteCommand(cmd);
  1961. }
  1962. return true;
  1963. }
  1964. internal bool ExecuteCommand(Commands cmd)
  1965. {
  1966. return ExecuteCommand((int)cmd);
  1967. }
  1968. #endregion
  1969. private void toggleSplitViewLayout_Click(object sender, EventArgs e)
  1970. {
  1971. EnabledSplitViewLayout(MainSplitContainer.Panel2.Height == 0 && MainSplitContainer.Height > 0);
  1972. }
  1973. private void EnabledSplitViewLayout(bool enabled)
  1974. {
  1975. if (enabled)
  1976. MainSplitContainer.SplitterDistance = (MainSplitContainer.Height / 5) * 2;
  1977. else
  1978. MainSplitContainer.SplitterDistance = MainSplitContainer.Height;
  1979. }
  1980. private void editCheckedOutFileToolStripMenuItem_Click(object sender, EventArgs e)
  1981. {
  1982. var item = GitTree.SelectedNode.Tag;
  1983. var gitItem = item as GitItem;
  1984. if (gitItem == null || !gitItem.IsBlob)
  1985. return;
  1986. var fileName = Path.Combine(Module.WorkingDir, (gitItem).FileName);
  1987. UICommands.StartFileEditorDialog(fileName);
  1988. }
  1989. #region Git file tree drag-drop
  1990. private Rectangle gitTreeDragBoxFromMouseDown;
  1991. private void GitTree_MouseDown(object sender, MouseEventArgs e)
  1992. {
  1993. //DRAG
  1994. if (e.Button == MouseButtons.Left)
  1995. {
  1996. // Remember the point where the mouse down occurred.
  1997. // The DragSize indicates the size that the mouse can move
  1998. // before a drag event should be started.
  1999. Size dragSize = SystemInformation.DragSize;
  2000. // Create a rectangle using the DragSize, with the mouse position being
  2001. // at the center of the rectangle.
  2002. gitTreeDragBoxFromMouseDown = new Rectangle(new Point(e.X - (dragSize.Width / 2),
  2003. e.Y - (dragSize.Height / 2)),
  2004. dragSize);
  2005. }
  2006. }
  2007. void GitTree_MouseMove(object sender, MouseEventArgs e)
  2008. {
  2009. TreeView gitTree = (TreeView)sender;
  2010. //DRAG
  2011. // If the mouse moves outside the rectangle, start the drag.
  2012. if (gitTreeDragBoxFromMouseDown != Rectangle.Empty &&
  2013. !gitTreeDragBoxFromMouseDown.Contains(e.X, e.Y))
  2014. {
  2015. StringCollection fileList = new StringCollection();
  2016. //foreach (GitItemStatus item in SelectedItems)
  2017. if (gitTree.SelectedNode != null)
  2018. {
  2019. GitItem item = gitTree.SelectedNode.Tag as GitItem;
  2020. if (item != null)
  2021. {
  2022. string fileName = Path.Combine(Module.WorkingDir, item.FileName);
  2023. fileList.Add(fileName.Replace('/', '\\'));
  2024. }
  2025. DataObject obj = new DataObject();
  2026. obj.SetFileDropList(fileList);
  2027. // Proceed with the drag and drop, passing in the list item.
  2028. DoDragDrop(obj, DragDropEffects.Copy);
  2029. gitTreeDragBoxFromMouseDown = Rectangle.Empty;
  2030. }
  2031. }
  2032. }
  2033. #endregion
  2034. private int getNextIdx(int curIdx, int maxIdx, bool searchBackward)
  2035. {
  2036. if (searchBackward)
  2037. {
  2038. if (curIdx == 0)
  2039. {
  2040. curIdx = maxIdx;
  2041. }
  2042. else
  2043. {
  2044. curIdx--;
  2045. }
  2046. }
  2047. else
  2048. {
  2049. if (curIdx == maxIdx)
  2050. {
  2051. curIdx = 0;
  2052. }
  2053. else
  2054. {
  2055. curIdx++;
  2056. }
  2057. }
  2058. return curIdx;
  2059. }
  2060. private Tuple<int, string> getNextPatchFile(bool searchBackward)
  2061. {
  2062. var revisions = RevisionGrid.GetSelectedRevisions();
  2063. if (revisions.Count == 0)
  2064. return null;
  2065. int idx = DiffFiles.SelectedIndex;
  2066. if (idx == -1)
  2067. return new Tuple<int, string>(idx, null);
  2068. idx = getNextIdx(idx, DiffFiles.GitItemStatuses.Count() - 1, searchBackward);
  2069. _dontUpdateOnIndexChange = true;
  2070. DiffFiles.SelectedIndex = idx;
  2071. _dontUpdateOnIndexChange = false;
  2072. return new Tuple<int, string>(idx, DiffText.GetSelectedPatch(RevisionGrid, DiffFiles.SelectedItem));
  2073. }
  2074. //
  2075. // diff context menu
  2076. //
  2077. private void openContainingFolderToolStripMenuItem_Click(object sender, EventArgs e)
  2078. {
  2079. if (!DiffFiles.SelectedItems.Any())
  2080. return;
  2081. foreach (var item in DiffFiles.SelectedItems)
  2082. {
  2083. string filePath = FormBrowseUtil.GetFullPathFromGitItemStatus(Module, item);
  2084. FormBrowseUtil.ShowFileOrParentFolderInFileExplorer(filePath);
  2085. }
  2086. }
  2087. /// <summary>
  2088. /// TODO: move logic to other source file?
  2089. /// </summary>
  2090. /// <param name="sender"></param>
  2091. /// <param name="e"></param>
  2092. private void diffShowInFileTreeToolStripMenuItem_Click(object sender, EventArgs e)
  2093. {
  2094. var diffGitItemStatus = DiffFiles.SelectedItems.First();
  2095. ExecuteCommand((int)Commands.FocusFileTree); // switch to view (and fills the first level of file tree data model if not already done)
  2096. var currentNodes = GitTree.Nodes;
  2097. TreeNode foundNode = null;
  2098. bool isIncompleteMatch = false;
  2099. var pathParts = UtilGetPathParts(diffGitItemStatus.Name);
  2100. for (int i = 0; i < pathParts.Length; i++)
  2101. {
  2102. string pathPart = pathParts[i];
  2103. string diffPathPart = pathPart.Replace("/", "\\");
  2104. var currentFoundNode = currentNodes.Cast<TreeNode>().FirstOrDefault(a =>
  2105. {
  2106. var treeGitItem = a.Tag as GitItem;
  2107. if (treeGitItem != null)
  2108. {
  2109. // TODO: what about case(in)sensitive handling?
  2110. return treeGitItem.Name == diffPathPart;
  2111. }
  2112. else
  2113. {
  2114. return false;
  2115. }
  2116. });
  2117. if (currentFoundNode == null)
  2118. {
  2119. isIncompleteMatch = true;
  2120. break;
  2121. }
  2122. foundNode = currentFoundNode;
  2123. if (i < pathParts.Length - 1) // if not the last path part...
  2124. {
  2125. foundNode.Expand(); // load more data
  2126. if (currentFoundNode.Nodes == null)
  2127. {
  2128. isIncompleteMatch = true;
  2129. break;
  2130. }
  2131. currentNodes = currentFoundNode.Nodes;
  2132. }
  2133. }
  2134. if (foundNode != null)
  2135. {
  2136. if (isIncompleteMatch)
  2137. {
  2138. MessageBox.Show(_nodeNotFoundNextAvailableParentSelected.Text);
  2139. }
  2140. GitTree.SelectedNode = foundNode;
  2141. GitTree.SelectedNode.EnsureVisible();
  2142. }
  2143. else
  2144. {
  2145. MessageBox.Show(_nodeNotFoundSelectionNotChanged.Text);
  2146. }
  2147. }
  2148. private string[] UtilGetPathParts(string path)
  2149. {
  2150. return path.Split('/');
  2151. }
  2152. private void fileTreeOpenContainingFolderToolStripMenuItem_Click(object sender, EventArgs e)
  2153. {
  2154. var gitItem = GitTree.SelectedNode.Tag as GitItem;
  2155. if (gitItem == null)
  2156. {
  2157. return;
  2158. }
  2159. var filePath = FormBrowseUtil.GetFullPathFromGitItem(Module, gitItem);
  2160. FormBrowseUtil.ShowFileOrFolderInFileExplorer(filePath);
  2161. }
  2162. private void fileTreeArchiveToolStripMenuItem_Click(object sender, EventArgs e)
  2163. {
  2164. var selectedRevisions = RevisionGrid.GetSelectedRevisions();
  2165. if (selectedRevisions.Count != 1)
  2166. {
  2167. MessageBox.Show("Select exactly one revision.");
  2168. return;
  2169. }
  2170. var gitItem = (GitItem)GitTree.SelectedNode.Tag;
  2171. UICommands.StartArchiveDialog(this, selectedRevisions.First(), null, gitItem.FileName);
  2172. }
  2173. private void fileTreeCleanWorkingTreeToolStripMenuItem_Click(object sender, EventArgs e)
  2174. {
  2175. var gitItem = (GitItem)GitTree.SelectedNode.Tag;
  2176. UICommands.StartCleanupRepositoryDialog(this, gitItem.FileName + "/"); // the trailing / marks a directory
  2177. }
  2178. private void DiffContextMenu_Opening(object sender, System.ComponentModel.CancelEventArgs e)
  2179. {
  2180. bool artificialRevSelected;
  2181. IList<GitRevision> selectedRevisions = RevisionGrid.GetSelectedRevisions();
  2182. if (selectedRevisions.Count == 0)
  2183. artificialRevSelected = false;
  2184. else
  2185. artificialRevSelected = selectedRevisions[0].IsArtificial();
  2186. if (selectedRevisions.Count > 1)
  2187. artificialRevSelected = artificialRevSelected || selectedRevisions[selectedRevisions.Count - 1].IsArtificial();
  2188. // disable items that need exactly one selected item
  2189. bool isExcactlyOneItemSelected = DiffFiles.SelectedItems.Count() == 1;
  2190. openWithDifftoolToolStripMenuItem.Enabled = isExcactlyOneItemSelected;
  2191. saveAsToolStripMenuItem1.Enabled = isExcactlyOneItemSelected;
  2192. diffShowInFileTreeToolStripMenuItem.Enabled = isExcactlyOneItemSelected;
  2193. fileHistoryDiffToolstripMenuItem.Enabled = isExcactlyOneItemSelected;
  2194. blameToolStripMenuItem.Enabled = isExcactlyOneItemSelected;
  2195. // openContainingFolderToolStripMenuItem.Enabled or not
  2196. {
  2197. openContainingFolderToolStripMenuItem.Enabled = false;
  2198. foreach (var item in DiffFiles.SelectedItems)
  2199. {
  2200. string filePath = FormBrowseUtil.GetFullPathFromGitItemStatus(Module, item);
  2201. if (FormBrowseUtil.FileOrParentDirectoryExists(filePath))
  2202. {
  2203. openContainingFolderToolStripMenuItem.Enabled = true;
  2204. break;
  2205. }
  2206. }
  2207. }
  2208. }
  2209. protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
  2210. {
  2211. base.OnClosing(e);
  2212. if (_dashboard != null)
  2213. _dashboard.SaveSplitterPositions();
  2214. }
  2215. protected override void OnClosed(EventArgs e)
  2216. {
  2217. SetWorkingDir("");
  2218. base.OnClosed(e);
  2219. }
  2220. private void CloneSvnToolStripMenuItemClick(object sender, EventArgs e)
  2221. {
  2222. UICommands.StartSvnCloneDialog(this, SetGitModule);
  2223. }
  2224. private void SvnRebaseToolStripMenuItem_Click(object sender, EventArgs e)
  2225. {
  2226. UICommands.StartSvnRebaseDialog(this);
  2227. }
  2228. private void SvnDcommitToolStripMenuItem_Click(object sender, EventArgs e)
  2229. {
  2230. UICommands.StartSvnDcommitDialog(this);
  2231. }
  2232. private void SvnFetchToolStripMenuItem_Click(object sender, EventArgs e)
  2233. {
  2234. UICommands.StartSvnFetchDialog(this);
  2235. }
  2236. private void expandAllStripMenuItem_Click(object sender, EventArgs e)
  2237. {
  2238. GitTree.ExpandAll();
  2239. }
  2240. private void collapseAllToolStripMenuItem_Click(object sender, EventArgs e)
  2241. {
  2242. GitTree.CollapseAll();
  2243. }
  2244. private void DiffFiles_DataSourceChanged(object sender, EventArgs e)
  2245. {
  2246. if (DiffFiles.GitItemStatuses == null || !DiffFiles.GitItemStatuses.Any())
  2247. DiffText.ViewPatch(String.Empty);
  2248. }
  2249. public override void AddTranslationItems(ITranslation translation)
  2250. {
  2251. base.AddTranslationItems(translation);
  2252. TranslationUtils.AddTranslationItemsFromFields(Name, _filterRevisionsHelper, translation);
  2253. TranslationUtils.AddTranslationItemsFromFields(Name, _filterBranchHelper, translation);
  2254. }
  2255. public override void TranslateItems(ITranslation translation)
  2256. {
  2257. base.TranslateItems(translation);
  2258. TranslationUtils.TranslateItemsFromFields(Name, _filterRevisionsHelper, translation);
  2259. TranslationUtils.TranslateItemsFromFields(Name, _filterBranchHelper, translation);
  2260. }
  2261. private void findInDiffToolStripMenuItem_Click(object sender, EventArgs e)
  2262. {
  2263. var candidates = DiffFiles.GitItemStatuses;
  2264. Func<string, IList<GitItemStatus>> FindDiffFilesMatches = (string name) =>
  2265. {
  2266. string nameAsLower = name.ToLower();
  2267. return candidates.Where(item =>
  2268. {
  2269. return item.Name != null && item.Name.ToLower().Contains(nameAsLower)
  2270. || item.OldName != null && item.OldName.ToLower().Contains(nameAsLower);
  2271. }
  2272. ).ToList();
  2273. };
  2274. GitItemStatus selectedItem;
  2275. using (var searchWindow = new SearchWindow<GitItemStatus>(FindDiffFilesMatches)
  2276. {
  2277. Owner = this
  2278. })
  2279. {
  2280. searchWindow.ShowDialog(this);
  2281. selectedItem = searchWindow.SelectedItem;
  2282. }
  2283. if (selectedItem != null)
  2284. {
  2285. DiffFiles.SelectedItem = selectedItem;
  2286. }
  2287. }
  2288. private void dontSetAsDefaultToolStripMenuItem_Click(object sender, EventArgs e)
  2289. {
  2290. Settings.DonSetAsLastPullAction = !dontSetAsDefaultToolStripMenuItem.Checked;
  2291. dontSetAsDefaultToolStripMenuItem.Checked = Settings.DonSetAsLastPullAction;
  2292. }
  2293. private void mergeToolStripMenuItem_Click(object sender, EventArgs e)
  2294. {
  2295. Module.LastPullAction = Settings.PullAction.Merge;
  2296. PullToolStripMenuItemClick(sender, e);
  2297. }
  2298. private void rebaseToolStripMenuItem1_Click(object sender, EventArgs e)
  2299. {
  2300. Module.LastPullAction = Settings.PullAction.Rebase;
  2301. PullToolStripMenuItemClick(sender, e);
  2302. }
  2303. private void fetchToolStripMenuItem_Click(object sender, EventArgs e)
  2304. {
  2305. Module.LastPullAction = Settings.PullAction.Fetch;
  2306. PullToolStripMenuItemClick(sender, e);
  2307. }
  2308. private void pullToolStripMenuItem1_Click(object sender, EventArgs e)
  2309. {
  2310. if (!Settings.DonSetAsLastPullAction)
  2311. Module.LastPullAction = Settings.PullAction.None;
  2312. PullToolStripMenuItemClick(sender, e);
  2313. //restore Settings.FormPullAction value
  2314. if (Settings.DonSetAsLastPullAction)
  2315. Module.LastPullActionToFormPullAction();
  2316. }
  2317. private void RefreshPullIcon()
  2318. {
  2319. switch (Module.LastPullAction)
  2320. {
  2321. case Settings.PullAction.Fetch:
  2322. toolStripButtonPull.Image = Properties.Resources.PullFetch;
  2323. toolStripButtonPull.ToolTipText = "Pull - fetch";
  2324. break;
  2325. case Settings.PullAction.FetchAll:
  2326. toolStripButtonPull.Image = Properties.Resources.PullFetchAll;
  2327. toolStripButtonPull.ToolTipText = "Pull - fetch all";
  2328. break;
  2329. case Settings.PullAction.Merge:
  2330. toolStripButtonPull.Image = Properties.Resources.PullMerge;
  2331. toolStripButtonPull.ToolTipText = "Pull - merge";
  2332. break;
  2333. case Settings.PullAction.Rebase:
  2334. toolStripButtonPull.Image = Properties.Resources.PullRebase;
  2335. toolStripButtonPull.ToolTipText = "Pull - rebase";
  2336. break;
  2337. default:
  2338. toolStripButtonPull.Image = Properties.Resources.Icon_4;
  2339. toolStripButtonPull.ToolTipText = "Open pull dialog";
  2340. break;
  2341. }
  2342. }
  2343. private void fetchAllToolStripMenuItem_Click(object sender, EventArgs e)
  2344. {
  2345. if (!Settings.DonSetAsLastPullAction)
  2346. Module.LastPullAction = Settings.PullAction.FetchAll;
  2347. RefreshPullIcon();
  2348. bool pullCompelted;
  2349. UICommands.StartPullDialog(this, true, out pullCompelted, true);
  2350. //restore Settings.FormPullAction value
  2351. if (Settings.DonSetAsLastPullAction)
  2352. Module.LastPullActionToFormPullAction();
  2353. }
  2354. private void resetFileToAToolStripMenuItem_Click(object sender, EventArgs e)
  2355. {
  2356. IList<GitRevision> revisions = RevisionGrid.GetSelectedRevisions();
  2357. if (!revisions.Any() || revisions.Count < 1 || revisions.Count > 2 || !DiffFiles.SelectedItems.Any())
  2358. {
  2359. return;
  2360. }
  2361. var files = DiffFiles.SelectedItems.Select(item => item.Name);
  2362. if (revisions.Count == 1)
  2363. {
  2364. if (!revisions[0].HasParent())
  2365. {
  2366. MessageBox.Show("Revision must have a parent. Abort.");
  2367. ////throw new ApplicationException("Revision must have a parent."); // todo: unified exception handling?
  2368. }
  2369. Module.CheckoutFiles(files, revisions[0].Guid + "^", false);
  2370. }
  2371. else
  2372. {
  2373. Module.CheckoutFiles(files, revisions[1].Guid, false);
  2374. }
  2375. }
  2376. private void resetFileToRemoteToolStripMenuItem_Click(object sender, EventArgs e)
  2377. {
  2378. IList<GitRevision> revisions = RevisionGrid.GetSelectedRevisions();
  2379. if (!revisions.Any() || !DiffFiles.SelectedItems.Any())
  2380. {
  2381. return;
  2382. }
  2383. var files = DiffFiles.SelectedItems.Select(item => item.Name);
  2384. Module.CheckoutFiles(files, revisions[0].Guid, false);
  2385. }
  2386. private void _NO_TRANSLATE_Workingdir_MouseUp(object sender, MouseEventArgs e)
  2387. {
  2388. if (e.Button == MouseButtons.Right)
  2389. OpenToolStripMenuItemClick(sender, e);
  2390. }
  2391. private void branchSelect_MouseUp(object sender, MouseEventArgs e)
  2392. {
  2393. if (e.Button == MouseButtons.Right)
  2394. CheckoutBranchToolStripMenuItemClick(sender, e);
  2395. }
  2396. private void RevisionInfo_CommandClick(object sender, CommitInfo.CommandEventArgs e)
  2397. {
  2398. if (e.Command == "gotocommit")
  2399. {
  2400. RevisionGrid.SetSelectedRevision(new GitRevision(Module, e.Data));
  2401. }
  2402. else if (e.Command == "gotobranch" || e.Command == "gototag")
  2403. {
  2404. string error = "";
  2405. CommitData commit = CommitData.GetCommitData(Module, e.Data, ref error);
  2406. if (commit != null)
  2407. RevisionGrid.SetSelectedRevision(new GitRevision(Module, commit.Guid));
  2408. }
  2409. }
  2410. private void SubmoduleToolStripButtonClick(object sender, EventArgs e)
  2411. {
  2412. var button = sender as ToolStripMenuItem;
  2413. if (button == null)
  2414. return;
  2415. if (button.Tag is GitModule)
  2416. SetGitModule(button.Tag as GitModule);
  2417. else
  2418. SetWorkingDir(button.Tag as string);
  2419. }
  2420. private void toolStripButtonLevelUp_DropDownOpening(object sender, EventArgs e)
  2421. {
  2422. LoadSubmodulesIntoDropDownMenu();
  2423. }
  2424. private void RemoveSubmoduleButtons()
  2425. {
  2426. _submodulesStatusImagesCTS.Cancel();
  2427. foreach (var item in toolStripButtonLevelUp.DropDownItems)
  2428. {
  2429. var toolStripButton = item as ToolStripMenuItem;
  2430. if (toolStripButton != null)
  2431. toolStripButton.Click -= SubmoduleToolStripButtonClick;
  2432. }
  2433. toolStripButtonLevelUp.DropDownItems.Clear();
  2434. }
  2435. private string GetModuleBranch(string path)
  2436. {
  2437. string branch = GitModule.GetSelectedBranchFast(path);
  2438. if (GitModule.IsDetachedHead(branch))
  2439. return "[no branch]";
  2440. return "[" + branch + "]";
  2441. }
  2442. private ToolStripMenuItem AddSubmoduleToMenu(string name, object module)
  2443. {
  2444. var spmenu = new ToolStripMenuItem(name);
  2445. spmenu.Click += SubmoduleToolStripButtonClick;
  2446. spmenu.Width = 200;
  2447. spmenu.Tag = module;
  2448. toolStripButtonLevelUp.DropDownItems.Add(spmenu);
  2449. return spmenu;
  2450. }
  2451. DateTime _previousUpdateTime;
  2452. private void LoadSubmodulesIntoDropDownMenu()
  2453. {
  2454. TimeSpan elapsed = DateTime.Now - _previousUpdateTime;
  2455. if (elapsed.TotalSeconds > 15)
  2456. UpdateSubmodulesList();
  2457. }
  2458. private CancellationTokenSource _submodulesStatusImagesCTS = new CancellationTokenSource();
  2459. private static Image GetItemImage(GitSubmoduleStatus gitSubmoduleStatus)
  2460. {
  2461. if (gitSubmoduleStatus == null)
  2462. return Resources.IconFolderSubmodule;
  2463. if (gitSubmoduleStatus.Status == SubmoduleStatus.FastForward)
  2464. return gitSubmoduleStatus.IsDirty ? Resources.IconSubmoduleRevisionUpDirty : Resources.IconSubmoduleRevisionUp;
  2465. if (gitSubmoduleStatus.Status == SubmoduleStatus.Rewind)
  2466. return gitSubmoduleStatus.IsDirty ? Resources.IconSubmoduleRevisionDownDirty : Resources.IconSubmoduleRevisionDown;
  2467. if (gitSubmoduleStatus.Status == SubmoduleStatus.NewerTime)
  2468. return gitSubmoduleStatus.IsDirty ? Resources.IconSubmoduleRevisionSemiUpDirty : Resources.IconSubmoduleRevisionSemiUp;
  2469. if (gitSubmoduleStatus.Status == SubmoduleStatus.OlderTime)
  2470. return gitSubmoduleStatus.IsDirty ? Resources.IconSubmoduleRevisionSemiDownDirty : Resources.IconSubmoduleRevisionSemiDown;
  2471. return !gitSubmoduleStatus.IsDirty ? Resources.Modified : Resources.IconSubmoduleDirty;
  2472. }
  2473. private Task GetSubmoduleStatusImageAsync(ToolStripMenuItem mi, GitModule module, string submodulePath)
  2474. {
  2475. if (String.IsNullOrEmpty(submodulePath))
  2476. {
  2477. mi.Image = Resources.IconFolderSubmodule;
  2478. return null;
  2479. }
  2480. var token = _submodulesStatusImagesCTS.Token;
  2481. return Task.Factory.StartNew(() =>
  2482. {
  2483. var submoduleStatus = GitCommandHelpers.GetCurrentSubmoduleChanges(module, submodulePath);
  2484. if (submoduleStatus != null && submoduleStatus.Commit != submoduleStatus.OldCommit)
  2485. {
  2486. var submodule = submoduleStatus.GetSubmodule(module);
  2487. submoduleStatus.CheckSubmoduleStatus(submodule);
  2488. }
  2489. return submoduleStatus;
  2490. }, token)
  2491. .ContinueWith((task) =>
  2492. {
  2493. mi.Image = GetItemImage(task.Result);
  2494. if (task.Result != null)
  2495. mi.Text += task.Result.AddedAndRemovedString();
  2496. },
  2497. CancellationToken.None,
  2498. TaskContinuationOptions.OnlyOnRanToCompletion,
  2499. TaskScheduler.FromCurrentSynchronizationContext());
  2500. }
  2501. private void UpdateSubmodulesList()
  2502. {
  2503. RemoveSubmoduleButtons();
  2504. _previousUpdateTime = DateTime.Now;
  2505. _submodulesStatusImagesCTS = new CancellationTokenSource();
  2506. foreach (var submodule in Module.GetSubmodulesLocalPathes().OrderBy(submoduleName => submoduleName))
  2507. {
  2508. var name = submodule;
  2509. string path = Module.GetSubmoduleFullPath(submodule);
  2510. if (Settings.DashboardShowCurrentBranch && !GitModule.IsBareRepository(path))
  2511. name = name + " " + GetModuleBranch(path);
  2512. var smi = AddSubmoduleToMenu(name, path);
  2513. var module = Module.GetSubmodule(submodule);
  2514. var submoduleName = module.GetCurrentSubmoduleLocalPath();
  2515. GetSubmoduleStatusImageAsync(smi, module.SuperprojectModule, submoduleName);
  2516. }
  2517. bool containSubmodules = toolStripButtonLevelUp.DropDownItems.Count != 0;
  2518. if (!containSubmodules)
  2519. toolStripButtonLevelUp.DropDownItems.Add(_noSubmodulesPresent.Text);
  2520. string currentSubmoduleName = null;
  2521. if (Module.SuperprojectModule != null)
  2522. {
  2523. var superprojectSeparator = new ToolStripSeparator();
  2524. toolStripButtonLevelUp.DropDownItems.Add(superprojectSeparator);
  2525. GitModule supersuperproject = Module.FindTopProjectModule();
  2526. if (Module.SuperprojectModule.WorkingDir != supersuperproject.WorkingDir)
  2527. {
  2528. var name = "Top project: " + Path.GetFileName(Path.GetDirectoryName(supersuperproject.WorkingDir));
  2529. string path = supersuperproject.WorkingDir;
  2530. if (Settings.DashboardShowCurrentBranch && !GitModule.IsBareRepository(path))
  2531. name = name + " " + GetModuleBranch(path);
  2532. var smi = AddSubmoduleToMenu(name, supersuperproject);
  2533. smi.Image = Resources.IconFolderSubmodule;
  2534. }
  2535. {
  2536. var name = "Superproject: ";
  2537. GitModule parentModule = Module.SuperprojectModule;
  2538. string localpath = "";
  2539. if (Module.SuperprojectModule.WorkingDir != supersuperproject.WorkingDir)
  2540. {
  2541. parentModule = supersuperproject;
  2542. localpath = Module.SuperprojectModule.WorkingDir.Substring(supersuperproject.WorkingDir.Length);
  2543. localpath = PathUtil.GetDirectoryName(localpath.ToPosixPath());
  2544. name = name + localpath;
  2545. }
  2546. else
  2547. name = name + Path.GetFileName(Path.GetDirectoryName(supersuperproject.WorkingDir));
  2548. string path = Module.SuperprojectModule.WorkingDir;
  2549. if (Settings.DashboardShowCurrentBranch && !GitModule.IsBareRepository(path))
  2550. name = name + " " + GetModuleBranch(path);
  2551. var smi = AddSubmoduleToMenu(name, Module.SuperprojectModule);
  2552. GetSubmoduleStatusImageAsync(smi, parentModule, localpath);
  2553. }
  2554. var submodules = supersuperproject.GetSubmodulesLocalPathes().OrderBy(submoduleName => submoduleName);
  2555. if (submodules.Any())
  2556. {
  2557. string localpath = Module.WorkingDir.Substring(supersuperproject.WorkingDir.Length);
  2558. localpath = PathUtil.GetDirectoryName(localpath.ToPosixPath());
  2559. foreach (var submodule in submodules)
  2560. {
  2561. var name = submodule;
  2562. string path = supersuperproject.GetSubmoduleFullPath(submodule);
  2563. if (Settings.DashboardShowCurrentBranch && !GitModule.IsBareRepository(path))
  2564. name = name + " " + GetModuleBranch(path);
  2565. var submenu = AddSubmoduleToMenu(name, path);
  2566. if (submodule == localpath)
  2567. {
  2568. currentSubmoduleName = Module.GetCurrentSubmoduleLocalPath();
  2569. submenu.Font = new Font(submenu.Font, FontStyle.Bold);
  2570. }
  2571. var module = supersuperproject.GetSubmodule(submodule);
  2572. var submoduleName = module.GetCurrentSubmoduleLocalPath();
  2573. GetSubmoduleStatusImageAsync(submenu, module.SuperprojectModule, submoduleName);
  2574. }
  2575. }
  2576. }
  2577. var separator = new ToolStripSeparator();
  2578. toolStripButtonLevelUp.DropDownItems.Add(separator);
  2579. var mi = new ToolStripMenuItem(updateAllSubmodulesToolStripMenuItem.Text);
  2580. mi.Click += UpdateAllSubmodulesToolStripMenuItemClick;
  2581. toolStripButtonLevelUp.DropDownItems.Add(mi);
  2582. if (currentSubmoduleName != null)
  2583. {
  2584. var usmi = new ToolStripMenuItem(_updateCurrentSubmodule.Text);
  2585. usmi.Tag = currentSubmoduleName;
  2586. usmi.Click += UpdateSubmoduleToolStripMenuItemClick;
  2587. toolStripButtonLevelUp.DropDownItems.Add(usmi);
  2588. }
  2589. }
  2590. private void toolStripButtonLevelUp_ButtonClick(object sender, EventArgs e)
  2591. {
  2592. if (Module.SuperprojectModule != null)
  2593. SetGitModule(Module.SuperprojectModule);
  2594. else
  2595. toolStripButtonLevelUp.ShowDropDown();
  2596. }
  2597. private void openWithDifftoolToolStripMenuItem_DropDownOpening(object sender, EventArgs e)
  2598. {
  2599. bool artificialRevSelected = false;
  2600. bool enableDiffDropDown = true;
  2601. bool showParentItems = false;
  2602. IList<GitRevision> revisions = RevisionGrid.GetSelectedRevisions();
  2603. if (revisions.Count > 0)
  2604. {
  2605. artificialRevSelected = revisions[0].IsArtificial();
  2606. if (revisions.Count == 2)
  2607. {
  2608. artificialRevSelected = artificialRevSelected || revisions[revisions.Count - 1].IsArtificial();
  2609. showParentItems = true;
  2610. }
  2611. else
  2612. enableDiffDropDown = revisions.Count == 1;
  2613. }
  2614. aBToolStripMenuItem.Enabled = enableDiffDropDown;
  2615. bLocalToolStripMenuItem.Enabled = enableDiffDropDown;
  2616. aLocalToolStripMenuItem.Enabled = enableDiffDropDown;
  2617. parentOfALocalToolStripMenuItem.Enabled = enableDiffDropDown;
  2618. parentOfBLocalToolStripMenuItem.Enabled = enableDiffDropDown;
  2619. parentOfALocalToolStripMenuItem.Visible = showParentItems;
  2620. parentOfBLocalToolStripMenuItem.Visible = showParentItems;
  2621. if (!enableDiffDropDown)
  2622. return;
  2623. //enable *<->Local items only when local file exists
  2624. foreach (var item in DiffFiles.SelectedItems)
  2625. {
  2626. string filePath = FormBrowseUtil.GetFullPathFromGitItemStatus(Module, item);
  2627. if (File.Exists(filePath))
  2628. {
  2629. bLocalToolStripMenuItem.Enabled = !artificialRevSelected;
  2630. aLocalToolStripMenuItem.Enabled = !artificialRevSelected;
  2631. parentOfALocalToolStripMenuItem.Enabled = !artificialRevSelected;
  2632. parentOfBLocalToolStripMenuItem.Enabled = !artificialRevSelected;
  2633. return;
  2634. }
  2635. }
  2636. }
  2637. private string GetMonoVersion()
  2638. {
  2639. Type type = Type.GetType("Mono.Runtime");
  2640. if (type != null)
  2641. {
  2642. MethodInfo displayName = type.GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static);
  2643. if (displayName != null)
  2644. return (string)displayName.Invoke(null, null);
  2645. }
  2646. return null;
  2647. }
  2648. private void reportAnIssueToolStripMenuItem_Click(object sender, EventArgs e)
  2649. {
  2650. string issueData = "--- GitExtensions";
  2651. try
  2652. {
  2653. issueData += Settings.GitExtensionsVersionString;
  2654. issueData += ", Git " + GitCommandHelpers.VersionInUse.Full;
  2655. issueData += ", " + Environment.OSVersion;
  2656. var monoVersion = GetMonoVersion();
  2657. if (monoVersion != null)
  2658. issueData += ", Mono " + monoVersion;
  2659. }
  2660. catch(Exception){}
  2661. Process.Start(@"https://github.com/gitextensions/gitextensions/issues/new?body=" + WebUtility.HtmlEncode(issueData));
  2662. }
  2663. private void checkForUpdatesToolStripMenuItem_Click(object sender, EventArgs e)
  2664. {
  2665. using (var updateForm = new FormUpdates(Module.AppVersion))
  2666. updateForm.SearchForUpdatesAndShow(Owner, true);
  2667. }
  2668. private void toolStripButtonPull_DropDownOpened(object sender, EventArgs e)
  2669. {
  2670. dontSetAsDefaultToolStripMenuItem.Checked = Settings.DonSetAsLastPullAction;
  2671. }
  2672. }
  2673. }