997 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
		
		
			
		
	
	
			997 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
|  | using System; | ||
|  | using System.Collections.Generic; | ||
|  | using System.IO; | ||
|  | using System.Linq; | ||
|  | 
 | ||
|  | using UnityEditor; | ||
|  | using UnityEditor.IMGUI.Controls; | ||
|  | using UnityEngine; | ||
|  | 
 | ||
|  | using Codice.Client.BaseCommands; | ||
|  | using Codice.CM.Common; | ||
|  | 
 | ||
|  | using PlasticGui; | ||
|  | using PlasticGui.WorkspaceWindow.PendingChanges; | ||
|  | using PlasticGui.WorkspaceWindow.PendingChanges.Changelists; | ||
|  | 
 | ||
|  | using Unity.PlasticSCM.Editor.AssetUtils; | ||
|  | using Unity.PlasticSCM.Editor.UI; | ||
|  | using Unity.PlasticSCM.Editor.UI.Tree; | ||
|  | using Unity.PlasticSCM.Editor.AssetsOverlays.Cache; | ||
|  | using Unity.PlasticSCM.Editor.AssetsOverlays; | ||
|  | #if UNITY_6000_2_OR_NEWER | ||
|  | using TreeViewItem = UnityEditor.IMGUI.Controls.TreeViewItem<int>; | ||
|  | #endif | ||
|  | 
 | ||
