Search
MixedRealitySearchUtility.cs
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.
using Microsoft.MixedReality.Toolkit.SceneSystem;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEditor;
using UnityEngine;
namespace Microsoft.MixedReality.Toolkit.Utilities.Editor.Search
{
///
/// Utility for retrieving a Unity object's serialized fields with a configurable search.
///
public static clast MixedRealitySearchUtility
{
///
/// True if a search is being executed. This must be false before calling StartProfileSearch.
///
public static bool Searching { get { return activeTask != null && !activeTask.IsCompleted; } }
private const int maxChildSearchDepth = 5;
private const int minSearchStringLength = 3;
private static Task activeTask;
///
/// Field names that shouldn't be displayed in a profile field search.
///
private static readonly HashSet serializedPropertiesToIgnore = new HashSet()
{
// Unity base clast fields
"m_Name",
"m_Script",
"m_Enabled",
"m_GameObject",
"m_ObjectHideFlags",
"m_CorrespondingSourceObject",
"m_PrefabInstance",
"m_Prefabastet",
"m_EditorHideFlags",
"m_EditorClastIdentifier",
// Profile base clast fields
"isCustomProfile",
};
///
/// Field types that don't need their child properties displayed.
///
private static readonly HashSet serializedPropertyTypesToFlatten = new HashSet()
{
typeof(SystemType).Name,
typeof(SceneInfo).Name,
};
///
/// Starts a profile search. 'Searching' must be false or an exception will be thrown.
///
/// Profile object to search.
/// Configuration for the search.
/// Action to invoke once search is complete - delivers final results.
public static async void StartProfileSearch(UnityEngine.Object profile, SearchConfig config, Action onSearchComplete)
{
if (activeTask != null && !activeTask.IsCompleted)
{
throw new Exception("Can't start a new search until the old one has completed.");
}
List searchResults = new List();
// Validate search configuration
if (string.IsNullOrEmpty(config.SearchFieldString))
{ // If the config is empty, bail early
onSearchComplete?.Invoke(true, profile, searchResults);
return;
}
// Generate keywords if we haven't yet
if (config.Keywords == null)
{
config.Keywords = new HashSet(config.SearchFieldString.Split(new string[] { " ", "," }, StringSplitOptions.RemoveEmptyEntries));
config.Keywords.RemoveWhere(s => s.Length < minSearchStringLength);
}
if (config.Keywords.Count == 0)
{ // If there are no useful keywords, bail early
onSearchComplete?.Invoke(true, profile, searchResults);
return;
}
// Launch the search task
bool cancelled = false;
try
{
activeTask = SearchProfileField(profile, config, searchResults);
await activeTask;
}
catch (Exception e)
{
// Profile was probably deleted in the middle of searching.
Debug.LogException(e);
cancelled = true;
}
finally
{
searchResults.Sort(delegate (ProfileSearchResult r1, ProfileSearchResult r2)
{
if (r1.ProfileMatchStrength != r2.ProfileMatchStrength)
{
return r2.ProfileMatchStrength.CompareTo(r1.ProfileMatchStrength);
}
else
{
return r2.Profile.name.CompareTo(r1.Profile.name);
}
});
searchResults.RemoveAll(r => r.Fields.Count