PendingChangesTab.cs 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEditor;
  4. using UnityEditor.IMGUI.Controls;
  5. using UnityEngine;
  6. using Codice.Client.BaseCommands;
  7. using Codice.Client.BaseCommands.EventTracking;
  8. using Codice.Client.Commands;
  9. using Codice.Client.Common;
  10. using Codice.Client.Common.FsNodeReaders;
  11. using Codice.Client.Common.Threading;
  12. using Codice.CM.Client.Gui;
  13. using Codice.CM.Common;
  14. using Codice.CM.Common.Merge;
  15. using Codice.LogWrapper;
  16. using GluonGui;
  17. using GluonGui.WorkspaceWindow.Views.Checkin.Operations;
  18. using PlasticGui;
  19. using PlasticGui.Help.Actions;
  20. using PlasticGui.Help.Conditions;
  21. using PlasticGui.WorkspaceWindow;
  22. using PlasticGui.WorkspaceWindow.Diff;
  23. using PlasticGui.WorkspaceWindow.Items;
  24. using PlasticGui.WorkspaceWindow.Open;
  25. using PlasticGui.WorkspaceWindow.PendingChanges;
  26. using PlasticGui.WorkspaceWindow.PendingChanges.Changelists;
  27. using Unity.PlasticSCM.Editor.AssetsOverlays;
  28. using Unity.PlasticSCM.Editor.AssetsOverlays.Cache;
  29. using Unity.PlasticSCM.Editor.AssetUtils;
  30. using Unity.PlasticSCM.Editor.Help;
  31. using Unity.PlasticSCM.Editor.Tool;
  32. using Unity.PlasticSCM.Editor.UI;
  33. using Unity.PlasticSCM.Editor.UI.Progress;
  34. using Unity.PlasticSCM.Editor.UI.Tree;
  35. using Unity.PlasticSCM.Editor.Views.PendingChanges.Dialogs;
  36. using Unity.PlasticSCM.Editor.Views.PendingChanges.PendingMergeLinks;
  37. using Unity.PlasticSCM.Editor.Views.Changesets;
  38. using GluonNewIncomingChangesUpdater = PlasticGui.Gluon.WorkspaceWindow.NewIncomingChangesUpdater;
  39. namespace Unity.PlasticSCM.Editor.Views.PendingChanges
  40. {
  41. internal partial class PendingChangesTab :
  42. IRefreshableView,
  43. PlasticProjectSettingsProvider.IAutoRefreshView,
  44. IPendingChangesView,
  45. CheckinUIOperation.ICheckinView,
  46. PendingChangesViewPendingChangeMenu.IMetaMenuOperations,
  47. IPendingChangesMenuOperations,
  48. IChangelistMenuOperations,
  49. IOpenMenuOperations,
  50. IFilesFilterPatternsMenuOperations,
  51. PendingChangesViewMenu.IGetSelectedNodes,
  52. ChangesetsTab.IGoBackToListener
  53. {
  54. internal IProgressControls ProgressControlsForTesting { get { return mProgressControls; } }
  55. internal HelpPanel HelpPanelForTesting { get { return mHelpPanel; } }
  56. internal void SetMergeLinksForTesting(
  57. IDictionary<MountPoint, IList<PendingMergeLink>> mergeLinks)
  58. {
  59. mPendingMergeLinks = mergeLinks;
  60. UpdateMergeLinksList();
  61. }
  62. internal string CommentText { get; set; }
  63. internal bool ForceToShowComment { get; set; }
  64. internal PendingChangesTab(
  65. WorkspaceInfo wkInfo,
  66. ViewHost viewHost,
  67. bool isGluonMode,
  68. WorkspaceWindow workspaceWindow,
  69. IViewSwitcher switcher,
  70. IMergeViewLauncher mergeViewLauncher,
  71. IHistoryViewLauncher historyViewLauncher,
  72. NewIncomingChangesUpdater developerNewIncomingChangesUpdater,
  73. GluonNewIncomingChangesUpdater gluonNewIncomingChangesUpdater,
  74. IAssetStatusCache assetStatusCache,
  75. StatusBar statusBar,
  76. EditorWindow parentWindow)
  77. {
  78. mWkInfo = wkInfo;
  79. mViewHost = viewHost;
  80. mIsGluonMode = isGluonMode;
  81. mWorkspaceWindow = workspaceWindow;
  82. mHistoryViewLauncher = historyViewLauncher;
  83. mDeveloperNewIncomingChangesUpdater = developerNewIncomingChangesUpdater;
  84. mGluonNewIncomingChangesUpdater = gluonNewIncomingChangesUpdater;
  85. mAssetStatusCache = assetStatusCache;
  86. mStatusBar = statusBar;
  87. mParentWindow = parentWindow;
  88. mGuiMessage = new UnityPlasticGuiMessage();
  89. mCheckedStateManager = new CheckedStateManager();
  90. mNewChangesInWk = NewChangesInWk.Build(
  91. mWkInfo,
  92. new BuildWorkspacekIsRelevantNewChange());
  93. BuildComponents(isGluonMode, parentWindow);
  94. mBorderColor = EditorGUIUtility.isProSkin
  95. ? (Color)new Color32(35, 35, 35, 255)
  96. : (Color)new Color32(153, 153, 153, 255);
  97. mProgressControls = new ProgressControlsForViews();
  98. mCooldownClearCheckinSuccessAction = new CooldownWindowDelayer(
  99. DelayedClearCheckinSuccess,
  100. UnityConstants.NOTIFICATION_CLEAR_INTERVAL);
  101. workspaceWindow.RegisterPendingChangesProgressControls(mProgressControls);
  102. mPendingChangesOperations = new PendingChangesOperations(
  103. mWkInfo,
  104. workspaceWindow,
  105. switcher,
  106. mergeViewLauncher,
  107. this,
  108. mProgressControls,
  109. workspaceWindow,
  110. null,
  111. null,
  112. null);
  113. InitIgnoreRulesAndRefreshView(mWkInfo.ClientPath, this);
  114. }
  115. internal void AutoRefresh()
  116. {
  117. if (mIsAutoRefreshDisabled)
  118. return;
  119. if (!PlasticGuiConfig.Get().Configuration.CommitAutoRefresh)
  120. return;
  121. if (mIsRefreshing || mWorkspaceWindow.IsOperationInProgress())
  122. return;
  123. if (mNewChangesInWk != null && !mNewChangesInWk.Detected())
  124. return;
  125. ((IRefreshableView)this).Refresh();
  126. }
  127. internal void ClearIsCommentWarningNeeded()
  128. {
  129. mIsEmptyCheckinCommentWarningNeeded = false;
  130. }
  131. internal void UpdateIsCommentWarningNeeded(string comment)
  132. {
  133. mIsEmptyCheckinCommentWarningNeeded =
  134. string.IsNullOrEmpty(comment) &&
  135. GuiClientConfig.Get().Configuration.ShowEmptyCommentWarning;
  136. mNeedsToShowEmptyCommentDialog = mIsEmptyCheckinCommentWarningNeeded;
  137. }
  138. internal void OnDisable()
  139. {
  140. mSearchField.downOrUpArrowKeyPressed -=
  141. SearchField_OnDownOrUpArrowKeyPressed;
  142. TreeHeaderSettings.Save(
  143. mPendingChangesTreeView.multiColumnHeader.state,
  144. UnityConstants.PENDING_CHANGES_TABLE_SETTINGS_NAME);
  145. }
  146. internal void Update()
  147. {
  148. mProgressControls.UpdateProgress(mParentWindow);
  149. // Displaying the dialog here, because showing it during the window's OnGUI function
  150. // caused errors
  151. if(mNeedsToShowEmptyCommentDialog)
  152. {
  153. mNeedsToShowEmptyCommentDialog = false;
  154. mHasPendingCheckinFromPreviousUpdate =
  155. EmptyCheckinMessageDialog.ShouldContinueWithCheckin(mParentWindow, mWkInfo);
  156. mIsEmptyCheckinCommentWarningNeeded = !mHasPendingCheckinFromPreviousUpdate;
  157. }
  158. }
  159. internal void OnGUI()
  160. {
  161. if (!string.IsNullOrEmpty(mGluonWarningMessage))
  162. DoWarningMessage(mGluonWarningMessage);
  163. DoActionsToolbar(
  164. mWkInfo,
  165. mIsGluonMode,
  166. mProgressControls);
  167. DoChangesArea(
  168. mWkInfo,
  169. mPendingChangesTreeView,
  170. mProgressControls.IsOperationRunning(),
  171. mIsGluonMode,
  172. mIsCheckedInSuccessful);
  173. if (HasPendingMergeLinks() && !mHasPendingMergeLinksFromGoBackTo)
  174. DoMergeLinksArea(mMergeLinksListView, mParentWindow.position.width);
  175. // Border
  176. Rect result = GUILayoutUtility.GetRect(mParentWindow.position.width, 1);
  177. EditorGUI.DrawRect(result, mBorderColor);
  178. DoCommentsSection();
  179. if (mProgressControls.HasNotification())
  180. {
  181. DrawProgressForViews.ForNotificationArea(mProgressControls.ProgressData);
  182. }
  183. DrawHelpPanel.For(mHelpPanel);
  184. }
  185. internal void DrawSearchFieldForPendingChangesTab()
  186. {
  187. DrawSearchField.For(
  188. mSearchField,
  189. mPendingChangesTreeView,
  190. UnityConstants.SEARCH_FIELD_WIDTH);
  191. }
  192. void IPendingChangesView.ClearComments()
  193. {
  194. ClearComments();
  195. }
  196. void IRefreshableView.Refresh()
  197. {
  198. if (!mAreIgnoreRulesInitialized)
  199. return;
  200. DrawAssetOverlay.ClearCache();
  201. if (mDeveloperNewIncomingChangesUpdater != null)
  202. mDeveloperNewIncomingChangesUpdater.Update();
  203. if (mGluonNewIncomingChangesUpdater != null)
  204. mGluonNewIncomingChangesUpdater.Update(DateTime.Now);
  205. FillPendingChanges(mNewChangesInWk);
  206. }
  207. void PlasticProjectSettingsProvider.IAutoRefreshView.DisableAutoRefresh()
  208. {
  209. mIsAutoRefreshDisabled = true;
  210. }
  211. void PlasticProjectSettingsProvider.IAutoRefreshView.EnableAutoRefresh()
  212. {
  213. mIsAutoRefreshDisabled = false;
  214. }
  215. void PlasticProjectSettingsProvider.IAutoRefreshView.ForceRefresh()
  216. {
  217. ((IRefreshableView)this).Refresh();
  218. }
  219. void IPendingChangesView.ClearChangesToCheck(List<string> changes)
  220. {
  221. mCheckedStateManager.ClearChangesToCheck(changes);
  222. mParentWindow.Repaint();
  223. }
  224. void IPendingChangesView.CleanCheckedElements(List<ChangeInfo> checkedChanges)
  225. {
  226. mCheckedStateManager.Clean(checkedChanges);
  227. mParentWindow.Repaint();
  228. }
  229. void IPendingChangesView.CheckChanges(List<string> changesToCheck)
  230. {
  231. mCheckedStateManager.SetChangesToCheck(changesToCheck);
  232. mParentWindow.Repaint();
  233. }
  234. bool IPendingChangesView.IncludeDependencies(
  235. IList<ChangeDependencies<ChangeInfo>> changesDependencies,
  236. string operation)
  237. {
  238. return DependenciesDialog.IncludeDependencies(
  239. mWkInfo, changesDependencies, operation, mParentWindow);
  240. }
  241. CheckinMergeNeededData IPendingChangesView.CheckinMergeNeeded()
  242. {
  243. return CheckinMergeNeededDialog.Merge(mWkInfo, mParentWindow);
  244. }
  245. SearchMatchesData IPendingChangesView.AskForMatches(string changePath)
  246. {
  247. throw new NotImplementedException();
  248. }
  249. void IPendingChangesView.CleanLinkedTasks()
  250. {
  251. }
  252. void CheckinUIOperation.ICheckinView.CollapseWarningMessagePanel()
  253. {
  254. mGluonWarningMessage = string.Empty;
  255. mParentWindow.Repaint();
  256. }
  257. void CheckinUIOperation.ICheckinView.ExpandWarningMessagePanel(string text)
  258. {
  259. mGluonWarningMessage = text;
  260. mParentWindow.Repaint();
  261. }
  262. void CheckinUIOperation.ICheckinView.ClearComments()
  263. {
  264. ClearComments();
  265. }
  266. bool PendingChangesViewPendingChangeMenu.IMetaMenuOperations.SelectionHasMeta()
  267. {
  268. return mPendingChangesTreeView.SelectionHasMeta();
  269. }
  270. void PendingChangesViewPendingChangeMenu.IMetaMenuOperations.DiffMeta()
  271. {
  272. if (LaunchTool.ShowDownloadPlasticExeWindow(
  273. mWkInfo,
  274. mIsGluonMode,
  275. TrackFeatureUseEvent.Features.InstallPlasticCloudFromDiffWorkspaceContent,
  276. TrackFeatureUseEvent.Features.InstallPlasticEnterpriseFromDiffWorkspaceContent,
  277. TrackFeatureUseEvent.Features.CancelPlasticInstallationFromDiffWorkspaceContent))
  278. return;
  279. ChangeInfo selectedChange = PendingChangesSelection
  280. .GetSelectedChange(mPendingChangesTreeView);
  281. ChangeInfo selectedChangeMeta = mPendingChangesTreeView.GetMetaChange(
  282. selectedChange);
  283. ChangeInfo changedForMoved = mPendingChangesTreeView.GetChangedForMoved(selectedChange);
  284. ChangeInfo changedForMovedMeta = (changedForMoved == null) ?
  285. null : mPendingChangesTreeView.GetMetaChange(changedForMoved);
  286. DiffOperation.DiffWorkspaceContent(
  287. mWkInfo,
  288. selectedChangeMeta,
  289. changedForMovedMeta,
  290. mProgressControls,
  291. null,
  292. null);
  293. }
  294. void PendingChangesViewPendingChangeMenu.IMetaMenuOperations.HistoryMeta()
  295. {
  296. ChangeInfo selectedChange = PendingChangesSelection
  297. .GetSelectedChange(mPendingChangesTreeView);
  298. ChangeInfo selectedChangeMeta = mPendingChangesTreeView.GetMetaChange(
  299. selectedChange);
  300. mHistoryViewLauncher.ShowHistoryView(
  301. selectedChangeMeta.RepositorySpec,
  302. selectedChangeMeta.RevInfo.ItemId,
  303. selectedChangeMeta.Path,
  304. selectedChangeMeta.IsDirectory);
  305. }
  306. void PendingChangesViewPendingChangeMenu.IMetaMenuOperations.OpenMeta()
  307. {
  308. List<string> selectedPaths = PendingChangesSelection
  309. .GetSelectedMetaPaths(mPendingChangesTreeView);
  310. FileSystemOperation.Open(selectedPaths);
  311. }
  312. void PendingChangesViewPendingChangeMenu.IMetaMenuOperations.OpenMetaWith()
  313. {
  314. List<string> selectedPaths = PendingChangesSelection
  315. .GetSelectedMetaPaths(mPendingChangesTreeView);
  316. OpenOperation.OpenWith(
  317. FileSystemOperation.GetExePath(),
  318. selectedPaths);
  319. }
  320. void PendingChangesViewPendingChangeMenu.IMetaMenuOperations.OpenMetaInExplorer()
  321. {
  322. List<string> selectedPaths = PendingChangesSelection
  323. .GetSelectedMetaPaths(mPendingChangesTreeView);
  324. if (selectedPaths.Count < 1)
  325. return;
  326. FileSystemOperation.OpenInExplorer(selectedPaths[0]);
  327. }
  328. SelectedChangesGroupInfo IPendingChangesMenuOperations.GetSelectedChangesGroupInfo()
  329. {
  330. return PendingChangesSelection.GetSelectedChangesGroupInfo(
  331. mWkInfo.ClientPath, mPendingChangesTreeView);
  332. }
  333. void IPendingChangesMenuOperations.Diff()
  334. {
  335. if (LaunchTool.ShowDownloadPlasticExeWindow(
  336. mWkInfo,
  337. mIsGluonMode,
  338. TrackFeatureUseEvent.Features.InstallPlasticCloudFromDiffWorkspaceContent,
  339. TrackFeatureUseEvent.Features.InstallPlasticEnterpriseFromDiffWorkspaceContent,
  340. TrackFeatureUseEvent.Features.CancelPlasticInstallationFromDiffWorkspaceContent))
  341. return;
  342. ChangeInfo selectedChange = PendingChangesSelection
  343. .GetSelectedChange(mPendingChangesTreeView);
  344. DiffOperation.DiffWorkspaceContent(
  345. mWkInfo,
  346. selectedChange,
  347. mPendingChangesTreeView.GetChangedForMoved(selectedChange),
  348. null,
  349. null,
  350. null);
  351. }
  352. void IPendingChangesMenuOperations.UndoChanges()
  353. {
  354. List<ChangeInfo> changesToUndo = PendingChangesSelection
  355. .GetSelectedChanges(mPendingChangesTreeView);
  356. List<ChangeInfo> dependenciesCandidates =
  357. mPendingChangesTreeView.GetDependenciesCandidates(changesToUndo, true);
  358. UndoChangesForMode(
  359. mWkInfo, mIsGluonMode,
  360. changesToUndo, dependenciesCandidates);
  361. }
  362. void IPendingChangesMenuOperations.SearchMatches()
  363. {
  364. ChangeInfo selectedChange = PendingChangesSelection
  365. .GetSelectedChange(mPendingChangesTreeView);
  366. if (selectedChange == null)
  367. return;
  368. SearchMatchesOperation operation = new SearchMatchesOperation(
  369. mWkInfo, mWorkspaceWindow, this,
  370. mProgressControls, mDeveloperNewIncomingChangesUpdater);
  371. operation.SearchMatches(
  372. selectedChange,
  373. PendingChangesSelection.GetAllChanges(mPendingChangesTreeView));
  374. }
  375. void IPendingChangesMenuOperations.ApplyLocalChanges()
  376. {
  377. List<ChangeInfo> selectedChanges = PendingChangesSelection
  378. .GetSelectedChanges(mPendingChangesTreeView);
  379. if (selectedChanges.Count == 0)
  380. return;
  381. ApplyLocalChangesOperation operation = new ApplyLocalChangesOperation(
  382. mWkInfo, mWorkspaceWindow, this,
  383. mProgressControls, mDeveloperNewIncomingChangesUpdater);
  384. operation.ApplyLocalChanges(
  385. selectedChanges,
  386. PendingChangesSelection.GetAllChanges(mPendingChangesTreeView));
  387. }
  388. void IPendingChangesMenuOperations.Delete()
  389. {
  390. List<string> privateDirectoriesToDelete;
  391. List<string> privateFilesToDelete;
  392. if (!mPendingChangesTreeView.GetSelectedPathsToDelete(
  393. out privateDirectoriesToDelete,
  394. out privateFilesToDelete))
  395. return;
  396. DeleteOperation.Delete(
  397. mWorkspaceWindow, mProgressControls,
  398. privateDirectoriesToDelete, privateFilesToDelete,
  399. mDeveloperNewIncomingChangesUpdater,
  400. RefreshAsset.UnityAssetDatabase);
  401. }
  402. void IPendingChangesMenuOperations.Annotate()
  403. {
  404. throw new NotImplementedException();
  405. }
  406. void IPendingChangesMenuOperations.History()
  407. {
  408. ChangeInfo selectedChange = PendingChangesSelection.
  409. GetSelectedChange(mPendingChangesTreeView);
  410. mHistoryViewLauncher.ShowHistoryView(
  411. selectedChange.RepositorySpec,
  412. selectedChange.RevInfo.ItemId,
  413. selectedChange.Path,
  414. selectedChange.IsDirectory);
  415. }
  416. SelectedChangesGroupInfo IChangelistMenuOperations.GetSelectedChangesGroupInfo()
  417. {
  418. return PendingChangesSelection.GetSelectedChangesGroupInfo(
  419. mWkInfo.ClientPath, mPendingChangesTreeView);
  420. }
  421. List<ChangeListInfo> IChangelistMenuOperations.GetSelectedChangelistInfos()
  422. {
  423. return PendingChangesSelection.GetSelectedChangeListInfos(
  424. mPendingChangesTreeView);
  425. }
  426. void IChangelistMenuOperations.Checkin()
  427. {
  428. List<ChangeInfo> changesToCheckin;
  429. List<ChangeInfo> dependenciesCandidates;
  430. mPendingChangesTreeView.GetCheckedChanges(
  431. PendingChangesSelection.GetSelectedChangelistNodes(mPendingChangesTreeView),
  432. false, out changesToCheckin, out dependenciesCandidates);
  433. CheckinChangesForMode(
  434. changesToCheckin, dependenciesCandidates,
  435. mWkInfo, mIsGluonMode, mKeepItemsLocked);
  436. }
  437. void IChangelistMenuOperations.Shelve()
  438. {
  439. if (mIsGluonMode)
  440. return;
  441. List<ChangeInfo> changesToShelve;
  442. List<ChangeInfo> dependenciesCandidates;
  443. mPendingChangesTreeView.GetCheckedChanges(
  444. PendingChangesSelection.GetSelectedChangelistNodes(mPendingChangesTreeView),
  445. false, out changesToShelve, out dependenciesCandidates);
  446. ShelveChanges(changesToShelve, dependenciesCandidates, mWkInfo);
  447. }
  448. void IChangelistMenuOperations.Undo()
  449. {
  450. List<ChangeInfo> changesToUndo;
  451. List<ChangeInfo> dependenciesCandidates;
  452. mPendingChangesTreeView.GetCheckedChanges(
  453. PendingChangesSelection.GetSelectedChangelistNodes(mPendingChangesTreeView),
  454. true, out changesToUndo, out dependenciesCandidates);
  455. UndoChangesForMode(
  456. mWkInfo, mIsGluonMode,
  457. changesToUndo, dependenciesCandidates);
  458. }
  459. void IChangelistMenuOperations.CreateNew()
  460. {
  461. ChangelistCreationData changelistCreationData =
  462. CreateChangelistDialog.CreateChangelist(mWkInfo, mParentWindow);
  463. ChangelistOperations.CreateNew(mWkInfo, this, changelistCreationData);
  464. }
  465. void IChangelistMenuOperations.MoveToNewChangelist(List<ChangeInfo> changes)
  466. {
  467. ChangelistCreationData changelistCreationData =
  468. CreateChangelistDialog.CreateChangelist(mWkInfo, mParentWindow);
  469. if (!changelistCreationData.Result)
  470. return;
  471. ChangelistOperations.CreateNew(mWkInfo, this, changelistCreationData);
  472. ChangelistOperations.MoveToChangelist(
  473. mWkInfo, this, changes,
  474. changelistCreationData.ChangelistInfo.Name);
  475. }
  476. void IChangelistMenuOperations.Edit()
  477. {
  478. ChangeListInfo changelistToEdit = PendingChangesSelection.GetSelectedChangeListInfo(
  479. mPendingChangesTreeView);
  480. ChangelistCreationData changelistCreationData = CreateChangelistDialog.EditChangelist(
  481. mWkInfo,
  482. changelistToEdit,
  483. mParentWindow);
  484. ChangelistOperations.Edit(mWkInfo, this, changelistToEdit, changelistCreationData);
  485. }
  486. void IChangelistMenuOperations.Delete()
  487. {
  488. ChangelistOperations.Delete(
  489. mWkInfo,
  490. this,
  491. PendingChangesSelection.GetSelectedChangelistNodes(mPendingChangesTreeView));
  492. }
  493. void IChangelistMenuOperations.MoveToChangelist(
  494. List<ChangeInfo> changes,
  495. string targetChangelist)
  496. {
  497. ChangelistOperations.MoveToChangelist(
  498. mWkInfo,
  499. this,
  500. changes,
  501. targetChangelist);
  502. }
  503. void IOpenMenuOperations.Open()
  504. {
  505. List<string> selectedPaths = PendingChangesSelection.
  506. GetSelectedPathsWithoutMeta(mPendingChangesTreeView);
  507. FileSystemOperation.Open(selectedPaths);
  508. }
  509. void IOpenMenuOperations.OpenWith()
  510. {
  511. List<string> selectedPaths = PendingChangesSelection.
  512. GetSelectedPathsWithoutMeta(mPendingChangesTreeView);
  513. OpenOperation.OpenWith(
  514. FileSystemOperation.GetExePath(),
  515. selectedPaths);
  516. }
  517. void IOpenMenuOperations.OpenWithCustom(string exePath, string args)
  518. {
  519. List<string> selectedPaths = PendingChangesSelection.
  520. GetSelectedPathsWithoutMeta(mPendingChangesTreeView);
  521. OpenOperation.OpenWith(exePath, selectedPaths);
  522. }
  523. void IOpenMenuOperations.OpenInExplorer()
  524. {
  525. List<string> selectedPaths = PendingChangesSelection
  526. .GetSelectedPathsWithoutMeta(mPendingChangesTreeView);
  527. if (selectedPaths.Count < 1)
  528. return;
  529. FileSystemOperation.OpenInExplorer(selectedPaths[0]);
  530. }
  531. void IFilesFilterPatternsMenuOperations.AddFilesFilterPatterns(
  532. FilterTypes type, FilterActions action, FilterOperationType operation)
  533. {
  534. List<string> selectedPaths = PendingChangesSelection.GetSelectedPaths(
  535. mPendingChangesTreeView);
  536. string[] rules = FilterRulesGenerator.GenerateRules(
  537. selectedPaths, mWkInfo.ClientPath, action, operation);
  538. bool isApplicableToAllWorkspaces = !mIsGluonMode;
  539. bool isAddOperation = operation == FilterOperationType.Add;
  540. FilterRulesConfirmationData filterRulesConfirmationData =
  541. FilterRulesConfirmationDialog.AskForConfirmation(
  542. rules, isAddOperation, isApplicableToAllWorkspaces, mParentWindow);
  543. AddFilesFilterPatternsOperation.Run(
  544. mWkInfo, mWorkspaceWindow, type, operation, filterRulesConfirmationData);
  545. }
  546. List<IPlasticTreeNode> PendingChangesViewMenu.IGetSelectedNodes.GetSelectedNodes()
  547. {
  548. return mPendingChangesTreeView.GetSelectedNodes();
  549. }
  550. void ChangesetsTab.IGoBackToListener.OnSuccessOperation()
  551. {
  552. mHasPendingMergeLinksFromGoBackTo = true;
  553. }
  554. void SearchField_OnDownOrUpArrowKeyPressed()
  555. {
  556. mPendingChangesTreeView.SetFocusAndEnsureSelectedItem();
  557. }
  558. void InitIgnoreRulesAndRefreshView(
  559. string wkPath, IRefreshableView view)
  560. {
  561. IThreadWaiter waiter = ThreadWaiter.GetWaiter(10);
  562. waiter.Execute(
  563. /*threadOperationDelegate*/ delegate
  564. {
  565. if (IsIgnoreConfigDefined.For(wkPath))
  566. return;
  567. AddIgnoreRules.WriteRules(
  568. wkPath, UnityConditions.GetMissingIgnoredRules(wkPath));
  569. },
  570. /*afterOperationDelegate*/ delegate
  571. {
  572. mAreIgnoreRulesInitialized = true;
  573. view.Refresh();
  574. if (waiter.Exception == null)
  575. return;
  576. mLog.ErrorFormat(
  577. "Error adding ignore rules for Unity: {0}",
  578. waiter.Exception);
  579. mLog.DebugFormat(
  580. "Stack trace: {0}",
  581. waiter.Exception.StackTrace);
  582. });
  583. }
  584. void FillPendingChanges(INewChangesInWk newChangesInWk)
  585. {
  586. if (mIsRefreshing)
  587. return;
  588. mIsRefreshing = true;
  589. List<ChangeInfo> changesToSelect =
  590. PendingChangesSelection.GetChangesToFocus(mPendingChangesTreeView);
  591. ((IProgressControls)mProgressControls).ShowProgress(PlasticLocalization.
  592. GetString(PlasticLocalization.Name.LoadingPendingChanges));
  593. IDictionary<MountPoint, IList<PendingMergeLink>> mergeLinks = null;
  594. WorkspaceStatusResult status = null;
  595. IThreadWaiter waiter = ThreadWaiter.GetWaiter();
  596. waiter.Execute(
  597. /*threadOperationDelegate*/ delegate
  598. {
  599. FilterManager.Get().Reload();
  600. WorkspaceStatusOptions options = WorkspaceStatusOptions.None;
  601. options |= WorkspaceStatusOptions.FindAdded;
  602. options |= WorkspaceStatusOptions.FindDeleted;
  603. options |= WorkspaceStatusOptions.FindMoved;
  604. options |= WorkspaceStatusOptions.SplitModifiedMoved;
  605. options |= PendingChangesOptions.GetWorkspaceStatusOptions();
  606. if (newChangesInWk != null)
  607. newChangesInWk.Detected();
  608. status = GetStatus.ForWorkspace(
  609. mWkInfo,
  610. options,
  611. PendingChangesOptions.GetMovedMatchingOptions());
  612. mergeLinks = PlasticGui.Plastic.API.GetPendingMergeLinks(mWkInfo);
  613. },
  614. /*afterOperationDelegate*/ delegate
  615. {
  616. mPendingMergeLinks = mergeLinks;
  617. try
  618. {
  619. if (waiter.Exception != null)
  620. {
  621. ExceptionsHandler.DisplayException(waiter.Exception);
  622. return;
  623. }
  624. UpdateChangesTree(status.Changes);
  625. UpdateMergeLinksList();
  626. PendingChangesSelection.SelectChanges(
  627. mPendingChangesTreeView, changesToSelect);
  628. }
  629. finally
  630. {
  631. ((IProgressControls)mProgressControls).HideProgress();
  632. //UpdateIsCommentWarningNeeded(CommentText);
  633. UpdateNotificationPanel();
  634. mIsRefreshing = false;
  635. }
  636. });
  637. }
  638. void DoCommentsSection()
  639. {
  640. EditorGUILayout.BeginVertical(UnityStyles.PendingChangesTab.Comment);
  641. EditorGUILayout.Space(10);
  642. EditorGUILayout.BeginHorizontal();
  643. EditorGUILayout.Space(2);
  644. EditorGUILayout.BeginVertical();
  645. GUILayout.FlexibleSpace();
  646. DrawUserIcon.ForPendingChangesTab(CommentText);
  647. GUILayout.FlexibleSpace();
  648. EditorGUILayout.EndVertical();
  649. float width = Mathf.Clamp(mParentWindow.position.width, 300f, 820f);
  650. DrawCommentTextArea.For(
  651. this,
  652. width,
  653. mProgressControls.IsOperationRunning());
  654. EditorGUILayout.Space(2);
  655. // To center the action buttons vertically
  656. EditorGUILayout.BeginVertical();
  657. GUILayout.FlexibleSpace();
  658. DoOperationsToolbar(
  659. mWkInfo,
  660. mIsGluonMode,
  661. mAdvancedDropdownMenu,
  662. mProgressControls.IsOperationRunning());
  663. GUILayout.FlexibleSpace();
  664. EditorGUILayout.EndVertical();
  665. GUILayout.FlexibleSpace();
  666. EditorGUILayout.EndHorizontal();
  667. EditorGUILayout.Space(10);
  668. EditorGUILayout.EndVertical();
  669. }
  670. void DoOperationsToolbar(
  671. WorkspaceInfo wkInfo,
  672. bool isGluonMode,
  673. GenericMenu advancedDropdownMenu,
  674. bool isOperationRunning)
  675. {
  676. EditorGUILayout.BeginHorizontal();
  677. using (new GuiEnabled(!isOperationRunning))
  678. {
  679. if(mHasPendingCheckinFromPreviousUpdate)
  680. {
  681. mHasPendingCheckinFromPreviousUpdate = false;
  682. CheckinForMode(wkInfo, isGluonMode, mKeepItemsLocked);
  683. }
  684. else if (DrawActionButton.ForCommentSection(
  685. PlasticLocalization.GetString(
  686. PlasticLocalization.Name.CheckinChanges)))
  687. {
  688. UpdateIsCommentWarningNeeded(CommentText);
  689. if (!mIsEmptyCheckinCommentWarningNeeded &&
  690. mPendingChangesTreeView.GetCheckedItemCount() > 0)
  691. {
  692. CheckinForMode(wkInfo, isGluonMode, mKeepItemsLocked);
  693. }
  694. }
  695. GUILayout.Space(2);
  696. if (DrawActionButton.ForCommentSection(PlasticLocalization.GetString(
  697. PlasticLocalization.Name.UndoChanges)))
  698. {
  699. TrackFeatureUseEvent.For(PlasticGui.Plastic.API.GetRepositorySpec(wkInfo),
  700. TrackFeatureUseEvent.Features.UndoTextButton);
  701. UndoForMode(wkInfo, isGluonMode);
  702. }
  703. if (isGluonMode)
  704. {
  705. mKeepItemsLocked = EditorGUILayout.ToggleLeft(
  706. PlasticLocalization.GetString(PlasticLocalization.Name.KeepLocked),
  707. mKeepItemsLocked,
  708. GUILayout.Width(UnityConstants.EXTRA_LARGE_BUTTON_WIDTH));
  709. }
  710. //TODO: Codice - beta: hide the advanced menu until the behavior is implemented
  711. /*else
  712. {
  713. var dropDownContent = new GUIContent(string.Empty);
  714. var dropDownRect = GUILayoutUtility.GetRect(
  715. dropDownContent, EditorStyles.toolbarDropDown);
  716. if (EditorGUI.DropdownButton(dropDownRect, dropDownContent,
  717. FocusType.Passive, EditorStyles.toolbarDropDown))
  718. advancedDropdownMenu.DropDown(dropDownRect);
  719. }*/
  720. }
  721. EditorGUILayout.EndHorizontal();
  722. }
  723. void UpdateChangesTree(List<ChangeInfo> changes)
  724. {
  725. mPendingChangesTreeView.BuildModel(changes, mCheckedStateManager);
  726. mPendingChangesTreeView.Refilter();
  727. mPendingChangesTreeView.Sort();
  728. mPendingChangesTreeView.Reload();
  729. }
  730. static void DoWarningMessage(string message)
  731. {
  732. GUILayout.Label(message, UnityStyles.WarningMessage);
  733. }
  734. void UpdateMergeLinksList()
  735. {
  736. mMergeLinksListView.BuildModel(mPendingMergeLinks);
  737. mMergeLinksListView.Reload();
  738. if (mPendingMergeLinks.Count == 0)
  739. mHasPendingMergeLinksFromGoBackTo = false;
  740. }
  741. void UpdateNotificationPanel()
  742. {
  743. if (PlasticGui.Plastic.API.IsFsReaderWatchLimitReached(mWkInfo))
  744. {
  745. ((IProgressControls)mProgressControls).ShowWarning(PlasticLocalization.
  746. GetString(PlasticLocalization.Name.NotifyLinuxWatchLimitWarning));
  747. return;
  748. }
  749. }
  750. void DoActionsToolbar(
  751. WorkspaceInfo workspaceInfo,
  752. bool isGluonMode,
  753. ProgressControlsForViews progressControls)
  754. {
  755. EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
  756. if (progressControls.IsOperationRunning())
  757. {
  758. DrawProgressForViews.ForIndeterminateProgress(
  759. progressControls.ProgressData);
  760. }
  761. GUILayout.FlexibleSpace();
  762. EditorGUILayout.EndHorizontal();
  763. }
  764. static void DoChangesArea(
  765. WorkspaceInfo wkInfo,
  766. PendingChangesTreeView changesTreeView,
  767. bool isOperationRunning,
  768. bool isGluonMode,
  769. bool isCheckedInSuccessful)
  770. {
  771. GUI.enabled = !isOperationRunning;
  772. Rect rect = GUILayoutUtility.GetRect(0, 100000, 0, 100000);
  773. changesTreeView.OnGUI(rect);
  774. if (changesTreeView.GetTotalItemCount() == 0)
  775. {
  776. DrawEmptyState(
  777. rect,
  778. isCheckedInSuccessful);
  779. }
  780. GUI.enabled = true;
  781. }
  782. static void DrawEmptyState(
  783. Rect rect,
  784. bool isCheckedInSuccessful)
  785. {
  786. if (isCheckedInSuccessful)
  787. {
  788. DrawTreeViewEmptyState.For(
  789. rect,
  790. PlasticLocalization.GetString(PlasticLocalization.Name.CheckinCompleted),
  791. Images.GetStepOkIcon());
  792. return;
  793. }
  794. DrawTreeViewEmptyState.For(
  795. rect,
  796. PlasticLocalization.GetString(PlasticLocalization.Name.NoPendingChanges));
  797. }
  798. bool HasPendingMergeLinks()
  799. {
  800. if (mPendingMergeLinks == null)
  801. return false;
  802. return mPendingMergeLinks.Count > 0;
  803. }
  804. static void DoMergeLinksArea(
  805. MergeLinksListView mergeLinksListView, float width)
  806. {
  807. GUILayout.Label(
  808. PlasticLocalization.GetString(
  809. PlasticLocalization.Name.MergeLinkDescriptionColumn),
  810. EditorStyles.boldLabel);
  811. float desiredTreeHeight = mergeLinksListView.DesiredHeight;
  812. Rect treeRect = GUILayoutUtility.GetRect(
  813. 0,
  814. width,
  815. desiredTreeHeight,
  816. desiredTreeHeight);
  817. mergeLinksListView.OnGUI(treeRect);
  818. }
  819. void BuildComponents(
  820. bool isGluonMode,
  821. EditorWindow plasticWindow)
  822. {
  823. mHelpPanel = new HelpPanel(plasticWindow);
  824. mAdvancedDropdownMenu = new GenericMenu();
  825. mAdvancedDropdownMenu.AddItem(new GUIContent(
  826. PlasticLocalization.GetString(PlasticLocalization.Name.UndoUnchangedButton)),
  827. false, () => { });
  828. mSearchField = new SearchField();
  829. mSearchField.downOrUpArrowKeyPressed += SearchField_OnDownOrUpArrowKeyPressed;
  830. PendingChangesTreeHeaderState headerState =
  831. PendingChangesTreeHeaderState.GetDefault(isGluonMode);
  832. TreeHeaderSettings.Load(headerState,
  833. UnityConstants.PENDING_CHANGES_TABLE_SETTINGS_NAME,
  834. (int)PendingChangesTreeColumn.Item, true);
  835. mPendingChangesTreeView = new PendingChangesTreeView(
  836. mWkInfo, mIsGluonMode, headerState,
  837. PendingChangesTreeHeaderState.GetColumnNames(),
  838. new PendingChangesViewMenu(mWkInfo, this, this, this, this, this, this, mIsGluonMode),
  839. mAssetStatusCache);
  840. mPendingChangesTreeView.Reload();
  841. mMergeLinksListView = new MergeLinksListView();
  842. mMergeLinksListView.Reload();
  843. }
  844. INewChangesInWk mNewChangesInWk;
  845. GenericMenu mAdvancedDropdownMenu;
  846. void ClearComments()
  847. {
  848. CommentText = string.Empty;
  849. ForceToShowComment = true;
  850. mParentWindow.Repaint();
  851. }
  852. PendingChangesTreeView mPendingChangesTreeView;
  853. MergeLinksListView mMergeLinksListView;
  854. HelpPanel mHelpPanel;
  855. volatile bool mAreIgnoreRulesInitialized = false;
  856. bool mIsRefreshing;
  857. bool mIsAutoRefreshDisabled;
  858. bool mIsEmptyCheckinCommentWarningNeeded = false;
  859. bool mNeedsToShowEmptyCommentDialog = false;
  860. bool mHasPendingCheckinFromPreviousUpdate = false;
  861. bool mHasPendingMergeLinksFromGoBackTo = false;
  862. bool mKeepItemsLocked;
  863. string mGluonWarningMessage;
  864. bool mIsCheckedInSuccessful;
  865. IDictionary<MountPoint, IList<PendingMergeLink>> mPendingMergeLinks;
  866. SearchField mSearchField;
  867. Color mBorderColor;
  868. readonly ProgressControlsForViews mProgressControls;
  869. readonly EditorWindow mParentWindow;
  870. readonly StatusBar mStatusBar;
  871. readonly CooldownWindowDelayer mCooldownClearCheckinSuccessAction;
  872. readonly IAssetStatusCache mAssetStatusCache;
  873. readonly PendingChangesOperations mPendingChangesOperations;
  874. readonly CheckedStateManager mCheckedStateManager;
  875. readonly GuiMessage.IGuiMessage mGuiMessage;
  876. readonly NewIncomingChangesUpdater mDeveloperNewIncomingChangesUpdater;
  877. readonly GluonNewIncomingChangesUpdater mGluonNewIncomingChangesUpdater;
  878. readonly bool mIsGluonMode;
  879. readonly IHistoryViewLauncher mHistoryViewLauncher;
  880. readonly WorkspaceWindow mWorkspaceWindow;
  881. readonly ViewHost mViewHost;
  882. readonly WorkspaceInfo mWkInfo;
  883. static readonly ILog mLog = LogManager.GetLogger("PendingChangesTab");
  884. }
  885. }