/// <summary> /// Applies one step of the async highlighting against the main scheme. /// </summary> /// <returns>Whether another step should be called.</returns> protected bool StepHiliteMain(AsyncHighlightState state) { if (!state.Enum.MoveNext()) { state.ActualSearchHits = state.Words; // As the main scheme has succeeded, the original word list is the same as the final one return(false); // Over! } // Get the current word WordPtr word = (WordPtr)state.Enum.Current; if (word.StartOffset < 0) { return(StartHiliteBackup(state)); // Fallback to the backup scheme } // Choose a color for highlighting this word state.PickNextColor(word.Original); // Select the supposed search hit location Select(word.StartOffset, word.Text.Length); // Check whether we've selected the proper thing if (String.Compare(SelectedText, word.Text, true, CultureInfo.InvariantCulture) != 0) { Trace.WriteLine(String.Format("Main highlighting expected to find \"{0}\" but got \"{1}\", aborting.", word.Text, SelectedText), "[JRTB]"); return(StartHiliteBackup(state)); // Fallback to the backup scheme } // Apply the coloring!! Win32Declarations.SendMessage(Handle, EditMessage.SETCHARFORMAT, SCF.SELECTION, ref state.Fmt); return(true); // Call more }
/// <summary> /// Initiates the async highlighting of the search hits. /// </summary> /// <param name="words">Words to be highlighted. MUST belong to a single document section.</param> public void HighlightWords(WordPtr[] words) { #region Preconditions if (words == null) { return; } // Validness check WordPtr.AssertValid(words, true); #endregion Preconditions _wordsSearchHits = null; // Here the real search hits will be stored; in case of main highlighting they correspond to the ones passed in _statuswriter = Core.UIManager.GetStatusWriter(this, StatusPane.UI); _statuswriter.ShowStatus("Highlighting search hits in the document…"); // Initiate the async hilite process _stateHilite = new AsyncHighlightState(words); if (StartHiliteMain(_stateHilite)) { Core.UserInterfaceAP.QueueJobAt(DateTime.Now.AddMilliseconds(500), "Highlight the search hits.", new MethodInvoker(StepHilite)); // Succeeded — queue execution } else { // Failed — deinitialize _stateHilite = null; _statuswriter.ClearStatus(); _statuswriter = null; Trace.WriteLine("Failed to initiate the main highlighting scheme.", "[JRTB]"); } }
public int Compare(object x, object y) { WordPtr inst1 = (WordPtr)x, inst2 = (WordPtr)y; if (inst1.SectionId < inst2.SectionId) { return(-1); } if (inst1.SectionId > inst2.SectionId) { return(1); } if (inst1.StartOffset < inst2.StartOffset) { return(-1); } if (inst1.StartOffset > inst2.StartOffset) { return(1); } return(0); }
/// <summary> /// Applies one step of the async highlighting against the backup scheme. /// </summary> /// <returns>Whether another step should be called.</returns> protected bool StepHiliteBackup(AsyncHighlightState state) { if (state.CurPos < 0) // Should we pick a new word form for searching it? { if (!state.Enum.MoveNext()) { // Completed!! // Sort the search hits in order of appearance and supply to the storage state.ActualSearchHitsCache.Sort(new WordPtrOffsetComparer()); state.ActualSearchHits = (WordPtr[])state.ActualSearchHitsCache.ToArray(typeof(WordPtr)); // Take the search hits return(false); // Finish it } state.CurPos = 0; // Start looking for it from the beginning } string sOriginal = (string)state.Enum.Current; WordPtr wordSearchHit = (WordPtr)state.HashWordForms[sOriginal]; // Choose a color for highlighting the hits of this text state.PickNextColor(wordSearchHit.Original); // Look for the next entry, starting from the very place we left it the prev time int nOldPos = state.CurPos; state.CurPos = Find(wordSearchHit.Text, state.CurPos, RichTextBoxFinds.NoHighlight | RichTextBoxFinds.WholeWord); if (state.CurPos < 0) // If not found, will be negative { return(true); // Switch to looking for the next entry, or complete the process if there are no more } if (state.CurPos <= nOldPos) // Sometimes the Find function will return a result BEFORE the search start :) { // Switch to looking for the next entry, or complete the process if there are no more state.CurPos = -1; return(true); } // Add the search hit data WordPtr hit = wordSearchHit; // Make a copy of the hit hit.StartOffset = state.CurPos; // The actual starting offset state.ActualSearchHitsCache.Add(hit); // Select the supposed search hit location Select(state.CurPos, wordSearchHit.Text.Length); state.CurPos += wordSearchHit.Text.Length; // Skip the already-found entry (otherwise we'll keep finding it again and again, eternally) // Apply the coloring!! Win32Declarations.SendMessage(Handle, EditMessage.SETCHARFORMAT, SCF.SELECTION, ref state.Fmt); return(true); // Try looking for the next entry }
public static void GetHighlightedTerms(Entry entry, string[] lexemes, out WordPtr[] anchors) { anchors = new WordPtr[entry.Count]; Trace.WriteLine("HighlightTerms -- the following terms were processed for highlighting: "); for (int i = 0; i < entry.Count; i++) { InstanceOffset instance = entry.Instance(i); uint offset = instance.Offset; string Lexeme = lexemes[instance.BaseID]; anchors[i].Original = Lexeme; anchors[i].Text = ReconstructWordform(offset, Lexeme, OMEnv.DictionaryServer); anchors[i].StartOffset = instance.OffsetNormal; anchors[i].SectionId = (int)instance.SectionId; anchors[i].Section = DocSectionHelper.FullNameByOrder(instance.SectionId); // trace section Trace.WriteLine(" [" + anchors[i].Text + "] at " + instance.OffsetNormal + ", section " + anchors[i].Section + ", sentence " + instance.Sentence); // end trace section } Array.Sort(anchors, new AnchorComparer()); }
/// <summary> /// Init instance. /// </summary> internal Marker(char marker, WordPtr data) { _markingChar = marker; _offsetData = data; }
/// <summary> /// Receives the formatted content with markers injected, collects the markers, updates the offsets and returns the content with markers cleaned up. /// </summary> /// <param name="content">Content with the markers.</param> /// <param name="offsets">Returns the updated offsets from the <see cref="InjectMarkers"/> method. Note that the number of offsets may decrease if some of the markers go out while formatting.</param> /// <returns>The cleaned up content without the markers.</returns> public string CollectMarkers(string content, out WordPtr[] offsets) { if (_markers == null) { throw new InvalidOperationException("The object must be first initialized by the InjectMarkers call."); } if (_markers.Count == 0) // No markers injected in the text { offsets = null; return(content); } // Locate markers int pos; ArrayList markers = new ArrayList(_markers.Count); // Collect here (some may need to be removed) foreach (Marker marker in _markers) { // Locate the marker pos = content.IndexOf(marker._markingChar); marker._offsetData.StartOffset = pos; if (pos != -1) // If the marker was found in the stream, keep it. Otherwise, drop by not adding to the new storage { markers.Add(marker); } else { Trace.WriteLine("[MFO] Warning! A marker was filtered out due to absense in the formatted stream."); // Pos == -1 } // TODO: what to do if marker is duplicated? // 1) use the first // 2) assume it's a bug and dispose of both offsets, leaving the marker chars intact // 3) add offsets for both } _markers = markers; // Keep the filtered set of markers if (_markers.Count == 0) // No markers left in the text { Trace.WriteLine("[MFO] Error! No markers were found in the formatted stream."); offsets = null; return(content); } // Arrange in order of appearance try { _markers.Sort(); } catch (InvalidOperationException) { // This means that some markers had indeed equal positions, which must not happen Trace.WriteLine("[MFO] Error! Some of the markers had equal positions in the formatted stream. Cancelling further processing."); offsets = null; return(content); } // Cut off and refresh offsets, collect the new offsets pos = 0; // Current position int shift = 0; // Number of cut-out chars to shift the subsequent offsets by StringBuilder stripped = new StringBuilder(content.Length); offsets = new WordPtr[_markers.Count]; foreach (Marker marker in _markers) { // Maintenance stripped.Append(content.Substring(pos, marker._offsetData.StartOffset - pos)); pos = marker._offsetData.StartOffset + 1; // Beyond the marker marker._offsetData.StartOffset -= shift; // Encounter the cut-off markers // Collect offsets[shift] = marker._offsetData; // Advance shift++; } // Copy content after the last marker stripped.Append(content.Substring(pos, content.Length - pos)); return(stripped.ToString( )); }