A game about forced loneliness, made by TACStudios
1using System.Collections.Generic; 2using System.IO; 3 4using UnityEditor; 5using UnityEngine; 6 7using Codice.Client.Common; 8using Codice.Client.Common.EventTracking; 9using Codice.CM.Common; 10using GluonGui; 11using PlasticGui; 12using PlasticGui.Gluon; 13using Unity.PlasticSCM.Editor.AssetsOverlays; 14using Unity.PlasticSCM.Editor.AssetsOverlays.Cache; 15using Unity.PlasticSCM.Editor.AssetUtils; 16using Unity.PlasticSCM.Editor.AssetUtils.Processor; 17using Unity.PlasticSCM.Editor.UI; 18using Unity.PlasticSCM.Editor.UI.Progress; 19using Unity.PlasticSCM.Editor.UI.Tree; 20 21namespace Unity.PlasticSCM.Editor.AssetMenu.Dialogs 22{ 23 internal class CheckinDialog : PlasticDialog 24 { 25 protected override Rect DefaultRect 26 { 27 get 28 { 29 var baseRect = base.DefaultRect; 30 return new Rect(baseRect.x, baseRect.y, 700, 450); 31 } 32 } 33 34 protected override string GetTitle() 35 { 36 return PlasticLocalization.GetString( 37 PlasticLocalization.Name.CheckinChanges); 38 } 39 40 internal static bool CheckinPaths( 41 WorkspaceInfo wkInfo, 42 List<string> paths, 43 IAssetStatusCache assetStatusCache, 44 bool isGluonMode, 45 IWorkspaceWindow workspaceWindow, 46 ViewHost viewHost, 47 WorkspaceOperationsMonitor workspaceOperationsMonitor, 48 ISaveAssets saveAssets, 49 GuiMessage.IGuiMessage guiMessage, 50 IMergeViewLauncher mergeViewLauncher, 51 IGluonViewSwitcher gluonViewSwitcher) 52 { 53 MetaCache metaCache = new MetaCache(); 54 metaCache.Build(paths); 55 56 CheckinDialog dialog = Create( 57 wkInfo, 58 paths, 59 assetStatusCache, 60 metaCache, 61 isGluonMode, 62 new ProgressControlsForDialogs(), 63 workspaceWindow, 64 viewHost, 65 workspaceOperationsMonitor, 66 saveAssets, 67 guiMessage, 68 mergeViewLauncher, 69 gluonViewSwitcher); 70 71 return dialog.RunModal(focusedWindow) == ResponseType.Ok; 72 } 73 74 protected override void OnModalGUI() 75 { 76 Title(PlasticLocalization.GetString(PlasticLocalization.Name.CheckinOnlyComment)); 77 78 GUI.SetNextControlName(CHECKIN_TEXTAREA_NAME); 79 80 mComment = GUILayout.TextArea( 81 mComment, 82 EditorStyles.textArea, 83 GUILayout.MinHeight(120)); 84 85 if (!mTextAreaFocused) 86 { 87 EditorGUI.FocusTextInControl(CHECKIN_TEXTAREA_NAME); 88 mTextAreaFocused = true; 89 } 90 91 Title(PlasticLocalization.GetString(PlasticLocalization.Name.Files)); 92 93 DoFileList( 94 mWkInfo, 95 mPaths, 96 mAssetStatusCache, 97 mMetaCache); 98 99 DrawProgressForDialogs.For( 100 mProgressControls.ProgressData); 101 102 DoButtonsArea(); 103 104 mProgressControls.ForcedUpdateProgress(this); 105 } 106 107 void DoFileList( 108 WorkspaceInfo wkInfo, 109 List<string> paths, 110 IAssetStatusCache assetStatusCache, 111 MetaCache metaCache) 112 { 113 mFileListScrollPosition = GUILayout.BeginScrollView( 114 mFileListScrollPosition, 115 EditorStyles.helpBox, 116 GUILayout.ExpandHeight(true)); 117 118 foreach (string path in paths) 119 { 120 if (MetaPath.IsMetaPath(path)) 121 continue; 122 123 Texture fileIcon = Directory.Exists(path) ? 124 Images.GetDirectoryIcon() : 125 Images.GetFileIcon(path); 126 127 string label = WorkspacePath.GetWorkspaceRelativePath( 128 wkInfo.ClientPath, path); 129 130 if (metaCache.HasMeta(path)) 131 label = string.Concat(label, UnityConstants.TREEVIEW_META_LABEL); 132 133 AssetsOverlays.AssetStatus assetStatus = 134 assetStatusCache.GetStatus(path); 135 136 Rect selectionRect = EditorGUILayout.GetControlRect(); 137 138 DoListViewItem(selectionRect, fileIcon, label, assetStatus); 139 } 140 141 GUILayout.EndScrollView(); 142 } 143 144 void DoListViewItem( 145 Rect itemRect, 146 Texture fileIcon, 147 string label, 148 AssetsOverlays.AssetStatus statusToDraw) 149 { 150 Texture overlayIcon = DrawAssetOverlay.DrawOverlayIcon. 151 GetOverlayIcon(statusToDraw); 152 153 itemRect = DrawTreeViewItem.DrawIconLeft( 154 itemRect, 155 UnityConstants.TREEVIEW_ROW_HEIGHT, 156 fileIcon, 157 overlayIcon); 158 159 GUI.Label(itemRect, label); 160 } 161 162 void DoButtonsArea() 163 { 164 using (new EditorGUILayout.HorizontalScope()) 165 { 166 GUILayout.FlexibleSpace(); 167 168 if (Application.platform == RuntimePlatform.WindowsEditor) 169 { 170 DoCheckinButton(); 171 DoCancelButton(); 172 return; 173 } 174 175 DoCancelButton(); 176 DoCheckinButton(); 177 } 178 } 179 180 void DoCheckinButton() 181 { 182 GUI.enabled = IsCheckinButtonEnabled(); 183 184 try 185 { 186 if (!AcceptButton(PlasticLocalization.GetString( 187 PlasticLocalization.Name.CheckinButton))) 188 return; 189 } 190 finally 191 { 192 if (!mSentCheckinTrackEvent) 193 { 194 TrackFeatureUseEvent.For( 195 PlasticGui.Plastic.API.GetRepositorySpec(mWkInfo), 196 TrackFeatureUseEvent.Features.ContextMenuCheckinDialogCheckin); 197 198 mSentCheckinTrackEvent = true; 199 } 200 201 GUI.enabled = true; 202 } 203 204 OkButtonWithCheckinAction(); 205 } 206 207 void DoCancelButton() 208 { 209 if (!NormalButton(PlasticLocalization.GetString( 210 PlasticLocalization.Name.CancelButton))) 211 return; 212 213 if (!mSentCancelTrackEvent) 214 { 215 TrackFeatureUseEvent.For( 216 PlasticGui.Plastic.API.GetRepositorySpec(mWkInfo), 217 TrackFeatureUseEvent.Features.ContextMenuCheckinDialogCancel); 218 219 mSentCancelTrackEvent = true; 220 } 221 222 CancelButtonAction(); 223 } 224 225 void OkButtonWithCheckinAction() 226 { 227 if (!IsCheckinButtonEnabled()) 228 return; 229 230 bool isCancelled; 231 mSaveAssets.ForPathsWithConfirmation( 232 mWkInfo.ClientPath, mPaths, mWorkspaceOperationsMonitor, 233 out isCancelled); 234 235 if (isCancelled) 236 return; 237 238 mIsRunningCheckin = true; 239 240 mPaths.AddRange(mMetaCache.GetExistingMeta(mPaths)); 241 242 if (mIsGluonMode) 243 { 244 CheckinDialogOperations.CheckinPathsPartial( 245 mWkInfo, 246 mPaths, 247 mComment, 248 mViewHost, 249 this, 250 mGuiMessage, 251 mProgressControls, 252 mGluonViewSwitcher); 253 return; 254 } 255 256 CheckinDialogOperations.CheckinPaths( 257 mWkInfo, 258 mPaths, 259 mComment, 260 mWorkspaceWindow, 261 this, 262 mGuiMessage, 263 mProgressControls, 264 mMergeViewLauncher); 265 } 266 267 bool IsCheckinButtonEnabled() 268 { 269 return !string.IsNullOrEmpty(mComment) && !mIsRunningCheckin; 270 } 271 272 static CheckinDialog Create( 273 WorkspaceInfo wkInfo, 274 List<string> paths, 275 IAssetStatusCache assetStatusCache, 276 MetaCache metaCache, 277 bool isGluonMode, 278 ProgressControlsForDialogs progressControls, 279 IWorkspaceWindow workspaceWindow, 280 ViewHost viewHost, 281 WorkspaceOperationsMonitor workspaceOperationsMonitor, 282 ISaveAssets saveAssets, 283 GuiMessage.IGuiMessage guiMessage, 284 IMergeViewLauncher mergeViewLauncher, 285 IGluonViewSwitcher gluonViewSwitcher) 286 { 287 var instance = CreateInstance<CheckinDialog>(); 288 instance.IsResizable = true; 289 instance.minSize = new Vector2(520, 370); 290 instance.mWkInfo = wkInfo; 291 instance.mPaths = paths; 292 instance.mAssetStatusCache = assetStatusCache; 293 instance.mMetaCache = metaCache; 294 instance.mIsGluonMode = isGluonMode; 295 instance.mProgressControls = progressControls; 296 instance.mWorkspaceWindow = workspaceWindow; 297 instance.mViewHost = viewHost; 298 instance.mWorkspaceOperationsMonitor = workspaceOperationsMonitor; 299 instance.mSaveAssets = saveAssets; 300 instance.mGuiMessage = guiMessage; 301 instance.mMergeViewLauncher = mergeViewLauncher; 302 instance.mGluonViewSwitcher = gluonViewSwitcher; 303 instance.mEnterKeyAction = instance.OkButtonWithCheckinAction; 304 instance.AddControlConsumingEnterKey(CHECKIN_TEXTAREA_NAME); 305 instance.mEscapeKeyAction = instance.CancelButtonAction; 306 return instance; 307 } 308 309 WorkspaceInfo mWkInfo; 310 List<string> mPaths; 311 IAssetStatusCache mAssetStatusCache; 312 MetaCache mMetaCache; 313 bool mIsGluonMode; 314 bool mTextAreaFocused; 315 string mComment; 316 317 bool mIsRunningCheckin; 318 Vector2 mFileListScrollPosition; 319 320 // IMGUI evaluates every frame, need to make sure feature tracks get sent only once 321 bool mSentCheckinTrackEvent = false; 322 bool mSentCancelTrackEvent = false; 323 324 ProgressControlsForDialogs mProgressControls; 325 326 IWorkspaceWindow mWorkspaceWindow; 327 WorkspaceOperationsMonitor mWorkspaceOperationsMonitor; 328 ISaveAssets mSaveAssets; 329 ViewHost mViewHost; 330 IMergeViewLauncher mMergeViewLauncher; 331 IGluonViewSwitcher mGluonViewSwitcher; 332 GuiMessage.IGuiMessage mGuiMessage; 333 334 const string CHECKIN_TEXTAREA_NAME = "checkin_textarea"; 335 336 class MetaCache 337 { 338 internal bool HasMeta(string path) 339 { 340 return mCache.Contains(MetaPath.GetMetaPath(path)); 341 } 342 343 internal List<string> GetExistingMeta(List<string> paths) 344 { 345 List<string> result = new List<string>(); 346 347 foreach (string path in paths) 348 { 349 string metaPath = MetaPath.GetMetaPath(path); 350 351 if (!mCache.Contains(metaPath)) 352 continue; 353 354 result.Add(metaPath); 355 } 356 357 return result; 358 } 359 360 internal void Build(List<string> paths) 361 { 362 HashSet<string> indexedKeys = BuildIndexedKeys(paths); 363 364 for (int i = paths.Count - 1; i >= 0; i--) 365 { 366 string currentPath = paths[i]; 367 368 if (!MetaPath.IsMetaPath(currentPath)) 369 continue; 370 371 string realPath = MetaPath.GetPathFromMetaPath(currentPath); 372 373 if (!indexedKeys.Contains(realPath)) 374 continue; 375 376 // found foo.c and foo.c.meta 377 // with the same chage types - move .meta to cache 378 mCache.Add(currentPath); 379 paths.RemoveAt(i); 380 } 381 } 382 383 static HashSet<string> BuildIndexedKeys(List<string> paths) 384 { 385 HashSet<string> result = new HashSet<string>(); 386 387 foreach (string path in paths) 388 { 389 if (MetaPath.IsMetaPath(path)) 390 continue; 391 392 result.Add(path); 393 } 394 395 return result; 396 } 397 398 HashSet<string> mCache = new HashSet<string>(); 399 } 400 } 401}