|  | namespace Unity.PlasticSCM.Editor.Views.PendingChanges | ||
|  | { | ||
|  |     internal class PendingChangesTreeView : PlasticTreeView | ||
|  |     { | ||
|  |         internal PendingChangesTreeView( | ||
|  |             WorkspaceInfo wkInfo, | ||
|  |             bool isGluonMode, | ||
|  |             PendingChangesTreeHeaderState headerState, | ||
|  |             List<string> columnNames, | ||
|  |             PendingChangesViewMenu menu, | ||
|  |             IAssetStatusCache assetStatusCache, | ||
|  |             Action doubleClickAction) | ||
|  |         { | ||
|  |             mWkInfo = wkInfo; | ||
|  |             mIsGluonMode = isGluonMode; | ||
|  |             mColumnNames = columnNames; | ||
|  |             mHeaderState = headerState; | ||
|  |             mMenu = menu; | ||
|  |             mAssetStatusCache = assetStatusCache; | ||
|  |             mDoubleClickAction = doubleClickAction; | ||
|  | 
 | ||
|  |             mPendingChangesTree = new UnityPendingChangesTree(); | ||
|  | 
 | ||
|  |             multiColumnHeader = new PendingChangesMultiColumnHeader( | ||
|  |                 this, | ||
|  |                 headerState, | ||
|  |                 mPendingChangesTree); | ||
|  |             multiColumnHeader.canSort = true; | ||
|  |             multiColumnHeader.sortingChanged += SortingChanged; | ||
|  | 
 | ||
|  |             customFoldoutYOffset = UnityConstants.TREEVIEW_FOLDOUT_Y_OFFSET; | ||
|  | 
 | ||
|  |             mDelayedFilterAction = new DelayedActionBySecondsRunner( | ||
|  |                 DelayedSearchChanged, UnityConstants.SEARCH_DELAYED_INPUT_ACTION_INTERVAL); | ||
|  |         } | ||
|  | 
 | ||
|  |         protected override void SingleClickedItem(int id) | ||
|  |         { | ||
|  |             SelectionChanged(new [] { id }); | ||
|  |         } | ||
|  | 
 | ||
|  |         protected override void SelectionChanged(IList<int> selectedIds) | ||
|  |         { | ||
|  |             mHeaderState.UpdateItemColumnHeader(this); | ||
|  | 
 | ||
|  |             if (mIsSelectionChangedEventDisabled) | ||
|  |                 return; | ||
|  | 
 | ||
|  |             List<UnityEngine.Object> assets = new List<UnityEngine.Object>(); | ||
|  | 
 | ||
|  |             foreach (ChangeInfo changeInfo in GetSelectedChanges(false)) | ||
|  |             { | ||
|  |                 UnityEngine.Object asset = LoadAsset.FromChangeInfo(changeInfo); | ||
|  | 
 | ||
|  |                 if (asset == null) | ||
|  |                     continue; | ||
|  | 
 | ||
|  |                 assets.Add(asset); | ||
|  |             } | ||
|  | 
 | ||
|  |             UnityEditor.Selection.objects = assets.ToArray(); | ||
|  | 
 | ||
|  |             if (assets.Count == 1) | ||
|  |                 EditorGUIUtility.PingObject(assets[0]); | ||
|  |         } | ||
|  | 
 | ||
|  |         protected void SelectionChanged() | ||
|  |         { | ||
|  |             SelectionChanged(GetSelection()); | ||
|  |         } | ||
|  | 
 | ||
|  |         public override void OnGUI(Rect rect) | ||
|  |         { | ||
|  |             MultiColumnHeader.DefaultStyles.background = | ||
|  |                 UnityStyles.Tree.Columns; | ||
|  | 
 | ||
|  |             try | ||
|  |             { | ||
|  |                 base.OnGUI(rect); | ||
|  | 
 | ||
|  |                 if (!base.HasFocus()) | ||
|  |                     return; | ||
|  | 
 | ||
|  |                 Event e = Event.current; | ||
|  | 
 | ||
|  |                 if (e.type != EventType.KeyDown) | ||
|  |                     return; | ||
|  | 
 | ||
|  |                 bool isProcessed = mMenu.ProcessKeyActionIfNeeded(e); | ||
|  | 
 | ||
|  |                 if (isProcessed) | ||
|  |                     e.Use(); | ||
|  |             } | ||
|  |             finally | ||
|  |             { | ||
|  |                 MultiColumnHeader.DefaultStyles.background = | ||
|  |                     UnityStyles.PendingChangesTab.DefaultMultiColumHeader; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         protected override bool CanChangeExpandedState(TreeViewItem item) | ||
|  |         { | ||
|  |             return item is ChangeCategoryTreeViewItem || item is ChangelistTreeViewItem; | ||
|  |         } | ||
|  | 
 | ||
|  |         protected override IList<TreeViewItem> BuildRows(TreeViewItem rootItem) | ||
|  |         { | ||
|  |             try | ||
|  |             { | ||
|  |                 RegenerateRows( | ||
|  |                     mPendingChangesTree, mTreeViewItemIds, this, | ||
|  |                     rootItem, mRows, mExpandCategories); | ||
|  |             } | ||
|  |             finally | ||
|  |             { | ||
|  |                 mExpandCategories = false; | ||
|  |             } | ||
|  | 
 | ||
|  |             return mRows; | ||
|  |         } | ||
|  | 
 | ||
|  |         protected override void CommandEventHandling() | ||
|  |         { | ||
|  |             // NOTE - empty override to prevent crash when pressing ctrl-a in the treeview | ||
|  |         } | ||
|  | 
 | ||
|  |         protected override void SearchChanged(string newSearch) | ||
|  |         { | ||
|  |             mDelayedFilterAction.Run(); | ||
|  |         } | ||
|  | 
 | ||
|  |         protected override void ContextClickedItem(int id) | ||
|  |         { | ||
|  |             mMenu.Popup(); | ||
|  |             Repaint(); | ||
|  |         } | ||
|  | 
 | ||
|  |         protected override void RowGUI(RowGUIArgs args) | ||
|  |         { | ||
|  |             if (args.item is ChangelistTreeViewItem) | ||
|  |             { | ||
|  |                 ChangelistTreeViewItemGUI( | ||
|  |                     this, | ||
|  |                     args.rowRect, rowHeight, | ||
|  |                     (ChangelistTreeViewItem)args.item, | ||
|  |                     args.selected, args.focused); | ||
|  |                 return; | ||
|  |             } | ||
|  | 
 | ||
|  |             if (args.item is ChangeCategoryTreeViewItem) | ||
|  |             { | ||
|  |                 CategoryTreeViewItemGUI( | ||
|  |                     this, | ||
|  |                     args.rowRect, rowHeight, | ||
|  |                     (ChangeCategoryTreeViewItem)args.item, | ||
|  |                     args.selected, args.focused); | ||
|  |                 return; | ||
|  |             } | ||
|  | 
 | ||
|  |             if (args.item is ChangeTreeViewItem) | ||
|  |             { | ||
|  |                 ChangeTreeViewItemGUI( | ||
|  |                     mWkInfo.ClientPath, | ||
|  |                     mIsGluonMode, | ||
|  |                     mAssetStatusCache, | ||
|  |                     this, | ||
|  |                     mPendingChangesTree, | ||
|  |                     (ChangeTreeViewItem)args.item, | ||
|  |                     args); | ||
|  |                 return; | ||
|  |             } | ||
|  | 
 | ||
|  |             base.RowGUI(args); | ||
|  |         } | ||
|  | 
 | ||
|  |         protected override void DoubleClickedItem(int id) | ||
|  |         { | ||
|  |             mDoubleClickAction(); | ||
|  |         } | ||
|  | 
 | ||
|  |         internal void BuildModel( | ||
|  |             List<ChangeInfo> changes, | ||
|  |             PendingChangesViewCheckedStateManager checkedStateManager) | ||
|  |         { | ||
|  |             mTreeViewItemIds.Clear(); | ||
|  | 
 | ||
|  |             mPendingChangesTree.BuildChangeCategories( | ||
|  |                 mWkInfo, | ||
|  |                 changes, | ||
|  |                 checkedStateManager); | ||
|  |         } | ||
|  | 
 | ||
|  |         internal ChangeInfo GetChangedForMoved(ChangeInfo moved) | ||
|  |         { | ||
|  |             return mPendingChangesTree.GetChangedForMoved(moved); | ||
|  |         } | ||
|  | 
 | ||
|  |         internal void Refilter() | ||
|  |         { | ||
|  |             Filter filter = new Filter(searchString); | ||
|  |             mPendingChangesTree.Filter(filter, mColumnNames); | ||
|  | 
 | ||
|  |             mExpandCategories = true; | ||
|  |         } | ||
|  | 
 | ||
|  |         internal void Sort() | ||
|  |         { | ||
|  |             int sortedColumnIdx = multiColumnHeader.state.sortedColumnIndex; | ||
|  |             bool sortAscending = multiColumnHeader.IsSortedAscending(sortedColumnIdx); | ||
|  | 
 | ||
|  |             mPendingChangesTree.Sort( | ||
|  |                 mColumnNames[sortedColumnIdx], | ||
|  |                 sortAscending); | ||
|  |         } | ||
|  | 
 | ||
|  |         internal bool GetSelectedPathsToDelete( | ||
|  |             out List<string> privateDirectories, | ||
|  |             out List<string> privateFiles) | ||
|  |         { | ||
|  |             privateDirectories = new List<string>(); | ||
|  |             privateFiles = new List<string>(); | ||
|  | 
 | ||
|  |             List<ChangeInfo> dirChanges = new List<ChangeInfo>(); | ||
|  |             List<ChangeInfo> fileChanges = new List<ChangeInfo>(); | ||
|  | 
 | ||
|  |             IList<int> selectedIds = GetSelection(); | ||
|  | 
 | ||
|  |             if (selectedIds.Count == 0) | ||
|  |                 return false; | ||
|  | 
 | ||
|  |             foreach (KeyValuePair<PendingChangeInfo, int> item | ||
|  |                 in mTreeViewItemIds.GetInfoItems()) | ||
|  |             { | ||
|  |                 if (!selectedIds.Contains(item.Value)) | ||
|  |                     continue; | ||
|  | 
 | ||
|  |                 ChangeInfo changeInfo = item.Key.ChangeInfo; | ||
|  | 
 | ||
|  |                 if (ChangeInfoType.IsControlled(changeInfo)) | ||
|  |                     continue; | ||
|  | 
 | ||
|  |                 if (changeInfo.IsDirectory) | ||
|  |                 { | ||
|  |                     dirChanges.Add(changeInfo); | ||
|  |                 } | ||
|  |                 else | ||
|  |                 { | ||
|  |                     fileChanges.Add(changeInfo); | ||
|  |                 } | ||
|  | 
 | ||
|  |                 ChangeInfo metaChangeInfo = mPendingChangesTree.GetMetaChange(changeInfo); | ||
|  | 
 | ||
|  |                 if (metaChangeInfo != null) | ||
|  |                 { | ||
|  |                     fileChanges.Add(metaChangeInfo); | ||
|  |                 } | ||
|  |             } | ||
|  | 
 | ||
|  |             privateDirectories = dirChanges.Select( | ||
|  |                 d => d.GetFullPath()).ToList(); | ||
|  |             privateFiles = fileChanges.Select( | ||
|  |                 f => f.GetFullPath()).ToList(); | ||
|  | 
 | ||
|  |             return true; | ||
|  |         } | ||
|  | 
 | ||
|  |         internal void GetCheckedChanges( | ||
|  |             List<ChangelistNode> selectedChangelists, | ||
|  |             bool bExcludePrivates, | ||
|  |             out List<ChangeInfo> changes, | ||
|  |             out List<ChangeInfo> dependenciesCandidates) | ||
|  |         { | ||
|  |             mPendingChangesTree.GetCheckedChanges( | ||
|  |                 selectedChangelists, | ||
|  |                 bExcludePrivates, | ||
|  |                 out changes, | ||
|  |                 out dependenciesCandidates); | ||
|  |         } | ||
|  | 
 | ||
|  |         internal List<ChangeInfo> GetAllChanges() | ||
|  |         { | ||
|  |             return mPendingChangesTree.GetAllChanges(); | ||
|  |         } | ||
|  | 
 | ||
|  |         internal ChangeInfo GetMetaChange(ChangeInfo change) | ||
|  |         { | ||
|  |             if (change == null) | ||
|  |                 return null; | ||
|  | 
 | ||
|  |             return mPendingChangesTree.GetMetaChange(change); | ||
|  |         } | ||
|  | 
 | ||
|  |         internal List<ChangeInfo> GetDependenciesCandidates( | ||
|  |             List<ChangeInfo> selectedChanges, bool bExcludePrivates) | ||
|  |         { | ||
|  |             return mPendingChangesTree.GetDependenciesCandidates( | ||
|  |                 selectedChanges, bExcludePrivates); | ||
|  |         } | ||
|  | 
 | ||
|  |         internal List<IPlasticTreeNode> GetSelectedNodes() | ||
|  |         { | ||
|  |             List<IPlasticTreeNode> result = new List<IPlasticTreeNode>(); | ||
|  | 
 | ||
|  |             IList<int> selectedIds = GetSelection(); | ||
|  | 
 | ||
|  |             if (selectedIds.Count == 0) | ||
|  |                 return result; | ||
|  | 
 | ||
|  |             foreach (KeyValuePair<IPlasticTreeNode, int> item | ||
|  |                 in mTreeViewItemIds.GetCategoryItems()) | ||
|  |             { | ||
|  |                 if (!selectedIds.Contains(item.Value)) | ||
|  |                     continue; | ||
|  | 
 | ||
|  |                 result.Add(item.Key); | ||
|  |             } | ||
|  | 
 | ||
|  |             foreach (KeyValuePair<PendingChangeInfo, int> item | ||
|  |                 in mTreeViewItemIds.GetInfoItems()) | ||
|  |             { | ||
|  |                 if (!selectedIds.Contains(item.Value)) | ||
|  |                     continue; | ||
|  | 
 | ||
|  |                 result.Add(item.Key); | ||
|  |             } | ||
|  | 
 | ||
|  |             return result; | ||
|  |         } | ||
|  | 
 | ||
|  |         internal List<ChangeInfo> GetSelectedChanges(bool includeMetaFiles) | ||
|  |         { | ||
|  |             List<ChangeInfo> result = new List<ChangeInfo>(); | ||
|  | 
 | ||
|  |             IList<int> selectedIds = GetSelection(); | ||
|  | 
 | ||
|  |             if (selectedIds.Count == 0) | ||
|  |                 return result; | ||
|  | 
 | ||
|  |             foreach (KeyValuePair<PendingChangeInfo, int> item | ||
|  |                 in mTreeViewItemIds.GetInfoItems()) | ||
|  |             { | ||
|  |                 if (!selectedIds.Contains(item.Value)) | ||
|  |                     continue; | ||
|  | 
 | ||
|  |                 result.Add(item.Key.ChangeInfo); | ||
|  |             } | ||
|  | 
 | ||
|  |             if (includeMetaFiles) | ||
|  |                 mPendingChangesTree.FillWithMeta(result); | ||
|  | 
 | ||
|  |             return result; | ||
|  |         } | ||
|  | 
 | ||
|  |         internal List<PendingChangeInfo> GetSelectedPendingChangeInfos() | ||
|  |         { | ||
|  |             List<PendingChangeInfo> result = new List<PendingChangeInfo>(); | ||
|  | 
 | ||
|  |             IList<int> selectedIds = GetSelection(); | ||
|  | 
 | ||
|  |             if (selectedIds.Count == 0) | ||
|  |                 return result; | ||
|  | 
 | ||
|  |             foreach (KeyValuePair<PendingChangeInfo, int> item | ||
|  |                 in mTreeViewItemIds.GetInfoItems()) | ||
|  |             { | ||
|  |                 if (!selectedIds.Contains(item.Value)) | ||
|  |                     continue; | ||
|  | 
 | ||
|  |                 result.Add(item.Key); | ||
|  |             } | ||
|  | 
 | ||
|  |             return result; | ||
|  |         } | ||
|  | 
 | ||
|  |         internal List<ChangelistNode> GetSelectedChangelistNodes() | ||
|  |         { | ||
|  |             List<ChangelistNode> result = new List<ChangelistNode>(); | ||
|  | 
 | ||
|  |             IList<int> selectedIds = GetSelection(); | ||
|  | 
 | ||
|  |             if (selectedIds.Count == 0) | ||
|  |                 return result; | ||
|  | 
 | ||
|  |             foreach (KeyValuePair<IPlasticTreeNode, int> item | ||
|  |                 in mTreeViewItemIds.GetCategoryItems()) | ||
|  |             { | ||
|  |                 if (!selectedIds.Contains(item.Value)) | ||
|  |                     continue; | ||
|  | 
 | ||
|  |                 if (item.Key is ChangelistNode) | ||
|  |                     result.Add((ChangelistNode)item.Key); | ||
|  |             } | ||
|  | 
 | ||
|  |             return result; | ||
|  |         } | ||
|  | 
 | ||
|  |         internal bool SelectionHasMeta() | ||
|  |         { | ||
|  |             ChangeInfo selectedChangeInfo = GetSelectedRow(); | ||
|  | 
 | ||
|  |             if (selectedChangeInfo == null) | ||
|  |                 return false; | ||
|  | 
 | ||
|  |             return mPendingChangesTree.HasMeta(selectedChangeInfo); | ||
|  |         } | ||
|  | 
 | ||
|  |         internal ChangeInfo GetSelectedRow() | ||
|  |         { | ||
|  |             IList<int> selectedIds = GetSelection(); | ||
|  | 
 | ||
|  |             if (selectedIds.Count == 0) | ||
|  |                 return null; | ||
|  | 
 | ||
|  |             int selectedId = selectedIds[0]; | ||
|  | 
 | ||
|  |             foreach (KeyValuePair<PendingChangeInfo, int> item | ||
|  |                 in mTreeViewItemIds.GetInfoItems()) | ||
|  |             { | ||
|  |                 if (selectedId == item.Value) | ||
|  |                     return item.Key.ChangeInfo; | ||
|  |             } | ||
|  | 
 | ||
|  |             return null; | ||
|  |         } | ||
|  | 
 | ||
|  |         internal ChangeInfo GetNearestAddedChange() | ||
|  |         { | ||
|  |             IList<int> selectedIds = GetSelection(); | ||
|  | 
 | ||
|  |             if (selectedIds.Count == 0) | ||
|  |                 return null; | ||
|  | 
 | ||
|  |             int id = selectedIds[0]; | ||
|  | 
 | ||
|  |             IList<TreeViewItem> treeViewItems = | ||
|  |                 FindRows(new List<int>() { id }); | ||
|  | 
 | ||
|  |             if (treeViewItems.Count == 0) | ||
|  |                 return null; | ||
|  | 
 | ||
|  |             PendingChangeInfo changeInfo = | ||
|  |                 ((ChangeTreeViewItem)treeViewItems[0]).ChangeInfo; | ||
|  |             PendingChangeCategory category = | ||
|  |                 (PendingChangeCategory)((IPlasticTreeNode)changeInfo).GetParent(); | ||
|  | 
 | ||
|  |             int itemIndex = category.GetChildPosition(changeInfo); | ||
|  | 
 | ||
|  |             ChangeInfo result = GetNextExistingAddedItem(category, itemIndex); | ||
|  | 
 | ||
|  |             if (result != null) | ||
|  |                 return result; | ||
|  | 
 | ||
|  |             return GetPreviousExistingAddedItem(category, itemIndex); | ||
|  |         } | ||
|  | 
 | ||
|  |         internal void SelectFirstPendingChangeOnTree() | ||
|  |         { | ||
|  |             int treeIdFirstItem = GetTreeIdFirstItem(); | ||
|  | 
 | ||
|  |             if (treeIdFirstItem == -1) | ||
|  |                 return; | ||
|  | 
 | ||
|  |             mIsSelectionChangedEventDisabled = true; | ||
|  | 
 | ||
|  |             try | ||
|  |             { | ||
|  |                 TableViewOperations.SetSelectionAndScroll( | ||
|  |                     this, new List<int> { treeIdFirstItem }); | ||
|  |             } | ||
|  |             finally | ||
|  |             { | ||
|  |                 mIsSelectionChangedEventDisabled = false; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         internal void SelectPreviouslySelectedPendingChanges( | ||
|  |             List<ChangeInfo> changesToSelect) | ||
|  |         { | ||
|  |             List<int> idsToSelect = new List<int>(); | ||
|  | 
 | ||
|  |             foreach (ChangeInfo change in changesToSelect) | ||
|  |             { | ||
|  |                 int changeId = GetTreeIdForItem(change); | ||
|  | 
 | ||
|  |                 if (changeId == -1) | ||
|  |                     continue; | ||
|  | 
 | ||
|  |                 idsToSelect.Add(changeId); | ||
|  |             } | ||
|  | 
 | ||
|  |             mIsSelectionChangedEventDisabled = true; | ||
|  |             try | ||
|  |             { | ||
|  |                 TableViewOperations.SetSelectionAndScroll( | ||
|  |                     this, idsToSelect); | ||
|  |             } | ||
|  |             finally | ||
|  |             { | ||
|  |                 mIsSelectionChangedEventDisabled = false; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         internal int GetCheckedItemCount() | ||
|  |         { | ||
|  |             return CheckableItems.GetCheckedChildNodeCount(mPendingChangesTree.GetNodes()); | ||
|  |         } | ||
|  | 
 | ||
|  |         internal int GetTotalItemCount() | ||
|  |         { | ||
|  |             return CheckableItems.GetTotalChildNodeCount(mPendingChangesTree.GetNodes()); | ||
|  |         } | ||
|  | 
 | ||
|  |         internal bool AreAllItemsChecked() | ||
|  |         { | ||
|  |             return GetCheckedItemCount() == GetTotalItemCount(); | ||
|  |         } | ||
|  | 
 | ||
|  |         ChangeInfo GetNextExistingAddedItem( | ||
|  |             PendingChangeCategory addedCategory, int targetAddedItemIndex) | ||
|  |         { | ||
|  |             int addedItemsCount = addedCategory.GetChildrenCount(); | ||
|  | 
 | ||
|  |             for (int i = targetAddedItemIndex + 1; i < addedItemsCount; i++) | ||
|  |             { | ||
|  |                 ChangeInfo currentChangeInfo = GetExistingAddedItem(addedCategory, i); | ||
|  | 
 | ||
|  |                 if (currentChangeInfo != null) | ||
|  |                     return currentChangeInfo; | ||
|  |             } | ||
|  | 
 | ||
|  |             return null; | ||
|  |         } | ||
|  | 
 | ||
|  |         ChangeInfo GetPreviousExistingAddedItem( | ||
|  |             PendingChangeCategory addedCategory, int targetAddedItemIndex) | ||
|  |         { | ||
|  |             for (int i = targetAddedItemIndex - 1; i >= 0; i--) | ||
|  |             { | ||
|  |                 ChangeInfo currentChangeInfo = GetExistingAddedItem(addedCategory, i); | ||
|  | 
 | ||
|  |                 if (currentChangeInfo != null) | ||
|  |                     return currentChangeInfo; | ||
|  |             } | ||
|  | 
 | ||
|  |             return null; | ||
|  |         } | ||
|  | 
 | ||
|  |         ChangeInfo GetExistingAddedItem( | ||
|  |             PendingChangeCategory addedCategory, int addedItemIndex) | ||
|  |         { | ||
|  |             ChangeInfo currentChangeInfo = ((PendingChangeInfo)((IPendingChangesNode)addedCategory) | ||
|  |                 .GetCurrentChanges()[addedItemIndex]).ChangeInfo; | ||
|  | 
 | ||
|  |             if (Directory.Exists(currentChangeInfo.Path) || | ||
|  |                 File.Exists(currentChangeInfo.Path)) | ||
|  |                 return currentChangeInfo; | ||
|  | 
 | ||
|  |             return null; | ||
|  |         } | ||
|  | 
 | ||
|  |         int GetTreeIdFirstItem() | ||
|  |         { | ||
|  |             PendingChangeInfo firstChange = mPendingChangesTree.GetFirstPendingChange(); | ||
|  | 
 | ||
|  |             if (firstChange == null) | ||
|  |                 return -1; | ||
|  | 
 | ||
|  |             int changeId; | ||
|  |             if (mTreeViewItemIds.TryGetInfoItemId(firstChange, out changeId)) | ||
|  |                 return changeId; | ||
|  | 
 | ||
|  |             return -1; | ||
|  |         } | ||
|  | 
 | ||
|  |         int GetTreeIdForItem(ChangeInfo change) | ||
|  |         { | ||
|  |             foreach (KeyValuePair<PendingChangeInfo, int> item in mTreeViewItemIds.GetInfoItems()) | ||
|  |             { | ||
|  |                 ChangeInfo changeInfo = item.Key.ChangeInfo; | ||
|  | 
 | ||
|  |                 if (changeInfo.ChangeTypes != change.ChangeTypes) | ||
|  |                     continue; | ||
|  | 
 | ||
|  |                 if (changeInfo.GetFullPath() != change.GetFullPath()) | ||
|  |                     continue; | ||
|  | 
 | ||
|  |                 return item.Value; | ||
|  |             } | ||
|  | 
 | ||
|  |             return -1; | ||
|  |         } | ||
|  | 
 | ||
|  |         void DelayedSearchChanged() | ||
|  |         { | ||
|  |             Refilter(); | ||
|  | 
 | ||
|  |             Sort(); | ||
|  | 
 | ||
|  |             Reload(); | ||
|  | 
 | ||
|  |             TableViewOperations.ScrollToSelection(this); | ||
|  |         } | ||
|  | 
 | ||
|  |         void SortingChanged(MultiColumnHeader multiColumnHeader) | ||
|  |         { | ||
|  |             Sort(); | ||
|  | 
 | ||
|  |             Reload(); | ||
|  |         } | ||
|  | 
 | ||
|  |         static void ChangelistTreeViewItemGUI( | ||
|  |             PendingChangesTreeView treeView, | ||
|  |             Rect rowRect, | ||
|  |             float rowHeight, | ||
|  |             ChangelistTreeViewItem item, | ||
|  |             bool isSelected, | ||
|  |             bool isFocused) | ||
|  |         { | ||
|  |             string label = item.Changelist.ChangelistInfo.Name; | ||
|  |             string secondaryLabel = item.Changelist.ChangelistInfo.Description; | ||
|  | 
 | ||
|  |             bool wasChecked = CheckableItems.GetIsCheckedValue(item.Changelist) ?? false; | ||
|  | 
 | ||
|  |             bool hadCheckedChildren = | ||
|  |                 ((ICheckablePlasticTreeCategoryGroup)item.Changelist).GetCheckedCategoriesCount() > 0; | ||
|  | 
 | ||
|  |             bool hadPartiallyCheckedChildren = | ||
|  |                 ((ICheckablePlasticTreeCategoryGroup)item.Changelist).GetPartiallyCheckedCategoriesCount() > 0; | ||
|  | 
 | ||
|  |             bool isChecked = DrawTreeViewItem.ForCheckableIndentedItem( | ||
|  |                 rowRect, | ||
|  |                 rowHeight, | ||
|  |                 item.depth, | ||
|  |                 label, | ||
|  |                 secondaryLabel, | ||
|  |                 isSelected, | ||
|  |                 isFocused, | ||
|  |                 wasChecked, | ||
|  |                 hadCheckedChildren, | ||
|  |                 hadPartiallyCheckedChildren); | ||
|  | 
 | ||
|  |             if (wasChecked != isChecked) | ||
|  |             { | ||
|  |                 CheckableItems.SetCheckedValue(item.Changelist, isChecked); | ||
|  |                 treeView.SelectionChanged(); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         static void CategoryTreeViewItemGUI( | ||
|  |             PendingChangesTreeView treeView, | ||
|  |             Rect rowRect, | ||
|  |             float rowHeight, | ||
|  |             ChangeCategoryTreeViewItem item, | ||
|  |             bool isSelected, | ||
|  |             bool isFocused) | ||
|  |         { | ||
|  |             string label = item.Category.CategoryName; | ||
|  |             string secondaryLabel = item.Category.GetCheckedChangesText(); | ||
|  | 
 | ||
|  |             bool wasChecked = CheckableItems.GetIsCheckedValueForCategory(item.Category) ?? false; | ||
|  |             bool hadCheckedChildren = | ||
|  |                 ((ICheckablePlasticTreeCategory)item.Category).GetCheckedChangesCount() > 0; | ||
|  | 
 | ||
|  |             bool isChecked = DrawTreeViewItem.ForCheckableIndentedItem( | ||
|  |                 rowRect, | ||
|  |                 rowHeight, | ||
|  |                 item.depth, | ||
|  |                 label, | ||
|  |                 secondaryLabel, | ||
|  |                 isSelected, | ||
|  |                 isFocused, | ||
|  |                 wasChecked, | ||
|  |                 hadCheckedChildren, | ||
|  |                 false); | ||
|  | 
 | ||
|  |             if (wasChecked != isChecked) | ||
|  |             { | ||
|  |                 CheckableItems.SetCheckedValue(item.Category, isChecked); | ||
|  |                 treeView.SelectionChanged(); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         static void ChangeTreeViewItemGUI( | ||
|  |             string wkPath, | ||
|  |             bool isGluonMode, | ||
|  |             IAssetStatusCache assetStatusCache, | ||
|  |             PendingChangesTreeView treeView, | ||
|  |             UnityPendingChangesTree pendingChangesTree, | ||
|  |             ChangeTreeViewItem item, | ||
|  |             RowGUIArgs args) | ||
|  |         { | ||
|  |             for (int visibleColumnIdx = 0; visibleColumnIdx < args.GetNumVisibleColumns(); visibleColumnIdx++) | ||
|  |             { | ||
|  |                 Rect cellRect = args.GetCellRect(visibleColumnIdx); | ||
|  | 
 | ||
|  |                 PendingChangesTreeColumn column = | ||
|  |                     (PendingChangesTreeColumn)args.GetColumn(visibleColumnIdx); | ||
|  | 
 | ||
|  |                 ChangeTreeViewItemCellGUI( | ||
|  |                     isGluonMode, | ||
|  |                     assetStatusCache, | ||
|  |                     cellRect, | ||
|  |                     treeView.rowHeight, | ||
|  |                     treeView, | ||
|  |                     pendingChangesTree, | ||
|  |                     item, | ||
|  |                     column, | ||
|  |                     args.selected, | ||
|  |                     args.focused); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         static void ChangeTreeViewItemCellGUI( | ||
|  |             bool isGluonMode, | ||
|  |             IAssetStatusCache assetStatusCache, | ||
|  |             Rect rect, | ||
|  |             float rowHeight, | ||
|  |             PendingChangesTreeView treeView, | ||
|  |             UnityPendingChangesTree pendingChangesTree, | ||
|  |             ChangeTreeViewItem item, | ||
|  |             PendingChangesTreeColumn column, | ||
|  |             bool isSelected, | ||
|  |             bool isFocused) | ||
|  |         { | ||
|  |             PendingChangeInfo changeInfo = item.ChangeInfo; | ||
|  | 
 | ||
|  |             string label = changeInfo.GetColumnText( | ||
|  |                 PendingChangesTreeHeaderState.GetColumnName(column)); | ||
|  | 
 | ||
|  |             if (column == PendingChangesTreeColumn.Item) | ||
|  |             { | ||
|  |                 if (pendingChangesTree.HasMeta(changeInfo.ChangeInfo)) | ||
|  |                     label = string.Concat(label, UnityConstants.TREEVIEW_META_LABEL); | ||
|  | 
 | ||
|  |                 Texture icon = GetIcon(changeInfo); | ||
|  | 
 | ||
|  |                 bool isConflicted = IsConflicted( | ||
|  |                     isGluonMode, assetStatusCache, | ||
|  |                     changeInfo.ChangeInfo.GetFullPath()); | ||
|  | 
 | ||
|  |                 Texture overlayIcon = | ||
|  |                     GetChangesOverlayIcon.ForPendingChange( | ||
|  |                         changeInfo.ChangeInfo, isConflicted); | ||
|  | 
 | ||
|  |                 bool wasChecked = ((ICheckablePlasticTreeNode)changeInfo).IsChecked() ?? false; | ||
|  | 
 | ||
|  |                 bool isChecked = DrawTreeViewItem.ForCheckableItemCell( | ||
|  |                     rect, rowHeight, item.depth, | ||
|  |                     icon, overlayIcon, label, | ||
|  |                     isSelected, isFocused, false, | ||
|  |                     wasChecked); | ||
|  | 
 | ||
|  |                 ((ICheckablePlasticTreeNode)changeInfo).UpdateCheckedState(isChecked); | ||
|  | 
 | ||
|  |                 if (wasChecked != isChecked) | ||
|  |                 { | ||
|  |                     UpdateCheckStateForSelection(treeView, item); | ||
|  |                     treeView.SelectionChanged(); | ||
|  |                 } | ||
|  | 
 | ||
|  |                 return; | ||
|  |             } | ||
|  | 
 | ||
|  |             if (column == PendingChangesTreeColumn.Size) | ||
|  |             { | ||
|  |                 DrawTreeViewItem.ForSecondaryLabelRightAligned( | ||
|  |                     rect, label, isSelected, isFocused, false); | ||
|  |                 return; | ||
|  |             } | ||
|  | 
 | ||
|  |             DrawTreeViewItem.ForSecondaryLabel( | ||
|  |                 rect, label, isSelected, isFocused, false); | ||
|  |         } | ||
|  | 
 | ||
|  |         static void UpdateCheckStateForSelection( | ||
|  |             PendingChangesTreeView treeView, | ||
|  |             ChangeTreeViewItem senderTreeViewItem) | ||
|  |         { | ||
|  |             IList<int> selectedIds = treeView.GetSelection(); | ||
|  | 
 | ||
|  |             if (selectedIds.Count <= 1) | ||
|  |                 return; | ||
|  | 
 | ||
|  |             if (!selectedIds.Contains(senderTreeViewItem.id)) | ||
|  |                 return; | ||
|  | 
 | ||
|  |             bool isChecked = ((ICheckablePlasticTreeNode)senderTreeViewItem.ChangeInfo).IsChecked() ?? false; | ||
|  | 
 | ||
|  |             foreach (TreeViewItem treeViewItem in treeView.FindRows(selectedIds)) | ||
|  |             { | ||
|  |                 if (treeViewItem is ChangeCategoryTreeViewItem) | ||
|  |                 { | ||
|  |                     ((ICheckablePlasticTreeCategory)((ChangeCategoryTreeViewItem)treeViewItem) | ||
|  |                         .Category).UpdateCheckedState(isChecked); | ||
|  |                     continue; | ||
|  |                 } | ||
|  | 
 | ||
|  |                 ((ICheckablePlasticTreeNode)((ChangeTreeViewItem)treeViewItem) | ||
|  |                     .ChangeInfo).UpdateCheckedState(isChecked); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         static void RegenerateRows( | ||
|  |             UnityPendingChangesTree pendingChangesTree, | ||
|  |             TreeViewItemIds<IPlasticTreeNode, PendingChangeInfo> treeViewItemIds, | ||
|  |             PendingChangesTreeView treeView, | ||
|  |             TreeViewItem rootItem, | ||
|  |             List<TreeViewItem> rows, | ||
|  |             bool expandCategories) | ||
|  |         { | ||
|  |             ClearRows(rootItem, rows); | ||
|  | 
 | ||
|  |             IEnumerable<IPlasticTreeNode> nodes = pendingChangesTree.GetNodes(); | ||
|  | 
 | ||
|  |             if (nodes == null) | ||
|  |                 return; | ||
|  | 
 | ||
|  |             foreach (IPlasticTreeNode node in nodes) | ||
|  |             { | ||
|  |                 if (node is ChangelistNode) | ||
|  |                 { | ||
|  |                     AddChangelistNode( | ||
|  |                         (ChangelistNode)node, | ||
|  |                         treeViewItemIds, | ||
|  |                         treeView, | ||
|  |                         rootItem, | ||
|  |                         rows, | ||
|  |                         expandCategories); | ||
|  |                     continue; | ||
|  |                 } | ||
|  | 
 | ||
|  |                 if (node is PendingChangeCategory) | ||
|  |                     AddPendingChangeCategory( | ||
|  |                         (PendingChangeCategory)node, | ||
|  |                         treeViewItemIds, | ||
|  |                         treeView, | ||
|  |                         rootItem, | ||
|  |                         rows, | ||
|  |                         expandCategories, | ||
|  |                         0); | ||
|  |             } | ||
|  | 
 | ||
|  |             if (!expandCategories) | ||
|  |                 return; | ||
|  | 
 | ||
|  |             treeView.state.expandedIDs = treeViewItemIds.GetCategoryIds(); | ||
|  |         } | ||
|  | 
 | ||
|  |         static void AddChangelistNode( | ||
|  |             ChangelistNode changelist, | ||
|  |             TreeViewItemIds<IPlasticTreeNode, PendingChangeInfo> treeViewItemIds, | ||
|  |             PendingChangesTreeView treeView, | ||
|  |             TreeViewItem rootItem, | ||
|  |             List<TreeViewItem> rows, | ||
|  |             bool expandCategories) | ||
|  |         { | ||
|  |             int changelistCategoryId; | ||
|  |             if (!treeViewItemIds.TryGetCategoryItemId(changelist, out changelistCategoryId)) | ||
|  |                 changelistCategoryId = treeViewItemIds.AddCategoryItem(changelist); | ||
|  | 
 | ||
|  |             ChangelistTreeViewItem changelistTreeViewItem = | ||
|  |                 new ChangelistTreeViewItem(changelistCategoryId, changelist); | ||
|  | 
 | ||
|  |             rootItem.AddChild(changelistTreeViewItem); | ||
|  |             rows.Add(changelistTreeViewItem); | ||
|  | 
 | ||
|  |             if (!expandCategories && | ||
|  |                 !treeView.IsExpanded(changelistTreeViewItem.id)) | ||
|  |                 return; | ||
|  | 
 | ||
|  |             IEnumerable<IPlasticTreeNode> categories = ((IPlasticTreeNode)changelist).GetChildren(); | ||
|  | 
 | ||
|  |             foreach (IPlasticTreeNode category in categories) | ||
|  |             { | ||
|  |                 AddPendingChangeCategory( | ||
|  |                     (PendingChangeCategory)category, | ||
|  |                     treeViewItemIds, | ||
|  |                     treeView, | ||
|  |                     changelistTreeViewItem, | ||
|  |                     rows, | ||
|  |                     expandCategories, | ||
|  |                     1); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         static void AddPendingChangeCategory( | ||
|  |             PendingChangeCategory category, | ||
|  |             TreeViewItemIds<IPlasticTreeNode, PendingChangeInfo> treeViewItemIds, | ||
|  |             PendingChangesTreeView treeView, | ||
|  |             TreeViewItem rootItem, | ||
|  |             List<TreeViewItem> rows, | ||
|  |             bool expandCategories, | ||
|  |             int depth) | ||
|  |         { | ||
|  |             int categoryId; | ||
|  |             if (!treeViewItemIds.TryGetCategoryItemId(category, out categoryId)) | ||
|  |                 categoryId = treeViewItemIds.AddCategoryItem(category); | ||
|  | 
 | ||
|  |             ChangeCategoryTreeViewItem categoryTreeViewItem = | ||
|  |                 new ChangeCategoryTreeViewItem(categoryId, category, depth); | ||
|  | 
 | ||
|  |             rootItem.AddChild(categoryTreeViewItem); | ||
|  |             rows.Add(categoryTreeViewItem); | ||
|  | 
 | ||
|  |             if (!expandCategories && | ||
|  |                 !treeView.IsExpanded(categoryTreeViewItem.id)) | ||
|  |                 return; | ||
|  | 
 | ||
|  |             foreach (PendingChangeInfo change in ((IPendingChangesNode)category).GetCurrentChanges()) | ||
|  |             { | ||
|  |                 int changeId; | ||
|  |                 if (!treeViewItemIds.TryGetInfoItemId(change, out changeId)) | ||
|  |                     changeId = treeViewItemIds.AddInfoItem(change); | ||
|  | 
 | ||
|  |                 TreeViewItem changeTreeViewItem = | ||
|  |                     new ChangeTreeViewItem(changeId, change, depth + 1); | ||
|  | 
 | ||
|  |                 categoryTreeViewItem.AddChild(changeTreeViewItem); | ||
|  |                 rows.Add(changeTreeViewItem); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         static void ClearRows( | ||
|  |             TreeViewItem rootItem, | ||
|  |             List<TreeViewItem> rows) | ||
|  |         { | ||
|  |             if (rootItem.hasChildren) | ||
|  |                 rootItem.children.Clear(); | ||
|  | 
 | ||
|  |             rows.Clear(); | ||
|  |         } | ||
|  | 
 | ||
|  |         static Texture GetIcon(PendingChangeInfo change) | ||
|  |         { | ||
|  |             if (change.ChangeInfo.IsDirectory) | ||
|  |                 return Images.GetFolderIcon(); | ||
|  | 
 | ||
|  |             string fullPath = change.ChangeInfo.GetFullPath(); | ||
|  |             return Images.GetFileIcon(fullPath); | ||
|  |         } | ||
|  | 
 | ||
|  |         static bool IsConflicted( | ||
|  |             bool isGluonMode, | ||
|  |             IAssetStatusCache assetStatusCache, | ||
|  |             string fullPath) | ||
|  |         { | ||
|  |             if (!isGluonMode) | ||
|  |                 return false; | ||
|  | 
 | ||
|  |             return ClassifyAssetStatus.IsConflicted( | ||
|  |                 assetStatusCache.GetStatus(fullPath)); | ||
|  |         } | ||
|  | 
 | ||
|  |         bool mExpandCategories; | ||
|  |         bool mIsSelectionChangedEventDisabled; | ||
|  | 
 | ||
|  |         TreeViewItemIds<IPlasticTreeNode, PendingChangeInfo> mTreeViewItemIds = | ||
|  |             new TreeViewItemIds<IPlasticTreeNode, PendingChangeInfo>(); | ||
|  | 
 | ||
|  |         UnityPendingChangesTree mPendingChangesTree; | ||
|  |         DelayedActionBySecondsRunner mDelayedFilterAction; | ||
|  | 
 | ||
|  |         readonly Action mDoubleClickAction; | ||
|  |         readonly IAssetStatusCache mAssetStatusCache; | ||
|  |         readonly PendingChangesViewMenu mMenu; | ||
|  |         readonly PendingChangesTreeHeaderState mHeaderState; | ||
|  |         readonly List<string> mColumnNames; | ||
|  |         readonly bool mIsGluonMode; | ||
|  |         readonly WorkspaceInfo mWkInfo; | ||
|  |     } | ||
|  | } |