// 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 _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 _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(); 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(); _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 list = new List(); 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 list = new List(); 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 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 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 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}", 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 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 rangeList = new List(); 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 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 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; } } }