UniTaskTrackerTreeView.cs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
  2. using UnityEngine;
  3. using UnityEditor;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.Reflection;
  7. using System;
  8. using UnityEditor.IMGUI.Controls;
  9. using Cysharp.Threading.Tasks.Internal;
  10. using System.Text;
  11. using System.Text.RegularExpressions;
  12. namespace Cysharp.Threading.Tasks.Editor
  13. {
  14. public class UniTaskTrackerViewItem : TreeViewItem
  15. {
  16. static Regex removeHref = new Regex("<a href.+>(.+)</a>", RegexOptions.Compiled);
  17. public string TaskType { get; set; }
  18. public string Elapsed { get; set; }
  19. public string Status { get; set; }
  20. string position;
  21. public string Position
  22. {
  23. get { return position; }
  24. set
  25. {
  26. position = value;
  27. PositionFirstLine = GetFirstLine(position);
  28. }
  29. }
  30. public string PositionFirstLine { get; private set; }
  31. static string GetFirstLine(string str)
  32. {
  33. var sb = new StringBuilder();
  34. for (int i = 0; i < str.Length; i++)
  35. {
  36. if (str[i] == '\r' || str[i] == '\n')
  37. {
  38. break;
  39. }
  40. sb.Append(str[i]);
  41. }
  42. return removeHref.Replace(sb.ToString(), "$1");
  43. }
  44. public UniTaskTrackerViewItem(int id) : base(id)
  45. {
  46. }
  47. }
  48. public class UniTaskTrackerTreeView : TreeView
  49. {
  50. const string sortedColumnIndexStateKey = "UniTaskTrackerTreeView_sortedColumnIndex";
  51. public IReadOnlyList<TreeViewItem> CurrentBindingItems;
  52. public UniTaskTrackerTreeView()
  53. : this(new TreeViewState(), new MultiColumnHeader(new MultiColumnHeaderState(new[]
  54. {
  55. new MultiColumnHeaderState.Column() { headerContent = new GUIContent("TaskType"), width = 20},
  56. new MultiColumnHeaderState.Column() { headerContent = new GUIContent("Elapsed"), width = 10},
  57. new MultiColumnHeaderState.Column() { headerContent = new GUIContent("Status"), width = 10},
  58. new MultiColumnHeaderState.Column() { headerContent = new GUIContent("Position")},
  59. })))
  60. {
  61. }
  62. UniTaskTrackerTreeView(TreeViewState state, MultiColumnHeader header)
  63. : base(state, header)
  64. {
  65. rowHeight = 20;
  66. showAlternatingRowBackgrounds = true;
  67. showBorder = true;
  68. header.sortingChanged += Header_sortingChanged;
  69. header.ResizeToFit();
  70. Reload();
  71. header.sortedColumnIndex = SessionState.GetInt(sortedColumnIndexStateKey, 1);
  72. }
  73. public void ReloadAndSort()
  74. {
  75. var currentSelected = this.state.selectedIDs;
  76. Reload();
  77. Header_sortingChanged(this.multiColumnHeader);
  78. this.state.selectedIDs = currentSelected;
  79. }
  80. private void Header_sortingChanged(MultiColumnHeader multiColumnHeader)
  81. {
  82. SessionState.SetInt(sortedColumnIndexStateKey, multiColumnHeader.sortedColumnIndex);
  83. var index = multiColumnHeader.sortedColumnIndex;
  84. var ascending = multiColumnHeader.IsSortedAscending(multiColumnHeader.sortedColumnIndex);
  85. var items = rootItem.children.Cast<UniTaskTrackerViewItem>();
  86. IOrderedEnumerable<UniTaskTrackerViewItem> orderedEnumerable;
  87. switch (index)
  88. {
  89. case 0:
  90. orderedEnumerable = ascending ? items.OrderBy(item => item.TaskType) : items.OrderByDescending(item => item.TaskType);
  91. break;
  92. case 1:
  93. orderedEnumerable = ascending ? items.OrderBy(item => double.Parse(item.Elapsed)) : items.OrderByDescending(item => double.Parse(item.Elapsed));
  94. break;
  95. case 2:
  96. orderedEnumerable = ascending ? items.OrderBy(item => item.Status) : items.OrderByDescending(item => item.Elapsed);
  97. break;
  98. case 3:
  99. orderedEnumerable = ascending ? items.OrderBy(item => item.Position) : items.OrderByDescending(item => item.PositionFirstLine);
  100. break;
  101. default:
  102. throw new ArgumentOutOfRangeException(nameof(index), index, null);
  103. }
  104. CurrentBindingItems = rootItem.children = orderedEnumerable.Cast<TreeViewItem>().ToList();
  105. BuildRows(rootItem);
  106. }
  107. protected override TreeViewItem BuildRoot()
  108. {
  109. var root = new TreeViewItem { depth = -1 };
  110. var children = new List<TreeViewItem>();
  111. TaskTracker.ForEachActiveTask((trackingId, awaiterType, status, created, stackTrace) =>
  112. {
  113. children.Add(new UniTaskTrackerViewItem(trackingId) { TaskType = awaiterType, Status = status.ToString(), Elapsed = (DateTime.UtcNow - created).TotalSeconds.ToString("00.00"), Position = stackTrace });
  114. });
  115. CurrentBindingItems = children;
  116. root.children = CurrentBindingItems as List<TreeViewItem>;
  117. return root;
  118. }
  119. protected override bool CanMultiSelect(TreeViewItem item)
  120. {
  121. return false;
  122. }
  123. protected override void RowGUI(RowGUIArgs args)
  124. {
  125. var item = args.item as UniTaskTrackerViewItem;
  126. for (var visibleColumnIndex = 0; visibleColumnIndex < args.GetNumVisibleColumns(); visibleColumnIndex++)
  127. {
  128. var rect = args.GetCellRect(visibleColumnIndex);
  129. var columnIndex = args.GetColumn(visibleColumnIndex);
  130. var labelStyle = args.selected ? EditorStyles.whiteLabel : EditorStyles.label;
  131. labelStyle.alignment = TextAnchor.MiddleLeft;
  132. switch (columnIndex)
  133. {
  134. case 0:
  135. EditorGUI.LabelField(rect, item.TaskType, labelStyle);
  136. break;
  137. case 1:
  138. EditorGUI.LabelField(rect, item.Elapsed, labelStyle);
  139. break;
  140. case 2:
  141. EditorGUI.LabelField(rect, item.Status, labelStyle);
  142. break;
  143. case 3:
  144. EditorGUI.LabelField(rect, item.PositionFirstLine, labelStyle);
  145. break;
  146. default:
  147. throw new ArgumentOutOfRangeException(nameof(columnIndex), columnIndex, null);
  148. }
  149. }
  150. }
  151. }
  152. }