No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

DiffTreeView.cs 16KB

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