DiffPanel.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. using System.Collections.Generic;
  2. using System.IO;
  3. using UnityEditor;
  4. using UnityEditor.IMGUI.Controls;
  5. using UnityEngine;
  6. using Codice.Client.BaseCommands.EventTracking;
  7. using Codice.Client.Commands;
  8. using Codice.Client.Common;
  9. using Codice.Client.Common.Threading;
  10. using Codice.CM.Common;
  11. using PlasticGui;
  12. using PlasticGui.WorkspaceWindow;
  13. using PlasticGui.WorkspaceWindow.BrowseRepository;
  14. using PlasticGui.WorkspaceWindow.Diff;
  15. using Unity.PlasticSCM.Editor.AssetUtils;
  16. using Unity.PlasticSCM.Editor.UI;
  17. using Unity.PlasticSCM.Editor.UI.Progress;
  18. using Unity.PlasticSCM.Editor.Tool;
  19. using Unity.PlasticSCM.Editor.Views.Diff.Dialogs;
  20. using Unity.PlasticSCM.Editor.Views.History;
  21. namespace Unity.PlasticSCM.Editor.Views.Diff
  22. {
  23. internal class DiffPanel :
  24. IDiffTreeViewMenuOperations,
  25. DiffTreeViewMenu.IMetaMenuOperations,
  26. UndeleteClientDiffsOperation.IGetRestorePathDialog
  27. {
  28. internal DiffPanel(
  29. WorkspaceInfo wkInfo,
  30. IWorkspaceWindow workspaceWindow,
  31. IRefreshView refreshView,
  32. IViewSwitcher viewSwitcher,
  33. IHistoryViewLauncher historyViewLauncher,
  34. EditorWindow parentWindow,
  35. bool isGluonMode)
  36. {
  37. mWkInfo = wkInfo;
  38. mWorkspaceWindow = workspaceWindow;
  39. mRefreshView = refreshView;
  40. mViewSwitcher = viewSwitcher;
  41. mHistoryViewLauncher = historyViewLauncher;
  42. mParentWindow = parentWindow;
  43. mGuiMessage = new UnityPlasticGuiMessage();
  44. mIsGluonMode = isGluonMode;
  45. BuildComponents();
  46. mProgressControls = new ProgressControlsForViews();
  47. }
  48. internal void ClearInfo()
  49. {
  50. ClearData();
  51. mParentWindow.Repaint();
  52. }
  53. internal void UpdateInfo(
  54. MountPointWithPath mountWithPath,
  55. ChangesetInfo csetInfo)
  56. {
  57. FillData(mountWithPath, csetInfo);
  58. mParentWindow.Repaint();
  59. }
  60. internal void OnDisable()
  61. {
  62. mSearchField.downOrUpArrowKeyPressed -=
  63. SearchField_OnDownOrUpArrowKeyPressed;
  64. }
  65. internal void Update()
  66. {
  67. mProgressControls.UpdateProgress(mParentWindow);
  68. }
  69. internal void OnGUI()
  70. {
  71. EditorGUILayout.BeginVertical();
  72. DoActionsToolbar(
  73. mDiffs,
  74. mDiffsBranchResolver,
  75. mProgressControls,
  76. mIsSkipMergeTrackingButtonVisible,
  77. mIsSkipMergeTrackingButtonChecked,
  78. mSearchField,
  79. mDiffTreeView);
  80. DoDiffTreeViewArea(
  81. mDiffTreeView,
  82. mProgressControls.IsOperationRunning());
  83. if (mProgressControls.HasNotification())
  84. {
  85. DrawProgressForViews.ForNotificationArea(
  86. mProgressControls.ProgressData);
  87. }
  88. EditorGUILayout.EndVertical();
  89. }
  90. void IDiffTreeViewMenuOperations.SaveRevisionAs()
  91. {
  92. TrackFeatureUseEvent.For(
  93. PlasticGui.Plastic.API.GetRepositorySpec(mWkInfo),
  94. TrackFeatureUseEvent.Features.SaveRevisionFromDiff);
  95. ClientDiffInfo clientDiffInfo =
  96. DiffSelection.GetSelectedDiff(mDiffTreeView);
  97. RepositorySpec repSpec = clientDiffInfo.DiffWithMount.Mount.RepSpec;
  98. RevisionInfo revision = clientDiffInfo.DiffWithMount.Difference.RevInfo;
  99. string defaultFileName = DefaultRevisionName.Get(
  100. Path.GetFileName(clientDiffInfo.DiffWithMount.Difference.Path), revision.Changeset);
  101. string destinationPath = SaveAction.GetDestinationPath(
  102. mWkInfo.ClientPath,
  103. clientDiffInfo.DiffWithMount.Difference.Path,
  104. defaultFileName);
  105. if (string.IsNullOrEmpty(destinationPath))
  106. return;
  107. SaveRevisionOperation.SaveRevision(
  108. repSpec,
  109. destinationPath,
  110. revision,
  111. mProgressControls);
  112. }
  113. SelectedDiffsGroupInfo IDiffTreeViewMenuOperations.GetSelectedDiffsGroupInfo()
  114. {
  115. return SelectedDiffsGroupInfo.BuildFromSelectedNodes(
  116. DiffSelection.GetSelectedDiffsWithoutMeta(mDiffTreeView));
  117. }
  118. void IDiffTreeViewMenuOperations.Diff()
  119. {
  120. if(LaunchTool.ShowDownloadPlasticExeWindow(
  121. mWkInfo,
  122. mIsGluonMode,
  123. TrackFeatureUseEvent.Features.InstallPlasticCloudFromDiffRevision,
  124. TrackFeatureUseEvent.Features.InstallPlasticEnterpriseFromDiffRevision,
  125. TrackFeatureUseEvent.Features.CancelPlasticInstallationFromDiffRevision))
  126. return;
  127. ClientDiffInfo clientDiffInfo =
  128. DiffSelection.GetSelectedDiff(mDiffTreeView);
  129. DiffOperation.DiffClientDiff(
  130. mWkInfo,
  131. clientDiffInfo.DiffWithMount.Mount.Mount,
  132. clientDiffInfo.DiffWithMount.Difference,
  133. xDiffLauncher: null,
  134. imageDiffLauncher: null);
  135. }
  136. void IDiffTreeViewMenuOperations.History()
  137. {
  138. if (LaunchTool.ShowDownloadPlasticExeWindow(
  139. mWkInfo,
  140. mIsGluonMode,
  141. TrackFeatureUseEvent.Features.InstallPlasticCloudFromShowHistory,
  142. TrackFeatureUseEvent.Features.InstallPlasticEnterpriseFromShowHistory,
  143. TrackFeatureUseEvent.Features.CancelPlasticInstallationFromShowHistory))
  144. return;
  145. ClientDiffInfo clientDiffInfo =
  146. DiffSelection.GetSelectedDiff(mDiffTreeView);
  147. mHistoryViewLauncher.ShowHistoryView(
  148. clientDiffInfo.DiffWithMount.Mount.RepSpec,
  149. clientDiffInfo.DiffWithMount.Difference.RevInfo.ItemId,
  150. clientDiffInfo.DiffWithMount.Difference.Path,
  151. clientDiffInfo.DiffWithMount.Difference.IsDirectory);
  152. }
  153. void IDiffTreeViewMenuOperations.RevertChanges()
  154. {
  155. RevertClientDiffsOperation.RevertChanges(
  156. mWkInfo,
  157. DiffSelection.GetSelectedDiffs(mDiffTreeView),
  158. mWorkspaceWindow,
  159. mProgressControls,
  160. mGuiMessage,
  161. AfterRevertOrUndeleteOperation);
  162. }
  163. void IDiffTreeViewMenuOperations.Undelete()
  164. {
  165. UndeleteClientDiffsOperation.Undelete(
  166. mWkInfo,
  167. DiffSelection.GetSelectedDiffs(mDiffTreeView),
  168. mRefreshView,
  169. mProgressControls,
  170. this,
  171. mGuiMessage,
  172. AfterRevertOrUndeleteOperation);
  173. }
  174. void IDiffTreeViewMenuOperations.UndeleteToSpecifiedPaths()
  175. {
  176. UndeleteClientDiffsOperation.UndeleteToSpecifiedPaths(
  177. mWkInfo,
  178. DiffSelection.GetSelectedDiffs(mDiffTreeView),
  179. mRefreshView,
  180. mProgressControls,
  181. this,
  182. mGuiMessage,
  183. AfterRevertOrUndeleteOperation);
  184. }
  185. bool DiffTreeViewMenu.IMetaMenuOperations.SelectionHasMeta()
  186. {
  187. return mDiffTreeView.SelectionHasMeta();
  188. }
  189. void DiffTreeViewMenu.IMetaMenuOperations.DiffMeta()
  190. {
  191. if (LaunchTool.ShowDownloadPlasticExeWindow(
  192. mWkInfo,
  193. mIsGluonMode,
  194. TrackFeatureUseEvent.Features.InstallPlasticCloudFromDiffRevision,
  195. TrackFeatureUseEvent.Features.InstallPlasticEnterpriseFromDiffRevision,
  196. TrackFeatureUseEvent.Features.CancelPlasticInstallationFromDiffRevision))
  197. return;
  198. ClientDiffInfo clientDiffInfo =
  199. DiffSelection.GetSelectedDiff(mDiffTreeView);
  200. ClientDiffInfo clientDiffInfoMeta =
  201. mDiffTreeView.GetMetaDiff(clientDiffInfo);
  202. DiffOperation.DiffClientDiff(
  203. mWkInfo,
  204. clientDiffInfoMeta.DiffWithMount.Mount.Mount,
  205. clientDiffInfoMeta.DiffWithMount.Difference,
  206. xDiffLauncher: null,
  207. imageDiffLauncher: null);
  208. }
  209. GetRestorePathData
  210. UndeleteClientDiffsOperation.IGetRestorePathDialog.GetRestorePath(
  211. string wkPath, string restorePath, string explanation,
  212. bool isDirectory, bool showSkipButton)
  213. {
  214. return GetRestorePathDialog.GetRestorePath(
  215. wkPath, restorePath, explanation, isDirectory,
  216. showSkipButton, mParentWindow);
  217. }
  218. void DiffTreeViewMenu.IMetaMenuOperations.HistoryMeta()
  219. {
  220. if (LaunchTool.ShowDownloadPlasticExeWindow(
  221. mWkInfo,
  222. mIsGluonMode,
  223. TrackFeatureUseEvent.Features.InstallPlasticCloudFromShowHistory,
  224. TrackFeatureUseEvent.Features.InstallPlasticEnterpriseFromShowHistory,
  225. TrackFeatureUseEvent.Features.CancelPlasticInstallationFromShowHistory))
  226. return;
  227. ClientDiffInfo clientDiffInfo =
  228. DiffSelection.GetSelectedDiff(mDiffTreeView);
  229. ClientDiffInfo clientDiffInfoMeta =
  230. mDiffTreeView.GetMetaDiff(clientDiffInfo);
  231. mHistoryViewLauncher.ShowHistoryView(
  232. clientDiffInfoMeta.DiffWithMount.Mount.RepSpec,
  233. clientDiffInfoMeta.DiffWithMount.Difference.RevInfo.ItemId,
  234. clientDiffInfoMeta.DiffWithMount.Difference.Path,
  235. clientDiffInfoMeta.DiffWithMount.Difference.IsDirectory);
  236. }
  237. void SearchField_OnDownOrUpArrowKeyPressed()
  238. {
  239. mDiffTreeView.SetFocusAndEnsureSelectedItem();
  240. }
  241. void AfterRevertOrUndeleteOperation()
  242. {
  243. RefreshAsset.UnityAssetDatabase();
  244. mViewSwitcher.ShowPendingChanges();
  245. }
  246. void ClearData()
  247. {
  248. mSelectedMountWithPath = null;
  249. mSelectedChangesetInfo = null;
  250. mDiffs = null;
  251. ClearDiffs();
  252. }
  253. void FillData(
  254. MountPointWithPath mountWithPath,
  255. ChangesetInfo csetInfo)
  256. {
  257. mSelectedMountWithPath = mountWithPath;
  258. mSelectedChangesetInfo = csetInfo;
  259. ((IProgressControls)mProgressControls).ShowProgress(
  260. PlasticLocalization.GetString(PlasticLocalization.Name.Loading));
  261. mIsSkipMergeTrackingButtonVisible = false;
  262. IThreadWaiter waiter = ThreadWaiter.GetWaiter(100);
  263. waiter.Execute(
  264. /*threadOperationDelegate*/ delegate
  265. {
  266. mDiffs = PlasticGui.Plastic.API.GetChangesetDifferences(
  267. mountWithPath, csetInfo);
  268. mDiffsBranchResolver = BuildBranchResolver.ForDiffs(mDiffs);
  269. },
  270. /*afterOperationDelegate*/ delegate
  271. {
  272. ((IProgressControls)mProgressControls).HideProgress();
  273. if (waiter.Exception != null)
  274. {
  275. ExceptionsHandler.DisplayException(waiter.Exception);
  276. return;
  277. }
  278. if (mSelectedMountWithPath != mountWithPath ||
  279. mSelectedChangesetInfo != csetInfo)
  280. return;
  281. if (mDiffs == null || mDiffs.Count == 0)
  282. {
  283. ClearDiffs();
  284. return;
  285. }
  286. mIsSkipMergeTrackingButtonVisible =
  287. ClientDiffList.HasMerges(mDiffs);
  288. bool skipMergeTracking =
  289. mIsSkipMergeTrackingButtonVisible &&
  290. mIsSkipMergeTrackingButtonChecked;
  291. UpdateDiffTreeView(
  292. mDiffs, mDiffsBranchResolver,
  293. skipMergeTracking, mDiffTreeView);
  294. });
  295. }
  296. void ClearDiffs()
  297. {
  298. mIsSkipMergeTrackingButtonVisible = false;
  299. ClearDiffTreeView(mDiffTreeView);
  300. ((IProgressControls)mProgressControls).ShowNotification(
  301. PlasticLocalization.GetString(PlasticLocalization.Name.NoContentToCompare));
  302. }
  303. static void ClearDiffTreeView(
  304. DiffTreeView diffTreeView)
  305. {
  306. diffTreeView.ClearModel();
  307. diffTreeView.Reload();
  308. }
  309. static void UpdateDiffTreeView(
  310. List<ClientDiff> diffs,
  311. BranchResolver brResolver,
  312. bool skipMergeTracking,
  313. DiffTreeView diffTreeView)
  314. {
  315. diffTreeView.BuildModel(
  316. diffs, brResolver, skipMergeTracking);
  317. diffTreeView.Refilter();
  318. diffTreeView.Sort();
  319. diffTreeView.Reload();
  320. }
  321. void DoActionsToolbar(
  322. List<ClientDiff> diffs,
  323. BranchResolver brResolver,
  324. ProgressControlsForViews progressControls,
  325. bool isSkipMergeTrackingButtonVisible,
  326. bool isSkipMergeTrackingButtonChecked,
  327. SearchField searchField,
  328. DiffTreeView diffTreeView)
  329. {
  330. EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
  331. if (progressControls.IsOperationRunning())
  332. {
  333. DrawProgressForViews.ForIndeterminateProgress(
  334. progressControls.ProgressData);
  335. }
  336. GUILayout.FlexibleSpace();
  337. if (isSkipMergeTrackingButtonVisible)
  338. {
  339. DoSkipMergeTrackingButton(
  340. diffs, brResolver,
  341. isSkipMergeTrackingButtonChecked,
  342. diffTreeView);
  343. }
  344. DrawSearchField.For(
  345. searchField,
  346. diffTreeView,
  347. UnityConstants.SEARCH_FIELD_WIDTH);
  348. VerifyIfSearchFieldIsRecentlyFocused(searchField);
  349. EditorGUILayout.EndHorizontal();
  350. }
  351. void VerifyIfSearchFieldIsRecentlyFocused(SearchField searchField)
  352. {
  353. if (searchField.HasFocus() != mIsSearchFieldFocused)
  354. {
  355. mIsSearchFieldFocused = !mIsSearchFieldFocused;
  356. if (mIsSearchFieldFocused)
  357. {
  358. TrackFeatureUseEvent.For(
  359. PlasticGui.Plastic.API.GetRepositorySpec(mWkInfo),
  360. TrackFeatureUseEvent.Features.ChangesetViewDiffSearchBox);
  361. }
  362. }
  363. }
  364. void DoSkipMergeTrackingButton(
  365. List<ClientDiff> diffs,
  366. BranchResolver brResolver,
  367. bool isSkipMergeTrackingButtonChecked,
  368. DiffTreeView diffTreeView)
  369. {
  370. bool wasChecked = isSkipMergeTrackingButtonChecked;
  371. GUIContent buttonContent = new GUIContent(
  372. PlasticLocalization.GetString(
  373. PlasticLocalization.Name.SkipDiffMergeTracking));
  374. GUIStyle buttonStyle = new GUIStyle(EditorStyles.toolbarButton);
  375. float buttonWidth = buttonStyle.CalcSize(buttonContent).x + 10;
  376. Rect toggleRect = GUILayoutUtility.GetRect(
  377. buttonContent, buttonStyle, GUILayout.Width(buttonWidth));
  378. bool isChecked = GUI.Toggle(
  379. toggleRect, wasChecked, buttonContent, buttonStyle);
  380. if (wasChecked == isChecked)
  381. return;
  382. // if user just checked the skip merge tracking button
  383. if (isChecked)
  384. {
  385. TrackFeatureUseEvent.For(
  386. PlasticGui.Plastic.API.GetRepositorySpec(mWkInfo),
  387. TrackFeatureUseEvent.Features.ChangesetViewSkipMergeTrackingButton);
  388. }
  389. UpdateDiffTreeView(diffs, brResolver, isChecked, diffTreeView);
  390. mIsSkipMergeTrackingButtonChecked = isChecked;
  391. }
  392. static void DoDiffTreeViewArea(
  393. DiffTreeView diffTreeView,
  394. bool isOperationRunning)
  395. {
  396. GUI.enabled = !isOperationRunning;
  397. Rect rect = GUILayoutUtility.GetRect(0, 100000, 0, 100000);
  398. diffTreeView.OnGUI(rect);
  399. GUI.enabled = true;
  400. }
  401. void BuildComponents()
  402. {
  403. mSearchField = new SearchField();
  404. mSearchField.downOrUpArrowKeyPressed += SearchField_OnDownOrUpArrowKeyPressed;
  405. mDiffTreeView = new DiffTreeView(new DiffTreeViewMenu(this, this));
  406. mDiffTreeView.Reload();
  407. }
  408. volatile List<ClientDiff> mDiffs;
  409. volatile BranchResolver mDiffsBranchResolver;
  410. bool mIsSkipMergeTrackingButtonVisible;
  411. bool mIsSkipMergeTrackingButtonChecked;
  412. SearchField mSearchField;
  413. bool mIsSearchFieldFocused = false;
  414. DiffTreeView mDiffTreeView;
  415. ChangesetInfo mSelectedChangesetInfo;
  416. MountPointWithPath mSelectedMountWithPath;
  417. readonly ProgressControlsForViews mProgressControls;
  418. readonly GuiMessage.IGuiMessage mGuiMessage;
  419. readonly EditorWindow mParentWindow;
  420. readonly IRefreshView mRefreshView;
  421. readonly IWorkspaceWindow mWorkspaceWindow;
  422. readonly IHistoryViewLauncher mHistoryViewLauncher;
  423. readonly IViewSwitcher mViewSwitcher;
  424. readonly WorkspaceInfo mWkInfo;
  425. readonly bool mIsGluonMode;
  426. }
  427. }