2022-01-16 05:40:49 +03:00

489 lines
18 KiB
C#

using UnityEngine;
using UnityEditor;
using System;
using UnityEditor.IMGUI.Controls;
using HeurekaGames.AssetHunterPRO.BaseTreeviewImpl.AssetTreeView;
using HeurekaGames.AssetHunterPRO.BaseTreeviewImpl;
//Only avaliable in 2018
#if UNITY_2018_1_OR_NEWER
using UnityEditor.Build.Reporting;
#endif
namespace HeurekaGames.AssetHunterPRO
{
public class AH_Window : EditorWindow
{
public const int WINDOWMENUITEMPRIO = 11;
public const string VERSION = "2.2.1";
private static AH_Window m_window;
[NonSerialized] bool m_Initialized;
[SerializeField] TreeViewState m_TreeViewState; // Serialized in the window layout file so it survives assembly reloading
[SerializeField] MultiColumnHeaderState m_MultiColumnHeaderState;
SearchField m_SearchField;
private AH_TreeViewWithTreeModel m_TreeView;
[SerializeField] public AH_BuildInfoManager buildInfoManager;
public bool m_BuildLogLoaded { get; set; }
//Button guiContent
[SerializeField] GUIContent guiContentLoadBuildInfo;
[SerializeField] GUIContent guiContentSettings;
[SerializeField] GUIContent guiContentGenerateReferenceGraph;
[SerializeField] GUIContent guiContentDuplicates;
//Only avaliable in 2018
#if UNITY_2018_1_OR_NEWER
[SerializeField] GUIContent guiContentBuildReport;
#endif
[SerializeField] GUIContent guiContentReadme;
[SerializeField] GUIContent guiContentDeleteAll;
[SerializeField] GUIContent guiContentRefresh;
//UI Rect
Vector2 uiStartPos = new Vector2(10, 50);
public static float ButtonMaxHeight = 18;
//Add menu named "Asset Hunter" to the window menu
[UnityEditor.MenuItem("Tools/Asset Hunter PRO/Asset Hunter PRO", priority = WINDOWMENUITEMPRIO)]
[UnityEditor.MenuItem("Window/Heureka/Asset Hunter PRO/Asset Hunter PRO _%h", priority = WINDOWMENUITEMPRIO)]
public static void OpenAssetHunter()
{
if (!m_window)
initializeWindow();
}
private static AH_Window initializeWindow()
{
//Open ReadMe
Heureka_PackageDataManagerEditor.SelectReadme();
m_window = EditorWindow.GetWindow<AH_Window>();
AH_TreeViewSelectionInfo.OnAssetDeleted += m_window.OnAssetDeleted;
#if UNITY_2018_1_OR_NEWER
EditorApplication.projectChanged += m_window.OnProjectChanged;
#elif UNITY_5_6_OR_NEWER
EditorApplication.projectWindowChanged += m_window.OnProjectChanged;
#endif
if (m_window.buildInfoManager == null)
m_window.buildInfoManager = ScriptableObject.CreateInstance<AH_BuildInfoManager>();
m_window.initializeGUIContent();
//Subscribe to changes to list of ignored items
AH_SettingsManager.Instance.IgnoreListUpdatedEvent += m_window.OnIgnoreListUpdatedEvent;
return m_window;
}
internal static AH_BuildInfoManager GetBuildInfoManager()
{
if (!m_window)
initializeWindow();
return m_window.buildInfoManager;
}
private void OnEnable()
{
AH_SerializationHelper.NewBuildInfoCreated += onBuildInfoCreated;
}
private void OnDisable()
{
AH_SerializationHelper.NewBuildInfoCreated -= onBuildInfoCreated;
}
void OnInspectorUpdate()
{
if (!m_window)
initializeWindow();
}
void OnGUI()
{
/*if (Application.isPlaying)
return;*/
InitIfNeeded();
doHeader();
if (buildInfoManager == null || !buildInfoManager.HasSelection)
{
doNoBuildInfoLoaded();
return;
}
if (buildInfoManager.IsProjectClean() && ((AH_MultiColumnHeader)m_TreeView.multiColumnHeader).ShowMode == AH_MultiColumnHeader.AssetShowMode.Unused)
{
Heureka_WindowStyler.DrawCenteredImage(m_window, AH_EditorData.Instance.AchievementIcon.Icon);
return;
}
doSearchBar(toolbarRect);
doTreeView(multiColumnTreeViewRect);
doBottomToolBar(bottomToolbarRect);
}
void OnProjectChanged()
{
buildInfoManager.ProjectDirty = true;
}
//Callback
private void OnAssetDeleted()
{
//TODO need to improve the deletion of empty folder. Currently leaves meta file behind, causing warnings
if (EditorUtility.DisplayDialog("Delete empty folders", "Do you want to delete any empty folders?", "Yes", "No"))
{
deleteEmptyFolders();
}
//This might be called excessively
if (AH_SettingsManager.Instance.AutoRefreshLog)
RefreshBuildLog();
}
//callback
private void onBuildInfoCreated(string path)
{
if (EditorUtility.DisplayDialog(
"New buildinfo log created",
"Do you want to load it into Asset Hunter",
"Ok", "Cancel"))
{
m_Initialized = false;
buildInfoManager.SelectBuildInfo(path);
}
}
void InitIfNeeded()
{
//We dont need to do stuff when in play mode
if (buildInfoManager && buildInfoManager.HasSelection && !m_Initialized)
{
// Check if it already exists (deserialized from window layout file or scriptable object)
if (m_TreeViewState == null)
m_TreeViewState = new TreeViewState();
bool firstInit = m_MultiColumnHeaderState == null;
var headerState = AH_TreeViewWithTreeModel.CreateDefaultMultiColumnHeaderState(multiColumnTreeViewRect.width);
if (MultiColumnHeaderState.CanOverwriteSerializedFields(m_MultiColumnHeaderState, headerState))
MultiColumnHeaderState.OverwriteSerializedFields(m_MultiColumnHeaderState, headerState);
m_MultiColumnHeaderState = headerState;
var multiColumnHeader = new AH_MultiColumnHeader(headerState);
if (firstInit)
multiColumnHeader.ResizeToFit();
var treeModel = new TreeModel<AH_TreeviewElement>(buildInfoManager.GetTreeViewData());
m_TreeView = new AH_TreeViewWithTreeModel(m_TreeViewState, multiColumnHeader, treeModel);
m_SearchField = new SearchField();
m_SearchField.downOrUpArrowKeyPressed += m_TreeView.SetFocusAndEnsureSelectedItem;
m_Initialized = true;
buildInfoManager.ProjectDirty = false;
}
//This is an (ugly) fix to make sure we dotn loose our icons due to some singleton issues after play/stop
if (guiContentRefresh.image == null)
initializeGUIContent();
}
private void deleteEmptyFolders()
{
checkEmptyFolder(Application.dataPath);
AssetDatabase.Refresh();
}
//This needs some work, it leaves the meta file. TAken out of codebase until a fix has been found
private bool checkEmptyFolder(string dataPath)
{
if (dataPath.EndsWith(".git", StringComparison.InvariantCultureIgnoreCase))
return false;
string[] files = System.IO.Directory.GetFiles(dataPath);
bool hasValidAsset = false;
for (int i = 0; i < files.Length; i++)
{
string relativePath;
string assetID;
AH_Utils.GetRelativePathAndAssetID(files[i], out relativePath, out assetID);
//This folder has a valid asset inside
if (!string.IsNullOrEmpty(assetID))
{
hasValidAsset = true;
break;
}
}
string[] folders = System.IO.Directory.GetDirectories(dataPath);
bool hasFolderWithContents = false;
for (int i = 0; i < folders.Length; i++)
{
bool folderIsEmpty = checkEmptyFolder(folders[i]);
if (!folderIsEmpty)
{
hasFolderWithContents = true;
}
else
{
//if (EditorUtility.DisplayDialog("Delete folder", folders[i] + " seems to be empty, do you want to delete it?", "Yes", "No"))
{
Debug.Log("AH: Deleting empty folder " + folders[i]);
AssetDatabase.DeleteAsset(FileUtil.GetProjectRelativePath(folders[i]));
}
}
}
return (!hasValidAsset && !hasFolderWithContents);
}
private void initializeGUIContent()
{
titleContent = new GUIContent("Asset Hunter", AH_EditorData.Instance.WindowPaneIcon.Icon);
guiContentLoadBuildInfo = new GUIContent("Load", AH_EditorData.Instance.LoadLogIcon.Icon, "Load info from a previous build");
guiContentSettings = new GUIContent("Settings", AH_EditorData.Instance.Settings.Icon, "Open settings");
guiContentGenerateReferenceGraph = new GUIContent("Dependencies", AH_EditorData.Instance.RefFromIcon.Icon, "See asset dependency graph");
guiContentDuplicates = new GUIContent("Duplicates", AH_EditorData.Instance.DuplicateIcon.Icon, "Find duplicate assets");
//Only avaliable in 2018
#if UNITY_2018_1_OR_NEWER
guiContentBuildReport = new GUIContent("Report", AH_EditorData.Instance.ReportIcon.Icon, "Build report overview (Build size information)");
#endif
guiContentReadme = new GUIContent("Info", AH_EditorData.Instance.HelpIcon.Icon, "Open the readme file for all installed Heureka Games products");
guiContentDeleteAll = new GUIContent("Clean ALL", AH_EditorData.Instance.DeleteIcon.Icon, "Delete ALL unused assets in project ({0}) Remember to manually exclude relevant assets in the settings window");
guiContentRefresh = new GUIContent(AH_EditorData.Instance.RefreshIcon.Icon, "Refresh data");
}
private void doNoBuildInfoLoaded()
{
Heureka_WindowStyler.DrawCenteredMessage(m_window, AH_EditorData.Instance.WindowHeaderIcon.Icon, 380f, 110f, "Buildinfo not yet loaded" + Environment.NewLine + "Load existing / create new build");
}
private void doHeader()
{
Heureka_WindowStyler.DrawGlobalHeader(Heureka_WindowStyler.clr_Pink, "ASSET HUNTER PRO", VERSION);
EditorGUILayout.BeginHorizontal();
bool infoLoaded = (buildInfoManager != null && buildInfoManager.HasSelection);
if (infoLoaded)
{
GUIContent RefreshGUIContent = new GUIContent(guiContentRefresh);
Color origColor = GUI.color;
if (buildInfoManager.ProjectDirty)
{
GUI.color = Heureka_WindowStyler.clr_Red;
RefreshGUIContent.tooltip = String.Format("{0}{1}", RefreshGUIContent.tooltip, " (Project has changed which means that treeview is out of date)");
}
if (doSelectionButton(RefreshGUIContent))
RefreshBuildLog();
GUI.color = origColor;
}
if (doSelectionButton(guiContentLoadBuildInfo))
openBuildInfoSelector();
if (doSelectionButton(guiContentDuplicates))
AH_DuplicatesWindow.Init(Docker.DockPosition.Left);
if (doSelectionButton(guiContentGenerateReferenceGraph))
AH_DependencyGraphWindow.Init(Docker.DockPosition.Right);
//Only avaliable in 2018
#if UNITY_2018_1_OR_NEWER
if (infoLoaded && doSelectionButton(guiContentBuildReport))
AH_BuildReportWindow.Init();
#endif
if (doSelectionButton(guiContentSettings))
AH_SettingsWindow.Init(true);
/*
#if AH_HAS_OLD_INSTALLED
//Transfer settings to PRO
GUIContent TransferSettingsContent = new GUIContent("Transfer Settings", "Transfer your settings from old Asset Hunter into PRO");
if (AH_VersionUpgrader.VersionUpgraderReady && GUILayout.Button(TransferSettingsContent, GUILayout.MaxHeight(18)))
AH_VersionUpgrader.RunUpgrade();
#endif
*/
if (infoLoaded && m_TreeView.GetCombinedUnusedSize() > 0)
{
string sizeAsString = AH_Utils.GetSizeAsString(m_TreeView.GetCombinedUnusedSize());
GUIContent instancedGUIContent = new GUIContent(guiContentDeleteAll);
instancedGUIContent.tooltip = string.Format(instancedGUIContent.tooltip, sizeAsString);
if (AH_SettingsManager.Instance.HideButtonText)
instancedGUIContent.text = null;
GUIStyle btnStyle = "button";
GUIStyle newStyle = new GUIStyle(btnStyle);
newStyle.normal.textColor = Heureka_WindowStyler.clr_Pink;
m_TreeView.DrawDeleteAllButton(instancedGUIContent, newStyle, GUILayout.MaxHeight(AH_SettingsManager.Instance.HideButtonText ? ButtonMaxHeight * 2f : ButtonMaxHeight));
}
GUILayout.FlexibleSpace();
GUILayout.Space(20);
if (m_TreeView != null)
m_TreeView.AssetSelectionToolBarGUI();
if (doSelectionButton(guiContentReadme))
{
Heureka_PackageDataManagerEditor.SelectReadme();
if (AH_EditorData.Instance.Documentation != null)
AssetDatabase.OpenAsset(AH_EditorData.Instance.Documentation);
}
EditorGUILayout.EndHorizontal();
}
private void doSearchBar(Rect rect)
{
if (m_TreeView != null)
m_TreeView.searchString = m_SearchField.OnGUI(rect, m_TreeView.searchString);
}
private void doTreeView(Rect rect)
{
if (m_TreeView != null)
m_TreeView.OnGUI(rect);
}
private void doBottomToolBar(Rect rect)
{
if (m_TreeView == null)
return;
GUILayout.BeginArea(rect);
using (new EditorGUILayout.HorizontalScope())
{
GUIStyle style = "miniButton";
if (GUILayout.Button("Expand All", style))
{
m_TreeView.ExpandAll();
}
if (GUILayout.Button("Collapse All", style))
{
m_TreeView.CollapseAll();
}
GUILayout.Label("Build: " + buildInfoManager.GetSelectedBuildDate() + " (" + buildInfoManager.GetSelectedBuildTarget() + ")");
GUILayout.FlexibleSpace();
GUILayout.Label(buildInfoManager.TreeView != null ? AssetDatabase.GetAssetPath(buildInfoManager.TreeView) : string.Empty);
GUILayout.FlexibleSpace();
if (((AH_MultiColumnHeader)m_TreeView.multiColumnHeader).mode == AH_MultiColumnHeader.Mode.SortedList || !string.IsNullOrEmpty(m_TreeView.searchString))
{
if (GUILayout.Button("Return to Treeview", style))
{
m_TreeView.ShowTreeMode();
}
}
GUIContent exportContent = new GUIContent("Export list", "Export all the assets in the list above to a json file");
if (GUILayout.Button(exportContent, style))
{
AH_ElementList.DumpCurrentListToFile(m_TreeView);
}
}
GUILayout.EndArea();
}
private bool doSelectionButton(GUIContent content)
{
GUIContent btnContent = new GUIContent(content);
if (AH_SettingsManager.Instance.HideButtonText)
btnContent.text = null;
return GUILayout.Button(btnContent, GUILayout.MaxHeight(AH_SettingsManager.Instance.HideButtonText ? ButtonMaxHeight * 2f : ButtonMaxHeight));
}
private void OnIgnoreListUpdatedEvent()
{
buildInfoManager.ProjectDirty = true;
if (AH_SettingsManager.Instance.AutoOpenLog)
RefreshBuildLog();
}
private void RefreshBuildLog()
{
if (buildInfoManager != null && buildInfoManager.HasSelection)
{
m_Initialized = false;
buildInfoManager.RefreshBuildInfo();
}
}
private void openBuildInfoSelector()
{
string fileSelected = EditorUtility.OpenFilePanel("", AH_SerializationHelper.GetBuildInfoFolder(), AH_SerializationHelper.BuildInfoExtension);
if (!string.IsNullOrEmpty(fileSelected))
{
m_Initialized = false;
buildInfoManager.SelectBuildInfo(fileSelected);
}
}
Rect toolbarRect
{
get { return new Rect(UiStartPos.x, UiStartPos.y + (AH_SettingsManager.Instance.HideButtonText ? 20 : 0), position.width - (UiStartPos.x * 2), 20f); }
}
Rect multiColumnTreeViewRect
{
get { return new Rect(UiStartPos.x, UiStartPos.y + 20 + (AH_SettingsManager.Instance.HideButtonText ? 20 : 0), position.width - (UiStartPos.x * 2), position.height - 90 - (AH_SettingsManager.Instance.HideButtonText ? 20 : 0)); }
}
Rect assetInfoRect
{
get { return new Rect(UiStartPos.x, position.height - 66f, position.width - (UiStartPos.x * 2), 16f); }
}
Rect bottomToolbarRect
{
get { return new Rect(UiStartPos.x, position.height - 18, position.width - (UiStartPos.x * 2), 16f); }
}
public Vector2 UiStartPos
{
get
{
return uiStartPos;
}
set
{
uiStartPos = value;
}
}
private void OnDestroy()
{
AH_TreeViewSelectionInfo.OnAssetDeleted -= m_window.OnAssetDeleted;
#if UNITY_2018_1_OR_NEWER
EditorApplication.projectChanged -= m_window.OnProjectChanged;
#elif UNITY_5_6_OR_NEWER
EditorApplication.projectWindowChanged -= m_window.OnProjectChanged;
#endif
}
}
}