Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / System / Windows / Documents / TextEditorSpelling.cs / 1305600 / TextEditorSpelling.cs
//---------------------------------------------------------------------------- // // File: TextEditorSpelling.cs // // Copyright (C) Microsoft Corporation. All rights reserved. // // Description: A Component of TextEditor supporting spelling. // //--------------------------------------------------------------------------- namespace System.Windows.Documents { using MS.Internal; using System.Windows; using System.Windows.Input; using MS.Internal.Commands; using System.Windows.Controls; using System.Windows.Markup; // XmlLanguage // A Component of TextEditor supporting spelling. internal static class TextEditorSpelling { //----------------------------------------------------- // // Class Internal Methods // //----------------------------------------------------- #region Class Internal Methods // Registers all text editing command handlers for a given control type internal static void _RegisterClassHandlers(Type controlType, bool registerEventListeners) { CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.CorrectSpellingError, new ExecutedRoutedEventHandler(OnCorrectSpellingError), new CanExecuteRoutedEventHandler(OnQueryStatusSpellingError)); CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.IgnoreSpellingError, new ExecutedRoutedEventHandler(OnIgnoreSpellingError), new CanExecuteRoutedEventHandler(OnQueryStatusSpellingError)); } // Worker for TextBox/RichTextBox.GetSpellingErrorAtPosition. internal static SpellingError GetSpellingErrorAtPosition(TextEditor This, ITextPointer position, LogicalDirection direction) { return (This.Speller == null) ? null : This.Speller.GetError(position, direction, true /* forceEvaluation */); } // Returns the error (if any) at the current selection. internal static SpellingError GetSpellingErrorAtSelection(TextEditor This) { if (This.Speller == null) { return null; } if (IsSelectionIgnoringErrors(This.Selection)) { // Some selection (large ones in particular) ignore errors. return null; } // If the selection is empty, we want to respect its direction // when poking around for spelling errors. // If it's non-empty, the selection start direction is always // backward, which is the opposite of what we want. LogicalDirection direction = This.Selection.IsEmpty ? This.Selection.Start.LogicalDirection : LogicalDirection.Forward; char character; ITextPointer position = GetNextTextPosition(This.Selection.Start, null /* limit */, direction, out character); if (position == null) { // There is no next character -- flip direction. // This is the end-of-document or end-of-paragraph case. direction = (direction == LogicalDirection.Forward) ? LogicalDirection.Backward : LogicalDirection.Forward; position = GetNextTextPosition(This.Selection.Start, null /* limit */, direction, out character); } else if (Char.IsWhiteSpace(character)) { // If direction points to whitespace // If the selection is empty // Look in the opposite direction. // Else // If the selection contains non-white space // Look at the first non-white space character forward. // Else // Look in the opposite direction. if (This.Selection.IsEmpty) { direction = (direction == LogicalDirection.Forward) ? LogicalDirection.Backward : LogicalDirection.Forward; position = GetNextTextPosition(This.Selection.Start, null /* limit */, direction, out character); } else { direction = LogicalDirection.Forward; position = GetNextNonWhiteSpacePosition(This.Selection.Start, This.Selection.End); if (position == null) { direction = LogicalDirection.Backward; position = GetNextTextPosition(This.Selection.Start, null /* limit */, direction, out character); } } } return (position == null) ? null : This.Speller.GetError(position, direction, false /* forceEvaluation */); } // Worker for TextBox/RichTextBox.GetNextSpellingErrorPosition. internal static ITextPointer GetNextSpellingErrorPosition(TextEditor This, ITextPointer position, LogicalDirection direction) { return (This.Speller == null) ? null : This.Speller.GetNextSpellingErrorPosition(position, direction); } #endregion Class Internal Methods //------------------------------------------------------ // // Private Methods // //----------------------------------------------------- #region Private Methods // Callback for EditingCommands.CorrectSpellingError. // // Corrects the error pointed to by Selection.Start with the string // specified in args.Data. private static void OnCorrectSpellingError(object target, ExecutedRoutedEventArgs args) { TextEditor This = TextEditor._GetTextEditor(target); if (This == null) return; string correctedText = args.Parameter as string; if (correctedText == null) return; SpellingError spellingError = GetSpellingErrorAtSelection(This); if (spellingError == null) return; using (This.Selection.DeclareChangeBlock()) { ITextPointer textStart; ITextPointer textEnd; bool dontUseRange = IsErrorAtNonMergeableInlineEdge(spellingError, out textStart, out textEnd); ITextPointer caretPosition; if (dontUseRange && textStart is TextPointer) { // We need a cast because ITextPointer's equivalent to DeleteTextInRun (DeleteContentToPostiion) // will remove empty TextElements, which we do not want. ((TextPointer)textStart).DeleteTextInRun(textStart.GetOffsetToPosition(textEnd)); textStart.InsertTextInRun(correctedText); caretPosition = textStart.CreatePointer(+correctedText.Length, LogicalDirection.Forward); } else { This.Selection.Select(spellingError.Start, spellingError.End); // Setting range.Text to correctedText might inadvertantly apply previous Run's formatting properties. // Save current formatting to avoid this. if (This.AcceptsRichContent) { ((TextSelection)This.Selection).SpringloadCurrentFormatting(); } // TextEditor.SetSelectedText() replaces current selection with new text and // also applies any springloaded properties to the text. XmlLanguage language = (XmlLanguage)spellingError.Start.GetValue(FrameworkElement.LanguageProperty); This.SetSelectedText(correctedText, language.GetSpecificCulture()); caretPosition = This.Selection.End; } // Collapse the selection to a caret following the new text. This.Selection.Select(caretPosition, caretPosition); } } // Returns true when one or both ends of the error lies at the inner edge of non-mergeable inline // such as Hyperlink. In this case, a TextRange will normalize its ends outside // the scope of the inline, and the corrected text will not be covered by it. // // We work around the common case, when the error is contained within a single // Run. In more complex cases we'll fail and fall back to using a TextRange. private static bool IsErrorAtNonMergeableInlineEdge(SpellingError spellingError, out ITextPointer textStart, out ITextPointer textEnd) { bool result = false; textStart = spellingError.Start.CreatePointer(LogicalDirection.Backward); while (textStart.CompareTo(spellingError.End) < 0 && textStart.GetPointerContext(LogicalDirection.Forward) != TextPointerContext.Text) { textStart.MoveToNextContextPosition(LogicalDirection.Forward); } textEnd = spellingError.End.CreatePointer(); while (textEnd.CompareTo(spellingError.Start) > 0 && textEnd.GetPointerContext(LogicalDirection.Backward) != TextPointerContext.Text) { textEnd.MoveToNextContextPosition(LogicalDirection.Backward); } if (textStart.GetPointerContext(LogicalDirection.Forward) != TextPointerContext.Text || textStart.CompareTo(spellingError.End) == 0) { return false; } Invariant.Assert(textEnd.GetPointerContext(LogicalDirection.Backward) == TextPointerContext.Text && textEnd.CompareTo(spellingError.Start) != 0); if (TextPointerBase.IsAtNonMergeableInlineStart(textStart) || TextPointerBase.IsAtNonMergeableInlineEnd(textEnd)) { if (typeof(Run).IsAssignableFrom(textStart.ParentType) && textStart.HasEqualScope(textEnd)) { result = true; } } return result; } // Callback for EditingCommands.IgnoreSpellingError. // // Ignores the error pointed to by Selection.Start and all other // duplicates for the lifetime of the TextEditor. private static void OnIgnoreSpellingError(object target, ExecutedRoutedEventArgs args) { TextEditor This = TextEditor._GetTextEditor(target); if (This == null) return; SpellingError spellingError = GetSpellingErrorAtSelection(This); if (spellingError == null) return; spellingError.IgnoreAll(); } // Callback for EditingCommands.CorrectSpellingError and EditingCommands.IgnoreSpellingError // QueryEnabled events. // // Both commands are enabled if Selection.Start currently points to a spelling error. private static void OnQueryStatusSpellingError(object target, CanExecuteRoutedEventArgs args) { TextEditor This = TextEditor._GetTextEditor(target); if (This == null) return; SpellingError spellingError = GetSpellingErrorAtSelection(This); args.CanExecute = (spellingError != null); } // Returns the position preceeding the next text character in a specified // direction, or null if no such position exists. // The scan will halt if limit is encounted; limit may be null. private static ITextPointer GetNextTextPosition(ITextPointer position, ITextPointer limit, LogicalDirection direction, out char character) { bool foundText = false; character = (char)0; while (position != null && !foundText && (limit == null || position.CompareTo(limit) < 0)) { switch (position.GetPointerContext(direction)) { case TextPointerContext.Text: char[] buffer = new char[1]; position.GetTextInRun(direction, buffer, 0, 1); character = buffer[0]; foundText = true; break; case TextPointerContext.ElementStart: case TextPointerContext.ElementEnd: if (TextSchema.IsFormattingType(position.GetElementType(direction))) { position = position.CreatePointer(+1); } else { position = null; } break; case TextPointerContext.EmbeddedElement: case TextPointerContext.None: default: position = null; break; } } return position; } // Returns the next non-white space character in the forward direction // from position, or null if no such position exists. // The return value will equal position if position is immediately followed // by a non-whitespace char. // // This method expects that limit is never null. The scan will halt if // limit is encountered. private static ITextPointer GetNextNonWhiteSpacePosition(ITextPointer position, ITextPointer limit) { char character; Invariant.Assert(limit != null); while (true) { if (position.CompareTo(limit) == 0) { position = null; break; } position = GetNextTextPosition(position, limit, LogicalDirection.Forward, out character); if (position == null) break; if (!Char.IsWhiteSpace(character)) break; position = position.CreatePointer(+1); }; return position; } // Returns true if an ITextSelection isn't in a state where we want // to acknowledge spelling errors. private static bool IsSelectionIgnoringErrors(ITextSelection selection) { bool isSelectionIgnoringErrors = false; // If the selection spans more than a single Block, ignore spelling errors. if (selection.Start is TextPointer) { isSelectionIgnoringErrors = ((TextPointer)selection.Start).ParentBlock != ((TextPointer)selection.End).ParentBlock; } // If the selection is large, ignore spelling errors. if (!isSelectionIgnoringErrors) { isSelectionIgnoringErrors = selection.Start.GetOffsetToPosition(selection.End) >= 256; } // If the selection contains unicode line breaks, ignore spelling errors. if (!isSelectionIgnoringErrors) { string text = selection.Text; for (int i = 0; i < text.Length && !isSelectionIgnoringErrors; i++) { isSelectionIgnoringErrors = TextPointerBase.IsCharUnicodeNewLine(text[i]); } } return isSelectionIgnoringErrors; } #endregion Private Methods } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ByteStack.cs
- ADMembershipProvider.cs
- Int32Collection.cs
- Decorator.cs
- LinearGradientBrush.cs
- Variant.cs
- WebSysDefaultValueAttribute.cs
- Claim.cs
- RegexCompilationInfo.cs
- OdbcCommand.cs
- BaseConfigurationRecord.cs
- SqlProviderManifest.cs
- QueryOpeningEnumerator.cs
- PropertyMapper.cs
- ResizeBehavior.cs
- CodeSnippetTypeMember.cs
- ProgressBarRenderer.cs
- MetadataException.cs
- securestring.cs
- ResourceDescriptionAttribute.cs
- StrongName.cs
- ManagementOptions.cs
- ForceCopyBuildProvider.cs
- SQLBytes.cs
- ClickablePoint.cs
- ApplicationProxyInternal.cs
- FreezableDefaultValueFactory.cs
- DrawingServices.cs
- CodeLabeledStatement.cs
- WebPartManagerInternals.cs
- InternalSafeNativeMethods.cs
- ContentTextAutomationPeer.cs
- Int32AnimationBase.cs
- AbstractSvcMapFileLoader.cs
- DeviceContexts.cs
- XmlSchemaExporter.cs
- DataComponentMethodGenerator.cs
- SafeReversePInvokeHandle.cs
- CreateUserWizardStep.cs
- IIS7UserPrincipal.cs
- DescendantOverDescendantQuery.cs
- SqlTypesSchemaImporter.cs
- OverloadGroupAttribute.cs
- _FtpDataStream.cs
- DesignerHelpers.cs
- InfoCardRSAOAEPKeyExchangeFormatter.cs
- PtsHost.cs
- KerberosSecurityTokenAuthenticator.cs
- KeyNotFoundException.cs
- UIElementHelper.cs
- DES.cs
- ResXFileRef.cs
- HttpWebRequestElement.cs
- ToolStripPanelRenderEventArgs.cs
- DataControlLinkButton.cs
- StoryFragments.cs
- XmlHierarchicalDataSourceView.cs
- sqlser.cs
- HwndSubclass.cs
- DateTimeParse.cs
- EmptyEnumerable.cs
- DocumentPaginator.cs
- SchemaLookupTable.cs
- SqlInfoMessageEvent.cs
- ConnectionPoint.cs
- RegisteredArrayDeclaration.cs
- rsa.cs
- DataGridItem.cs
- HttpHandlerActionCollection.cs
- ColorAnimation.cs
- PasswordTextContainer.cs
- ILGenerator.cs
- CustomAttributeBuilder.cs
- RegisteredExpandoAttribute.cs
- ConvertBinder.cs
- BufferBuilder.cs
- FixedSOMTableRow.cs
- ContactManager.cs
- X509SecurityToken.cs
- DataKeyCollection.cs
- WebBrowsableAttribute.cs
- LayoutEditorPart.cs
- InternalResources.cs
- PbrsForward.cs
- BinaryEditor.cs
- XmlStrings.cs
- ApplicationTrust.cs
- ToolStripArrowRenderEventArgs.cs
- SqlDataSourceView.cs
- ServiceNameCollection.cs
- XmlWellformedWriter.cs
- SkipQueryOptionExpression.cs
- XPathNodeIterator.cs
- AbstractSvcMapFileLoader.cs
- TransformConverter.cs
- IPEndPointCollection.cs
- ImpersonationContext.cs
- RequiredFieldValidator.cs
- ToolTipAutomationPeer.cs
- KeyEventArgs.cs