private async void SearchTextBox_TextChanged(object sender, TextChangedEventArgs e) { // Skip default if (SearchTextBox.Text == "" || SearchTextBox.Text == App.DefaultTextboxText) { return; } // If InterfaceOption.ExtendedFunctions is enabled and we have selected web mode then don't do anything here if ((interfaceOption & InterfaceOption.ExtendedFunctions) == InterfaceOption.ExtendedFunctions && SearchModeComboBox.SelectedIndex == 1) { return; // Don't do anything } // Do search depending on current setting Triplet <List <ClueFragment>, List <Document>, FormatIndicator> triplet = await SearchTextBox_TextChangedDoSeaerch(); // Retrive return values List <ClueFragment> nextClues = triplet.Key; List <Document> foundDocuments = triplet.Value; FormatIndicator formatIndicator = triplet.Tag; // Set up return results ClueFragmentSelectionpane.ItemsSource = nextClues; DocumentSelectionPane.ItemsSource = foundDocuments; // Validation: If ShowValidationSymbol is enabled then show whether we find anything if ((interfaceOption & InterfaceOption.ShowValidationSymbol) == InterfaceOption.ShowValidationSymbol) { if (foundDocuments != null && foundDocuments.Count > 0) { ValidationSymbolText.Content = "✓"; // Also display format indicator of current input format in tooltip when it's a tick switch (formatIndicator) { case FormatIndicator.ID: ValidationSymbolText.ToolTip = "Perform a search using ID"; break; case FormatIndicator.Constrained: ValidationSymbolText.ToolTip = "Perform a search using constraints"; break; case FormatIndicator.SimpleClue: ValidationSymbolText.ToolTip = "Perform a search using simple clue format"; break; case FormatIndicator.Ambiguous: ValidationSymbolText.ToolTip = "Perform an ambiguous serach"; break; case FormatIndicator.Initiation: ValidationSymbolText.ToolTip = "Initializing a search"; break; default: ValidationSymbolText.ToolTip = "Unrecognized format"; break; } } else { ValidationSymbolText.Content = "!"; } } // Show search popup SearchPopup.IsOpen = true; }
/// <summary> /// Break an input for all three search modes (ExistingCluesOnly, AllClueCombinations, General) + all formats for general mode (ID, constraint, shorthand, ambiguous): /// - Break input into clue segments, along with potential CA (without []) and other elements /// GUID form: ID0000[ContentElement] /// Constriant form: A-B-C;A-B;…#metaname#metaname@metavalue[ContentElement]"keyword" /// Shorthand clue form: A-B-C-clue or meta(value or name, can be partial) (where "clue or metavalue" part is stored as the last keyphrase, not as metavalues array) /// Ambiguous form: A B C /// </summary> /// <param name="input">User input, user might use [[ ]] and -- in search text to match []- in actual search target, which is not suggested to contain such but anyway</param> /// <param name="keyPhrases">Clue key phrases, the last one might indicuate a category or a target document meta</param> /// <param name="contentAddress"></param> private void BreakTextIntoFragments(string input, out string[] keyPhrases, out string[] metakeys, out string[] metavalues, out string contentAddress, out string keyword, out FormatIndicator formatIndicator) { // Trim input = input.Trim(); // Set up default values keyPhrases = null; metakeys = null; metavalues = null; contentAddress = null; keyword = null; // Handle ambiguous form if (input.Contains('-') == false && input.Contains('[') == false && input.Contains(' ') == true) { // Setup format formatIndicator = FormatIndicator.Ambiguous; // Escape (double space) string doubleSpaceEscapeSymbol = "~%S&!"; keyPhrases = input.Replace(" ", doubleSpaceEscapeSymbol).Split(new char[] { ' ' }); // Escape back for (int i = 0; i < keyPhrases.Length; i++) { keyPhrases[i] = keyPhrases[i].Replace(doubleSpaceEscapeSymbol, " "); } return; } // Escape [[ string openSquareEscapeSymbol = "~%O&!"; string escaped = input.Replace("[[", openSquareEscapeSymbol); // Notice input is trimmed, and later processing assumes no beginning and trailing spaces // Escape ]] string closeSquareEscapeSymbol = "~%C&!"; escaped = escaped.Replace("]]", closeSquareEscapeSymbol); // Escape -- string dashEscapeSymbol = Home.dashEscapeSymbol; escaped = escaped.Replace("--", dashEscapeSymbol); // Extract content address: on first and last occurence (so CA might make use of some embeded [] format?) int beginIndex = escaped.IndexOf('['); int endIndex = escaped.LastIndexOf(']'); if (beginIndex >= 0 && beginIndex < endIndex) { contentAddress = escaped.Substring(beginIndex, endIndex - beginIndex); } else { contentAddress = null; } // If we have anything left for actual clues, use it if (beginIndex > 0 || beginIndex == -1) { // Get the part before CEA if (beginIndex > 0) { escaped = escaped.Substring(0, beginIndex); } // Extract ID if (escaped.Length > 2 && escaped.ToUpper().IndexOf("ID") == 0) { keyPhrases = new string[1]; keyPhrases[0] = keyPhrases[0].Substring(2); } else if (escaped.Length <= 2) { keyPhrases = new string[] { escaped }; } else { // Split: A-B-C;A-B;…#metaname#metaname@metavalue string[] clues = escaped.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); // Extract last clue: A-B-C#metaname#metaname@metavalue or #metaname#metaname@metavalue string lastClue = clues[clues.Length - 1]; string metaStrings = lastClue; int nearestSeperatorIndex = Math.Min(lastClue.IndexOf('#') == -1 ? int.MaxValue : lastClue.IndexOf('#'), lastClue.IndexOf('@') == -1 ? int.MaxValue : lastClue.IndexOf('@')); if (nearestSeperatorIndex != int.MaxValue) { metaStrings = lastClue.Substring(nearestSeperatorIndex); clues[clues.Length - 1] = lastClue.Substring(0, nearestSeperatorIndex); // Nearest seperator index could just be 0 } else { metaStrings = null; } if (clues[clues.Length - 1] == "") { clues = clues.Take(clues.Length - 1).ToArray(); // Remove empty clues } // Extract meta contraints: #metaname#metaname@metavalue, where for meta section order doesn’t matter if (metaStrings != null) { List <string> metavaluesList = new List <string>(); metakeys = metaStrings.Split(new char[] { ' ', '#' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < metakeys.Length; i++) { int metaValueSeperatorIndex = metakeys[i].IndexOf('@'); if (metaValueSeperatorIndex != -1) { metavaluesList.Add(metakeys[i].Substring(metaValueSeperatorIndex)); metakeys[i] = metakeys[i].Substring(0, metaValueSeperatorIndex); } } metakeys = metakeys.Where(x => !string.IsNullOrEmpty(x)).ToArray(); // How expensive is such preparation work.... metavalues = metavaluesList.ToArray(); } // Assign return values keyPhrases = clues; } } // Extract keyword for contraints if (endIndex > 0 && endIndex != escaped.Length - 1) { keyword = escaped.Substring(endIndex + 1).Replace("\"", ""); } // Return escape back to content if (contentAddress != null) { contentAddress = contentAddress.Replace(openSquareEscapeSymbol, "["); contentAddress = contentAddress.Replace(closeSquareEscapeSymbol, "]"); contentAddress = contentAddress.Replace(dashEscapeSymbol, "-"); } if (keyPhrases != null) { for (int i = 0; i < keyPhrases.Length; i++) { keyPhrases[i] = keyPhrases[i].Replace(openSquareEscapeSymbol, "["); keyPhrases[i] = keyPhrases[i].Replace(closeSquareEscapeSymbol, "]"); keyPhrases[i] = keyPhrases[i].Replace(dashEscapeSymbol, "-"); } } // Decide on format if (keyPhrases != null && keyPhrases[0].ToUpper().IndexOf("ID") == 0) { formatIndicator = FormatIndicator.ID; } else if (metakeys != null || metavalues != null) { formatIndicator = FormatIndicator.Constrained; } else if (input.IndexOf('-') > 0 || input.IndexOf('[') > 0) { formatIndicator = FormatIndicator.SimpleClue; } else if (input.Contains('-') == false && input.Contains(' ') == false) { formatIndicator = FormatIndicator.Initiation; } else { formatIndicator = FormatIndicator.Unrecognized; } }
private async void SearchTextBox_TextChanged(object sender, TextChangedEventArgs e) { //<Development> Consider porting Web mode with Lightning's recent urls to boost usability // Skip default if (SearchTextBox.Text == "" || SearchTextBox.Text == App.DefaultTextboxText) { return; } // If InterfaceOption.ExtendedFunctions is enabled and we have selected web mode then don't do anything here if ((InterfaceOption & InterfaceOption.ExtendedFunctions) == InterfaceOption.ExtendedFunctions && ComboBoxSelection == SearchComboBoxEnum.Web) { return; // Don't do anything } // Select only the line current cursor in on for search (e.g. in case of multiline) // Ref: https://stackoverflow.com/questions/17909651/c-sharp-get-cursor-line-in-richtextbox // Ref: https://stackoverflow.com/questions/31651305/how-to-get-textboxs-line-from-mouse-position string searchString = string.Empty; try { int lineIndex = SearchTextBox.GetLineIndexFromCharacterIndex(SearchTextBox.CaretIndex); if (lineIndex == -1) { return; } searchString = SearchTextBox.GetLineText(lineIndex); } catch (Exception) { return; } if (string.IsNullOrWhiteSpace(searchString)) { return; } // Do search depending on current setting Triplet <List <ClueFragment>, List <Document>, FormatIndicator> triplet = await Task.Run(() => SearchTextBox_TextChangedDoSeaerch(searchString)); // Retrive return values List <ClueFragment> nextClues = triplet.Key; List <Document> foundDocuments = triplet.Value; FormatIndicator formatIndicator = triplet.Tag; // Set up return results if (nextClues != null) { for (int i = 0; i < nextClues.Count; i++) { if (i < 10) { nextClues[i].Index = "F" + (i + 1); // Use functional keys to quickly select a suggested clue } else { nextClues[i].Index = string.Empty; } } } ClueFragmentSelectionpane.ItemsSource = nextClues; DocumentSelectionPane.ItemsSource = foundDocuments; // Validation: If ShowValidationSymbol is enabled then show whether we find anything if ((InterfaceOption & InterfaceOption.ShowValidationSymbol) == InterfaceOption.ShowValidationSymbol) { if (foundDocuments != null && foundDocuments.Count > 0) { ValidationSymbolText.Content = "✓"; // Also display format indicator of current input format in tooltip when it's a tick switch (formatIndicator) { case FormatIndicator.ID: ValidationSymbolText.ToolTip = "Perform a search using ID"; break; case FormatIndicator.Constrained: ValidationSymbolText.ToolTip = "Perform a search using constraints"; break; case FormatIndicator.SimpleClue: ValidationSymbolText.ToolTip = "Perform a search using simple clue format"; break; case FormatIndicator.Ambiguous: ValidationSymbolText.ToolTip = "Perform an ambiguous serach"; break; case FormatIndicator.Initiation: ValidationSymbolText.ToolTip = "Initializing a search"; break; default: ValidationSymbolText.ToolTip = "Unrecognized format"; break; } } else { ValidationSymbolText.Content = "!"; } } }