using C4IT.FASD.Base; using C4IT.MultiLanguage; using F4SD_AdaptableIcon; using F4SD_AdaptableIcon.Enums; using FasdDesktopUi.Basics.CustomEvents; using FasdDesktopUi.Basics.Models; using FasdDesktopUi.Basics.UiActions; using FasdDesktopUi.Basics.UserControls.SearchResult; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Windows; using System.Windows.Controls; using static C4IT.Logging.cLogManager; namespace FasdDesktopUi.Basics.UserControls { public partial class CustomSearchResultCollection : UserControl { private Dictionary _searchCategories; #region IndexOfSelectedResultItem private int _indexOfSelectedResultItem = int.MinValue; public int IndexOfSelectedResultItem { get { return _indexOfSelectedResultItem; } set { if (_indexOfSelectedResultItem == value) return; if (value < -1) _indexOfSelectedResultItem = int.MinValue; else if (value == -1) _indexOfSelectedResultItem = GetSearchResultCount() - 1; else if (value == GetSearchResultCount()) _indexOfSelectedResultItem = 0; else _indexOfSelectedResultItem = value; HandleIndexOfSelectedResultItemChanged(); } } #endregion private cMenuDataBase _lastSelectedMenuData = null; public bool ShowSearchResultDetails { get { return cFasdCockpitConfig.Instance.ShowSearchResultDetails; } set { cFasdCockpitConfig.Instance.ShowSearchResultDetails = value; cFasdCockpitConfig.Instance.Save("ShowSearchResultDetails"); } } public CustomSearchResultCollection() { InitializeComponent(); } protected override void OnInitialized(EventArgs e) { base.OnInitialized(e); AddHandler(CustomEventManager.IndexChangedEvent, new CustomEventManager.IndexChangedHandlerDelegate(UpdateIndexOfSelectedResultItem)); AddHandler(CustomEventManager.MenuDataChangedEvent, new CustomEventManager.MenuDataChangedHandlerDelegate((_, args) => _lastSelectedMenuData = args.MenuData)); } private void UpdateIndexOfSelectedResultItem(object sender, IndexEventArgs args) { try { if (!(args.OriginalSource is SearchResultCategory category)) return; var indexOfSender = _searchCategories.Values.ToList().IndexOf(category); int updatedIndex = args.NewValue; for (int i = 0; i < indexOfSender; i++) { updatedIndex += _searchCategories.Values.ToList()[i].GetItemCount(); } IndexOfSelectedResultItem = updatedIndex; } catch (Exception ex) { LogException(ex); } } public bool IsEmpty() => MainStackPanel.Children.Count == 0; internal int GetSearchResultCount() { int itemCount = 0; foreach (var resultCategory in _searchCategories.Values) { itemCount += resultCategory.GetItemCount(); } return itemCount; } private void HandleIndexOfSelectedResultItemChanged() { try { int totalResultItemCount = 0; foreach (var category in _searchCategories.Values) { int categoryItemCount = category.GetItemCount(); if (IndexOfSelectedResultItem > totalResultItemCount) category.HiglightItemAt(-1); if (IndexOfSelectedResultItem < totalResultItemCount + categoryItemCount) category.HiglightItemAt(IndexOfSelectedResultItem - totalResultItemCount); totalResultItemCount += categoryItemCount; } } catch (Exception E) { LogException(E); } } public void SetHeaderText(string headerText, bool hideDetailsCheckbox = false) { try { HeaderTextBlock.Text = headerText; HeaderTextBlock.Visibility = string.IsNullOrEmpty(headerText) ? Visibility.Collapsed : Visibility.Visible; ShowDetailsCheckBox.Visibility = string.IsNullOrEmpty(headerText) || hideDetailsCheckbox ? Visibility.Collapsed : Visibility.Visible; } catch (Exception E) { LogException(E); } } private void ProcessNewItems() { UpdateCornerRadius(); UpdateSearchResultDetailsShown(ShowSearchResultDetails); } public void ShowLoadingTextItem(string itemText) { try { ClearControl(); var menuItem = new CustomMenuItem(false) { MenuData = new cMenuDataLoading(itemText) }; MainStackPanel.Children.Add(menuItem); ProcessNewItems(); } catch (Exception E) { LogException(E); } } public void ShowSearchResults(cFilteredResults SearchResults, string headerText, ISearchUiProvider searchUiProvider) { try { ClearControl(); SetHeaderText(headerText); if (SearchResults?.Results is null || SearchResults.Results.Count == 0) ProcessNoSearchResults(); else ProcessSearchResults(); ProcessNewItems(); } catch (Exception E) { LogException(E); } void ProcessNoSearchResults() { var resultItemControl = new CustomMenuItem(false) { MenuData = new cMenuDataBase() { MenuText = cMultiLanguageSupport.GetItem("SearchBar.NoResults"), MenuIcon = new IconData(enumInternIcons.menuBar_search_noResults) } }; MainStackPanel.Children.Add(resultItemControl); } void ProcessSearchResults() { if (!_searchCategories.TryGetValue(enumFasdInformationClass.Main, out var mainCategory)) return; List menuDataList = new List(); mainCategory.UpdateSearchResults(SearchResults.Results, searchUiProvider); UpdatePendingInformationClasses(new HashSet()); } } public void ShowSearchHistory() { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { ClearControl(); SetHeaderText(cMultiLanguageSupport.GetItem("Searchbar.History.Title"), true); if (cSearchManager.Instance.HistoryList.Count <= 0) { this.Visibility = Visibility.Collapsed; return; } this.Visibility = Visibility.Visible; foreach (var historyEntry in cSearchManager.Instance.HistoryList) { var menuData = new cMenuDataBase() { MenuText = historyEntry.DisplayText, UiAction = new cUiProcessSearchHistoryEntry(historyEntry) }; if (historyEntry.isSeen) { menuData.MenuIcon = new IconData(MaterialIcons.MaterialIconType.ic_visibility); menuData.MenuIconSize = 0.75; } MainStackPanel.Children.Add(new CustomMenuItem(true) { MenuData = menuData }); } ProcessNewItems(); } catch (Exception E) { LogException(E); } finally { LogMethodEnd(CM); } } public void UpdateSearchRelations(ILookup relations) { try { if (_searchCategories is null) return; int indexOfMenuData = -1; int indexOfMenuDataCategory = -1; foreach (var relation in relations) { if (!_searchCategories.TryGetValue(relation.Key, out var category)) continue; category.UpdateSearchRelations(relation); if (indexOfMenuData != -1) continue; indexOfMenuData = GetIndexOf(relation.Select(value => value.Data), _lastSelectedMenuData?.Data); if (indexOfMenuData != -1) indexOfMenuDataCategory = GetIndexOf(_searchCategories.Values, category); } ProcessNewItems(); if (indexOfMenuData == -1) return; IndexOfSelectedResultItem = indexOfMenuData + _searchCategories.Take(indexOfMenuDataCategory).Sum(category => category.Value.GetItemCount()); } catch (Exception ex) { LogException(ex); } // even if not ideal, seems to be the most performant solution for retrieving the index of IEnumerable int GetIndexOf(IEnumerable data, object value) { int index = 0; foreach (var item in data) { if (item.Equals(value)) return index; index++; } return -1; } } private void ClearControl() { MainStackPanel.Children.Clear(); var mainCategory = new SearchResultCategory() { IsPending = false }; _searchCategories = new Dictionary() { [enumFasdInformationClass.Main] = mainCategory }; MainStackPanel.Children.Add(mainCategory); _lastSelectedMenuData = null; IndexOfSelectedResultItem = int.MinValue; HandleIndexOfSelectedResultItemChanged(); } public void SelectCurrentResultItem() { try { int totalResultItemCount = 0; foreach (var category in _searchCategories.Values) { int categoryItemCount = category.GetItemCount(); if (IndexOfSelectedResultItem < totalResultItemCount + categoryItemCount) { category.SelectItemAt(IndexOfSelectedResultItem - totalResultItemCount); return; } totalResultItemCount += categoryItemCount; } } catch (Exception E) { LogException(E); } } private void UpdateCornerRadius() { try { const double cornerRadius = 10; if (MainStackPanel.Children.Count <= 0) return; if (MainStackPanel.Children[0] is CustomMenuItem resultItemFirst) { var tempCornerRadius = resultItemFirst.MenuItemBorder.CornerRadius; tempCornerRadius.TopLeft = cornerRadius; tempCornerRadius.TopRight = cornerRadius; resultItemFirst.MenuItemBorder.CornerRadius = tempCornerRadius; } if (MainStackPanel.Children[MainStackPanel.Children.Count - 1] is CustomMenuItem resultItemLast) { var tempCornerRadiusLast = resultItemLast.MenuItemBorder.CornerRadius; tempCornerRadiusLast.BottomLeft = cornerRadius; tempCornerRadiusLast.BottomRight = cornerRadius; resultItemLast.MenuItemBorder.CornerRadius = tempCornerRadiusLast; } } catch (Exception E) { LogException(E); } } private void ShowDetailsCheckBox_Checked(object sender, RoutedEventArgs e) { if (!(sender is CheckBox checkBox)) return; cFasdCockpitConfig.Instance.ShowSearchResultDetails = checkBox.IsChecked == true; cFasdCockpitConfig.Instance.Save("ShowSearchResultDetails"); UpdateSearchResultDetailsShown(checkBox.IsChecked); } private void UpdateSearchResultDetailsShown(bool? showDetailHeadings) { try { if (showDetailHeadings is null) return; if (MainStackPanel?.Children is null || MainStackPanel.Children.Count <= 0) return; foreach (var searchResult in MainStackPanel.Children.OfType()) { searchResult.ShowDetailHeadings(showDetailHeadings.Value); } foreach (var searchResult in MainStackPanel.Children.OfType()) { searchResult.ShowDetailHeadings(showDetailHeadings.Value); } } catch (Exception ex) { LogException(ex); } } public void SetPendingInformationClasses(HashSet informationClasses) { try { MainStackPanel.Children.Clear(); _searchCategories = new Dictionary(); foreach (var informationClass in informationClasses.Reverse()) { var searchResultCategory = new SearchResultCategory() { Title = string.Format(cMultiLanguageSupport.GetItem("Searchbar.Relations.SearchFor"), informationClass), IsPending = true, TitleIcon = GetIconFrom(informationClass), Margin = new Thickness(0, 7.5, 0, 0) }; _searchCategories.Add(informationClass, searchResultCategory); MainStackPanel.Children.Add(searchResultCategory); } } catch (Exception ex) { LogException(ex); } IconData GetIconFrom(enumFasdInformationClass informationClass) { switch (informationClass) { case enumFasdInformationClass.Computer: return new IconData(enumInternIcons.misc_computer); case enumFasdInformationClass.User: return new IconData(enumInternIcons.misc_user); case enumFasdInformationClass.Ticket: return new IconData(enumInternIcons.menuBar_mail); case enumFasdInformationClass.VirtualSession: return new IconData(MaterialIcons.MaterialIconType.ic_cloud_queue); case enumFasdInformationClass.MobileDevice: return new IconData(MaterialIcons.MaterialIconType.ic_smartphone); default: return new IconData(enumInternIcons.f4sd); } } } public void UpdatePendingInformationClasses(HashSet informationClasses) { try { if (_searchCategories is null) return; var finishedInformationClasses = _searchCategories.Where(category => !informationClasses.Contains(category.Key)).Select(category => category.Value); foreach (var pendingCategory in finishedInformationClasses) { pendingCategory.IsPending = false; if (pendingCategory.GetItemCount() == 0) pendingCategory.Margin = new Thickness(0); else pendingCategory.Margin = new Thickness(0, 7.5, 0, 0); } if (IndexOfSelectedResultItem != int.MinValue) return; if (_searchCategories.Values.Any(c => c.IsPending)) return; IndexOfSelectedResultItem = _searchCategories.Values.Sum(c => c.GetItemCount()) - 1; } catch (Exception ex) { LogException(ex); } } } }