A game about forced loneliness, made by TACStudios
1using System.Collections.Generic;
2
3using UnityEditor.IMGUI.Controls;
4using UnityEngine;
5
6using Codice.Client.Commands;
7using Codice.Client.Common;
8using Codice.CM.Common;
9using Codice.Utils;
10using PlasticGui;
11using PlasticGui.WorkspaceWindow.Diff;
12using Unity.PlasticSCM.Editor.UI;
13using Unity.PlasticSCM.Editor.UI.Tree;
14
15namespace Unity.PlasticSCM.Editor.Views.Diff
16{
17 internal class DiffTreeView : PlasticTreeView
18 {
19 internal DiffTreeView(DiffTreeViewMenu menu)
20 {
21 mMenu = menu;
22
23 customFoldoutYOffset = UnityConstants.TREEVIEW_FOLDOUT_Y_OFFSET;
24
25 mCooldownFilterAction = new CooldownWindowDelayer(
26 DelayedSearchChanged, UnityConstants.SEARCH_DELAYED_INPUT_ACTION_INTERVAL);
27
28 EnableHorizontalScrollbar();
29 }
30
31 public override void OnGUI(Rect rect)
32 {
33 base.OnGUI(rect);
34
35 Event e = Event.current;
36
37 if (e.type != EventType.KeyDown)
38 return;
39
40 bool isProcessed = mMenu.ProcessKeyActionIfNeeded(e);
41
42 if (isProcessed)
43 e.Use();
44 }
45
46 protected override bool CanChangeExpandedState(TreeViewItem item)
47 {
48 return item is ChangeCategoryTreeViewItem
49 || item is MergeCategoryTreeViewItem;
50 }
51
52 protected override IList<TreeViewItem> BuildRows(TreeViewItem rootItem)
53 {
54 try
55 {
56 RegenerateRows(
57 mDiffTree,
58 mTreeViewItemIds,
59 this,
60 rootItem,
61 mRows,
62 mExpandCategories);
63 }
64 finally
65 {
66 mExpandCategories = false;
67 }
68
69 return mRows;
70 }
71
72 protected override void CommandEventHandling()
73 {
74 // NOTE - empty override to prevent crash when pressing ctrl-a in the treeview
75 }
76
77 protected override void SearchChanged(string newSearch)
78 {
79 mCooldownFilterAction.Ping();
80 }
81
82 protected override void ContextClickedItem(int id)
83 {
84 mMenu.Popup();
85 Repaint();
86 }
87
88 protected override void RowGUI(RowGUIArgs args)
89 {
90 float itemWidth;
91 TreeViewItemGUI(
92 args.item, args.rowRect, rowHeight, mDiffTree, args.selected, args.focused, out itemWidth);
93
94 float rowWidth = baseIndent + args.item.depth * depthIndentWidth +
95 itemWidth + UnityConstants.TREEVIEW_ROW_WIDTH_OFFSET;
96
97 if (rowWidth > mLargestRowWidth)
98 mLargestRowWidth = rowWidth;
99 }
100
101 protected override void AfterRowsGUI()
102 {
103 if (mHorizontalColumn != null)
104 mHorizontalColumn.width = mLargestRowWidth;
105
106 base.AfterRowsGUI();
107 }
108
109 internal void ClearModel()
110 {
111 mTreeViewItemIds.Clear();
112
113 mDiffTree = new UnityDiffTree();
114 }
115
116 internal void BuildModel(
117 WorkspaceInfo wkInfo,
118 List<ClientDiff> diffs,
119 BranchResolver brResolver,
120 bool skipMergeTracking)
121 {
122 mTreeViewItemIds.Clear();
123
124 mDiffTree.BuildCategories(wkInfo, diffs, brResolver, skipMergeTracking);
125 }
126
127 internal void Refilter()
128 {
129 Filter filter = new Filter(searchString);
130 mDiffTree.Filter(filter, ColumnsNames);
131
132 mExpandCategories = true;
133 }
134
135 internal void Sort()
136 {
137 mDiffTree.Sort(
138 PlasticLocalization.GetString(PlasticLocalization.Name.PathColumn),
139 sortAscending: true);
140 }
141
142 internal ClientDiffInfo GetMetaDiff(ClientDiffInfo diff)
143 {
144 return mDiffTree.GetMetaDiff(diff);
145 }
146
147 internal bool SelectionHasMeta()
148 {
149 if (!HasSelection())
150 return false;
151
152 ClientDiffInfo selectedDiff = GetSelectedDiffs(false)[0];
153
154 if (selectedDiff == null)
155 return false;
156
157 return mDiffTree.HasMeta(selectedDiff);
158 }
159
160 internal List<ClientDiffInfo> GetSelectedDiffs(bool includeMetaFiles)
161 {
162 List<ClientDiffInfo> result = new List<ClientDiffInfo>();
163
164 IList<int> selectedIds = GetSelection();
165
166 if (selectedIds.Count == 0)
167 return result;
168
169 foreach (KeyValuePair<ITreeViewNode, int> item
170 in mTreeViewItemIds.GetInfoItems())
171 {
172 if (!selectedIds.Contains(item.Value))
173 continue;
174
175 if (!(item.Key is ClientDiffInfo))
176 continue;
177
178 result.Add((ClientDiffInfo)item.Key);
179 }
180
181 if (includeMetaFiles)
182 mDiffTree.FillWithMeta(result);
183
184 return result;
185 }
186
187 void DelayedSearchChanged()
188 {
189 Refilter();
190
191 Sort();
192
193 Reload();
194
195 TableViewOperations.ScrollToSelection(this);
196 }
197
198 void EnableHorizontalScrollbar()
199 {
200 mHorizontalColumn = new MultiColumnHeaderState.Column();
201 mHorizontalColumn.autoResize = false;
202
203 MultiColumnHeaderState.Column[] cols = { mHorizontalColumn };
204 MultiColumnHeaderState headerState = new MultiColumnHeaderState(cols);
205
206 multiColumnHeader = new MultiColumnHeader(headerState);
207 multiColumnHeader.height = 0f;
208 }
209
210 static void RegenerateRows(
211 UnityDiffTree diffTree,
212 TreeViewItemIds<IDiffCategory, ITreeViewNode> treeViewItemIds,
213 TreeView treeView,
214 TreeViewItem rootItem,
215 List<TreeViewItem> rows,
216 bool expandCategories)
217 {
218 ClearRows(rootItem, rows);
219
220 List<IDiffCategory> categories = diffTree.GetNodes();
221
222 if (categories == null)
223 return;
224
225 foreach (IDiffCategory category in categories)
226 {
227 if (category is CategoryGroup &&
228 ((CategoryGroup)category).CategoryType == CategoryGroup.Type.MergeCategory)
229 {
230 AddMergeCategory(
231 rootItem,
232 category,
233 rows,
234 treeViewItemIds,
235 treeView,
236 expandCategories);
237 }
238
239 if (category is ChangeCategory)
240 {
241 AddChangeCategory(
242 rootItem,
243 category,
244 rows,
245 treeViewItemIds,
246 treeView,
247 expandCategories);
248 }
249 }
250
251 if (!expandCategories)
252 return;
253
254 treeView.state.expandedIDs = treeViewItemIds.GetCategoryIds();
255 }
256
257 static void ClearRows(
258 TreeViewItem rootItem,
259 List<TreeViewItem> rows)
260 {
261 if (rootItem.hasChildren)
262 rootItem.children.Clear();
263
264 rows.Clear();
265 }
266
267 static void AddMergeCategory(
268 TreeViewItem rootItem,
269 IDiffCategory category,
270 List<TreeViewItem> rows,
271 TreeViewItemIds<IDiffCategory, ITreeViewNode> treeViewItemIds,
272 TreeView treeView,
273 bool expandCategories)
274 {
275 int categoryId;
276 if (!treeViewItemIds.TryGetCategoryItemId(category, out categoryId))
277 categoryId = treeViewItemIds.AddCategoryItem(category);
278
279 MergeCategoryTreeViewItem mergeCategoryTreeViewItem =
280 new MergeCategoryTreeViewItem(
281 categoryId,
282 rootItem.depth + 1,
283 (CategoryGroup)category);
284
285 rootItem.AddChild(mergeCategoryTreeViewItem);
286 rows.Add(mergeCategoryTreeViewItem);
287
288 if (!expandCategories &&
289 !treeView.IsExpanded(mergeCategoryTreeViewItem.id))
290 return;
291
292 for (int i = 0; i < category.GetChildrenCount(); i++)
293 {
294 IDiffCategory child = (IDiffCategory)((ITreeViewNode)category)
295 .GetChild(i);
296
297 AddChangeCategory(
298 mergeCategoryTreeViewItem,
299 child,
300 rows,
301 treeViewItemIds,
302 treeView,
303 expandCategories);
304 }
305 }
306
307 static void AddChangeCategory(
308 TreeViewItem parentItem,
309 IDiffCategory category,
310 List<TreeViewItem> rows,
311 TreeViewItemIds<IDiffCategory, ITreeViewNode> treeViewItemIds,
312 TreeView treeView,
313 bool expandCategories)
314 {
315 int categoryId;
316 if (!treeViewItemIds.TryGetCategoryItemId(category, out categoryId))
317 categoryId = treeViewItemIds.AddCategoryItem(category);
318
319 ChangeCategoryTreeViewItem changeCategoryTreeViewItem =
320 new ChangeCategoryTreeViewItem(
321 categoryId,
322 parentItem.depth + 1,
323 (ChangeCategory)category);
324
325 parentItem.AddChild(changeCategoryTreeViewItem);
326 rows.Add(changeCategoryTreeViewItem);
327
328 if (!expandCategories &&
329 !treeView.IsExpanded(changeCategoryTreeViewItem.id))
330 return;
331
332 AddClientDiffs(
333 changeCategoryTreeViewItem,
334 (ITreeViewNode)category,
335 rows,
336 treeViewItemIds);
337 }
338
339 static void AddClientDiffs(
340 TreeViewItem parentItem,
341 ITreeViewNode parentNode,
342 List<TreeViewItem> rows,
343 TreeViewItemIds<IDiffCategory, ITreeViewNode> treeViewItemIds)
344 {
345 for (int i = 0; i < parentNode.GetChildrenCount(); i++)
346 {
347 ITreeViewNode child = parentNode.GetChild(i);
348
349 int nodeId;
350 if (!treeViewItemIds.TryGetInfoItemId(child, out nodeId))
351 nodeId = treeViewItemIds.AddInfoItem(child);
352
353 TreeViewItem changeTreeViewItem =
354 new ClientDiffTreeViewItem(
355 nodeId,
356 parentItem.depth + 1,
357 (ClientDiffInfo)child);
358
359 parentItem.AddChild(changeTreeViewItem);
360 rows.Add(changeTreeViewItem);
361 }
362 }
363
364 static void TreeViewItemGUI(
365 TreeViewItem item,
366 Rect rowRect,
367 float rowHeight,
368 UnityDiffTree diffTree,
369 bool isSelected,
370 bool isFocused,
371 out float itemWidth)
372 {
373 if (item is MergeCategoryTreeViewItem)
374 {
375 MergeCategoryTreeViewItemGUI(
376 rowRect,
377 (MergeCategoryTreeViewItem)item,
378 isSelected,
379 isFocused,
380 out itemWidth);
381 return;
382 }
383
384 if (item is ChangeCategoryTreeViewItem)
385 {
386 ChangeCategoryTreeViewItemGUI(
387 rowRect,
388 (ChangeCategoryTreeViewItem)item,
389 isSelected,
390 isFocused,
391 out itemWidth);
392 return;
393 }
394
395 if (item is ClientDiffTreeViewItem)
396 {
397 ClientDiffTreeViewItemGUI(
398 rowRect,
399 rowHeight,
400 diffTree,
401 (ClientDiffTreeViewItem)item,
402 isSelected,
403 isFocused,
404 out itemWidth);
405 return;
406 }
407
408 itemWidth = 0;
409 }
410
411 static void MergeCategoryTreeViewItemGUI(
412 Rect rowRect,
413 MergeCategoryTreeViewItem item,
414 bool isSelected,
415 bool isFocused,
416 out float itemWidth)
417 {
418 string label = item.Category.CategoryName;
419 string infoLabel = PlasticLocalization.Name.ItemsCount.GetString(
420 item.Category.GetChildrenCount());
421
422 itemWidth = CalculateLabelWidth(label);
423
424 DrawTreeViewItem.ForCategoryItem(
425 rowRect,
426 item.depth,
427 label,
428 infoLabel,
429 isSelected,
430 isFocused);
431 }
432
433 static void ChangeCategoryTreeViewItemGUI(
434 Rect rowRect,
435 ChangeCategoryTreeViewItem item,
436 bool isSelected,
437 bool isFocused,
438 out float itemWidth)
439 {
440 string label = item.Category.CategoryName;
441 string infoLabel = PlasticLocalization.Name.ItemsCount.GetString(
442 item.Category.GetChildrenCount());
443
444 itemWidth = CalculateLabelWidth(label);
445
446 DrawTreeViewItem.ForCategoryItem(
447 rowRect,
448 item.depth,
449 label,
450 infoLabel,
451 isSelected,
452 isFocused);
453 }
454
455 static void ClientDiffTreeViewItemGUI(
456 Rect rowRect,
457 float rowHeight,
458 UnityDiffTree diffTree,
459 ClientDiffTreeViewItem item,
460 bool isSelected,
461 bool isFocused,
462 out float itemWidth)
463 {
464 string label = ClientDiffView.GetColumnText(
465 item.Difference.DiffWithMount.Mount.RepSpec,
466 item.Difference.DiffWithMount.Difference,
467 PlasticLocalization.GetString(PlasticLocalization.Name.PathColumn));
468
469 if (diffTree.HasMeta(item.Difference))
470 label = string.Concat(label, UnityConstants.TREEVIEW_META_LABEL);
471
472 Texture icon = GetClientDiffIcon(
473 item.Difference.DiffWithMount.Difference.IsDirectory,
474 label);
475
476 itemWidth = CalculateItemWidth(label, icon, rowHeight);
477
478 DrawTreeViewItem.ForItemCell(
479 rowRect,
480 rowHeight,
481 item.depth,
482 icon,
483 null,
484 label,
485 isSelected,
486 isFocused,
487 false,
488 false);
489 }
490
491 static float CalculateItemWidth(
492 string label,
493 Texture icon,
494 float rowHeight)
495 {
496 float labelWidth = CalculateLabelWidth(label);
497 float iconWidth = rowHeight * ((float)icon.width / icon.height);
498
499 return labelWidth + iconWidth;
500 }
501
502 static float CalculateLabelWidth(string label)
503 {
504 GUIContent content = new GUIContent(label);
505 Vector2 contentSize = DefaultStyles.label.CalcSize(content);
506
507 return contentSize.x;
508 }
509
510 static Texture GetClientDiffIcon(bool isDirectory, string path)
511 {
512 if (isDirectory)
513 return Images.GetDirectoryIcon();
514
515 return Images.GetFileIconFromCmPath(path);
516 }
517
518 bool mExpandCategories;
519
520 TreeViewItemIds<IDiffCategory, ITreeViewNode> mTreeViewItemIds =
521 new TreeViewItemIds<IDiffCategory, ITreeViewNode>();
522
523 UnityDiffTree mDiffTree = new UnityDiffTree();
524
525 MultiColumnHeaderState.Column mHorizontalColumn;
526 float mLargestRowWidth;
527
528 readonly CooldownWindowDelayer mCooldownFilterAction;
529
530 static readonly List<string> ColumnsNames = new List<string> {
531 PlasticLocalization.GetString(PlasticLocalization.Name.PathColumn)};
532 readonly DiffTreeViewMenu mMenu;
533 }
534}