PlasticWindow.cs 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979
  1. using System;
  2. using UnityEditor;
  3. using UnityEngine;
  4. using Codice.Client.BaseCommands.EventTracking;
  5. using Codice.Client.Common;
  6. using Codice.Client.Common.Connection;
  7. using Codice.Client.Common.Encryption;
  8. using Codice.Client.Common.EventTracking;
  9. using Codice.Client.Common.FsNodeReaders;
  10. using Codice.Client.Common.FsNodeReaders.Watcher;
  11. using Codice.Client.Common.Threading;
  12. using Codice.CM.Common;
  13. using Codice.LogWrapper;
  14. using CodiceApp.EventTracking;
  15. using GluonGui;
  16. using PlasticGui;
  17. using PlasticGui.Gluon;
  18. using PlasticGui.WebApi;
  19. using Unity.PlasticSCM.Editor.AssetMenu;
  20. using Unity.PlasticSCM.Editor.AssetUtils;
  21. using Unity.PlasticSCM.Editor.AssetsOverlays.Cache;
  22. using Unity.PlasticSCM.Editor.AssetsOverlays;
  23. using Unity.PlasticSCM.Editor.AssetUtils.Processor;
  24. using Unity.PlasticSCM.Editor.Configuration;
  25. using Unity.PlasticSCM.Editor.Inspector;
  26. using Unity.PlasticSCM.Editor.Tool;
  27. using Unity.PlasticSCM.Editor.UI;
  28. using Unity.PlasticSCM.Editor.UI.Avatar;
  29. using Unity.PlasticSCM.Editor.UI.Progress;
  30. using Unity.PlasticSCM.Editor.Views.CreateWorkspace;
  31. using Unity.PlasticSCM.Editor.Views.Welcome;
  32. using GluonCheckIncomingChanges = PlasticGui.Gluon.WorkspaceWindow.CheckIncomingChanges;
  33. using GluonNewIncomingChangesUpdater = PlasticGui.Gluon.WorkspaceWindow.NewIncomingChangesUpdater;
  34. using EventTracking = PlasticGui.EventTracking.EventTracking;
  35. using System.Linq;
  36. using Unity.PlasticSCM.Editor.Configuration.CloudEdition.Welcome;
  37. using Unity.PlasticSCM.Editor.Views.PendingChanges.Dialogs;
  38. namespace Unity.PlasticSCM.Editor
  39. {
  40. internal class PlasticWindow : EditorWindow,
  41. PlasticGui.WorkspaceWindow.CheckIncomingChanges.IAutoRefreshIncomingChangesView,
  42. GluonCheckIncomingChanges.IAutoRefreshIncomingChangesView,
  43. CreateWorkspaceView.ICreateWorkspaceListener
  44. {
  45. internal WorkspaceWindow WorkspaceWindowForTesting { get { return mWorkspaceWindow; } }
  46. internal ViewSwitcher ViewSwitcherForTesting { get { return mViewSwitcher; } }
  47. internal IPlasticAPI PlasticApiForTesting { get { return mPlasticAPI; } }
  48. internal IPlasticWebRestApi PlasticWebRestApiForTesting { get { return mPlasticWebRestApi; } }
  49. internal CmConnection CmConnectionForTesting { get { return CmConnection.Get(); } }
  50. internal void SetupWindowTitle(bool hasNotification)
  51. {
  52. titleContent = new GUIContent(
  53. UnityConstants.PLASTIC_WINDOW_TITLE,
  54. hasNotification ?
  55. Images.GetImage(Images.Name.IconPlasticViewNotify) :
  56. Images.GetImage(Images.Name.IconPlasticView));
  57. }
  58. internal void DisableCollabIfEnabledWhenLoaded()
  59. {
  60. mDisableCollabIfEnabledWhenLoaded = true;
  61. }
  62. internal void ShowPendingChanges()
  63. {
  64. mAssetOperations.ShowPendingChanges();
  65. }
  66. internal void Add()
  67. {
  68. mAssetOperations.Add();
  69. }
  70. internal void Checkout()
  71. {
  72. mAssetOperations.Checkout();
  73. }
  74. internal void Checkin()
  75. {
  76. mAssetOperations.Checkin();
  77. }
  78. internal void Undo()
  79. {
  80. mAssetOperations.Undo();
  81. }
  82. internal void ShowDiff()
  83. {
  84. mAssetOperations.ShowDiff();
  85. }
  86. internal void ShowHistory()
  87. {
  88. mAssetOperations.ShowHistory();
  89. }
  90. void PlasticGui.WorkspaceWindow.CheckIncomingChanges.IAutoRefreshIncomingChangesView.IfVisible()
  91. {
  92. mViewSwitcher.AutoRefreshIncomingChangesView();
  93. }
  94. void GluonCheckIncomingChanges.IAutoRefreshIncomingChangesView.IfVisible()
  95. {
  96. mViewSwitcher.AutoRefreshIncomingChangesView();
  97. }
  98. void CreateWorkspaceView.ICreateWorkspaceListener.OnWorkspaceCreated(
  99. WorkspaceInfo wkInfo, bool isGluonMode)
  100. {
  101. mWkInfo = wkInfo;
  102. mIsGluonMode = isGluonMode;
  103. mWelcomeView = null;
  104. if (mIsGluonMode)
  105. ConfigurePartialWorkspace.AsFullyChecked(mWkInfo);
  106. InitializePlastic();
  107. Repaint();
  108. }
  109. internal void RefreshWorkspaceUI()
  110. {
  111. InitializePlastic();
  112. Repaint();
  113. OnFocus();
  114. }
  115. void OnEnable()
  116. {
  117. wantsMouseMove = true;
  118. if (mException != null)
  119. return;
  120. minSize = new Vector2(
  121. UnityConstants.PLASTIC_WINDOW_MIN_SIZE_WIDTH,
  122. UnityConstants.PLASTIC_WINDOW_MIN_SIZE_HEIGHT);
  123. SetupWindowTitle(false);
  124. GuiMessage.Initialize(new UnityPlasticGuiMessage(this));
  125. PlasticApp.InitializeIfNeeded();
  126. RegisterApplicationFocusHandlers(this);
  127. PlasticMethodExceptionHandling.InitializeAskCredentialsUi(
  128. new CredentialsUiImpl(this));
  129. ClientEncryptionServiceProvider.SetEncryptionPasswordProvider(
  130. new MissingEncryptionPasswordPromptHandler(this));
  131. mPlasticAPI = new PlasticAPI();
  132. mPlasticWebRestApi = new PlasticWebRestApi();
  133. mEventSenderScheduler = EventTracking.Configure(
  134. mPlasticWebRestApi,
  135. AssetsPath.IsRunningAsUPMPackage() ?
  136. ApplicationIdentifier.UnityPackage : ApplicationIdentifier.UnityAssetStorePlugin,
  137. IdentifyEventPlatform.Get());
  138. if (mEventSenderScheduler != null)
  139. {
  140. mPingEventLoop = new PingEventLoop();
  141. mPingEventLoop.Start();
  142. mPingEventLoop.SetUnityVersion(Application.unityVersion);
  143. }
  144. InitializePlastic();
  145. }
  146. void OnDisable()
  147. {
  148. AssetsProcessors.Disable();
  149. if (mWkInfo != null)
  150. {
  151. MonoFileSystemWatcher.IsEnabled = false;
  152. WorkspaceFsNodeReaderCachesCleaner.CleanWorkspaceFsNodeReader(mWkInfo);
  153. }
  154. if (mException != null)
  155. return;
  156. if (mWkInfo == null)
  157. {
  158. ClosePlasticWindow(this);
  159. return;
  160. }
  161. mViewSwitcher.OnDisable();
  162. ClosePlasticWindow(this);
  163. }
  164. void OnDestroy()
  165. {
  166. if (mException != null)
  167. return;
  168. if (mWkInfo == null)
  169. return;
  170. if (!mWorkspaceWindow.IsOperationInProgress())
  171. return;
  172. bool bCloseWindow = GuiMessage.ShowQuestion(
  173. PlasticLocalization.GetString(PlasticLocalization.Name.OperationRunning),
  174. PlasticLocalization.GetString(PlasticLocalization.Name.ConfirmClosingRunningOperation),
  175. PlasticLocalization.GetString(PlasticLocalization.Name.YesButton));
  176. if (bCloseWindow)
  177. return;
  178. mForceToOpen = true;
  179. ShowPlasticWindow(this);
  180. }
  181. void OnFocus()
  182. {
  183. if (mException != null)
  184. return;
  185. if (mWkInfo == null)
  186. return;
  187. mViewSwitcher.AutoRefreshPendingChangesView();
  188. mViewSwitcher.AutoRefreshIncomingChangesView();
  189. }
  190. void OnGUI()
  191. {
  192. if (mException != null)
  193. {
  194. DoExceptionErrorArea();
  195. return;
  196. }
  197. try
  198. {
  199. // IMPORTANT: disable collab (if needed)
  200. // must be executed before the next if statement
  201. // where we check if collab is enabled
  202. if (mDisableCollabIfEnabledWhenLoaded)
  203. {
  204. mDisableCollabIfEnabledWhenLoaded = false;
  205. DisableCollabIfEnabled(ProjectPath.FromApplicationDataPath(
  206. Application.dataPath));
  207. }
  208. if (CollabPlugin.IsEnabled())
  209. {
  210. // execute Close() once after all inspectors update
  211. // to avoid our window to be drawn in back color
  212. EditorApplication.delayCall = Close;
  213. return;
  214. }
  215. bool isPlasticExeAvailable = IsExeAvailable.ForMode(mIsGluonMode);
  216. bool clientNeedsConfiguration = UnityConfigurationChecker.NeedsConfiguration();
  217. var welcomeView = GetWelcomeView();
  218. if (clientNeedsConfiguration && welcomeView.autoLoginState == AutoLogin.State.Off)
  219. {
  220. welcomeView.autoLoginState = AutoLogin.State.Started;
  221. }
  222. if (welcomeView.autoLoginState == AutoLogin.State.OrganizationChoosed)
  223. {
  224. OnEnable();
  225. welcomeView.autoLoginState = AutoLogin.State.InitializingPlastic;
  226. }
  227. if (NeedsToDisplayWelcomeView(clientNeedsConfiguration, mWkInfo))
  228. {
  229. welcomeView.OnGUI(clientNeedsConfiguration);
  230. return;
  231. }
  232. DoHeader(
  233. mWkInfo,
  234. mWorkspaceWindow,
  235. mViewSwitcher,
  236. mViewSwitcher,
  237. mIsGluonMode,
  238. mIncomingChangesNotificationPanel);
  239. DoTabToolbar(
  240. isPlasticExeAvailable,
  241. mWkInfo,
  242. mViewSwitcher,
  243. mIsGluonMode);
  244. mViewSwitcher.TabViewGUI();
  245. if (mWorkspaceWindow.IsOperationInProgress())
  246. DrawProgressForOperations.For(
  247. mWorkspaceWindow, mWorkspaceWindow.Progress,
  248. position.width);
  249. mNotificationDrawer.DoDrawer();
  250. }
  251. catch (Exception ex)
  252. {
  253. if (IsExitGUIException(ex))
  254. throw;
  255. GUI.enabled = true;
  256. if (IsIMGUIPaintException(ex))
  257. {
  258. ExceptionsHandler.LogException("PlasticWindow", ex);
  259. return;
  260. }
  261. mException = ex;
  262. DoExceptionErrorArea();
  263. ExceptionsHandler.HandleException("OnGUI", ex);
  264. }
  265. }
  266. void Update()
  267. {
  268. if (mException != null)
  269. return;
  270. if (mWkInfo == null)
  271. return;
  272. try
  273. {
  274. double currentUpdateTime = EditorApplication.timeSinceStartup;
  275. double elapsedSeconds = currentUpdateTime - mLastUpdateTime;
  276. mViewSwitcher.Update();
  277. mWorkspaceWindow.OnParentUpdated(elapsedSeconds);
  278. if (mWelcomeView != null)
  279. mWelcomeView.Update();
  280. mLastUpdateTime = currentUpdateTime;
  281. }
  282. catch (Exception ex)
  283. {
  284. mException = ex;
  285. ExceptionsHandler.HandleException("Update", ex);
  286. }
  287. }
  288. internal void InitializePlastic()
  289. {
  290. if (mForceToOpen)
  291. {
  292. mForceToOpen = false;
  293. return;
  294. }
  295. try
  296. {
  297. if (UnityConfigurationChecker.NeedsConfiguration())
  298. return;
  299. mWkInfo = FindWorkspace.InfoForApplicationPath(
  300. Application.dataPath, mPlasticAPI);
  301. if (mWkInfo == null)
  302. {
  303. return;
  304. }
  305. MonoFileSystemWatcher.IsEnabled = true;
  306. SetupCloudProjectIdIfNeeded(mWkInfo, mPlasticAPI);
  307. DisableVCSIfEnabled(mWkInfo.ClientPath);
  308. mIsGluonMode = mPlasticAPI.IsGluonWorkspace(mWkInfo);
  309. IAssetStatusCache assetStatusCache =
  310. new AssetStatusCache(
  311. mWkInfo,
  312. mIsGluonMode,
  313. RepaintProjectWindow);
  314. AssetsProcessors.Enable(
  315. mPlasticAPI,
  316. assetStatusCache);
  317. if (mEventSenderScheduler != null)
  318. {
  319. mPingEventLoop.SetWorkspace(mWkInfo);
  320. ((IPlasticWebRestApi)mPlasticWebRestApi).SetToken(
  321. CmConnection.Get().BuildWebApiTokenForCloudEditionDefaultUser());
  322. }
  323. InitializeNewIncomingChanges(mWkInfo, mIsGluonMode);
  324. ViewHost viewHost = new ViewHost();
  325. PlasticGui.WorkspaceWindow.PendingChanges.PendingChanges pendingChanges =
  326. new PlasticGui.WorkspaceWindow.PendingChanges.PendingChanges(mWkInfo);
  327. mViewSwitcher = new ViewSwitcher(
  328. mWkInfo,
  329. viewHost,
  330. mIsGluonMode,
  331. pendingChanges,
  332. mDeveloperNewIncomingChangesUpdater,
  333. mGluonNewIncomingChangesUpdater,
  334. mIncomingChangesNotificationPanel,
  335. assetStatusCache,
  336. mNotificationDrawer,
  337. this);
  338. mCooldownAutoRefreshPendingChangesAction = new CooldownWindowDelayer(
  339. mViewSwitcher.AutoRefreshPendingChangesView,
  340. UnityConstants.AUTO_REFRESH_PENDING_CHANGES_DELAYED_INTERVAL);
  341. mWorkspaceWindow = new WorkspaceWindow(
  342. mWkInfo,
  343. viewHost,
  344. mViewSwitcher,
  345. mViewSwitcher,
  346. mDeveloperNewIncomingChangesUpdater,
  347. this);
  348. mViewSwitcher.SetWorkspaceWindow(mWorkspaceWindow);
  349. mViewSwitcher.ShowInitialView();
  350. UnityStyles.Initialize(Repaint);
  351. AssetOperations.IAssetSelection inspectorAssetSelection =
  352. new InspectorAssetSelection();
  353. AssetOperations.IAssetSelection projectViewAssetSelection =
  354. new ProjectViewAssetSelection();
  355. AssetOperations inspectorAssetOperations =
  356. new AssetOperations(
  357. mWkInfo,
  358. mWorkspaceWindow,
  359. mViewSwitcher,
  360. mViewSwitcher,
  361. viewHost,
  362. mDeveloperNewIncomingChangesUpdater,
  363. assetStatusCache,
  364. mViewSwitcher,
  365. mViewSwitcher,
  366. this,
  367. inspectorAssetSelection,
  368. mIsGluonMode);
  369. mAssetOperations =
  370. new AssetOperations(
  371. mWkInfo,
  372. mWorkspaceWindow,
  373. mViewSwitcher,
  374. mViewSwitcher,
  375. viewHost,
  376. mDeveloperNewIncomingChangesUpdater,
  377. assetStatusCache,
  378. mViewSwitcher,
  379. mViewSwitcher,
  380. this,
  381. projectViewAssetSelection,
  382. mIsGluonMode);
  383. DrawInspectorOperations.Enable(
  384. inspectorAssetOperations,
  385. assetStatusCache,
  386. inspectorAssetSelection);
  387. DrawAssetOverlay.Initialize(
  388. assetStatusCache,
  389. RepaintProjectWindow);
  390. mLastUpdateTime = EditorApplication.timeSinceStartup;
  391. }
  392. catch (Exception ex)
  393. {
  394. mException = ex;
  395. ExceptionsHandler.HandleException("InitializePlastic", ex);
  396. }
  397. }
  398. void InitializeNewIncomingChanges(
  399. WorkspaceInfo wkInfo,
  400. bool bIsGluonMode)
  401. {
  402. if (bIsGluonMode)
  403. {
  404. Gluon.IncomingChangesNotificationPanel gluonPanel =
  405. new Gluon.IncomingChangesNotificationPanel(this);
  406. mGluonNewIncomingChangesUpdater =
  407. NewIncomingChanges.BuildUpdaterForGluon(
  408. wkInfo,
  409. this,
  410. gluonPanel,
  411. new GluonCheckIncomingChanges.CalculateIncomingChanges());
  412. mIncomingChangesNotificationPanel = gluonPanel;
  413. return;
  414. }
  415. Developer.IncomingChangesNotificationPanel developerPanel =
  416. new Developer.IncomingChangesNotificationPanel(this);
  417. mDeveloperNewIncomingChangesUpdater =
  418. NewIncomingChanges.BuildUpdaterForDeveloper(
  419. wkInfo, this, developerPanel);
  420. mIncomingChangesNotificationPanel = developerPanel;
  421. }
  422. void OnApplicationActivated()
  423. {
  424. if (mException != null)
  425. return;
  426. Reload.IfWorkspaceConfigChanged(
  427. mPlasticAPI, mWkInfo, mIsGluonMode,
  428. ExecuteFullReload);
  429. if (mWkInfo == null)
  430. return;
  431. ((IWorkspaceWindow)mWorkspaceWindow).UpdateTitle();
  432. NewIncomingChanges.LaunchUpdater(
  433. mDeveloperNewIncomingChangesUpdater,
  434. mGluonNewIncomingChangesUpdater);
  435. // When Unity Editor window is activated it writes some files to its Temp folder.
  436. // This causes the fswatcher to process those events.
  437. // We need to wait until the fswatcher finishes processing the events,
  438. // otherwise the NewChangesInWk method will return TRUE, causing
  439. // the pending changes view to unwanted auto-refresh.
  440. // So, we need to delay the auto-refresh call in order
  441. // to give the fswatcher enough time to process the events.
  442. // Note that the OnFocus event is not affected by this issue.
  443. mCooldownAutoRefreshPendingChangesAction.Ping();
  444. mViewSwitcher.AutoRefreshIncomingChangesView();
  445. }
  446. void OnApplicationDeactivated()
  447. {
  448. if (mException != null)
  449. return;
  450. if (mWkInfo == null)
  451. return;
  452. NewIncomingChanges.StopUpdater(
  453. mDeveloperNewIncomingChangesUpdater,
  454. mGluonNewIncomingChangesUpdater);
  455. }
  456. void ExecuteFullReload()
  457. {
  458. mException = null;
  459. DisposeNewIncomingChanges(this);
  460. InitializePlastic();
  461. }
  462. void DoExceptionErrorArea()
  463. {
  464. string labelText = PlasticLocalization.GetString(
  465. PlasticLocalization.Name.UnexpectedError);
  466. string buttonText = PlasticLocalization.GetString(
  467. PlasticLocalization.Name.ReloadButton);
  468. DrawActionHelpBox.For(
  469. Images.GetErrorDialogIcon(), labelText, buttonText,
  470. ExecuteFullReload);
  471. }
  472. internal WelcomeView GetWelcomeView()
  473. {
  474. if (mWelcomeView != null)
  475. return mWelcomeView;
  476. mWelcomeView = new WelcomeView(
  477. this,
  478. this,
  479. mPlasticAPI,
  480. CmConnection.Get(),
  481. mPlasticWebRestApi);
  482. return mWelcomeView;
  483. }
  484. static void DoHeader(
  485. WorkspaceInfo workspaceInfo,
  486. WorkspaceWindow workspaceWindow,
  487. IMergeViewLauncher mergeViewLauncher,
  488. IGluonViewSwitcher gluonSwitcher,
  489. bool isGluonMode,
  490. IIncomingChangesNotificationPanel incomingChangesNotificationPanel)
  491. {
  492. EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
  493. GUILayout.Label(
  494. workspaceWindow.HeaderTitle,
  495. UnityStyles.PlasticWindow.HeaderTitleLabel);
  496. GUILayout.FlexibleSpace();
  497. DrawIncomingChangesNotificationPanel.ForMode(
  498. workspaceInfo, workspaceWindow,
  499. mergeViewLauncher, gluonSwitcher, isGluonMode,
  500. incomingChangesNotificationPanel.IsVisible,
  501. incomingChangesNotificationPanel.Data);
  502. //TODO: Codice - beta: hide the switcher until the update dialog is implemented
  503. //DrawGuiModeSwitcher.ForMode(
  504. // isGluonMode, plasticClient, changesTreeView, editorWindow);
  505. EditorGUILayout.EndHorizontal();
  506. }
  507. static void DoTabToolbar(
  508. bool isPlasticExeAvailable,
  509. WorkspaceInfo workspaceInfo,
  510. ViewSwitcher viewSwitcher,
  511. bool isGluonMode)
  512. {
  513. EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
  514. viewSwitcher.TabButtonsGUI();
  515. GUILayout.FlexibleSpace();
  516. DoLaunchButtons(isPlasticExeAvailable, workspaceInfo, isGluonMode);
  517. EditorGUILayout.EndHorizontal();
  518. }
  519. static void DoLaunchButtons(
  520. bool isPlasticExeAvailable,
  521. WorkspaceInfo wkInfo,
  522. bool isGluonMode)
  523. {
  524. //TODO: Codice - beta: hide the diff button until the behavior is implemented
  525. /*GUILayout.Button(PlasticLocalization.GetString(
  526. PlasticLocalization.Name.DiffWindowMenuItemDiff),
  527. EditorStyles.toolbarButton,
  528. GUILayout.Width(UnityConstants.REGULAR_BUTTON_WIDTH));*/
  529. if (isGluonMode)
  530. {
  531. var label = PlasticLocalization.GetString(PlasticLocalization.Name.ConfigureGluon);
  532. if (DrawActionButton.For(label))
  533. LaunchTool.OpenWorkspaceConfiguration(wkInfo, isGluonMode);
  534. }
  535. else
  536. {
  537. var label = PlasticLocalization.GetString(PlasticLocalization.Name.LaunchBranchExplorer);
  538. if (DrawActionButton.For(label))
  539. LaunchTool.OpenBranchExplorer(wkInfo, isGluonMode);
  540. }
  541. if (GUILayout.Button(new GUIContent(
  542. EditorGUIUtility.IconContent("settings")), EditorStyles.toolbarButton))
  543. {
  544. GenericMenu menu = new GenericMenu();
  545. string openToolText = isGluonMode ?
  546. PlasticLocalization.GetString(PlasticLocalization.Name.LaunchGluonButton) :
  547. PlasticLocalization.GetString(PlasticLocalization.Name.LaunchPlasticButton);
  548. menu.AddItem(
  549. new GUIContent(openToolText),
  550. false,
  551. () => LaunchTool.OpenGUIForMode(wkInfo, isGluonMode));
  552. var plasticWindow = EditorWindow.GetWindow<PlasticWindow>();
  553. menu.AddItem(
  554. new GUIContent(
  555. PlasticLocalization.GetString(
  556. PlasticLocalization.Name.Options)),
  557. false,
  558. () => PendingChangesOptionsDialog.ChangeOptions(wkInfo, PlasticAssetsProcessor.mPendingChangesTab, plasticWindow));
  559. menu.AddItem(
  560. new GUIContent(
  561. PlasticLocalization.GetString(
  562. PlasticLocalization.Name.InviteMembers)),
  563. false,
  564. InviteMemberButton_clicked,
  565. null);
  566. // If the user has the simplified UI key of type .txt in the Assets folder
  567. // TODO: Remove when Simplified UI is complete
  568. if (AssetDatabase.FindAssets("simplifieduikey t:textasset", new[] { "Assets" }).Any())
  569. menu.AddItem(new GUIContent("Try Simplified UI"),
  570. false,
  571. TrySimplifiedUIButton_Clicked,
  572. null);
  573. menu.AddSeparator("");
  574. menu.AddItem(
  575. new GUIContent(
  576. PlasticLocalization.GetString(
  577. PlasticLocalization.Name.TurnOffPlasticSCM)),
  578. false,
  579. TurnOffPlasticButton_Clicked,
  580. null);
  581. menu.ShowAsContext();
  582. }
  583. }
  584. static void InviteMemberButton_clicked(object obj)
  585. {
  586. Application.OpenURL("https://www.plasticscm.com/dashboard/cloud/unity_cloud/users-and-groups");
  587. }
  588. static void TrySimplifiedUIButton_Clicked(object obj)
  589. {
  590. PlasticSCMWindow.ShowWindow();
  591. }
  592. static void TurnOffPlasticButton_Clicked(object obj)
  593. {
  594. ShowWindow.Plastic();
  595. TurnOffPlasticWindow.ShowWindow();
  596. }
  597. static void SetupCloudProjectIdIfNeeded(
  598. WorkspaceInfo wkInfo,
  599. IPlasticAPI plasticApi)
  600. {
  601. if (SetupCloudProjectId.HasCloudProjectId())
  602. return;
  603. SetupCloudProjectId.ForWorkspace(wkInfo, plasticApi);
  604. mLog.DebugFormat("Setup CloudProjectId on Project: {0}",
  605. wkInfo.ClientPath);
  606. }
  607. static void DisableVCSIfEnabled(string projectPath)
  608. {
  609. if (!VCSPlugin.IsEnabled())
  610. return;
  611. VCSPlugin.Disable();
  612. mLog.DebugFormat("Disabled VCS Plugin on Project: {0}",
  613. projectPath);
  614. }
  615. static void DisposeNewIncomingChanges(PlasticWindow window)
  616. {
  617. NewIncomingChanges.DisposeUpdater(
  618. window.mDeveloperNewIncomingChangesUpdater,
  619. window.mGluonNewIncomingChangesUpdater);
  620. window.mDeveloperNewIncomingChangesUpdater = null;
  621. window.mGluonNewIncomingChangesUpdater = null;
  622. }
  623. static void RegisterApplicationFocusHandlers(PlasticWindow window)
  624. {
  625. EditorWindowFocus.OnApplicationActivated += window.OnApplicationActivated;
  626. EditorWindowFocus.OnApplicationDeactivated += window.OnApplicationDeactivated;
  627. }
  628. static void UnRegisterApplicationFocusHandlers(PlasticWindow window)
  629. {
  630. EditorWindowFocus.OnApplicationActivated -= window.OnApplicationActivated;
  631. EditorWindowFocus.OnApplicationDeactivated -= window.OnApplicationDeactivated;
  632. }
  633. static bool IsExitGUIException(Exception ex)
  634. {
  635. return ex is ExitGUIException;
  636. }
  637. static bool IsIMGUIPaintException(Exception ex)
  638. {
  639. if (!(ex is ArgumentException))
  640. return false;
  641. return ex.Message.StartsWith("Getting control") &&
  642. ex.Message.Contains("controls when doing repaint");
  643. }
  644. static void ClosePlasticWindow(PlasticWindow window)
  645. {
  646. UnRegisterApplicationFocusHandlers(window);
  647. PlasticApp.Dispose();
  648. DrawInspectorOperations.Disable();
  649. DrawAssetOverlay.Dispose();
  650. if (window.mEventSenderScheduler != null)
  651. {
  652. window.mPingEventLoop.Stop();
  653. window.mEventSenderScheduler.End();
  654. }
  655. DisposeNewIncomingChanges(window);
  656. AvatarImages.Dispose();
  657. }
  658. static void ShowPlasticWindow(PlasticWindow window)
  659. {
  660. EditorWindow dockWindow = FindEditorWindow.ToDock<PlasticWindow>();
  661. PlasticWindow newPlasticWindow = InstantiateFrom(window);
  662. if (DockEditorWindow.IsAvailable())
  663. DockEditorWindow.To(dockWindow, newPlasticWindow);
  664. newPlasticWindow.Show();
  665. newPlasticWindow.Focus();
  666. }
  667. static bool NeedsToDisplayWelcomeView(
  668. bool clientNeedsConfiguration,
  669. WorkspaceInfo wkInfo)
  670. {
  671. if (clientNeedsConfiguration)
  672. return true;
  673. if (wkInfo == null)
  674. return true;
  675. return false;
  676. }
  677. static void RepaintProjectWindow()
  678. {
  679. EditorWindow projectWindow = FindEditorWindow.ProjectWindow();
  680. if (projectWindow == null)
  681. return;
  682. projectWindow.Repaint();
  683. }
  684. static void DisableCollabIfEnabled(string projectPath)
  685. {
  686. if (!CollabPlugin.IsEnabled())
  687. return;
  688. CollabPlugin.Disable();
  689. mLog.DebugFormat("Disabled Collab Plugin on Project: {0}",
  690. projectPath);
  691. }
  692. static PlasticWindow InstantiateFrom(PlasticWindow window)
  693. {
  694. PlasticWindow result = Instantiate(window);
  695. result.mWkInfo = window.mWkInfo;
  696. result.mWorkspaceWindow = window.mWorkspaceWindow;
  697. result.mViewSwitcher = window.mViewSwitcher;
  698. result.mCooldownAutoRefreshPendingChangesAction = window.mCooldownAutoRefreshPendingChangesAction;
  699. result.mDeveloperNewIncomingChangesUpdater = window.mDeveloperNewIncomingChangesUpdater;
  700. result.mGluonNewIncomingChangesUpdater = window.mGluonNewIncomingChangesUpdater;
  701. result.mException = window.mException;
  702. result.mLastUpdateTime = window.mLastUpdateTime;
  703. result.mIsGluonMode = window.mIsGluonMode;
  704. result.mIncomingChangesNotificationPanel = window.mIncomingChangesNotificationPanel;
  705. result.mWelcomeView = window.mWelcomeView;
  706. result.mPlasticAPI = window.mPlasticAPI;
  707. result.mEventSenderScheduler = window.mEventSenderScheduler;
  708. result.mPingEventLoop = window.mPingEventLoop;
  709. return result;
  710. }
  711. static class Reload
  712. {
  713. internal static void IfWorkspaceConfigChanged(
  714. IPlasticAPI plasticApi,
  715. WorkspaceInfo lastWkInfo,
  716. bool lastIsGluonMode,
  717. Action reloadAction)
  718. {
  719. string applicationPath = Application.dataPath;
  720. bool isGluonMode = false;
  721. WorkspaceInfo wkInfo = null;
  722. IThreadWaiter waiter = ThreadWaiter.GetWaiter(10);
  723. waiter.Execute(
  724. /*threadOperationDelegate*/ delegate
  725. {
  726. wkInfo = FindWorkspace.
  727. InfoForApplicationPath(applicationPath, plasticApi);
  728. if (wkInfo != null)
  729. isGluonMode = plasticApi.IsGluonWorkspace(wkInfo);
  730. },
  731. /*afterOperationDelegate*/ delegate
  732. {
  733. if (waiter.Exception != null)
  734. return;
  735. if (!IsWorkspaceConfigChanged(
  736. lastWkInfo, wkInfo,
  737. lastIsGluonMode, isGluonMode))
  738. return;
  739. reloadAction();
  740. });
  741. }
  742. static bool IsWorkspaceConfigChanged(
  743. WorkspaceInfo lastWkInfo,
  744. WorkspaceInfo currentWkInfo,
  745. bool lastIsGluonMode,
  746. bool currentIsGluonMode)
  747. {
  748. if (lastIsGluonMode != currentIsGluonMode)
  749. return true;
  750. if (lastWkInfo == null || currentWkInfo == null)
  751. return true;
  752. return !lastWkInfo.Equals(currentWkInfo);
  753. }
  754. }
  755. [SerializeField]
  756. bool mForceToOpen;
  757. [NonSerialized]
  758. WorkspaceInfo mWkInfo;
  759. Exception mException;
  760. IIncomingChangesNotificationPanel mIncomingChangesNotificationPanel;
  761. double mLastUpdateTime = 0f;
  762. CooldownWindowDelayer mCooldownAutoRefreshPendingChangesAction;
  763. ViewSwitcher mViewSwitcher;
  764. WelcomeView mWelcomeView;
  765. internal NotificationDrawer mNotificationDrawer = new NotificationDrawer();
  766. PlasticGui.WorkspaceWindow.NewIncomingChangesUpdater mDeveloperNewIncomingChangesUpdater;
  767. GluonNewIncomingChangesUpdater mGluonNewIncomingChangesUpdater;
  768. WorkspaceWindow mWorkspaceWindow;
  769. bool mIsGluonMode;
  770. bool mDisableCollabIfEnabledWhenLoaded;
  771. PlasticAPI mPlasticAPI;
  772. static PlasticWebRestApi mPlasticWebRestApi;
  773. EventSenderScheduler mEventSenderScheduler;
  774. PingEventLoop mPingEventLoop;
  775. IAssetMenuOperations mAssetOperations;
  776. static readonly ILog mLog = LogManager.GetLogger("PlasticWindow");
  777. }
  778. }