using System; using System.Linq; using UnityEditor; using UnityEngine; using Codice.Client.BaseCommands; using Codice.Client.BaseCommands.EventTracking; using Codice.Client.Common; using Codice.Client.Common.FsNodeReaders.Watcher; using Codice.Client.Common.Threading; using Codice.CM.Common; using Codice.LogWrapper; using GluonGui; using PlasticGui; using PlasticGui.WorkspaceWindow.NotificationBar; using Unity.PlasticSCM.Editor.AssetMenu; using Unity.PlasticSCM.Editor.AssetUtils; using Unity.PlasticSCM.Editor.Configuration; using Unity.PlasticSCM.Editor.Configuration.CloudEdition.Welcome; using Unity.PlasticSCM.Editor.Inspector; using Unity.PlasticSCM.Editor.Tool; using Unity.PlasticSCM.Editor.UI; using Unity.PlasticSCM.Editor.UI.Avatar; using Unity.PlasticSCM.Editor.UI.Progress; using Unity.PlasticSCM.Editor.UI.StatusBar; using Unity.PlasticSCM.Editor.Views.CreateWorkspace; using Unity.PlasticSCM.Editor.Views.Welcome; using Unity.PlasticSCM.Editor.WebApi; using GluonCheckIncomingChanges = PlasticGui.Gluon.WorkspaceWindow.CheckIncomingChanges; using GluonNewIncomingChangesUpdater = PlasticGui.Gluon.WorkspaceWindow.NewIncomingChangesUpdater; using PlasticAssetModificationProcessor = Unity.PlasticSCM.Editor.AssetUtils.Processor.AssetModificationProcessor; namespace Unity.PlasticSCM.Editor { /// /// The Plastic SCM window. /// public class PlasticWindow : EditorWindow, PlasticGui.WorkspaceWindow.CheckIncomingChanges.IAutoRefreshIncomingChangesView, GluonCheckIncomingChanges.IAutoRefreshIncomingChangesView, CreateWorkspaceView.ICreateWorkspaceListener { internal WorkspaceWindow WorkspaceWindowForTesting { get { return mWorkspaceWindow; } } internal ViewSwitcher ViewSwitcherForTesting { get { return mViewSwitcher; } } internal CmConnection CmConnectionForTesting { get { return CmConnection.Get(); } } /// /// Open the Plastic SCM window. /// public static void Open() { ShowWindow.Plastic(); } internal void SetupWindowTitle(PlasticNotification.Status status) { Texture windowIcon = PlasticNotification.GetIcon(status); // The titleContent icon does not update unless we also update the title text // Temporarily doing it by adding space characters string title = UnityConstants.PLASTIC_WINDOW_TITLE; title += String.Concat(Enumerable.Repeat(" ", (int)status)); titleContent = new GUIContent(title, windowIcon); } internal void DisableCollabIfEnabledWhenLoaded() { mDisableCollabIfEnabledWhenLoaded = true; } void PlasticGui.WorkspaceWindow.CheckIncomingChanges.IAutoRefreshIncomingChangesView.IfVisible() { mViewSwitcher.AutoRefreshIncomingChangesView(); } void GluonCheckIncomingChanges.IAutoRefreshIncomingChangesView.IfVisible() { mViewSwitcher.AutoRefreshIncomingChangesView(); } void CreateWorkspaceView.ICreateWorkspaceListener.OnWorkspaceCreated( WorkspaceInfo wkInfo, bool isGluonMode) { mWkInfo = wkInfo; mIsGluonMode = isGluonMode; mWelcomeView = null; PlasticPlugin.Enable(); if (mIsGluonMode) ConfigurePartialWorkspace.AsFullyChecked(mWkInfo); InitializePlastic(); Repaint(); } internal void RefreshWorkspaceUI() { InitializePlastic(); Repaint(); OnFocus(); } void OnEnable() { PlasticPlugin.Enable(); wantsMouseMove = true; if (mException != null) return; minSize = new Vector2( UnityConstants.PLASTIC_WINDOW_MIN_SIZE_WIDTH, UnityConstants.PLASTIC_WINDOW_MIN_SIZE_HEIGHT); SetupWindowTitle(PlasticNotification.Status.None); RegisterApplicationFocusHandlers(this); InitializePlastic(); } void OnDisable() { // We need to disable FSWatcher because otherwise it hangs // when you move the window between monitors with different scale MonoFileSystemWatcher.IsEnabled = false; if (mException != null) return; if (mWkInfo == null) { ClosePlasticWindow(this); return; } mViewSwitcher.OnDisable(); ClosePlasticWindow(this); } void OnDestroy() { if (mException != null) return; if (mWkInfo == null) return; if (!mWorkspaceWindow.IsOperationInProgress()) return; bool bCloseWindow = GuiMessage.ShowQuestion( PlasticLocalization.GetString(PlasticLocalization.Name.OperationRunning), PlasticLocalization.GetString(PlasticLocalization.Name.ConfirmClosingRunningOperation), PlasticLocalization.GetString(PlasticLocalization.Name.YesButton)); if (bCloseWindow) return; mForceToOpen = true; ShowPlasticWindow(this); } void OnFocus() { if (mException != null) return; if (mWkInfo == null) return; // We don't want to auto-refresh the views when the window // is focused due to a right mouse button click because // if there is no internet connection a dialog appears and // it prevents being able to open the context menu in order // to close the Plastic SCM window if (Mouse.IsRightMouseButtonPressed(Event.current)) return; mViewSwitcher.AutoRefreshPendingChangesView(); mViewSwitcher.AutoRefreshIncomingChangesView(); } void OnGUI() { if (mException != null) { DoExceptionErrorArea(); return; } try { // IMPORTANT: disable collab (if needed) // must be executed before the next if statement // where we check if collab is enabled if (mDisableCollabIfEnabledWhenLoaded) { mDisableCollabIfEnabledWhenLoaded = false; DisableCollabIfEnabled(ProjectPath.FromApplicationDataPath( ApplicationDataPath.Get())); } if (CollabPlugin.IsEnabled()) { // execute Close() once after all inspectors update // to avoid our window to be drawn in back color EditorApplication.delayCall = Close; return; } bool isPlasticExeAvailable = IsExeAvailable.ForMode(mIsGluonMode); bool clientNeedsConfiguration = UnityConfigurationChecker.NeedsConfiguration(); var welcomeView = GetWelcomeView(); if (clientNeedsConfiguration && welcomeView.autoLoginState == AutoLogin.State.Off) { welcomeView.autoLoginState = AutoLogin.State.Started; } if (welcomeView.autoLoginState == AutoLogin.State.OrganizationChoosed) { OnEnable(); welcomeView.autoLoginState = AutoLogin.State.InitializingPlastic; } if (NeedsToDisplayWelcomeView(clientNeedsConfiguration, mWkInfo)) { welcomeView.OnGUI(clientNeedsConfiguration); return; } //TODO: Codice - beta: hide the switcher until the update dialog is implemented //DrawGuiModeSwitcher.ForMode( // isGluonMode, plasticClient, changesTreeView, editorWindow); DoTabToolbar( isPlasticExeAvailable, mWkInfo, mViewSwitcher, mShowDownloadPlasticExeWindow, mProcessExecutor, mIsGluonMode); mViewSwitcher.TabViewGUI(); if (mWorkspaceWindow.IsOperationInProgress()) DrawProgressForOperations.For( mWorkspaceWindow, mWorkspaceWindow.Progress, position.width); mStatusBar.OnGUI( mWkInfo, mWorkspaceWindow, mViewSwitcher, mViewSwitcher, mIncomingChangesNotifier, mIsGluonMode); } catch (Exception ex) { if (IsExitGUIException(ex)) throw; GUI.enabled = true; if (IsIMGUIPaintException(ex)) { ExceptionsHandler.LogException("PlasticWindow", ex); return; } mException = ex; DoExceptionErrorArea(); ExceptionsHandler.HandleException("OnGUI", ex); } } void Update() { if (mException != null) return; if (mWkInfo == null) return; try { double currentUpdateTime = EditorApplication.timeSinceStartup; double elapsedSeconds = currentUpdateTime - mLastUpdateTime; mViewSwitcher.Update(); mWorkspaceWindow.OnParentUpdated(elapsedSeconds); if (mWelcomeView != null) mWelcomeView.Update(); mLastUpdateTime = currentUpdateTime; } catch (Exception ex) { mException = ex; ExceptionsHandler.HandleException("Update", ex); } } internal void InitializePlastic() { if (mForceToOpen) { mForceToOpen = false; return; } try { if (UnityConfigurationChecker.NeedsConfiguration()) return; mWkInfo = FindWorkspace.InfoForApplicationPath( ApplicationDataPath.Get(), PlasticGui.Plastic.API); if (mWkInfo == null) return; PlasticPlugin.EnableForWorkspace(); SetupCloudProjectIdIfNeeded(mWkInfo, PlasticGui.Plastic.API); DisableVCSIfEnabled(mWkInfo.ClientPath); mIsGluonMode = PlasticGui.Plastic.API.IsGluonWorkspace(mWkInfo); ViewHost viewHost = new ViewHost(); mStatusBar = new StatusBar(); mViewSwitcher = new ViewSwitcher( mWkInfo, viewHost, mIsGluonMode, PlasticPlugin.AssetStatusCache, mShowDownloadPlasticExeWindow, mProcessExecutor, PlasticPlugin.WorkspaceOperationsMonitor, mStatusBar, this); InitializeNewIncomingChanges(mWkInfo, mIsGluonMode, mViewSwitcher); mCooldownAutoRefreshPendingChangesAction = new CooldownWindowDelayer( mViewSwitcher.AutoRefreshPendingChangesView, UnityConstants.AUTO_REFRESH_PENDING_CHANGES_DELAYED_INTERVAL); mWorkspaceWindow = new WorkspaceWindow( mWkInfo, viewHost, mViewSwitcher, mViewSwitcher, mDeveloperNewIncomingChangesUpdater, this); mViewSwitcher.SetWorkspaceWindow(mWorkspaceWindow); mViewSwitcher.ShowInitialView(); PlasticPlugin.WorkspaceOperationsMonitor.RegisterWindow( mWorkspaceWindow, viewHost, mDeveloperNewIncomingChangesUpdater); UnityStyles.Initialize(Repaint); AssetMenuItems.BuildOperations( mWkInfo, mWorkspaceWindow, mViewSwitcher, mViewSwitcher, viewHost, mDeveloperNewIncomingChangesUpdater, PlasticPlugin.AssetStatusCache, mViewSwitcher, mViewSwitcher, mShowDownloadPlasticExeWindow, this, mIsGluonMode); DrawInspectorOperations.BuildOperations( mWkInfo, mWorkspaceWindow, mViewSwitcher, mViewSwitcher, viewHost, mDeveloperNewIncomingChangesUpdater, PlasticPlugin.AssetStatusCache, mViewSwitcher, mViewSwitcher, mShowDownloadPlasticExeWindow, this, mIsGluonMode); mLastUpdateTime = EditorApplication.timeSinceStartup; mViewSwitcher.ShowBranchesViewIfNeeded(); if (!EditionToken.IsCloudEdition()) return; InitializeNotificationBarUpdater( mWkInfo, mStatusBar.NotificationBar); } catch (Exception ex) { mException = ex; ExceptionsHandler.HandleException("InitializePlastic", ex); } } void InitializeNewIncomingChanges( WorkspaceInfo wkInfo, bool bIsGluonMode, ViewSwitcher viewSwitcher) { if (bIsGluonMode) { Gluon.IncomingChangesNotifier gluonNotifier = new Gluon.IncomingChangesNotifier(this); mGluonNewIncomingChangesUpdater = NewIncomingChanges.BuildUpdaterForGluon( wkInfo, viewSwitcher, gluonNotifier, this, gluonNotifier, new GluonCheckIncomingChanges.CalculateIncomingChanges()); mIncomingChangesNotifier = gluonNotifier; return; } Developer.IncomingChangesNotifier developerNotifier = new Developer.IncomingChangesNotifier(this); mDeveloperNewIncomingChangesUpdater = NewIncomingChanges.BuildUpdaterForDeveloper( wkInfo, viewSwitcher, developerNotifier, this, developerNotifier); mIncomingChangesNotifier = developerNotifier; } void InitializeNotificationBarUpdater( WorkspaceInfo wkInfo, INotificationBar notificationBar) { mNotificationBarUpdater = new NotificationBarUpdater( notificationBar, PlasticGui.Plastic.WebRestAPI, new UnityPlasticTimerBuilder(), new NotificationBarUpdater.NotificationBarConfig(), ScreenResolution.Get()); mNotificationBarUpdater.Start(); mNotificationBarUpdater.SetWorkspace(wkInfo); } void OnApplicationActivated() { if (mException != null) return; Reload.IfWorkspaceConfigChanged( PlasticGui.Plastic.API, mWkInfo, mIsGluonMode, ExecuteFullReload); if (mWkInfo == null) return; ((IWorkspaceWindow)mWorkspaceWindow).UpdateTitle(); NewIncomingChanges.LaunchUpdater( mDeveloperNewIncomingChangesUpdater, mGluonNewIncomingChangesUpdater); // When Unity Editor window is activated it writes some files to its Temp folder. // This causes the fswatcher to process those events. // We need to wait until the fswatcher finishes processing the events, // otherwise the NewChangesInWk method will return TRUE, causing // the pending changes view to unwanted auto-refresh. // So, we need to delay the auto-refresh call in order // to give the fswatcher enough time to process the events. // Note that the OnFocus event is not affected by this issue. mCooldownAutoRefreshPendingChangesAction.Ping(); mViewSwitcher.AutoRefreshIncomingChangesView(); } void OnApplicationDeactivated() { if (mException != null) return; if (mWkInfo == null) return; NewIncomingChanges.StopUpdater( mDeveloperNewIncomingChangesUpdater, mGluonNewIncomingChangesUpdater); } void ExecuteFullReload() { mException = null; DisposeNewIncomingChanges(this); DisposeNotificationBarUpdater(this); InitializePlastic(); } void DoExceptionErrorArea() { string labelText = PlasticLocalization.GetString( PlasticLocalization.Name.UnexpectedError); string buttonText = PlasticLocalization.GetString( PlasticLocalization.Name.ReloadButton); DrawActionHelpBox.For( Images.GetErrorDialogIcon(), labelText, buttonText, ExecuteFullReload); } internal WelcomeView GetWelcomeView() { if (mWelcomeView != null) return mWelcomeView; mWelcomeView = new WelcomeView( this, this, PlasticGui.Plastic.API, PlasticGui.Plastic.WebRestAPI, CmConnection.Get()); return mWelcomeView; } static void DoSearchField(ViewSwitcher viewSwitcher) { if (viewSwitcher.IsViewSelected(ViewSwitcher.SelectedTab.PendingChanges)) { viewSwitcher.PendingChangesTab.DrawSearchFieldForPendingChangesTab(); return; } if (viewSwitcher.IsViewSelected(ViewSwitcher.SelectedTab.Changesets)) { viewSwitcher.ChangesetsTab.DrawSearchFieldForChangesetsTab(); return; } if (viewSwitcher.IsViewSelected(ViewSwitcher.SelectedTab.History)) { viewSwitcher.HistoryTab.DrawSearchFieldForHistoryTab(); return; } if (viewSwitcher.IsViewSelected(ViewSwitcher.SelectedTab.Branches)) { viewSwitcher.BranchesTab.DrawSearchFieldForBranchesTab(); return; } } static void DoTabToolbar( bool isPlasticExeAvailable, WorkspaceInfo workspaceInfo, ViewSwitcher viewSwitcher, LaunchTool.IShowDownloadPlasticExeWindow showDownloadPlasticExeWindow, LaunchTool.IProcessExecutor processExecutor, bool isGluonMode) { EditorGUILayout.BeginHorizontal(EditorStyles.toolbar); viewSwitcher.TabButtonsGUI(); GUILayout.FlexibleSpace(); DoSearchField(viewSwitcher); DoLaunchButtons( isPlasticExeAvailable, workspaceInfo, viewSwitcher, showDownloadPlasticExeWindow, processExecutor, isGluonMode); EditorGUILayout.EndHorizontal(); } static void OpenBranchListViewAndSendEvent( WorkspaceInfo wkInfo, ViewSwitcher viewSwitcher) { viewSwitcher.ShowBranchesView(); TrackFeatureUseEvent.For( PlasticGui.Plastic.API.GetRepositorySpec(wkInfo), TrackFeatureUseEvent.Features.OpenBranchesView); } static void ShowBranchesContextMenu( WorkspaceInfo wkInfo, ViewSwitcher viewSwitcher, LaunchTool.IShowDownloadPlasticExeWindow showDownloadPlasticExeWindow, LaunchTool.IProcessExecutor processExecutor, bool isGluonMode) { GenericMenu menu = new GenericMenu(); string branchesListView = PlasticLocalization.GetString( PlasticLocalization.Name.Branches); menu.AddItem( new GUIContent(branchesListView), false, () => OpenBranchListViewAndSendEvent(wkInfo, viewSwitcher)); string branchExplorer = PlasticLocalization.GetString( PlasticLocalization.Name.BranchExplorerMenu); menu.AddItem( new GUIContent(branchExplorer), false, () => LaunchTool.OpenBranchExplorer( showDownloadPlasticExeWindow, processExecutor, wkInfo, isGluonMode)); menu.ShowAsContext(); } static void ShowSettingsContextMenu( LaunchTool.IShowDownloadPlasticExeWindow showDownloadPlasticExeWindow, LaunchTool.IProcessExecutor processExecutor, WorkspaceInfo wkInfo, bool isGluonMode) { GenericMenu menu = new GenericMenu(); string openToolText = isGluonMode ? PlasticLocalization.GetString(PlasticLocalization.Name.LaunchGluonButton) : PlasticLocalization.GetString(PlasticLocalization.Name.LaunchPlasticButton); menu.AddItem( new GUIContent(openToolText), false, () => LaunchTool.OpenGUIForMode( showDownloadPlasticExeWindow, processExecutor, wkInfo, isGluonMode)); if (EditionToken.IsCloudEdition()) { menu.AddItem(new GUIContent( PlasticLocalization.GetString( PlasticLocalization.Name.InviteMembers)), false, InviteMemberButton_clicked, PlasticGui.Plastic.API.GetRepositorySpec(wkInfo)); } menu.AddSeparator(""); menu.AddItem( new GUIContent( PlasticLocalization.GetString( PlasticLocalization.Name.Options)), false, () => SettingsService.OpenProjectSettings(UnityConstants.PROJECT_SETTINGS_TAB_PATH)); // If the user has the simplified UI key of type .txt in the Assets folder // TODO: Remove when Simplified UI is complete if (AssetDatabase.FindAssets("simplifieduikey t:textasset", new[] { "Assets" }).Any()) menu.AddItem(new GUIContent("Try Simplified UI"), false, TrySimplifiedUIButton_Clicked, null); //TODO: Localization menu.AddItem( new GUIContent(PlasticAssetModificationProcessor.ForceCheckout ? PlasticLocalization.GetString(PlasticLocalization.Name.DisableForcedCheckout) : PlasticLocalization.GetString(PlasticLocalization.Name.EnableForcedCheckout)), false, ForceCheckout_Clicked, null); menu.ShowAsContext(); } static void DoLaunchButtons( bool isPlasticExeAvailable, WorkspaceInfo wkInfo, ViewSwitcher viewSwitcher, LaunchTool.IShowDownloadPlasticExeWindow showDownloadPlasticExeWindow, LaunchTool.IProcessExecutor processExecutor, bool isGluonMode) { //TODO: Codice - beta: hide the diff button until the behavior is implemented /*GUILayout.Button(PlasticLocalization.GetString( PlasticLocalization.Name.DiffWindowMenuItemDiff), EditorStyles.toolbarButton, GUILayout.Width(UnityConstants.REGULAR_BUTTON_WIDTH));*/ if (viewSwitcher.IsViewSelected(ViewSwitcher.SelectedTab.Changesets)) { viewSwitcher.ChangesetsTab.DrawDateFilter(); } if (viewSwitcher.IsViewSelected(ViewSwitcher.SelectedTab.Branches)) { viewSwitcher.BranchesTab.DrawDateFilter(); } Texture refreshIcon = Images.GetRefreshIcon(); string refreshIconTooltip = PlasticLocalization.GetString( PlasticLocalization.Name.RefreshButton); if (DrawLaunchButton(refreshIcon, refreshIconTooltip)) { viewSwitcher.RefreshSelectedView(); } if (viewSwitcher.IsViewSelected(ViewSwitcher.SelectedTab.PendingChanges)) { Texture2D icon = Images.GetUndoIcon(); string tooltip = PlasticLocalization.GetString( PlasticLocalization.Name.UndoSelectedChanges); if (DrawLaunchButton(icon, tooltip)) { TrackFeatureUseEvent.For( PlasticGui.Plastic.API.GetRepositorySpec(wkInfo), TrackFeatureUseEvent.Features.UndoIconButton); viewSwitcher.PendingChangesTab.UndoForMode(wkInfo, isGluonMode); } } if (isGluonMode) { string label = PlasticLocalization.GetString(PlasticLocalization.Name.ConfigureGluon); if (DrawActionButton.For(label)) LaunchTool.OpenWorkspaceConfiguration( showDownloadPlasticExeWindow, processExecutor, wkInfo, isGluonMode); } else { Texture2D icon = Images.GetBranchIcon(); string tooltip = PlasticLocalization.GetString(PlasticLocalization.Name.Branches); if (DrawLaunchButton(icon, tooltip)) { ShowBranchesContextMenu( wkInfo, viewSwitcher, showDownloadPlasticExeWindow, processExecutor, isGluonMode); } } //TODO: Add settings button tooltip localization if (DrawLaunchButton(Images.GetSettingsIcon(), string.Empty)) { ShowSettingsContextMenu( showDownloadPlasticExeWindow, processExecutor, wkInfo, isGluonMode); } } static bool DrawLaunchButton(Texture icon, string tooltip) { return GUILayout.Button( new GUIContent(icon, tooltip), EditorStyles.toolbarButton, GUILayout.Width(26)); } static void InviteMemberButton_clicked(object obj) { RepositorySpec repSpec = (RepositorySpec)obj; string organizationName = ServerOrganizationParser. GetOrganizationFromServer(repSpec.Server); CurrentUserAdminCheckResponse response = null; IThreadWaiter waiter = ThreadWaiter.GetWaiter(50); waiter.Execute( /*threadOperationDelegate*/ delegate { ServerProfile serverProfile = CmConnection.Get(). GetProfileManager().GetProfileForServer(repSpec.Server); string authToken = serverProfile != null ? CmConnection.Get(). BuildWebApiTokenForCloudEditionForUser( serverProfile.Server, serverProfile.GetSEIDWorkingMode(), serverProfile.SecurityConfig): CmConnection.Get(). BuildWebApiTokenForCloudEditionForUser( repSpec.Server, ClientConfig.Get().GetSEIDWorkingMode(), ClientConfig.Get().GetSecurityConfig()); if (string.IsNullOrEmpty(authToken)) authToken = CmConnection.Get(). BuildWebApiTokenForCloudEditionDefaultUser(); if (string.IsNullOrEmpty(authToken)) { return; } response = WebRestApiClient.PlasticScm.IsUserAdmin( organizationName, authToken); }, /*afterOperationDelegate*/ delegate { if (waiter.Exception != null) { ExceptionsHandler.LogException( "IsUserAdmin", waiter.Exception); OpenCloudDashboardUsersGroupsUrl(organizationName); return; } if (response == null) { mLog.DebugFormat( "Error checking if the user is the organization admin for {0}", organizationName); OpenCloudDashboardUsersGroupsUrl(organizationName); return; } if (response.Error != null) { mLog.DebugFormat( "Error checking if the user is the organization admin: {0}", string.Format("Unable to get IsUserAdminResponse: {0} [code {1}]", response.Error.Message, response.Error.ErrorCode)); OpenCloudDashboardUsersGroupsUrl(organizationName); return; } if (response.IsCurrentUserAdmin) { OpenCloudDashboardUsersGroupsUrl(response.OrganizationName); return; } GuiMessage.ShowInformation( PlasticLocalization.GetString(PlasticLocalization.Name.InviteMembersTitle), PlasticLocalization.GetString(PlasticLocalization.Name.InviteMembersMessage)); }); } static void OpenCloudDashboardUsersGroupsUrl(string organization) { Application.OpenURL("https://www.plasticscm.com/dashboard/cloud/" + organization + "/users-and-groups"); } static void TrySimplifiedUIButton_Clicked(object obj) { PlasticSCMWindow.ShowWindow(); } static void ForceCheckout_Clicked(object obj) { PlasticAssetModificationProcessor.SetForceCheckoutOption( !PlasticAssetModificationProcessor.ForceCheckout); } static void SetupCloudProjectIdIfNeeded( WorkspaceInfo wkInfo, IPlasticAPI plasticApi) { if (SetupCloudProjectId.HasCloudProjectId()) return; SetupCloudProjectId.ForWorkspace(wkInfo, plasticApi); mLog.DebugFormat("Setup CloudProjectId on Project: {0}", wkInfo.ClientPath); } static void DisableVCSIfEnabled(string projectPath) { if (!VCSPlugin.IsEnabled()) return; VCSPlugin.Disable(); mLog.DebugFormat("Disabled VCS Plugin on Project: {0}", projectPath); } static void DisposeNewIncomingChanges(PlasticWindow window) { NewIncomingChanges.DisposeUpdater( window.mDeveloperNewIncomingChangesUpdater, window.mGluonNewIncomingChangesUpdater); window.mDeveloperNewIncomingChangesUpdater = null; window.mGluonNewIncomingChangesUpdater = null; } static void DisposeNotificationBarUpdater(PlasticWindow window) { if (window.mNotificationBarUpdater == null) return; window.mNotificationBarUpdater.Dispose(); window.mNotificationBarUpdater = null; } static void RegisterApplicationFocusHandlers(PlasticWindow window) { EditorWindowFocus.OnApplicationActivated += window.OnApplicationActivated; EditorWindowFocus.OnApplicationDeactivated += window.OnApplicationDeactivated; } static void UnRegisterApplicationFocusHandlers(PlasticWindow window) { EditorWindowFocus.OnApplicationActivated -= window.OnApplicationActivated; EditorWindowFocus.OnApplicationDeactivated -= window.OnApplicationDeactivated; } static bool IsExitGUIException(Exception ex) { return ex is ExitGUIException; } static bool IsIMGUIPaintException(Exception ex) { if (!(ex is ArgumentException)) return false; return ex.Message.StartsWith("Getting control") && ex.Message.Contains("controls when doing repaint"); } static void ClosePlasticWindow(PlasticWindow window) { UnRegisterApplicationFocusHandlers(window); if (PlasticPlugin.WorkspaceOperationsMonitor != null) PlasticPlugin.WorkspaceOperationsMonitor.UnRegisterWindow(); DisposeNewIncomingChanges(window); DisposeNotificationBarUpdater(window); AvatarImages.Dispose(); } static void ShowPlasticWindow(PlasticWindow window) { EditorWindow dockWindow = FindEditorWindow.ToDock(); PlasticWindow newPlasticWindow = InstantiateFrom(window); if (DockEditorWindow.IsAvailable()) DockEditorWindow.To(dockWindow, newPlasticWindow); newPlasticWindow.Show(); newPlasticWindow.Focus(); } static bool NeedsToDisplayWelcomeView( bool clientNeedsConfiguration, WorkspaceInfo wkInfo) { if (clientNeedsConfiguration) return true; if (wkInfo == null) return true; return false; } static void DisableCollabIfEnabled(string projectPath) { if (!CollabPlugin.IsEnabled()) return; CollabPlugin.Disable(); mLog.DebugFormat("Disabled Collab Plugin on Project: {0}", projectPath); } static PlasticWindow InstantiateFrom(PlasticWindow window) { PlasticWindow result = Instantiate(window); result.mWkInfo = window.mWkInfo; result.mWorkspaceWindow = window.mWorkspaceWindow; result.mViewSwitcher = window.mViewSwitcher; result.mCooldownAutoRefreshPendingChangesAction = window.mCooldownAutoRefreshPendingChangesAction; result.mDeveloperNewIncomingChangesUpdater = window.mDeveloperNewIncomingChangesUpdater; result.mGluonNewIncomingChangesUpdater = window.mGluonNewIncomingChangesUpdater; result.mException = window.mException; result.mLastUpdateTime = window.mLastUpdateTime; result.mIsGluonMode = window.mIsGluonMode; result.mIncomingChangesNotifier = window.mIncomingChangesNotifier; result.mStatusBar = window.mStatusBar; result.mWelcomeView = window.mWelcomeView; result.mNotificationBarUpdater = window.mNotificationBarUpdater; return result; } internal PlasticProjectSettingsProvider.IAutoRefreshView GetPendingChangesView() { return mViewSwitcher != null ? mViewSwitcher.PendingChangesTab : null; } static class Reload { internal static void IfWorkspaceConfigChanged( IPlasticAPI plasticApi, WorkspaceInfo lastWkInfo, bool lastIsGluonMode, Action reloadAction) { string applicationPath = ApplicationDataPath.Get(); bool isGluonMode = false; WorkspaceInfo wkInfo = null; IThreadWaiter waiter = ThreadWaiter.GetWaiter(10); waiter.Execute( /*threadOperationDelegate*/ delegate { wkInfo = FindWorkspace. InfoForApplicationPath(applicationPath, plasticApi); if (wkInfo != null) isGluonMode = plasticApi.IsGluonWorkspace(wkInfo); }, /*afterOperationDelegate*/ delegate { if (waiter.Exception != null) return; if (!IsWorkspaceConfigChanged( lastWkInfo, wkInfo, lastIsGluonMode, isGluonMode)) return; reloadAction(); }); } static bool IsWorkspaceConfigChanged( WorkspaceInfo lastWkInfo, WorkspaceInfo currentWkInfo, bool lastIsGluonMode, bool currentIsGluonMode) { if (lastIsGluonMode != currentIsGluonMode) return true; if (lastWkInfo == null || currentWkInfo == null) return true; return !lastWkInfo.Equals(currentWkInfo); } } [SerializeField] bool mForceToOpen; [NonSerialized] WorkspaceInfo mWkInfo; Exception mException; internal IIncomingChangesNotifier mIncomingChangesNotifier; double mLastUpdateTime = 0f; CooldownWindowDelayer mCooldownAutoRefreshPendingChangesAction; internal ViewSwitcher mViewSwitcher; WelcomeView mWelcomeView; StatusBar mStatusBar; NotificationBarUpdater mNotificationBarUpdater; PlasticGui.WorkspaceWindow.NewIncomingChangesUpdater mDeveloperNewIncomingChangesUpdater; GluonNewIncomingChangesUpdater mGluonNewIncomingChangesUpdater; WorkspaceWindow mWorkspaceWindow; bool mIsGluonMode; bool mDisableCollabIfEnabledWhenLoaded; LaunchTool.IShowDownloadPlasticExeWindow mShowDownloadPlasticExeWindow = new LaunchTool.ShowDownloadPlasticExeWindow(); LaunchTool.IProcessExecutor mProcessExecutor = new LaunchTool.ProcessExecutor(); static readonly ILog mLog = LogManager.GetLogger("PlasticWindow"); } }