DependencyViewerWindow.cs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. using System;
  2. using System.IO;
  3. using UnityEditor;
  4. using UnityEngine;
  5. using System.Linq;
  6. using UnityEditor.UIElements;
  7. using UnityEngine.UIElements;
  8. using System.Collections.Generic;
  9. using Object = UnityEngine.Object;
  10. namespace IntelligentProjectAnalyzer.Editor.DependencyViewer
  11. {
  12. /// <summary>
  13. /// An editor window that displays the dependencies and references for a selected asset.
  14. /// It uses UI Toolkit for its interface and a DependencyGraph for data processing.
  15. /// </summary>
  16. public class DependencyViewerWindow : EditorWindow
  17. {
  18. private const string UxmlPath = "DependencyViewerWindow.uxml";
  19. private const string USSPath = "DependencyViewerWindow.uss";
  20. private ObjectField _assetSelector;
  21. private ListView _dependenciesList;
  22. private ListView _referencesList;
  23. private Button _refreshButton;
  24. private Object _selectedAsset;
  25. private DependencyGraph _graph;
  26. [MenuItem("Tools/Analyzer/Dependency Viewer")]
  27. public static void ShowWindow()
  28. {
  29. var wnd = GetWindow<DependencyViewerWindow>();
  30. wnd.titleContent = new GUIContent("Dependency Viewer");
  31. }
  32. public void CreateGUI()
  33. {
  34. var visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(FindAssetPath(UxmlPath));
  35. if (visualTree == null)
  36. {
  37. rootVisualElement.Add(new Label($"Could not find UXML file at path '{UxmlPath}'. Make sure it's in an 'Editor' folder."));
  38. return;
  39. }
  40. visualTree.CloneTree(rootVisualElement);
  41. var styleSheet = AssetDatabase.LoadAssetAtPath<StyleSheet>(FindAssetPath(USSPath));
  42. if (styleSheet != null)
  43. {
  44. rootVisualElement.styleSheets.Add(styleSheet);
  45. }
  46. _graph = new DependencyGraph();
  47. _assetSelector = rootVisualElement.Q<ObjectField>("script-selector");
  48. _dependenciesList = rootVisualElement.Q<ListView>("dependencies-list");
  49. _referencesList = rootVisualElement.Q<ListView>("references-list");
  50. _refreshButton = rootVisualElement.Q<Button>("refresh-button");
  51. _assetSelector.objectType = typeof(Object);
  52. _assetSelector.RegisterValueChangedCallback(OnAssetSelected);
  53. _refreshButton.clicked += OnRefreshClicked;
  54. ConfigureListView(_dependenciesList);
  55. ConfigureListView(_referencesList);
  56. }
  57. private static void ConfigureListView(ListView listView)
  58. {
  59. listView.makeItem = () =>
  60. {
  61. var root = new VisualElement { style = { flexDirection = FlexDirection.Row, alignItems = Align.Center }};
  62. var objField = new ObjectField { objectType = typeof(Object), style = { flexGrow = 1 } };
  63. objField.SetEnabled(false);
  64. var pingButton = new Button { text = "Ping", style = { flexShrink = 0, marginLeft = 5 }};
  65. pingButton.clicked += () =>
  66. {
  67. if (pingButton.userData is Object objToPing)
  68. {
  69. EditorGUIUtility.PingObject(objToPing);
  70. }
  71. };
  72. root.Add(objField);
  73. root.Add(pingButton);
  74. return root;
  75. };
  76. listView.bindItem = (element, index) =>
  77. {
  78. var objField = element.Q<ObjectField>();
  79. var pingButton = element.Q<Button>();
  80. var guid = listView.itemsSource[index] as string;
  81. var assetPath = AssetDatabase.GUIDToAssetPath(guid);
  82. var asset = AssetDatabase.LoadAssetAtPath<Object>(assetPath);
  83. if (objField != null) objField.value = asset;
  84. if (pingButton != null) pingButton.userData = asset;
  85. };
  86. }
  87. private void OnAssetSelected(ChangeEvent<Object> evt)
  88. {
  89. var newAsset = evt.newValue;
  90. if (newAsset == null)
  91. {
  92. _selectedAsset = null;
  93. PopulateLists();
  94. return;
  95. }
  96. // --- Validation Step 1: Check if it's a project asset ---
  97. var assetPath = AssetDatabase.GetAssetPath(newAsset);
  98. if (string.IsNullOrEmpty(assetPath) || !assetPath.StartsWith("Assets/"))
  99. {
  100. EditorUtility.DisplayDialog("Invalid Asset Location", "Please select an asset from the project's 'Assets' folder. Assets from packages or built-in resources are not supported.", "OK");
  101. _assetSelector.SetValueWithoutNotify(null); // Clear the selection
  102. _selectedAsset = null;
  103. PopulateLists();
  104. return;
  105. }
  106. // If all checks pass, update the selection and populate the lists.
  107. _selectedAsset = newAsset;
  108. PopulateLists();
  109. }
  110. private void OnRefreshClicked()
  111. {
  112. _graph.BuildGraph();
  113. PopulateLists();
  114. Debug.Log("Dependency data refreshed.");
  115. }
  116. private void PopulateLists()
  117. {
  118. string guid = null;
  119. if (_selectedAsset != null)
  120. {
  121. var assetPath = AssetDatabase.GetAssetPath(_selectedAsset);
  122. guid = AssetDatabase.AssetPathToGUID(assetPath);
  123. }
  124. if (string.IsNullOrEmpty(guid))
  125. {
  126. _dependenciesList.itemsSource = new List<string>();
  127. _referencesList.itemsSource = new List<string>();
  128. }
  129. else
  130. {
  131. _dependenciesList.itemsSource = _graph.GetDependencies(guid);
  132. _referencesList.itemsSource = _graph.GetReferences(guid);
  133. }
  134. _dependenciesList.Rebuild();
  135. _referencesList.Rebuild();
  136. }
  137. private static string FindAssetPath(string assetName)
  138. {
  139. var guids = AssetDatabase.FindAssets(Path.GetFileNameWithoutExtension(assetName));
  140. return guids.Select(AssetDatabase.GUIDToAssetPath).FirstOrDefault(path => Path.GetFileName(path).Equals(assetName, StringComparison.OrdinalIgnoreCase));
  141. }
  142. }
  143. }