A game about forced loneliness, made by TACStudios
1using System.Collections.Generic;
2using System.IO;
3using System.Linq;
4
5using UnityEditor;
6using UnityEditor.IMGUI.Controls;
7using UnityEngine;
8
9using Codice.Client.BaseCommands;
10using Codice.CM.Common;
11
12using PlasticGui;
13using PlasticGui.WorkspaceWindow.PendingChanges;
14using PlasticGui.WorkspaceWindow.PendingChanges.Changelists;
15
16using Unity.PlasticSCM.Editor.AssetUtils;
17using Unity.PlasticSCM.Editor.UI;
18using Unity.PlasticSCM.Editor.UI.Tree;
19using Unity.PlasticSCM.Editor.AssetsOverlays.Cache;
20using Unity.PlasticSCM.Editor.AssetsOverlays;
21
22namespace Unity.PlasticSCM.Editor.Views.PendingChanges
23{
24 internal class PendingChangesTreeView : PlasticTreeView
25 {
26 internal PendingChangesTreeView(
27 WorkspaceInfo wkInfo,
28 bool isGluonMode,
29 PendingChangesTreeHeaderState headerState,
30 List<string> columnNames,
31 PendingChangesViewMenu menu,
32 IAssetStatusCache assetStatusCache)
33 {
34 mWkInfo = wkInfo;
35 mIsGluonMode = isGluonMode;
36 mColumnNames = columnNames;
37 mHeaderState = headerState;
38 mMenu = menu;
39 mAssetStatusCache = assetStatusCache;
40
41 mPendingChangesTree = new UnityPendingChangesTree();
42
43 multiColumnHeader = new PendingChangesMultiColumnHeader(
44 this,
45 headerState,
46 mPendingChangesTree);
47 multiColumnHeader.canSort = true;
48 multiColumnHeader.sortingChanged += SortingChanged;
49
50 customFoldoutYOffset = UnityConstants.TREEVIEW_FOLDOUT_Y_OFFSET;
51
52 mCooldownFilterAction = new CooldownWindowDelayer(
53 DelayedSearchChanged, UnityConstants.SEARCH_DELAYED_INPUT_ACTION_INTERVAL);
54 }
55
56 protected override void SingleClickedItem(int id)
57 {
58 SelectionChanged(new [] { id });
59 }
60
61 protected override void SelectionChanged(IList<int> selectedIds)
62 {
63 mHeaderState.UpdateItemColumnHeader(this);
64
65 if (mIsSelectionChangedEventDisabled)
66 return;
67
68 List<UnityEngine.Object> assets = new List<UnityEngine.Object>();
69
70 foreach (ChangeInfo changeInfo in GetSelectedChanges(false))
71 {
72 UnityEngine.Object asset = LoadAsset.FromChangeInfo(changeInfo);
73
74 if (asset == null)
75 continue;
76
77 assets.Add(asset);
78 }
79
80 UnityEditor.Selection.objects = assets.ToArray();
81
82 if (assets.Count == 1)
83 EditorGUIUtility.PingObject(assets[0]);
84 }
85
86 protected void SelectionChanged()
87 {
88 SelectionChanged(GetSelection());
89 }
90
91 public override void OnGUI(Rect rect)
92 {
93 MultiColumnHeader.DefaultStyles.background =
94 UnityStyles.Tree.Columns;
95
96 try
97 {
98 base.OnGUI(rect);
99
100 if (!base.HasFocus())
101 return;
102
103 Event e = Event.current;
104
105 if (e.type != EventType.KeyDown)
106 return;
107
108 bool isProcessed = mMenu.ProcessKeyActionIfNeeded(e);
109
110 if (isProcessed)
111 e.Use();
112 }
113 finally
114 {
115 MultiColumnHeader.DefaultStyles.background =
116 UnityStyles.PendingChangesTab.DefaultMultiColumHeader;
117 }
118 }
119
120 protected override bool CanChangeExpandedState(TreeViewItem item)
121 {
122 return item is ChangeCategoryTreeViewItem || item is ChangelistTreeViewItem;
123 }
124
125 protected override IList<TreeViewItem> BuildRows(TreeViewItem rootItem)
126 {
127 try
128 {
129 RegenerateRows(
130 mPendingChangesTree, mTreeViewItemIds, this,
131 rootItem, mRows, mExpandCategories);
132 }
133 finally
134 {
135 mExpandCategories = false;
136 }
137
138 return mRows;
139 }
140
141 protected override void CommandEventHandling()
142 {
143 // NOTE - empty override to prevent crash when pressing ctrl-a in the treeview
144 }
145
146 protected override void SearchChanged(string newSearch)
147 {
148 mCooldownFilterAction.Ping();
149 }
150
151 protected override void ContextClickedItem(int id)
152 {
153 mMenu.Popup();
154 Repaint();
155 }
156
157 protected override void RowGUI(RowGUIArgs args)
158 {
159 if (args.item is ChangelistTreeViewItem)
160 {
161 ChangelistTreeViewItemGUI(
162 this,
163 args.rowRect, rowHeight,
164 (ChangelistTreeViewItem)args.item,
165 args.selected, args.focused);
166 return;
167 }
168
169 if (args.item is ChangeCategoryTreeViewItem)
170 {
171 CategoryTreeViewItemGUI(
172 this,
173 args.rowRect, rowHeight,
174 (ChangeCategoryTreeViewItem)args.item,
175 args.selected, args.focused);
176 return;
177 }
178
179 if (args.item is ChangeTreeViewItem)
180 {
181 ChangeTreeViewItemGUI(
182 mWkInfo.ClientPath,
183 mIsGluonMode,
184 mAssetStatusCache,
185 this,
186 mPendingChangesTree,
187 (ChangeTreeViewItem)args.item,
188 args);
189 return;
190 }
191
192 base.RowGUI(args);
193 }
194
195 internal void BuildModel(List<ChangeInfo> changes, PendingChangesViewCheckedStateManager checkedStateManager)
196 {
197 mTreeViewItemIds.Clear();
198
199 mPendingChangesTree.BuildChangeCategories(
200 mWkInfo,
201 changes,
202 checkedStateManager);
203 }
204
205 internal ChangeInfo GetChangedForMoved(ChangeInfo moved)
206 {
207 return mPendingChangesTree.GetChangedForMoved(moved);
208 }
209
210 internal void Refilter()
211 {
212 Filter filter = new Filter(searchString);
213 mPendingChangesTree.Filter(filter, mColumnNames);
214
215 mExpandCategories = true;
216 }
217
218 internal void Sort()
219 {
220 int sortedColumnIdx = multiColumnHeader.state.sortedColumnIndex;
221 bool sortAscending = multiColumnHeader.IsSortedAscending(sortedColumnIdx);
222
223 mPendingChangesTree.Sort(
224 mColumnNames[sortedColumnIdx],
225 sortAscending);
226 }
227
228 internal bool GetSelectedPathsToDelete(
229 out List<string> privateDirectories,
230 out List<string> privateFiles)
231 {
232 privateDirectories = new List<string>();
233 privateFiles = new List<string>();
234
235 List<ChangeInfo> dirChanges = new List<ChangeInfo>();
236 List<ChangeInfo> fileChanges = new List<ChangeInfo>();
237
238 IList<int> selectedIds = GetSelection();
239
240 if (selectedIds.Count == 0)
241 return false;
242
243 foreach (KeyValuePair<PendingChangeInfo, int> item
244 in mTreeViewItemIds.GetInfoItems())
245 {
246 if (!selectedIds.Contains(item.Value))
247 continue;
248
249 ChangeInfo changeInfo = item.Key.ChangeInfo;
250
251 if (ChangeInfoType.IsControlled(changeInfo))
252 continue;
253
254 if (changeInfo.IsDirectory)
255 {
256 dirChanges.Add(changeInfo);
257 }
258 else
259 {
260 fileChanges.Add(changeInfo);
261 }
262
263 ChangeInfo metaChangeInfo = mPendingChangesTree.GetMetaChange(changeInfo);
264
265 if (metaChangeInfo != null)
266 {
267 fileChanges.Add(metaChangeInfo);
268 }
269 }
270
271 privateDirectories = dirChanges.Select(
272 d => d.GetFullPath()).ToList();
273 privateFiles = fileChanges.Select(
274 f => f.GetFullPath()).ToList();
275
276 return true;
277 }
278
279 internal void GetCheckedChanges(
280 List<ChangelistNode> selectedChangelists,
281 bool bExcludePrivates,
282 out List<ChangeInfo> changes,
283 out List<ChangeInfo> dependenciesCandidates)
284 {
285 mPendingChangesTree.GetCheckedChanges(
286 selectedChangelists,
287 bExcludePrivates,
288 out changes,
289 out dependenciesCandidates);
290 }
291
292 internal List<ChangeInfo> GetAllChanges()
293 {
294 return mPendingChangesTree.GetAllChanges();
295 }
296
297 internal ChangeInfo GetMetaChange(ChangeInfo change)
298 {
299 if (change == null)
300 return null;
301
302 return mPendingChangesTree.GetMetaChange(change);
303 }
304
305 internal List<ChangeInfo> GetDependenciesCandidates(
306 List<ChangeInfo> selectedChanges, bool bExcludePrivates)
307 {
308 return mPendingChangesTree.GetDependenciesCandidates(
309 selectedChanges, bExcludePrivates);
310 }
311
312 internal List<IPlasticTreeNode> GetSelectedNodes()
313 {
314 List<IPlasticTreeNode> result = new List<IPlasticTreeNode>();
315
316 IList<int> selectedIds = GetSelection();
317
318 if (selectedIds.Count == 0)
319 return result;
320
321 foreach (KeyValuePair<IPlasticTreeNode, int> item
322 in mTreeViewItemIds.GetCategoryItems())
323 {
324 if (!selectedIds.Contains(item.Value))
325 continue;
326
327 result.Add(item.Key);
328 }
329
330 foreach (KeyValuePair<PendingChangeInfo, int> item
331 in mTreeViewItemIds.GetInfoItems())
332 {
333 if (!selectedIds.Contains(item.Value))
334 continue;
335
336 result.Add(item.Key);
337 }
338
339 return result;
340 }
341
342 internal List<ChangeInfo> GetSelectedChanges(bool includeMetaFiles)
343 {
344 List<ChangeInfo> result = new List<ChangeInfo>();
345
346 IList<int> selectedIds = GetSelection();
347
348 if (selectedIds.Count == 0)
349 return result;
350
351 foreach (KeyValuePair<PendingChangeInfo, int> item
352 in mTreeViewItemIds.GetInfoItems())
353 {
354 if (!selectedIds.Contains(item.Value))
355 continue;
356
357 result.Add(item.Key.ChangeInfo);
358 }
359
360 if (includeMetaFiles)
361 mPendingChangesTree.FillWithMeta(result);
362
363 return result;
364 }
365
366 internal List<PendingChangeInfo> GetSelectedPendingChangeInfos()
367 {
368 List<PendingChangeInfo> result = new List<PendingChangeInfo>();
369
370 IList<int> selectedIds = GetSelection();
371
372 if (selectedIds.Count == 0)
373 return result;
374
375 foreach (KeyValuePair<PendingChangeInfo, int> item
376 in mTreeViewItemIds.GetInfoItems())
377 {
378 if (!selectedIds.Contains(item.Value))
379 continue;
380
381 result.Add(item.Key);
382 }
383
384 return result;
385 }
386
387 internal List<ChangelistNode> GetSelectedChangelistNodes()
388 {
389 List<ChangelistNode> result = new List<ChangelistNode>();
390
391 IList<int> selectedIds = GetSelection();
392
393 if (selectedIds.Count == 0)
394 return result;
395
396 foreach (KeyValuePair<IPlasticTreeNode, int> item
397 in mTreeViewItemIds.GetCategoryItems())
398 {
399 if (!selectedIds.Contains(item.Value))
400 continue;
401
402 if (item.Key is ChangelistNode)
403 result.Add((ChangelistNode)item.Key);
404 }
405
406 return result;
407 }
408
409 internal bool SelectionHasMeta()
410 {
411 ChangeInfo selectedChangeInfo = GetSelectedRow();
412
413 if (selectedChangeInfo == null)
414 return false;
415
416 return mPendingChangesTree.HasMeta(selectedChangeInfo);
417 }
418
419 internal ChangeInfo GetSelectedRow()
420 {
421 IList<int> selectedIds = GetSelection();
422
423 if (selectedIds.Count == 0)
424 return null;
425
426 int selectedId = selectedIds[0];
427
428 foreach (KeyValuePair<PendingChangeInfo, int> item
429 in mTreeViewItemIds.GetInfoItems())
430 {
431 if (selectedId == item.Value)
432 return item.Key.ChangeInfo;
433 }
434
435 return null;
436 }
437
438 internal ChangeInfo GetNearestAddedChange()
439 {
440 IList<int> selectedIds = GetSelection();
441
442 if (selectedIds.Count == 0)
443 return null;
444
445 int id = selectedIds[0];
446
447 IList<TreeViewItem> treeViewItems =
448 FindRows(new List<int>() { id });
449
450 if (treeViewItems.Count == 0)
451 return null;
452
453 PendingChangeInfo changeInfo =
454 ((ChangeTreeViewItem)treeViewItems[0]).ChangeInfo;
455 PendingChangeCategory category =
456 (PendingChangeCategory)((IPlasticTreeNode)changeInfo).GetParent();
457
458 int itemIndex = category.GetChildPosition(changeInfo);
459
460 ChangeInfo result = GetNextExistingAddedItem(category, itemIndex);
461
462 if (result != null)
463 return result;
464
465 return GetPreviousExistingAddedItem(category, itemIndex);
466 }
467
468 internal void SelectFirstPendingChangeOnTree()
469 {
470 int treeIdFirstItem = GetTreeIdFirstItem();
471
472 if (treeIdFirstItem == -1)
473 return;
474
475 mIsSelectionChangedEventDisabled = true;
476
477 try
478 {
479 TableViewOperations.SetSelectionAndScroll(
480 this, new List<int> { treeIdFirstItem });
481 }
482 finally
483 {
484 mIsSelectionChangedEventDisabled = false;
485 }
486 }
487
488 internal void SelectPreviouslySelectedPendingChanges(
489 List<ChangeInfo> changesToSelect)
490 {
491 List<int> idsToSelect = new List<int>();
492
493 foreach (ChangeInfo change in changesToSelect)
494 {
495 int changeId = GetTreeIdForItem(change);
496
497 if (changeId == -1)
498 continue;
499
500 idsToSelect.Add(changeId);
501 }
502
503 mIsSelectionChangedEventDisabled = true;
504 try
505 {
506 TableViewOperations.SetSelectionAndScroll(
507 this, idsToSelect);
508 }
509 finally
510 {
511 mIsSelectionChangedEventDisabled = false;
512 }
513 }
514
515 internal int GetCheckedItemCount()
516 {
517 return CheckableItems.GetCheckedChildNodeCount(mPendingChangesTree.GetNodes());
518 }
519
520 internal int GetTotalItemCount()
521 {
522 return CheckableItems.GetTotalChildNodeCount(mPendingChangesTree.GetNodes());
523 }
524
525 internal bool AreAllItemsChecked()
526 {
527 return GetCheckedItemCount() == GetTotalItemCount();
528 }
529
530 ChangeInfo GetNextExistingAddedItem(
531 PendingChangeCategory addedCategory, int targetAddedItemIndex)
532 {
533 int addedItemsCount = addedCategory.GetChildrenCount();
534
535 for (int i = targetAddedItemIndex + 1; i < addedItemsCount; i++)
536 {
537 ChangeInfo currentChangeInfo = GetExistingAddedItem(addedCategory, i);
538
539 if (currentChangeInfo != null)
540 return currentChangeInfo;
541 }
542
543 return null;
544 }
545
546 ChangeInfo GetPreviousExistingAddedItem(
547 PendingChangeCategory addedCategory, int targetAddedItemIndex)
548 {
549 for (int i = targetAddedItemIndex - 1; i >= 0; i--)
550 {
551 ChangeInfo currentChangeInfo = GetExistingAddedItem(addedCategory, i);
552
553 if (currentChangeInfo != null)
554 return currentChangeInfo;
555 }
556
557 return null;
558 }
559
560 ChangeInfo GetExistingAddedItem(
561 PendingChangeCategory addedCategory, int addedItemIndex)
562 {
563 ChangeInfo currentChangeInfo = ((PendingChangeInfo)((IPendingChangesNode)addedCategory)
564 .GetCurrentChanges()[addedItemIndex]).ChangeInfo;
565
566 if (Directory.Exists(currentChangeInfo.Path) ||
567 File.Exists(currentChangeInfo.Path))
568 return currentChangeInfo;
569
570 return null;
571 }
572
573 int GetTreeIdFirstItem()
574 {
575 PendingChangeInfo firstChange = mPendingChangesTree.GetFirstPendingChange();
576
577 if (firstChange == null)
578 return -1;
579
580 int changeId;
581 if (mTreeViewItemIds.TryGetInfoItemId(firstChange, out changeId))
582 return changeId;
583
584 return -1;
585 }
586
587 int GetTreeIdForItem(ChangeInfo change)
588 {
589 foreach (KeyValuePair<PendingChangeInfo, int> item in mTreeViewItemIds.GetInfoItems())
590 {
591 ChangeInfo changeInfo = item.Key.ChangeInfo;
592
593 if (changeInfo.ChangeTypes != change.ChangeTypes)
594 continue;
595
596 if (changeInfo.GetFullPath() != change.GetFullPath())
597 continue;
598
599 return item.Value;
600 }
601
602 return -1;
603 }
604
605 void DelayedSearchChanged()
606 {
607 Refilter();
608
609 Sort();
610
611 Reload();
612
613 TableViewOperations.ScrollToSelection(this);
614 }
615
616 void SortingChanged(MultiColumnHeader multiColumnHeader)
617 {
618 Sort();
619
620 Reload();
621 }
622
623 static void ChangelistTreeViewItemGUI(
624 PendingChangesTreeView treeView,
625 Rect rowRect,
626 float rowHeight,
627 ChangelistTreeViewItem item,
628 bool isSelected,
629 bool isFocused)
630 {
631 string label = item.Changelist.ChangelistInfo.Name;
632 string secondaryLabel = item.Changelist.ChangelistInfo.Description;
633
634 bool wasChecked = CheckableItems.GetIsCheckedValue(item.Changelist) ?? false;
635
636 bool hadCheckedChildren =
637 ((ICheckablePlasticTreeCategoryGroup)item.Changelist).GetCheckedCategoriesCount() > 0;
638
639 bool hadPartiallyCheckedChildren =
640 ((ICheckablePlasticTreeCategoryGroup)item.Changelist).GetPartiallyCheckedCategoriesCount() > 0;
641
642 bool isChecked = DrawTreeViewItem.ForCheckableCategoryItem(
643 rowRect,
644 rowHeight,
645 item.depth,
646 label,
647 secondaryLabel,
648 isSelected,
649 isFocused,
650 wasChecked,
651 hadCheckedChildren,
652 hadPartiallyCheckedChildren);
653
654 if (wasChecked != isChecked)
655 {
656 CheckableItems.SetCheckedValue(item.Changelist, isChecked);
657 treeView.SelectionChanged();
658 }
659 }
660
661 static void CategoryTreeViewItemGUI(
662 PendingChangesTreeView treeView,
663 Rect rowRect,
664 float rowHeight,
665 ChangeCategoryTreeViewItem item,
666 bool isSelected,
667 bool isFocused)
668 {
669 string label = item.Category.CategoryName;
670 string secondaryLabel = item.Category.GetCheckedChangesText();
671
672 bool wasChecked = CheckableItems.GetIsCheckedValueForCategory(item.Category) ?? false;
673 bool hadCheckedChildren =
674 ((ICheckablePlasticTreeCategory)item.Category).GetCheckedChangesCount() > 0;
675
676 bool isChecked = DrawTreeViewItem.ForCheckableCategoryItem(
677 rowRect,
678 rowHeight,
679 item.depth,
680 label,
681 secondaryLabel,
682 isSelected,
683 isFocused,
684 wasChecked,
685 hadCheckedChildren,
686 false);
687
688 if (wasChecked != isChecked)
689 {
690 CheckableItems.SetCheckedValue(item.Category, isChecked);
691 treeView.SelectionChanged();
692 }
693 }
694
695 static void ChangeTreeViewItemGUI(
696 string wkPath,
697 bool isGluonMode,
698 IAssetStatusCache assetStatusCache,
699 PendingChangesTreeView treeView,
700 UnityPendingChangesTree pendingChangesTree,
701 ChangeTreeViewItem item,
702 RowGUIArgs args)
703 {
704 for (int visibleColumnIdx = 0; visibleColumnIdx < args.GetNumVisibleColumns(); visibleColumnIdx++)
705 {
706 Rect cellRect = args.GetCellRect(visibleColumnIdx);
707
708 PendingChangesTreeColumn column =
709 (PendingChangesTreeColumn)args.GetColumn(visibleColumnIdx);
710
711 ChangeTreeViewItemCellGUI(
712 isGluonMode,
713 assetStatusCache,
714 cellRect,
715 treeView.rowHeight,
716 treeView,
717 pendingChangesTree,
718 item,
719 column,
720 args.selected,
721 args.focused);
722 }
723 }
724
725 static void ChangeTreeViewItemCellGUI(
726 bool isGluonMode,
727 IAssetStatusCache assetStatusCache,
728 Rect rect,
729 float rowHeight,
730 PendingChangesTreeView treeView,
731 UnityPendingChangesTree pendingChangesTree,
732 ChangeTreeViewItem item,
733 PendingChangesTreeColumn column,
734 bool isSelected,
735 bool isFocused)
736 {
737 PendingChangeInfo changeInfo = item.ChangeInfo;
738
739 string label = changeInfo.GetColumnText(
740 PendingChangesTreeHeaderState.GetColumnName(column));
741
742 if (column == PendingChangesTreeColumn.Item)
743 {
744 if (pendingChangesTree.HasMeta(changeInfo.ChangeInfo))
745 label = string.Concat(label, UnityConstants.TREEVIEW_META_LABEL);
746
747 Texture icon = GetIcon(changeInfo);
748
749 bool isConflicted = IsConflicted(
750 isGluonMode, assetStatusCache,
751 changeInfo.ChangeInfo.GetFullPath());
752
753 Texture overlayIcon =
754 GetChangesOverlayIcon.ForPendingChange(
755 changeInfo.ChangeInfo, isConflicted);
756
757 bool wasChecked = ((ICheckablePlasticTreeNode)changeInfo).IsChecked() ?? false;
758
759 bool isChecked = DrawTreeViewItem.ForCheckableItemCell(
760 rect, rowHeight, item.depth,
761 icon, overlayIcon, label,
762 isSelected, isFocused, false,
763 wasChecked);
764
765 ((ICheckablePlasticTreeNode)changeInfo).UpdateCheckedState(isChecked);
766
767 if (wasChecked != isChecked)
768 {
769 UpdateCheckStateForSelection(treeView, item);
770 treeView.SelectionChanged();
771 }
772
773 return;
774 }
775
776 if (column == PendingChangesTreeColumn.Size)
777 {
778 DrawTreeViewItem.ForSecondaryLabelRightAligned(
779 rect, label, isSelected, isFocused, false);
780 return;
781 }
782
783 DrawTreeViewItem.ForSecondaryLabel(
784 rect, label, isSelected, isFocused, false);
785 }
786
787 static void UpdateCheckStateForSelection(
788 PendingChangesTreeView treeView,
789 ChangeTreeViewItem senderTreeViewItem)
790 {
791 IList<int> selectedIds = treeView.GetSelection();
792
793 if (selectedIds.Count <= 1)
794 return;
795
796 if (!selectedIds.Contains(senderTreeViewItem.id))
797 return;
798
799 bool isChecked = ((ICheckablePlasticTreeNode)senderTreeViewItem.ChangeInfo).IsChecked() ?? false;
800
801 foreach (TreeViewItem treeViewItem in treeView.FindRows(selectedIds))
802 {
803 if (treeViewItem is ChangeCategoryTreeViewItem)
804 {
805 ((ICheckablePlasticTreeCategory)((ChangeCategoryTreeViewItem)treeViewItem)
806 .Category).UpdateCheckedState(isChecked);
807 continue;
808 }
809
810 ((ICheckablePlasticTreeNode)((ChangeTreeViewItem)treeViewItem)
811 .ChangeInfo).UpdateCheckedState(isChecked);
812 }
813 }
814
815 static void RegenerateRows(
816 UnityPendingChangesTree pendingChangesTree,
817 TreeViewItemIds<IPlasticTreeNode, PendingChangeInfo> treeViewItemIds,
818 PendingChangesTreeView treeView,
819 TreeViewItem rootItem,
820 List<TreeViewItem> rows,
821 bool expandCategories)
822 {
823 ClearRows(rootItem, rows);
824
825 IEnumerable<IPlasticTreeNode> nodes = pendingChangesTree.GetNodes();
826
827 if (nodes == null)
828 return;
829
830 foreach (IPlasticTreeNode node in nodes)
831 {
832 if (node is ChangelistNode)
833 {
834 AddChangelistNode(
835 (ChangelistNode)node,
836 treeViewItemIds,
837 treeView,
838 rootItem,
839 rows,
840 expandCategories);
841 continue;
842 }
843
844 if (node is PendingChangeCategory)
845 AddPendingChangeCategory(
846 (PendingChangeCategory)node,
847 treeViewItemIds,
848 treeView,
849 rootItem,
850 rows,
851 expandCategories,
852 0);
853 }
854
855 if (!expandCategories)
856 return;
857
858 treeView.state.expandedIDs = treeViewItemIds.GetCategoryIds();
859 }
860
861 static void AddChangelistNode(
862 ChangelistNode changelist,
863 TreeViewItemIds<IPlasticTreeNode, PendingChangeInfo> treeViewItemIds,
864 PendingChangesTreeView treeView,
865 TreeViewItem rootItem,
866 List<TreeViewItem> rows,
867 bool expandCategories)
868 {
869 int changelistCategoryId;
870 if (!treeViewItemIds.TryGetCategoryItemId(changelist, out changelistCategoryId))
871 changelistCategoryId = treeViewItemIds.AddCategoryItem(changelist);
872
873 ChangelistTreeViewItem changelistTreeViewItem =
874 new ChangelistTreeViewItem(changelistCategoryId, changelist);
875
876 rootItem.AddChild(changelistTreeViewItem);
877 rows.Add(changelistTreeViewItem);
878
879 if (!expandCategories &&
880 !treeView.IsExpanded(changelistTreeViewItem.id))
881 return;
882
883 IEnumerable<IPlasticTreeNode> categories = ((IPlasticTreeNode)changelist).GetChildren();
884
885 foreach (IPlasticTreeNode category in categories)
886 {
887 AddPendingChangeCategory(
888 (PendingChangeCategory)category,
889 treeViewItemIds,
890 treeView,
891 changelistTreeViewItem,
892 rows,
893 expandCategories,
894 1);
895 }
896 }
897
898 static void AddPendingChangeCategory(
899 PendingChangeCategory category,
900 TreeViewItemIds<IPlasticTreeNode, PendingChangeInfo> treeViewItemIds,
901 PendingChangesTreeView treeView,
902 TreeViewItem rootItem,
903 List<TreeViewItem> rows,
904 bool expandCategories,
905 int depth)
906 {
907 int categoryId;
908 if (!treeViewItemIds.TryGetCategoryItemId(category, out categoryId))
909 categoryId = treeViewItemIds.AddCategoryItem(category);
910
911 ChangeCategoryTreeViewItem categoryTreeViewItem =
912 new ChangeCategoryTreeViewItem(categoryId, category, depth);
913
914 rootItem.AddChild(categoryTreeViewItem);
915 rows.Add(categoryTreeViewItem);
916
917 if (!expandCategories &&
918 !treeView.IsExpanded(categoryTreeViewItem.id))
919 return;
920
921 foreach (PendingChangeInfo change in ((IPendingChangesNode)category).GetCurrentChanges())
922 {
923 int changeId;
924 if (!treeViewItemIds.TryGetInfoItemId(change, out changeId))
925 changeId = treeViewItemIds.AddInfoItem(change);
926
927 TreeViewItem changeTreeViewItem =
928 new ChangeTreeViewItem(changeId, change, depth + 1);
929
930 categoryTreeViewItem.AddChild(changeTreeViewItem);
931 rows.Add(changeTreeViewItem);
932 }
933 }
934
935 static void ClearRows(
936 TreeViewItem rootItem,
937 List<TreeViewItem> rows)
938 {
939 if (rootItem.hasChildren)
940 rootItem.children.Clear();
941
942 rows.Clear();
943 }
944
945 static Texture GetIcon(PendingChangeInfo change)
946 {
947 if (change.ChangeInfo.IsDirectory)
948 return Images.GetDirectoryIcon();
949
950 string fullPath = change.ChangeInfo.GetFullPath();
951 return Images.GetFileIcon(fullPath);
952 }
953
954 static bool IsConflicted(
955 bool isGluonMode,
956 IAssetStatusCache assetStatusCache,
957 string fullPath)
958 {
959 if (!isGluonMode)
960 return false;
961
962 return ClassifyAssetStatus.IsConflicted(
963 assetStatusCache.GetStatus(fullPath));
964 }
965
966 bool mExpandCategories;
967 bool mIsSelectionChangedEventDisabled;
968
969 TreeViewItemIds<IPlasticTreeNode, PendingChangeInfo> mTreeViewItemIds =
970 new TreeViewItemIds<IPlasticTreeNode, PendingChangeInfo>();
971
972 UnityPendingChangesTree mPendingChangesTree;
973 CooldownWindowDelayer mCooldownFilterAction;
974
975 readonly PendingChangesTreeHeaderState mHeaderState;
976 readonly PendingChangesViewMenu mMenu;
977 readonly IAssetStatusCache mAssetStatusCache;
978 readonly List<string> mColumnNames;
979 readonly bool mIsGluonMode;
980 readonly WorkspaceInfo mWkInfo;
981 }
982}