No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

PlasticWindow.cs 39KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126
  1. using System;
  2. using System.Linq;
  3. using UnityEditor;
  4. using UnityEngine;
  5. using Codice.Client.BaseCommands;
  6. using Codice.Client.BaseCommands.EventTracking;
  7. using Codice.Client.Common;
  8. using Codice.Client.Common.FsNodeReaders.Watcher;
  9. using Codice.Client.Common.Threading;
  10. using Codice.CM.Common;
  11. using Codice.LogWrapper;
  12. using GluonGui;
  13. using PlasticGui;
  14. using PlasticGui.WorkspaceWindow.NotificationBar;
  15. using Unity.PlasticSCM.Editor.AssetMenu;
  16. using Unity.PlasticSCM.Editor.AssetUtils;
  17. using Unity.PlasticSCM.Editor.Configuration;
  18. using Unity.PlasticSCM.Editor.Configuration.CloudEdition.Welcome;
  19. using Unity.PlasticSCM.Editor.Inspector;
  20. using Unity.PlasticSCM.Editor.Tool;
  21. using Unity.PlasticSCM.Editor.UI;
  22. using Unity.PlasticSCM.Editor.UI.Avatar;
  23. using Unity.PlasticSCM.Editor.UI.Progress;
  24. using Unity.PlasticSCM.Editor.UI.StatusBar;
  25. using Unity.PlasticSCM.Editor.Views.CreateWorkspace;
  26. using Unity.PlasticSCM.Editor.Views.Welcome;
  27. using Unity.PlasticSCM.Editor.WebApi;
  28. using GluonCheckIncomingChanges = PlasticGui.Gluon.WorkspaceWindow.CheckIncomingChanges;
  29. using GluonNewIncomingChangesUpdater = PlasticGui.Gluon.WorkspaceWindow.NewIncomingChangesUpdater;
  30. using PlasticAssetModificationProcessor = Unity.PlasticSCM.Editor.AssetUtils.Processor.AssetModificationProcessor;
  31. namespace Unity.PlasticSCM.Editor
  32. {
  33. internal class PlasticWindow : EditorWindow,
  34. PlasticGui.WorkspaceWindow.CheckIncomingChanges.IAutoRefreshIncomingChangesView,
  35. GluonCheckIncomingChanges.IAutoRefreshIncomingChangesView,
  36. CreateWorkspaceView.ICreateWorkspaceListener
  37. {
  38. internal WorkspaceWindow WorkspaceWindowForTesting { get { return mWorkspaceWindow; } }
  39. internal ViewSwitcher ViewSwitcherForTesting { get { return mViewSwitcher; } }
  40. internal CmConnection CmConnectionForTesting { get { return CmConnection.Get(); } }
  41. internal void SetupWindowTitle(PlasticNotification.Status status)
  42. {
  43. Texture windowIcon = PlasticNotification.GetIcon(status);
  44. // The titleContent icon does not update unless we also update the title text
  45. // Temporarily doing it by adding space characters
  46. string title = UnityConstants.PLASTIC_WINDOW_TITLE;
  47. title += String.Concat(Enumerable.Repeat(" ", (int)status));
  48. titleContent = new GUIContent(title, windowIcon);
  49. }
  50. internal void DisableCollabIfEnabledWhenLoaded()
  51. {
  52. mDisableCollabIfEnabledWhenLoaded = true;
  53. }
  54. void PlasticGui.WorkspaceWindow.CheckIncomingChanges.IAutoRefreshIncomingChangesView.IfVisible()
  55. {
  56. mViewSwitcher.AutoRefreshIncomingChangesView();
  57. }
  58. void GluonCheckIncomingChanges.IAutoRefreshIncomingChangesView.IfVisible()
  59. {
  60. mViewSwitcher.AutoRefreshIncomingChangesView();
  61. }
  62. void CreateWorkspaceView.ICreateWorkspaceListener.OnWorkspaceCreated(
  63. WorkspaceInfo wkInfo, bool isGluonMode)
  64. {
  65. mWkInfo = wkInfo;
  66. mIsGluonMode = isGluonMode;
  67. mWelcomeView = null;
  68. PlasticPlugin.Enable();
  69. if (mIsGluonMode)
  70. ConfigurePartialWorkspace.AsFullyChecked(mWkInfo);
  71. InitializePlastic();
  72. Repaint();
  73. }
  74. internal void RefreshWorkspaceUI()
  75. {
  76. InitializePlastic();
  77. Repaint();
  78. OnFocus();
  79. }
  80. void OnEnable()
  81. {
  82. PlasticPlugin.Enable();
  83. wantsMouseMove = true;
  84. if (mException != null)
  85. return;
  86. minSize = new Vector2(
  87. UnityConstants.PLASTIC_WINDOW_MIN_SIZE_WIDTH,
  88. UnityConstants.PLASTIC_WINDOW_MIN_SIZE_HEIGHT);
  89. SetupWindowTitle(PlasticNotification.Status.None);
  90. RegisterApplicationFocusHandlers(this);
  91. InitializePlastic();
  92. }
  93. void OnDisable()
  94. {
  95. // We need to disable FSWatcher because otherwise it hangs
  96. // when you move the window between monitors with different scale
  97. MonoFileSystemWatcher.IsEnabled = false;
  98. if (mException != null)
  99. return;
  100. if (mWkInfo == null)
  101. {
  102. ClosePlasticWindow(this);
  103. return;
  104. }
  105. mViewSwitcher.OnDisable();
  106. ClosePlasticWindow(this);
  107. }
  108. void OnDestroy()
  109. {
  110. if (mException != null)
  111. return;
  112. if (mWkInfo == null)
  113. return;
  114. if (!mWorkspaceWindow.IsOperationInProgress())
  115. return;
  116. bool bCloseWindow = GuiMessage.ShowQuestion(
  117. PlasticLocalization.GetString(PlasticLocalization.Name.OperationRunning),
  118. PlasticLocalization.GetString(PlasticLocalization.Name.ConfirmClosingRunningOperation),
  119. PlasticLocalization.GetString(PlasticLocalization.Name.YesButton));
  120. if (bCloseWindow)
  121. return;
  122. mForceToOpen = true;
  123. ShowPlasticWindow(this);
  124. }
  125. void OnFocus()
  126. {
  127. if (mException != null)
  128. return;
  129. if (mWkInfo == null)
  130. return;
  131. // We don't want to auto-refresh the views when the window
  132. // is focused due to a right mouse button click because
  133. // if there is no internet connection a dialog appears and
  134. // it prevents being able to open the context menu in order
  135. // to close the Plastic SCM window
  136. if (Mouse.IsRightMouseButtonPressed(Event.current))
  137. return;
  138. mViewSwitcher.AutoRefreshPendingChangesView();
  139. mViewSwitcher.AutoRefreshIncomingChangesView();
  140. }
  141. void OnGUI()
  142. {
  143. if (mException != null)
  144. {
  145. DoExceptionErrorArea();
  146. return;
  147. }
  148. try
  149. {
  150. // IMPORTANT: disable collab (if needed)
  151. // must be executed before the next if statement
  152. // where we check if collab is enabled
  153. if (mDisableCollabIfEnabledWhenLoaded)
  154. {
  155. mDisableCollabIfEnabledWhenLoaded = false;
  156. DisableCollabIfEnabled(ProjectPath.FromApplicationDataPath(
  157. ApplicationDataPath.Get()));
  158. }
  159. if (CollabPlugin.IsEnabled())
  160. {
  161. // execute Close() once after all inspectors update
  162. // to avoid our window to be drawn in back color
  163. EditorApplication.delayCall = Close;
  164. return;
  165. }
  166. bool isPlasticExeAvailable = IsExeAvailable.ForMode(mIsGluonMode);
  167. bool clientNeedsConfiguration = UnityConfigurationChecker.NeedsConfiguration();
  168. var welcomeView = GetWelcomeView();
  169. if (clientNeedsConfiguration && welcomeView.autoLoginState == AutoLogin.State.Off)
  170. {
  171. welcomeView.autoLoginState = AutoLogin.State.Started;
  172. }
  173. if (welcomeView.autoLoginState == AutoLogin.State.OrganizationChoosed)
  174. {
  175. OnEnable();
  176. welcomeView.autoLoginState = AutoLogin.State.InitializingPlastic;
  177. }
  178. if (NeedsToDisplayWelcomeView(clientNeedsConfiguration, mWkInfo))
  179. {
  180. welcomeView.OnGUI(clientNeedsConfiguration);
  181. return;
  182. }
  183. //TODO: Codice - beta: hide the switcher until the update dialog is implemented
  184. //DrawGuiModeSwitcher.ForMode(
  185. // isGluonMode, plasticClient, changesTreeView, editorWindow);
  186. DoTabToolbar(
  187. isPlasticExeAvailable,
  188. mWkInfo,
  189. mViewSwitcher,
  190. mShowDownloadPlasticExeWindow,
  191. mProcessExecutor,
  192. mIsGluonMode);
  193. mViewSwitcher.TabViewGUI();
  194. if (mWorkspaceWindow.IsOperationInProgress())
  195. DrawProgressForOperations.For(
  196. mWorkspaceWindow, mWorkspaceWindow.Progress,
  197. position.width);
  198. mStatusBar.OnGUI(
  199. mWkInfo,
  200. mWorkspaceWindow,
  201. mViewSwitcher,
  202. mViewSwitcher,
  203. mIncomingChangesNotifier,
  204. mIsGluonMode);
  205. }
  206. catch (Exception ex)
  207. {
  208. if (IsExitGUIException(ex))
  209. throw;
  210. GUI.enabled = true;
  211. if (IsIMGUIPaintException(ex))
  212. {
  213. ExceptionsHandler.LogException("PlasticWindow", ex);
  214. return;
  215. }
  216. mException = ex;
  217. DoExceptionErrorArea();
  218. ExceptionsHandler.HandleException("OnGUI", ex);
  219. }
  220. }
  221. void Update()
  222. {
  223. if (mException != null)
  224. return;
  225. if (mWkInfo == null)
  226. return;
  227. try
  228. {
  229. double currentUpdateTime = EditorApplication.timeSinceStartup;
  230. double elapsedSeconds = currentUpdateTime - mLastUpdateTime;
  231. mViewSwitcher.Update();
  232. mWorkspaceWindow.OnParentUpdated(elapsedSeconds);
  233. if (mWelcomeView != null)
  234. mWelcomeView.Update();
  235. mLastUpdateTime = currentUpdateTime;
  236. }
  237. catch (Exception ex)
  238. {
  239. mException = ex;
  240. ExceptionsHandler.HandleException("Update", ex);
  241. }
  242. }
  243. internal void InitializePlastic()
  244. {
  245. if (mForceToOpen)
  246. {
  247. mForceToOpen = false;
  248. return;
  249. }
  250. try
  251. {
  252. if (UnityConfigurationChecker.NeedsConfiguration())
  253. return;
  254. mWkInfo = FindWorkspace.InfoForApplicationPath(
  255. ApplicationDataPath.Get(), PlasticGui.Plastic.API);
  256. if (mWkInfo == null)
  257. return;
  258. PlasticPlugin.EnableForWorkspace();
  259. SetupCloudProjectIdIfNeeded(mWkInfo, PlasticGui.Plastic.API);
  260. DisableVCSIfEnabled(mWkInfo.ClientPath);
  261. mIsGluonMode = PlasticGui.Plastic.API.IsGluonWorkspace(mWkInfo);
  262. ViewHost viewHost = new ViewHost();
  263. mStatusBar = new StatusBar();
  264. mViewSwitcher = new ViewSwitcher(
  265. mWkInfo,
  266. viewHost,
  267. mIsGluonMode,
  268. PlasticPlugin.AssetStatusCache,
  269. mShowDownloadPlasticExeWindow,
  270. mProcessExecutor,
  271. PlasticPlugin.WorkspaceOperationsMonitor,
  272. mStatusBar,
  273. this);
  274. InitializeNewIncomingChanges(mWkInfo, mIsGluonMode, mViewSwitcher);
  275. mCooldownAutoRefreshPendingChangesAction = new CooldownWindowDelayer(
  276. mViewSwitcher.AutoRefreshPendingChangesView,
  277. UnityConstants.AUTO_REFRESH_PENDING_CHANGES_DELAYED_INTERVAL);
  278. mWorkspaceWindow = new WorkspaceWindow(
  279. mWkInfo,
  280. viewHost,
  281. mViewSwitcher,
  282. mViewSwitcher,
  283. mDeveloperNewIncomingChangesUpdater,
  284. this);
  285. mViewSwitcher.SetWorkspaceWindow(mWorkspaceWindow);
  286. mViewSwitcher.ShowInitialView();
  287. PlasticPlugin.WorkspaceOperationsMonitor.RegisterWindow(
  288. mWorkspaceWindow,
  289. viewHost,
  290. mDeveloperNewIncomingChangesUpdater);
  291. UnityStyles.Initialize(Repaint);
  292. AssetMenuItems.BuildOperations(
  293. mWkInfo,
  294. mWorkspaceWindow,
  295. mViewSwitcher,
  296. mViewSwitcher,
  297. viewHost,
  298. mDeveloperNewIncomingChangesUpdater,
  299. PlasticPlugin.AssetStatusCache,
  300. mViewSwitcher,
  301. mViewSwitcher,
  302. mShowDownloadPlasticExeWindow,
  303. this,
  304. mIsGluonMode);
  305. DrawInspectorOperations.BuildOperations(
  306. mWkInfo,
  307. mWorkspaceWindow,
  308. mViewSwitcher,
  309. mViewSwitcher,
  310. viewHost,
  311. mDeveloperNewIncomingChangesUpdater,
  312. PlasticPlugin.AssetStatusCache,
  313. mViewSwitcher,
  314. mViewSwitcher,
  315. mShowDownloadPlasticExeWindow,
  316. this,
  317. mIsGluonMode);
  318. mLastUpdateTime = EditorApplication.timeSinceStartup;
  319. mViewSwitcher.ShowBranchesViewIfNeeded();
  320. if (!EditionToken.IsCloudEdition())
  321. return;
  322. InitializeNotificationBarUpdater(
  323. mWkInfo, mStatusBar.NotificationBar);
  324. }
  325. catch (Exception ex)
  326. {
  327. mException = ex;
  328. ExceptionsHandler.HandleException("InitializePlastic", ex);
  329. }
  330. }
  331. void InitializeNewIncomingChanges(
  332. WorkspaceInfo wkInfo,
  333. bool bIsGluonMode,
  334. ViewSwitcher viewSwitcher)
  335. {
  336. if (bIsGluonMode)
  337. {
  338. Gluon.IncomingChangesNotifier gluonNotifier =
  339. new Gluon.IncomingChangesNotifier(this);
  340. mGluonNewIncomingChangesUpdater =
  341. NewIncomingChanges.BuildUpdaterForGluon(
  342. wkInfo, viewSwitcher, gluonNotifier, this, gluonNotifier,
  343. new GluonCheckIncomingChanges.CalculateIncomingChanges());
  344. mIncomingChangesNotifier = gluonNotifier;
  345. return;
  346. }
  347. Developer.IncomingChangesNotifier developerNotifier =
  348. new Developer.IncomingChangesNotifier(this);
  349. mDeveloperNewIncomingChangesUpdater =
  350. NewIncomingChanges.BuildUpdaterForDeveloper(
  351. wkInfo, viewSwitcher, developerNotifier,
  352. this, developerNotifier);
  353. mIncomingChangesNotifier = developerNotifier;
  354. }
  355. void InitializeNotificationBarUpdater(
  356. WorkspaceInfo wkInfo,
  357. INotificationBar notificationBar)
  358. {
  359. mNotificationBarUpdater = new NotificationBarUpdater(
  360. notificationBar,
  361. PlasticGui.Plastic.WebRestAPI,
  362. new UnityPlasticTimerBuilder(),
  363. new NotificationBarUpdater.NotificationBarConfig(),
  364. ScreenResolution.Get());
  365. mNotificationBarUpdater.Start();
  366. mNotificationBarUpdater.SetWorkspace(wkInfo);
  367. }
  368. void OnApplicationActivated()
  369. {
  370. if (mException != null)
  371. return;
  372. Reload.IfWorkspaceConfigChanged(
  373. PlasticGui.Plastic.API, mWkInfo, mIsGluonMode,
  374. ExecuteFullReload);
  375. if (mWkInfo == null)
  376. return;
  377. ((IWorkspaceWindow)mWorkspaceWindow).UpdateTitle();
  378. NewIncomingChanges.LaunchUpdater(
  379. mDeveloperNewIncomingChangesUpdater,
  380. mGluonNewIncomingChangesUpdater);
  381. // When Unity Editor window is activated it writes some files to its Temp folder.
  382. // This causes the fswatcher to process those events.
  383. // We need to wait until the fswatcher finishes processing the events,
  384. // otherwise the NewChangesInWk method will return TRUE, causing
  385. // the pending changes view to unwanted auto-refresh.
  386. // So, we need to delay the auto-refresh call in order
  387. // to give the fswatcher enough time to process the events.
  388. // Note that the OnFocus event is not affected by this issue.
  389. mCooldownAutoRefreshPendingChangesAction.Ping();
  390. mViewSwitcher.AutoRefreshIncomingChangesView();
  391. }
  392. void OnApplicationDeactivated()
  393. {
  394. if (mException != null)
  395. return;
  396. if (mWkInfo == null)
  397. return;
  398. NewIncomingChanges.StopUpdater(
  399. mDeveloperNewIncomingChangesUpdater,
  400. mGluonNewIncomingChangesUpdater);
  401. }
  402. void ExecuteFullReload()
  403. {
  404. mException = null;
  405. DisposeNewIncomingChanges(this);
  406. DisposeNotificationBarUpdater(this);
  407. InitializePlastic();
  408. }
  409. void DoExceptionErrorArea()
  410. {
  411. string labelText = PlasticLocalization.GetString(
  412. PlasticLocalization.Name.UnexpectedError);
  413. string buttonText = PlasticLocalization.GetString(
  414. PlasticLocalization.Name.ReloadButton);
  415. DrawActionHelpBox.For(
  416. Images.GetErrorDialogIcon(), labelText, buttonText,
  417. ExecuteFullReload);
  418. }
  419. internal WelcomeView GetWelcomeView()
  420. {
  421. if (mWelcomeView != null)
  422. return mWelcomeView;
  423. mWelcomeView = new WelcomeView(
  424. this,
  425. this,
  426. PlasticGui.Plastic.API,
  427. PlasticGui.Plastic.WebRestAPI,
  428. CmConnection.Get());
  429. return mWelcomeView;
  430. }
  431. static void DoSearchField(ViewSwitcher viewSwitcher)
  432. {
  433. if (viewSwitcher.IsViewSelected(ViewSwitcher.SelectedTab.PendingChanges))
  434. {
  435. viewSwitcher.PendingChangesTab.DrawSearchFieldForPendingChangesTab();
  436. return;
  437. }
  438. if (viewSwitcher.IsViewSelected(ViewSwitcher.SelectedTab.Changesets))
  439. {
  440. viewSwitcher.ChangesetsTab.DrawSearchFieldForChangesetsTab();
  441. return;
  442. }
  443. if (viewSwitcher.IsViewSelected(ViewSwitcher.SelectedTab.History))
  444. {
  445. viewSwitcher.HistoryTab.DrawSearchFieldForHistoryTab();
  446. return;
  447. }
  448. if (viewSwitcher.IsViewSelected(ViewSwitcher.SelectedTab.Branches))
  449. {
  450. viewSwitcher.BranchesTab.DrawSearchFieldForBranchesTab();
  451. return;
  452. }
  453. }
  454. static void DoTabToolbar(
  455. bool isPlasticExeAvailable,
  456. WorkspaceInfo workspaceInfo,
  457. ViewSwitcher viewSwitcher,
  458. LaunchTool.IShowDownloadPlasticExeWindow showDownloadPlasticExeWindow,
  459. LaunchTool.IProcessExecutor processExecutor,
  460. bool isGluonMode)
  461. {
  462. EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
  463. viewSwitcher.TabButtonsGUI();
  464. GUILayout.FlexibleSpace();
  465. DoSearchField(viewSwitcher);
  466. DoLaunchButtons(
  467. isPlasticExeAvailable,
  468. workspaceInfo,
  469. viewSwitcher,
  470. showDownloadPlasticExeWindow,
  471. processExecutor,
  472. isGluonMode);
  473. EditorGUILayout.EndHorizontal();
  474. }
  475. static void OpenBranchListViewAndSendEvent(
  476. WorkspaceInfo wkInfo,
  477. ViewSwitcher viewSwitcher)
  478. {
  479. viewSwitcher.ShowBranchesView();
  480. TrackFeatureUseEvent.For(
  481. PlasticGui.Plastic.API.GetRepositorySpec(wkInfo),
  482. TrackFeatureUseEvent.Features.OpenBranchesView);
  483. }
  484. static void ShowBranchesContextMenu(
  485. WorkspaceInfo wkInfo,
  486. ViewSwitcher viewSwitcher,
  487. LaunchTool.IShowDownloadPlasticExeWindow showDownloadPlasticExeWindow,
  488. LaunchTool.IProcessExecutor processExecutor,
  489. bool isGluonMode)
  490. {
  491. GenericMenu menu = new GenericMenu();
  492. string branchesListView = PlasticLocalization.GetString(
  493. PlasticLocalization.Name.Branches);
  494. menu.AddItem(
  495. new GUIContent(branchesListView),
  496. false,
  497. () => OpenBranchListViewAndSendEvent(wkInfo, viewSwitcher));
  498. string branchExplorer = PlasticLocalization.GetString(
  499. PlasticLocalization.Name.BranchExplorerMenu);
  500. menu.AddItem(
  501. new GUIContent(branchExplorer),
  502. false,
  503. () => LaunchTool.OpenBranchExplorer(
  504. showDownloadPlasticExeWindow,
  505. processExecutor,
  506. wkInfo,
  507. isGluonMode));
  508. menu.ShowAsContext();
  509. }
  510. static void ShowSettingsContextMenu(
  511. LaunchTool.IShowDownloadPlasticExeWindow showDownloadPlasticExeWindow,
  512. LaunchTool.IProcessExecutor processExecutor,
  513. WorkspaceInfo wkInfo,
  514. bool isGluonMode)
  515. {
  516. GenericMenu menu = new GenericMenu();
  517. string openToolText = isGluonMode ?
  518. PlasticLocalization.GetString(PlasticLocalization.Name.LaunchGluonButton) :
  519. PlasticLocalization.GetString(PlasticLocalization.Name.LaunchPlasticButton);
  520. menu.AddItem(
  521. new GUIContent(openToolText),
  522. false,
  523. () => LaunchTool.OpenGUIForMode(
  524. showDownloadPlasticExeWindow,
  525. processExecutor,
  526. wkInfo,
  527. isGluonMode));
  528. if (EditionToken.IsCloudEdition())
  529. {
  530. menu.AddItem(new GUIContent(
  531. PlasticLocalization.GetString(
  532. PlasticLocalization.Name.InviteMembers)),
  533. false,
  534. InviteMemberButton_clicked,
  535. PlasticGui.Plastic.API.GetRepositorySpec(wkInfo));
  536. }
  537. menu.AddSeparator("");
  538. menu.AddItem(
  539. new GUIContent(
  540. PlasticLocalization.GetString(
  541. PlasticLocalization.Name.Options)),
  542. false,
  543. () => SettingsService.OpenProjectSettings(UnityConstants.PROJECT_SETTINGS_TAB_PATH));
  544. // If the user has the simplified UI key of type .txt in the Assets folder
  545. // TODO: Remove when Simplified UI is complete
  546. if (AssetDatabase.FindAssets("simplifieduikey t:textasset", new[] { "Assets" }).Any())
  547. menu.AddItem(new GUIContent("Try Simplified UI"),
  548. false,
  549. TrySimplifiedUIButton_Clicked,
  550. null);
  551. //TODO: Localization
  552. menu.AddItem(
  553. new GUIContent(PlasticAssetModificationProcessor.ForceCheckout ?
  554. PlasticLocalization.GetString(PlasticLocalization.Name.DisableForcedCheckout) :
  555. PlasticLocalization.GetString(PlasticLocalization.Name.EnableForcedCheckout)),
  556. false,
  557. ForceCheckout_Clicked,
  558. null);
  559. menu.ShowAsContext();
  560. }
  561. static void DoLaunchButtons(
  562. bool isPlasticExeAvailable,
  563. WorkspaceInfo wkInfo,
  564. ViewSwitcher viewSwitcher,
  565. LaunchTool.IShowDownloadPlasticExeWindow showDownloadPlasticExeWindow,
  566. LaunchTool.IProcessExecutor processExecutor,
  567. bool isGluonMode)
  568. {
  569. //TODO: Codice - beta: hide the diff button until the behavior is implemented
  570. /*GUILayout.Button(PlasticLocalization.GetString(
  571. PlasticLocalization.Name.DiffWindowMenuItemDiff),
  572. EditorStyles.toolbarButton,
  573. GUILayout.Width(UnityConstants.REGULAR_BUTTON_WIDTH));*/
  574. if (viewSwitcher.IsViewSelected(ViewSwitcher.SelectedTab.Changesets))
  575. {
  576. viewSwitcher.ChangesetsTab.DrawDateFilter();
  577. }
  578. if (viewSwitcher.IsViewSelected(ViewSwitcher.SelectedTab.Branches))
  579. {
  580. viewSwitcher.BranchesTab.DrawDateFilter();
  581. }
  582. Texture refreshIcon = Images.GetRefreshIcon();
  583. string refreshIconTooltip = PlasticLocalization.GetString(
  584. PlasticLocalization.Name.RefreshButton);
  585. if (DrawLaunchButton(refreshIcon, refreshIconTooltip))
  586. {
  587. viewSwitcher.RefreshSelectedView();
  588. }
  589. if (viewSwitcher.IsViewSelected(ViewSwitcher.SelectedTab.PendingChanges))
  590. {
  591. Texture2D icon = Images.GetUndoIcon();
  592. string tooltip = PlasticLocalization.GetString(
  593. PlasticLocalization.Name.UndoSelectedChanges);
  594. if (DrawLaunchButton(icon, tooltip))
  595. {
  596. TrackFeatureUseEvent.For(
  597. PlasticGui.Plastic.API.GetRepositorySpec(wkInfo),
  598. TrackFeatureUseEvent.Features.UndoIconButton);
  599. viewSwitcher.PendingChangesTab.UndoForMode(wkInfo, isGluonMode);
  600. }
  601. }
  602. if (isGluonMode)
  603. {
  604. string label = PlasticLocalization.GetString(PlasticLocalization.Name.ConfigureGluon);
  605. if (DrawActionButton.For(label))
  606. LaunchTool.OpenWorkspaceConfiguration(
  607. showDownloadPlasticExeWindow,
  608. processExecutor,
  609. wkInfo,
  610. isGluonMode);
  611. }
  612. else
  613. {
  614. Texture2D icon = Images.GetBranchIcon();
  615. string tooltip = PlasticLocalization.GetString(PlasticLocalization.Name.Branches);
  616. if (DrawLaunchButton(icon, tooltip))
  617. {
  618. ShowBranchesContextMenu(
  619. wkInfo,
  620. viewSwitcher,
  621. showDownloadPlasticExeWindow,
  622. processExecutor,
  623. isGluonMode);
  624. }
  625. }
  626. //TODO: Add settings button tooltip localization
  627. if (DrawLaunchButton(Images.GetSettingsIcon(), string.Empty))
  628. {
  629. ShowSettingsContextMenu(
  630. showDownloadPlasticExeWindow,
  631. processExecutor,
  632. wkInfo,
  633. isGluonMode);
  634. }
  635. }
  636. static bool DrawLaunchButton(Texture icon, string tooltip)
  637. {
  638. return GUILayout.Button(
  639. new GUIContent(icon, tooltip),
  640. EditorStyles.toolbarButton,
  641. GUILayout.Width(26));
  642. }
  643. static void InviteMemberButton_clicked(object obj)
  644. {
  645. RepositorySpec repSpec = (RepositorySpec)obj;
  646. string organizationName = ServerOrganizationParser.
  647. GetOrganizationFromServer(repSpec.Server);
  648. CurrentUserAdminCheckResponse response = null;
  649. IThreadWaiter waiter = ThreadWaiter.GetWaiter(50);
  650. waiter.Execute(
  651. /*threadOperationDelegate*/
  652. delegate
  653. {
  654. ServerProfile serverProfile = CmConnection.Get().
  655. GetProfileManager().GetProfileForServer(repSpec.Server);
  656. string authToken = serverProfile != null ?
  657. CmConnection.Get().
  658. BuildWebApiTokenForCloudEditionForUser(
  659. serverProfile.Server,
  660. serverProfile.GetSEIDWorkingMode(),
  661. serverProfile.SecurityConfig):
  662. CmConnection.Get().
  663. BuildWebApiTokenForCloudEditionForUser(
  664. repSpec.Server,
  665. ClientConfig.Get().GetSEIDWorkingMode(),
  666. ClientConfig.Get().GetSecurityConfig());
  667. if (string.IsNullOrEmpty(authToken))
  668. authToken = CmConnection.Get().
  669. BuildWebApiTokenForCloudEditionDefaultUser();
  670. if (string.IsNullOrEmpty(authToken))
  671. {
  672. return;
  673. }
  674. response = WebRestApiClient.PlasticScm.IsUserAdmin(
  675. organizationName,
  676. authToken);
  677. },
  678. /*afterOperationDelegate*/
  679. delegate
  680. {
  681. if (waiter.Exception != null)
  682. {
  683. ExceptionsHandler.LogException(
  684. "IsUserAdmin",
  685. waiter.Exception);
  686. OpenCloudDashboardUsersGroupsUrl(organizationName);
  687. return;
  688. }
  689. if (response == null)
  690. {
  691. mLog.DebugFormat(
  692. "Error checking if the user is the organization admin for {0}",
  693. organizationName);
  694. OpenCloudDashboardUsersGroupsUrl(organizationName);
  695. return;
  696. }
  697. if (response.Error != null)
  698. {
  699. mLog.DebugFormat(
  700. "Error checking if the user is the organization admin: {0}",
  701. string.Format("Unable to get IsUserAdminResponse: {0} [code {1}]",
  702. response.Error.Message,
  703. response.Error.ErrorCode));
  704. OpenCloudDashboardUsersGroupsUrl(organizationName);
  705. return;
  706. }
  707. if (response.IsCurrentUserAdmin)
  708. {
  709. OpenCloudDashboardUsersGroupsUrl(response.OrganizationName);
  710. return;
  711. }
  712. GuiMessage.ShowInformation(
  713. PlasticLocalization.GetString(PlasticLocalization.Name.InviteMembersTitle),
  714. PlasticLocalization.GetString(PlasticLocalization.Name.InviteMembersMessage));
  715. });
  716. }
  717. static void OpenCloudDashboardUsersGroupsUrl(string organization)
  718. {
  719. Application.OpenURL("https://www.plasticscm.com/dashboard/cloud/" +
  720. organization +
  721. "/users-and-groups");
  722. }
  723. static void TrySimplifiedUIButton_Clicked(object obj)
  724. {
  725. PlasticSCMWindow.ShowWindow();
  726. }
  727. static void ForceCheckout_Clicked(object obj)
  728. {
  729. PlasticAssetModificationProcessor.SetForceCheckoutOption(
  730. !PlasticAssetModificationProcessor.ForceCheckout);
  731. }
  732. static void SetupCloudProjectIdIfNeeded(
  733. WorkspaceInfo wkInfo,
  734. IPlasticAPI plasticApi)
  735. {
  736. if (SetupCloudProjectId.HasCloudProjectId())
  737. return;
  738. SetupCloudProjectId.ForWorkspace(wkInfo, plasticApi);
  739. mLog.DebugFormat("Setup CloudProjectId on Project: {0}",
  740. wkInfo.ClientPath);
  741. }
  742. static void DisableVCSIfEnabled(string projectPath)
  743. {
  744. if (!VCSPlugin.IsEnabled())
  745. return;
  746. VCSPlugin.Disable();
  747. mLog.DebugFormat("Disabled VCS Plugin on Project: {0}",
  748. projectPath);
  749. }
  750. static void DisposeNewIncomingChanges(PlasticWindow window)
  751. {
  752. NewIncomingChanges.DisposeUpdater(
  753. window.mDeveloperNewIncomingChangesUpdater,
  754. window.mGluonNewIncomingChangesUpdater);
  755. window.mDeveloperNewIncomingChangesUpdater = null;
  756. window.mGluonNewIncomingChangesUpdater = null;
  757. }
  758. static void DisposeNotificationBarUpdater(PlasticWindow window)
  759. {
  760. if (window.mNotificationBarUpdater == null)
  761. return;
  762. window.mNotificationBarUpdater.Dispose();
  763. window.mNotificationBarUpdater = null;
  764. }
  765. static void RegisterApplicationFocusHandlers(PlasticWindow window)
  766. {
  767. EditorWindowFocus.OnApplicationActivated += window.OnApplicationActivated;
  768. EditorWindowFocus.OnApplicationDeactivated += window.OnApplicationDeactivated;
  769. }
  770. static void UnRegisterApplicationFocusHandlers(PlasticWindow window)
  771. {
  772. EditorWindowFocus.OnApplicationActivated -= window.OnApplicationActivated;
  773. EditorWindowFocus.OnApplicationDeactivated -= window.OnApplicationDeactivated;
  774. }
  775. static bool IsExitGUIException(Exception ex)
  776. {
  777. return ex is ExitGUIException;
  778. }
  779. static bool IsIMGUIPaintException(Exception ex)
  780. {
  781. if (!(ex is ArgumentException))
  782. return false;
  783. return ex.Message.StartsWith("Getting control") &&
  784. ex.Message.Contains("controls when doing repaint");
  785. }
  786. static void ClosePlasticWindow(PlasticWindow window)
  787. {
  788. UnRegisterApplicationFocusHandlers(window);
  789. if (PlasticPlugin.WorkspaceOperationsMonitor != null)
  790. PlasticPlugin.WorkspaceOperationsMonitor.UnRegisterWindow();
  791. DisposeNewIncomingChanges(window);
  792. DisposeNotificationBarUpdater(window);
  793. AvatarImages.Dispose();
  794. }
  795. static void ShowPlasticWindow(PlasticWindow window)
  796. {
  797. EditorWindow dockWindow = FindEditorWindow.ToDock<PlasticWindow>();
  798. PlasticWindow newPlasticWindow = InstantiateFrom(window);
  799. if (DockEditorWindow.IsAvailable())
  800. DockEditorWindow.To(dockWindow, newPlasticWindow);
  801. newPlasticWindow.Show();
  802. newPlasticWindow.Focus();
  803. }
  804. static bool NeedsToDisplayWelcomeView(
  805. bool clientNeedsConfiguration,
  806. WorkspaceInfo wkInfo)
  807. {
  808. if (clientNeedsConfiguration)
  809. return true;
  810. if (wkInfo == null)
  811. return true;
  812. return false;
  813. }
  814. static void DisableCollabIfEnabled(string projectPath)
  815. {
  816. if (!CollabPlugin.IsEnabled())
  817. return;
  818. CollabPlugin.Disable();
  819. mLog.DebugFormat("Disabled Collab Plugin on Project: {0}",
  820. projectPath);
  821. }
  822. static PlasticWindow InstantiateFrom(PlasticWindow window)
  823. {
  824. PlasticWindow result = Instantiate(window);
  825. result.mWkInfo = window.mWkInfo;
  826. result.mWorkspaceWindow = window.mWorkspaceWindow;
  827. result.mViewSwitcher = window.mViewSwitcher;
  828. result.mCooldownAutoRefreshPendingChangesAction = window.mCooldownAutoRefreshPendingChangesAction;
  829. result.mDeveloperNewIncomingChangesUpdater = window.mDeveloperNewIncomingChangesUpdater;
  830. result.mGluonNewIncomingChangesUpdater = window.mGluonNewIncomingChangesUpdater;
  831. result.mException = window.mException;
  832. result.mLastUpdateTime = window.mLastUpdateTime;
  833. result.mIsGluonMode = window.mIsGluonMode;
  834. result.mIncomingChangesNotifier = window.mIncomingChangesNotifier;
  835. result.mStatusBar = window.mStatusBar;
  836. result.mWelcomeView = window.mWelcomeView;
  837. result.mNotificationBarUpdater = window.mNotificationBarUpdater;
  838. return result;
  839. }
  840. internal PlasticProjectSettingsProvider.IAutoRefreshView GetPendingChangesView()
  841. {
  842. return mViewSwitcher != null ? mViewSwitcher.PendingChangesTab : null;
  843. }
  844. static class Reload
  845. {
  846. internal static void IfWorkspaceConfigChanged(
  847. IPlasticAPI plasticApi,
  848. WorkspaceInfo lastWkInfo,
  849. bool lastIsGluonMode,
  850. Action reloadAction)
  851. {
  852. string applicationPath = ApplicationDataPath.Get();
  853. bool isGluonMode = false;
  854. WorkspaceInfo wkInfo = null;
  855. IThreadWaiter waiter = ThreadWaiter.GetWaiter(10);
  856. waiter.Execute(
  857. /*threadOperationDelegate*/ delegate
  858. {
  859. wkInfo = FindWorkspace.
  860. InfoForApplicationPath(applicationPath, plasticApi);
  861. if (wkInfo != null)
  862. isGluonMode = plasticApi.IsGluonWorkspace(wkInfo);
  863. },
  864. /*afterOperationDelegate*/ delegate
  865. {
  866. if (waiter.Exception != null)
  867. return;
  868. if (!IsWorkspaceConfigChanged(
  869. lastWkInfo, wkInfo,
  870. lastIsGluonMode, isGluonMode))
  871. return;
  872. reloadAction();
  873. });
  874. }
  875. static bool IsWorkspaceConfigChanged(
  876. WorkspaceInfo lastWkInfo,
  877. WorkspaceInfo currentWkInfo,
  878. bool lastIsGluonMode,
  879. bool currentIsGluonMode)
  880. {
  881. if (lastIsGluonMode != currentIsGluonMode)
  882. return true;
  883. if (lastWkInfo == null || currentWkInfo == null)
  884. return true;
  885. return !lastWkInfo.Equals(currentWkInfo);
  886. }
  887. }
  888. [SerializeField]
  889. bool mForceToOpen;
  890. [NonSerialized]
  891. WorkspaceInfo mWkInfo;
  892. Exception mException;
  893. internal IIncomingChangesNotifier mIncomingChangesNotifier;
  894. double mLastUpdateTime = 0f;
  895. CooldownWindowDelayer mCooldownAutoRefreshPendingChangesAction;
  896. internal ViewSwitcher mViewSwitcher;
  897. WelcomeView mWelcomeView;
  898. StatusBar mStatusBar;
  899. NotificationBarUpdater mNotificationBarUpdater;
  900. PlasticGui.WorkspaceWindow.NewIncomingChangesUpdater mDeveloperNewIncomingChangesUpdater;
  901. GluonNewIncomingChangesUpdater mGluonNewIncomingChangesUpdater;
  902. WorkspaceWindow mWorkspaceWindow;
  903. bool mIsGluonMode;
  904. bool mDisableCollabIfEnabledWhenLoaded;
  905. LaunchTool.IShowDownloadPlasticExeWindow mShowDownloadPlasticExeWindow =
  906. new LaunchTool.ShowDownloadPlasticExeWindow();
  907. LaunchTool.IProcessExecutor mProcessExecutor =
  908. new LaunchTool.ProcessExecutor();
  909. static readonly ILog mLog = LogManager.GetLogger("PlasticWindow");
  910. }
  911. }