Files
ZuneShell.dll/ZuneUI/Search.cs
T

498 lines
19 KiB
C#

// Decompiled with JetBrains decompiler
// Type: ZuneUI.Search
// Assembly: ZuneShell, Version=4.7.0.0, Culture=neutral, PublicKeyToken=ddd0da4d3e678217
// MVID: FC8028F3-A47B-4FB4-B35B-11D1752D8264
// Assembly location: C:\Program Files\Zune\ZuneShell.dll
using Microsoft.Iris;
using Microsoft.Zune.Util;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Security;
using System.Text;
namespace ZuneUI
{
public class Search : ModelItem
{
private string _keywords = "";
private string[] _processedKeywords;
private static Search _singletonInstance;
private bool _ignoreAccented;
private Dictionary<char, char> _accentTable;
private Command _executeCommand;
private Hashtable _keywordLinkTable;
private Command _searchFocusHotkey;
private Choice _filterList;
private SearchResultFilterType _selectedFilter;
private SearchResultContextType _usersContextType = SearchResultContextType.Undefined;
private SearchHintHelper _hintHelper;
private static List<SearchResultFilterCommand> _searchResultFilterCommandTypes;
public static Search Instance
{
get
{
if (_singletonInstance == null)
_singletonInstance = new Search();
return _singletonInstance;
}
}
internal static bool HasInstance => _singletonInstance != null;
private Search()
{
this._executeCommand = new Command();
this._ignoreAccented = string.Compare(CultureInfo.CurrentCulture.TwoLetterISOLanguageName, "en", true) == 0;
this._accentTable = new Dictionary<char, char>();
this._accentTable.Add('À', 'A');
this._accentTable.Add('Á', 'A');
this._accentTable.Add('Â', 'A');
this._accentTable.Add('Ã', 'A');
this._accentTable.Add('Ä', 'A');
this._accentTable.Add('Å', 'A');
this._accentTable.Add('à', 'a');
this._accentTable.Add('á', 'a');
this._accentTable.Add('â', 'a');
this._accentTable.Add('ã', 'a');
this._accentTable.Add('ä', 'a');
this._accentTable.Add('å', 'a');
this._accentTable.Add('È', 'E');
this._accentTable.Add('É', 'E');
this._accentTable.Add('Ê', 'E');
this._accentTable.Add('Ë', 'E');
this._accentTable.Add('è', 'e');
this._accentTable.Add('é', 'e');
this._accentTable.Add('ê', 'e');
this._accentTable.Add('ë', 'e');
this._accentTable.Add('Ì', 'I');
this._accentTable.Add('Í', 'I');
this._accentTable.Add('Î', 'I');
this._accentTable.Add('Ï', 'I');
this._accentTable.Add('ì', 'i');
this._accentTable.Add('í', 'i');
this._accentTable.Add('î', 'i');
this._accentTable.Add('ï', 'i');
this._accentTable.Add('Ò', 'O');
this._accentTable.Add('Ó', 'O');
this._accentTable.Add('Ô', 'O');
this._accentTable.Add('Õ', 'O');
this._accentTable.Add('Ö', 'O');
this._accentTable.Add('ò', 'o');
this._accentTable.Add('ó', 'o');
this._accentTable.Add('ô', 'o');
this._accentTable.Add('õ', 'o');
this._accentTable.Add('ö', 'o');
this._accentTable.Add('Ù', 'U');
this._accentTable.Add('Ú', 'U');
this._accentTable.Add('Û', 'U');
this._accentTable.Add('Ü', 'U');
this._accentTable.Add('ù', 'u');
this._accentTable.Add('ú', 'u');
this._accentTable.Add('û', 'u');
this._accentTable.Add('ü', 'u');
}
protected override void OnDispose(bool disposing)
{
if (disposing && this._filterList != null)
this._filterList.ChosenChanged -= new EventHandler(this.FilterListChosenChanged);
base.OnDispose(disposing);
}
public Choice FilterList
{
get
{
if (this._filterList == null)
{
this._filterList = new Choice(this);
this._filterList.Options = new ArrayListDataSet();
this._filterList.ChosenChanged += new EventHandler(this.FilterListChosenChanged);
this.UpdateFiltersList();
}
this._filterList.ChosenIndex = 0;
return this._filterList;
}
}
private void FilterListChosenChanged(object sender, EventArgs args)
{
if (this._filterList == null)
return;
SearchResultFilterCommand chosenValue = (SearchResultFilterCommand)this._filterList.ChosenValue;
if (chosenValue == null)
return;
this.SelectedFilterType = chosenValue.Type;
}
public void UpdateFiltersList()
{
if (this._filterList == null)
return;
if (_searchResultFilterCommandTypes == null)
{
_searchResultFilterCommandTypes = new List<SearchResultFilterCommand>();
_searchResultFilterCommandTypes.Add(SearchResultFilter.All);
_searchResultFilterCommandTypes.Add(SearchResultFilter.Artists);
_searchResultFilterCommandTypes.Add(SearchResultFilter.Albums);
_searchResultFilterCommandTypes.Add(SearchResultFilter.Tracks);
_searchResultFilterCommandTypes.Add(SearchResultFilter.MusicVideos);
_searchResultFilterCommandTypes.Add(SearchResultFilter.TVShows);
_searchResultFilterCommandTypes.Add(SearchResultFilter.Movies);
_searchResultFilterCommandTypes.Add(SearchResultFilter.OtherVideo);
_searchResultFilterCommandTypes.Add(SearchResultFilter.Podcasts);
_searchResultFilterCommandTypes.Add(SearchResultFilter.Playlists);
_searchResultFilterCommandTypes.Add(SearchResultFilter.Channels);
_searchResultFilterCommandTypes.Add(SearchResultFilter.WindowsPhoneApps);
_searchResultFilterCommandTypes.Add(SearchResultFilter.Profile);
}
this._filterList.Options.Clear();
for (int index = 0; index < _searchResultFilterCommandTypes.Count; ++index)
{
SearchResultFilterCommand filterCommandType = _searchResultFilterCommandTypes[index];
if (filterCommandType.HasResults)
this._filterList.Options.Add(filterCommandType);
}
}
public void Navigate(string command, IDictionary commandArguments)
{
if (string.IsNullOrEmpty(command))
return;
if (command.Contains("Marketplace\\"))
SQMLog.Log(SQMDataId.SearchMarketplaceResultsCount, 1);
else if (command.Contains("Collection\\"))
SQMLog.Log(SQMDataId.SearchCollectionResultsCount, 1);
ZuneShell.DefaultInstance.Execute(command, commandArguments);
}
public void RecordContextMenuType(SearchResultContextMenuType type) => SQMLog.LogToStream(SQMDataId.SearchContextMenuAction, (uint)type);
public SearchResultFilterType SelectedFilterType
{
get => this._selectedFilter;
set
{
if (this._selectedFilter == value)
return;
this._selectedFilter = value;
this.FirePropertyChanged(nameof(SelectedFilterType));
SQMLog.Log(SQMDataId.SearchFiltersCount, 1);
SQMLog.LogToStream(SQMDataId.SearchFiltersSelection, (uint)this._selectedFilter);
}
}
public SearchResultContextType UsersContextType
{
get => this._usersContextType;
set
{
if (this._usersContextType == value)
return;
this._usersContextType = value;
this.FirePropertyChanged(nameof(UsersContextType));
}
}
public SearchHintHelper HintHelper
{
get
{
if (this._hintHelper == null)
this._hintHelper = new SearchHintHelper();
return this._hintHelper;
}
}
public Command SearchFocusHotkey
{
get
{
if (this._searchFocusHotkey == null)
this._searchFocusHotkey = new Command(this);
return this._searchFocusHotkey;
}
}
public string Keywords
{
get => this._keywords.Trim();
private set
{
if (!(this._keywords != value) || string.IsNullOrEmpty(value))
return;
this._keywords = value;
this._processedKeywords = null;
this.FirePropertyChanged(nameof(Keywords));
}
}
public void Execute(string keywords)
{
this.Keywords = keywords;
if (this._executeCommand == null)
return;
this._executeCommand.Invoke();
}
public Command Executed => this._executeCommand;
public SearchKeywordLink KeywordLink => (SearchKeywordLink)this.KeywordLinkTable[this.Keywords.ToLower()];
private Hashtable KeywordLinkTable
{
get
{
if (this._keywordLinkTable == null)
{
this._keywordLinkTable = new Hashtable();
foreach (SearchKeywordLink searchKeywordLink in new SearchKeywordLink[1]
{
new SearchKeywordLink(StringId.IDS_APPLICATIONS, StringId.IDS_SEARCH_MARKETPLACE_GAMES_LINK, StringId.IDS_SEARCH_MARKETPLACE_GAMES_KEYWORDS, "Marketplace\\Apps\\Home")
})
{
for (int index = 0; index < searchKeywordLink.Keywords.Length; ++index)
this._keywordLinkTable[searchKeywordLink.Keywords[index].ToLower().Trim()] = searchKeywordLink;
}
}
return this._keywordLinkTable;
}
}
public bool IsValidKeyword(string keywords)
{
if (string.IsNullOrEmpty(keywords))
return false;
string str = keywords.Trim();
return !string.IsNullOrEmpty(str) && (str.Length > 1 || this.IsValidCjkCharacter(str[0]));
}
private bool IsValidCjkCharacter(char c)
{
ushort num = c;
return num >= 12352 && (num > 12351 && num < 12544 || num > 13311 && num < 19904 || (num > 19967 && num < 40960 || num > 44031 && num < 55216));
}
public string FormatResult(string keywordStyle, string item0, string item1)
{
List<string> list = new List<string>();
this.AddResult(keywordStyle, list, item0);
this.AddResult(keywordStyle, list, item1);
return this.FormatResult(list);
}
public string FormatResult(string keywordStyle, string item0, string item1, string item2)
{
List<string> list = new List<string>();
this.AddResult(keywordStyle, list, item0);
this.AddResult(keywordStyle, list, item1);
this.AddResult(keywordStyle, list, item2);
return this.FormatResult(list);
}
private void AddResult(string keywordStyle, List<string> list, string item)
{
if (string.IsNullOrEmpty(item))
return;
if (keywordStyle != null)
list.Add(this.HighlightKeywords(item, keywordStyle));
else
list.Add(item);
}
private string FormatResult(List<string> list)
{
switch (list.Count)
{
case 1:
return list[0];
case 2:
return string.Format(Shell.LoadString(StringId.IDS_FOUND_ITEM_BUTTON1), list[0], list[1]);
case 3:
return string.Format(Shell.LoadString(StringId.IDS_FOUND_ITEM_BUTTON2), list[0], list[1], list[2]);
default:
return "";
}
}
public string HighlightKeywords(string target, string styleName)
{
int startIndex = 0;
if (target == null)
return "";
StringBuilder stringBuilder = new StringBuilder(target.Length + styleName.Length * 4 + 10);
List<IndexRange> keywords = this.FindKeywords(this.ProcessKeywords(), target);
for (int index = 0; index < keywords.Count; ++index)
{
IndexRange indexRange = keywords[index];
if (indexRange.indexStart > startIndex)
{
string str = target.Substring(startIndex, indexRange.indexStart - startIndex);
stringBuilder.Append(SecurityElement.Escape(str));
}
string str1 = target.Substring(indexRange.indexStart, indexRange.indexEnd - indexRange.indexStart);
stringBuilder.Append(string.Format("<{0}>{1}</{0}>", styleName, SecurityElement.Escape(str1)));
startIndex = indexRange.indexEnd;
}
if (startIndex < target.Length)
{
string str = target.Substring(startIndex);
stringBuilder.Append(SecurityElement.Escape(str));
}
return stringBuilder.ToString();
}
private List<IndexRange> FindKeywords(string[] keywords, string text)
{
StringBuilder stringBuilder = new StringBuilder(text.Length);
for (int index = 0; index < text.Length; ++index)
stringBuilder.Append(this.MapAccentedChar(text[index]));
string str = stringBuilder.ToString();
List<IndexRange> rangeList = new List<IndexRange>();
foreach (string keyword in keywords)
{
int startIndex = 0;
while (true)
{
int num = str.IndexOf(keyword, startIndex, StringComparison.OrdinalIgnoreCase);
if (num >= 0)
{
char c1 = num > 0 ? str[num - 1] : ' ';
char c2 = num + keyword.Length < str.Length ? str[num + keyword.Length] : ' ';
if (!char.IsLetterOrDigit(c1) && (keyword.Length >= 2 || !char.IsLetterOrDigit(c2)))
{
IndexRange keyRange;
keyRange.indexStart = num;
keyRange.indexEnd = num + keyword.Length;
this.AddRange(keyRange, rangeList);
}
startIndex = num + keyword.Length;
}
else
break;
}
}
this.CollapseRanges(rangeList);
return rangeList;
}
private void CollapseRanges(List<IndexRange> rangeList)
{
for (int index1 = 0; index1 < rangeList.Count; ++index1)
{
int index2 = index1 + 1;
while (index2 < rangeList.Count)
{
IndexRange range1 = rangeList[index1];
IndexRange range2 = rangeList[index2];
if (range1.indexEnd > range2.indexStart)
{
if (range1.indexEnd >= range2.indexEnd)
{
rangeList.RemoveAt(index2);
}
else
{
range1.indexEnd = range2.indexEnd;
rangeList[index1] = range1;
rangeList.RemoveAt(index2);
}
}
else
break;
}
}
}
private void AddRange(IndexRange keyRange, List<IndexRange> rangeList)
{
int index;
for (index = 0; index < rangeList.Count; ++index)
{
IndexRange range = rangeList[index];
if (keyRange.indexStart <= range.indexStart)
break;
}
rangeList.Insert(index, keyRange);
}
private string[] ProcessKeywords()
{
if (this._processedKeywords == null)
{
StringBuilder stringBuilder = new StringBuilder(this._keywords.Length);
bool flag = false;
for (int index = 0; index < this._keywords.Length; ++index)
{
char keyword = this._keywords[index];
switch (keyword)
{
case '\t':
case '\n':
case '\r':
case '!':
case '"':
case '%':
case '&':
case '(':
case ')':
case '+':
case '-':
case ';':
case '<':
case '>':
case '{':
case '}':
stringBuilder.Append(' ');
flag = true;
break;
case '\'':
char c1 = index > 0 ? this._keywords[index - 1] : ' ';
char c2 = index + 1 < this._keywords.Length ? this._keywords[index + 1] : ' ';
if (char.IsLetterOrDigit(c1) && char.IsLetterOrDigit(c2))
{
stringBuilder.Append(keyword);
break;
}
stringBuilder.Append(' ');
flag = true;
break;
default:
stringBuilder.Append(this.MapAccentedChar(keyword));
break;
}
}
this._processedKeywords = stringBuilder.ToString().Split(new char[1]
{
' '
}, StringSplitOptions.RemoveEmptyEntries);
if (flag)
{
Array.Resize(ref this._processedKeywords, this._processedKeywords.Length + 1);
this._processedKeywords[this._processedKeywords.Length - 1] = this._keywords;
}
}
return this._processedKeywords;
}
private char MapAccentedChar(char original)
{
char key = original;
char ch;
if (this._ignoreAccented && this._accentTable.TryGetValue(key, out ch))
key = ch;
return key;
}
private struct IndexRange
{
public int indexStart;
public int indexEnd;
}
}
}