//----------------------------------------------------- // // Constructors // //----------------------------------------------------- #region Constructors /// <summary> /// Creates new instance of CaretElement. /// </summary> /// <param name="textEditor"> /// TextEditor that owns this Adorner. /// </param> /// <param name="isBlinkEnabled"> /// Blinking for caret animation. Drag target caret does not need blinking, /// </param> internal CaretElement(TextEditor textEditor, bool isBlinkEnabled) : base(textEditor.TextView.RenderScope) { Invariant.Assert(textEditor.TextView != null && textEditor.TextView.RenderScope != null, "Assert: textView != null && RenderScope != null"); _textEditor = textEditor; // Set the animation whether do it or not. _isBlinkEnabled = isBlinkEnabled; // caret position _left = 0.0; _top = 0.0; // caret dimensions _systemCaretWidth = SystemParameters.CaretWidth; _height = 0.0; // Set AllowDropProperty as "False" not to inherit the value from the ancestor. AllowDrop = false; _caretElement = new CaretSubElement(); _caretElement.ClipToBounds = false; AddVisualChild(_caretElement); }
internal static void _OnApplyProperty(TextEditor This, DependencyProperty formattingProperty, object propertyValue, bool applyToParagraphs, PropertyValueAction propertyValueAction) { if (This == null || !This._IsEnabled || This.IsReadOnly || !This.AcceptsRichContent || !(This.Selection is TextSelection)) { return; } // Check whether the property is known if (!TextSchema.IsParagraphProperty(formattingProperty) && !TextSchema.IsCharacterProperty(formattingProperty)) { Invariant.Assert(false, "The property '" + formattingProperty.Name + "' is unknown to TextEditor"); return; } TextSelection selection = (TextSelection)This.Selection; if (TextSchema.IsStructuralCharacterProperty(formattingProperty) && !TextRangeEdit.CanApplyStructuralInlineProperty(selection.Start, selection.End)) { // Ignore structural commands fires in inappropriate context. return; } TextEditorTyping._FlushPendingInputItems(This); // Forget previously suggested horizontal position TextEditorSelection._ClearSuggestedX(This); // Break merged typing sequence TextEditorTyping._BreakTypingSequence(This); // Apply property selection.ApplyPropertyValue(formattingProperty, propertyValue, applyToParagraphs, propertyValueAction); }
/// <summary> /// Creates a flow document from the editor's contents. /// </summary> public static FlowDocument CreateFlowDocumentForEditor(TextEditor editor) { IHighlighter highlighter = editor.TextArea.GetService(typeof(IHighlighter)) as IHighlighter; FlowDocument doc = new FlowDocument(ConvertTextDocumentToBlock(editor.Document, highlighter)); doc.FontFamily = editor.FontFamily; doc.FontSize = editor.FontSize; return doc; }
//------------------------------------------------------ // // Internal Methods // //------------------------------------------------------ #region Internal Methods // Sets the caret in response to a mouse down or mouse up event. internal static void SetCaretPositionOnMouseEvent(TextEditor This, Point mouseDownPoint, MouseButton changedButton, int clickCount) { // Get the character position of the mouse event. ITextPointer cursorPosition = This.TextView.GetTextPositionFromPoint(mouseDownPoint, /*snapToText:*/true); if (cursorPosition == null) { // Cursor is between pages in a document viewer. MoveFocusToUiScope(This); return; } // Forget previously suggested horizontal position TextEditorSelection._ClearSuggestedX(This); // Discard typing undo unit merging TextEditorTyping._BreakTypingSequence(This); // Clear springload formatting if (This.Selection is TextSelection) { ((TextSelection)This.Selection).ClearSpringloadFormatting(); } // Clear flags for forcing word and paragraphexpansion // (which should be true only in case of doubleClick+drag or tripleClick+drag) This._forceWordSelection = false; This._forceParagraphSelection = false; if (changedButton == MouseButton.Right || clickCount == 1) { // If mouse clicked within selection enter dragging mode, otherwise start building a selection if (changedButton != MouseButton.Left || !This._dragDropProcess.SourceOnMouseLeftButtonDown(mouseDownPoint)) { // Mouse down happend outside of current selection // so position the selection at the clicked location. This.Selection.SetSelectionByMouse(cursorPosition, mouseDownPoint); } } else if (clickCount == 2 && (Keyboard.Modifiers & ModifierKeys.Shift) == 0 && This.Selection.IsEmpty) { // Double click only works when Shift is not pressed This._forceWordSelection = true; This._forceParagraphSelection = false; This.Selection.SelectWord(cursorPosition); } else if (clickCount == 3 && (Keyboard.Modifiers & ModifierKeys.Shift) == 0) { // Triple click only works when Shift is not pressed if (This.AcceptsRichContent) { This._forceParagraphSelection = true; This._forceWordSelection = false; This.Selection.SelectParagraph(cursorPosition); } } }
// 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 */); }
public void CopyEditorSettings(TextEditor source) { string language = source.SyntaxHighlighting != null ? source.SyntaxHighlighting.Name : null; editor.TextArea.TextView.LineTransformers.RemoveWhere(x => x is HighlightingColorizer); editor.TextArea.TextView.LineTransformers.Insert(0, new CustomizableHighlightingColorizer(source.SyntaxHighlighting.MainRuleSet, CustomizedHighlightingColor.FetchCustomizations(language))); CustomizableHighlightingColorizer.ApplyCustomizationsToDefaultElements(editor, CustomizedHighlightingColor.FetchCustomizations(language)); HighlightingOptions.ApplyToRendering(editor, CustomizedHighlightingColor.FetchCustomizations(language)); editor.TextArea.TextView.Redraw(); // manually redraw if default elements didn't change but customized highlightings did }
// Decreases the indent level of the Block at selection start. internal static void DecreaseIndentation(TextEditor This) { TextSelection thisSelection = (TextSelection)This.Selection; ListItem parentListItem = TextPointerBase.GetListItem(thisSelection.Start); ListItem immediateListItem = TextPointerBase.GetImmediateListItem(thisSelection.Start); DecreaseIndentation(thisSelection, parentListItem, immediateListItem); }
/// <summary> /// Constructor /// </summary> /// <param name="t"></param> public EditorHelper(TextEditor t) { textEditor = t; t.KeyUp += OnKeyUp; CanEat = new bool[ 10 ]; for ( int i = 0; i < 10; i++ ) { CanEat[ i ] = false; } }
//------------------------------------------------------ // // Constructors // //------------------------------------------------------ #region Constructors // Creates a new TextStore instance. // The interesting initialization is in Attach/Detach. internal TextStore(TextEditor textEditor) { // We have only weak reference to TextEditor so it is free to be GCed. _weakTextEditor = new ScopeWeakReference(textEditor); // initialize Cookies. _threadFocusCookie = UnsafeNativeMethods.TF_INVALID_COOKIE; _editSinkCookie = UnsafeNativeMethods.TF_INVALID_COOKIE; _editCookie = UnsafeNativeMethods.TF_INVALID_COOKIE; _transitoryExtensionSinkCookie = UnsafeNativeMethods.TF_INVALID_COOKIE; }
public EnhancedScrollBar(TextEditor editor, TextMarkerService textMarkerService, IChangeWatcher changeWatcher) { if (editor == null) throw new ArgumentNullException("editor"); this.editor = editor; this.textMarkerService = textMarkerService; this.changeWatcher = changeWatcher; editor.Loaded += editor_Loaded; if (editor.IsLoaded) { editor_Loaded(null, null); } }
public BreakPointMargin(TextEditor TxEditor) { this.TxEditor = TxEditor; BreakPointList = new List<int>(); this.HorizontalAlignment = HorizontalAlignment.Left; this.VerticalAlignment = VerticalAlignment.Top; this.TxEditor.TextArea.TextView.VisualLinesChanged += OnVisualLinesChanged; this.RenderSize = new System.Windows.Size( 20, 100 ); this.Height = 500; this.Width = 20; this.Background = Brushes.Silver; }
//----------------------------------------------------- // // Constructors // //----------------------------------------------------- #region Constructors // Creates a new instance. We have at most one Speller instance // per TextEditor. internal Speller(TextEditor textEditor) { _textEditor = textEditor; _textEditor.TextContainer.Change += new TextContainerChangeEventHandler(OnTextContainerChange); // Schedule some idle time to start examining the document. if (_textEditor.TextContainer.SymbolCount > 0) { ScheduleIdleCallback(); } _defaultCulture = InputLanguageManager.Current != null ? InputLanguageManager.Current.CurrentInputLanguage : Thread.CurrentThread.CurrentCulture; }
//------------------------------------------------------ // // Constructors // //------------------------------------------------------ // Contstructor. // TextSelection does not have a public constructor. It is only accessible // through TextEditor's Selection property. internal TextSelection(TextEditor textEditor) : base(textEditor.TextContainer.Start, textEditor.TextContainer.Start) { ITextSelection thisSelection = (ITextSelection)this; Invariant.Assert(textEditor.UiScope != null); // Attach the selection to its editor _textEditor = textEditor; // Initialize active pointers of the selection - anchor and moving pointers SetActivePositions(/*AnchorPosition:*/thisSelection.Start, thisSelection.End); // Activate selection in case if this control has keyboard focus already thisSelection.UpdateCaretAndHighlight(); }
// Helper for UpdateCaretStateWorker -- Calculate the scroll origin position to scroll caret // with the scroll origin position so that we can ensure of displaying caret with the wrapped word. // // There are four cases of different corrdinate by the flow direction on UiScope and Paragraph. // UiScope has two flow direction which is LeftToRightflow directioin and another is RightToLeft. // Paragraph has also two flow direction which is LeftToRightflow directioin and another is RightToLeft. // // The below is the example of how horizontal corrdinate and scroll origin value base on the different // four cases. So we have to calculate the scroll to origin position base on the case. Simply we can // get the scroll to origin value as zero if UiScope and Paragraph's flow direction is the same. // Otherwise, the scroll to origin value is the extent width value that is the max width. // // <<For instance>> // Case 1. // UiScope FlowDirection: LTR(LeftToRight) // Paragraph FlowDirection: LTR(LefTToRight) // Horizontal origin: "Left" // Scroll horizontal origin: "0" // Wrapping to: "Left" // ABC ...... // XYZ| // // Case 2. // UiScope FlowDirection: LTR(LeftToRight) // Paragraph FlowDirection: RTL(RightToLeft) // Horizontal origin: "Left" // Scroll horizontal origin: "Max:Extent Width" // Wrapping to: "Right" // ......ABC // XYZ| // // Case 3. // UiScope FlowDirection: RTL(RightToLeft) // Paragraph FlowDirection: RTL(RightToLeft) // horizontal origin: "Right" // Scroll horizontal origin: "0" // Wrapping to: "Right" // ......ABC // XYZ| // // Case 4. // UiScope FlowDirection: RTL(RightToLeft) // Paragraph FlowDirection: LTR(LefTToRight) // horizontal origin: "Right" // Scroll horizontal origin: "Max:Extent Width" // Wrapping to: "Left" // ABC ...... // XYZ| private static double CalculateScrollToOriginPosition(TextEditor textEditor, ITextPointer caretPosition, double horizontalCaretPosition) { double scrollToOriginPosition = double.NaN; if (textEditor.UiScope is TextBoxBase) { double viewportWidth = ((TextBoxBase)textEditor.UiScope).ViewportWidth; double extentWidth = ((TextBoxBase)textEditor.UiScope).ExtentWidth; // Calculate the scroll to the origin position position when the horizontal scroll is available if (viewportWidth != 0 && extentWidth != 0 && viewportWidth < extentWidth) { bool needScrollToOriginPosition = false; // Check whether we need to calculate the scroll origin position to scroll it with the caret // position. If the caret position is out of the current visual viewport area, the scroll // to origin positioin will be calculated to scroll into the origin position first that // ensure of displaying the wrapped word. // // Note that horizontalCaretPosition is always relative to the viewport, not the document. if (horizontalCaretPosition < 0 || horizontalCaretPosition >= viewportWidth) { needScrollToOriginPosition = true; } if (needScrollToOriginPosition) { // Set the scroll original position as zero scrollToOriginPosition = 0; // Get the flow direction of uiScope FlowDirection uiScopeflowDirection = (FlowDirection)textEditor.UiScope.GetValue(FrameworkElement.FlowDirectionProperty); // Get the flow direction of the current paragraph and compare it with uiScope's flow direction. Block paragraphOrBlockUIContainer = (caretPosition is TextPointer) ? ((TextPointer)caretPosition).ParagraphOrBlockUIContainer : null; if (paragraphOrBlockUIContainer != null) { FlowDirection pagraphFlowDirection = paragraphOrBlockUIContainer.FlowDirection; // If the flow direction is different between uiScopoe and paragaph, // the original scroll position is the extent width value. if (uiScopeflowDirection != pagraphFlowDirection) { scrollToOriginPosition = extentWidth; } } // Adjust scroll position by current viewport offset scrollToOriginPosition -= ((TextBoxBase)textEditor.UiScope).HorizontalOffset; } } } return scrollToOriginPosition; }
//...................................................... // // Caret Support // //...................................................... // Redraws a caret using current setting for italic - taking springload formatting into account. private static void RefreshCaret(TextEditor textEditor, ITextSelection textSelection) { object fontStylePropertyValue; bool italic; if (textSelection == null || textSelection.CaretElement == null) { return; } // NOTE: We are using GetCurrentValue to take springload formatting into account. fontStylePropertyValue = ((TextSelection)textSelection).GetCurrentValue(TextElement.FontStyleProperty); italic = (textEditor.AcceptsRichContent && fontStylePropertyValue != DependencyProperty.UnsetValue && (FontStyle)fontStylePropertyValue == FontStyles.Italic); textSelection.CaretElement.RefreshCaret(italic); }
// Get the caret brush that is the inverted color from the system window or background color. internal static Brush GetCaretBrush(TextEditor textEditor) { Color backgroundColor; ITextSelection focusedTextSelection; object backgroundPropertyValue; // If TextBoxBase.CaretBrush has been set, use that instead of the default inverting behavior. Brush caretBrush = (Brush)textEditor.UiScope.GetValue(TextBoxBase.CaretBrushProperty); if (caretBrush != null) { return caretBrush; } // Get the default background from the system color or UiScope's background backgroundPropertyValue = textEditor.UiScope.GetValue(System.Windows.Controls.Panel.BackgroundProperty); if (backgroundPropertyValue != null && backgroundPropertyValue != DependencyProperty.UnsetValue && backgroundPropertyValue is SolidColorBrush) { backgroundColor = ((SolidColorBrush)backgroundPropertyValue).Color; } else { backgroundColor = SystemColors.WindowColor; } // Get the background color from current selection focusedTextSelection = textEditor.Selection; if (focusedTextSelection is TextSelection) { backgroundPropertyValue = ((TextSelection)focusedTextSelection).GetCurrentValue(TextElement.BackgroundProperty); if (backgroundPropertyValue != null && backgroundPropertyValue != DependencyProperty.UnsetValue) { if (backgroundPropertyValue is SolidColorBrush) { backgroundColor = ((SolidColorBrush)backgroundPropertyValue).Color; } } } // Invert the color to get the caret color from the system window or background color. byte r = (byte)~(backgroundColor.R); byte g = (byte)~(backgroundColor.G); byte b = (byte)~(backgroundColor.B); caretBrush = new SolidColorBrush(Color.FromRgb(r, g, b)); caretBrush.Freeze(); return caretBrush; }
internal static DataObject _CreateDataObject(TextEditor This, bool isDragDrop) { DataObject dataObject; // Create the data object for drag and drop. // (new UIPermission(UIPermissionClipboard.AllClipboard)).Assert();//BlessedAssert try { dataObject = new DataObject(); } finally { UIPermission.RevertAssert(); } // Get plain text and copy it into the data object. string textString = This.Selection.Text; if (textString != String.Empty) { // Copy plain text into data object. // ConfirmDataFormatSetting rasies a public event - could throw recoverable exception. if (ConfirmDataFormatSetting(This.UiScope, dataObject, DataFormats.Text)) { CriticalSetDataWrapper(dataObject,DataFormats.Text, textString); } // Copy unicode text into data object. // ConfirmDataFormatSetting rasies a public event - could throw recoverable exception. if (ConfirmDataFormatSetting(This.UiScope, dataObject, DataFormats.UnicodeText)) { CriticalSetDataWrapper(dataObject,DataFormats.UnicodeText, textString); } } // Get the rtf and xaml text and then copy it into the data object after confirm data format. // We do this only if our content is rich if (This.AcceptsRichContent) { // This ensures that in the confines of partial trust RTF is not enabled. // We use unmanaged code permission over clipboard permission since // the latter is available in intranet zone and this is something that will // fail in intranet too. if (SecurityHelper.CheckUnmanagedCodePermission()) { // In FullTrust we allow all rich formats on the clipboard Stream wpfContainerMemory = null; // null wpfContainerMemory on entry means that container is optional // and will be not created when there is no images in the range. // Create in-memory wpf package, and serialize the content of selection into it string xamlTextWithImages = WpfPayload.SaveRange(This.Selection, ref wpfContainerMemory, /*useFlowDocumentAsRoot:*/false); if (xamlTextWithImages.Length > 0) { // ConfirmDataFormatSetting raises a public event - could throw recoverable exception. if (wpfContainerMemory != null && ConfirmDataFormatSetting(This.UiScope, dataObject, DataFormats.XamlPackage)) { dataObject.SetData(DataFormats.XamlPackage, wpfContainerMemory); } // ConfirmDataFormatSetting raises a public event - could throw recoverable exception. if (ConfirmDataFormatSetting(This.UiScope, dataObject, DataFormats.Rtf)) { // Convert xaml to rtf text to set rtf data into data object. string rtfText = ConvertXamlToRtf(xamlTextWithImages, wpfContainerMemory); if (rtfText != String.Empty) { dataObject.SetData(DataFormats.Rtf, rtfText, true); } } } // Add a CF_BITMAP if we have only one image selected. Image image = This.Selection.GetUIElementSelected() as Image; if (image != null && image.Source is System.Windows.Media.Imaging.BitmapSource) { dataObject.SetImage((System.Windows.Media.Imaging.BitmapSource)image.Source); } } // Xaml format is availabe both in Full Trust and in Partial Trust // Need to re-serialize xaml to avoid image references within a container: StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture); XmlTextWriter xmlWriter = new XmlTextWriter(stringWriter); TextRangeSerialization.WriteXaml(xmlWriter, This.Selection, /*useFlowDocumentAsRoot:*/false, /*wpfPayload:*/null); string xamlText = stringWriter.ToString(); // if (xamlText.Length > 0) { // ConfirmDataFormatSetting rasies a public event - could throw recoverable exception. if (ConfirmDataFormatSetting(This.UiScope, dataObject, DataFormats.Xaml)) { // Place Xaml data onto the dataobject using safe setter CriticalSetDataWrapper(dataObject, DataFormats.Xaml, xamlText); // The dataobject itself must hold an information about permission set // of the source appdomain. Set it there: // Package permission set for the current appdomain PermissionSet psCurrentAppDomain = SecurityHelper.ExtractAppDomainPermissionSetMinusSiteOfOrigin(); string permissionSetCurrentAppDomain = psCurrentAppDomain.ToString(); CriticalSetDataWrapper(dataObject, DataFormats.ApplicationTrust, permissionSetCurrentAppDomain); } } } // Notify application about our data object preparation completion DataObjectCopyingEventArgs dataObjectCopyingEventArgs = new DataObjectCopyingEventArgs(dataObject, /*isDragDrop:*/isDragDrop); This.UiScope.RaiseEvent(dataObjectCopyingEventArgs); if (dataObjectCopyingEventArgs.CommandCancelled) { dataObject = null; } return dataObject; }
private static bool PasteContentData(TextEditor This, IDataObject dataObject, IDataObject dataObjectToApply, string formatToApply) { // CF_BITMAP - pasting a single image. if (formatToApply == DataFormats.Bitmap && dataObjectToApply is DataObject) { // This demand is present to explicitly disable RTF independant of any // asserts in the confines of partial trust // We check unmanaged code instead of all clipboard because in paste // there is a high level assert for all clipboard in commandmanager.cs if (This.AcceptsRichContent && This.Selection is TextSelection && SecurityHelper.CheckUnmanagedCodePermission()) { System.Windows.Media.Imaging.BitmapSource bitmapSource = GetPasteData(dataObjectToApply, DataFormats.Bitmap) as System.Windows.Media.Imaging.BitmapSource; if (bitmapSource != null) { // Pack the image into a WPF container MemoryStream packagedImage = WpfPayload.SaveImage(bitmapSource, WpfPayload.ImageBmpContentType); // Place it onto a data object dataObjectToApply = new DataObject(); formatToApply = DataFormats.XamlPackage; dataObjectToApply.SetData(DataFormats.XamlPackage, packagedImage); } } } if (formatToApply == DataFormats.XamlPackage) { // This demand is present to explicitly disable RTF independant of any // asserts in the confines of partial trust // We check unmanaged code instead of all clipboard because in paste // there is a high level assert for all clipboard in commandmanager.cs if (This.AcceptsRichContent && This.Selection is TextSelection && SecurityHelper.CheckUnmanagedCodePermission()) { object pastedData = GetPasteData(dataObjectToApply, DataFormats.XamlPackage); MemoryStream pastedMemoryStream = pastedData as MemoryStream; if (pastedMemoryStream != null) { object element = WpfPayload.LoadElement(pastedMemoryStream); if ((element is Section || element is Span) && PasteTextElement(This, (TextElement)element)) { return true; } else if (element is FrameworkElement) { ((TextSelection)This.Selection).InsertEmbeddedUIElement((FrameworkElement)element); return true; } } } // Fall to Xaml: dataObjectToApply = dataObject; // go back to source data object if (dataObjectToApply.GetDataPresent(DataFormats.Xaml)) { formatToApply = DataFormats.Xaml; } else if (SecurityHelper.CheckUnmanagedCodePermission() && dataObjectToApply.GetDataPresent(DataFormats.Rtf)) { formatToApply = DataFormats.Rtf; } else if (dataObjectToApply.GetDataPresent(DataFormats.UnicodeText)) { formatToApply = DataFormats.UnicodeText; } else if (dataObjectToApply.GetDataPresent(DataFormats.Text)) { formatToApply = DataFormats.Text; } } if (formatToApply == DataFormats.Xaml) { if (This.AcceptsRichContent && This.Selection is TextSelection) { object pastedData = GetPasteData(dataObjectToApply, DataFormats.Xaml); if (pastedData != null && PasteXaml(This, pastedData.ToString())) { return true; } } // Fall to Rtf: dataObjectToApply = dataObject; // go back to source data object if (SecurityHelper.CheckUnmanagedCodePermission() && dataObjectToApply.GetDataPresent(DataFormats.Rtf)) { formatToApply = DataFormats.Rtf; } else if (dataObjectToApply.GetDataPresent(DataFormats.UnicodeText)) { formatToApply = DataFormats.UnicodeText; } else if (dataObjectToApply.GetDataPresent(DataFormats.Text)) { formatToApply = DataFormats.Text; } } if (formatToApply == DataFormats.Rtf) { // This demand is present to explicitly disable RTF independant of any // asserts in the confines of partial trust // We check unmanaged code instead of all clipboard because in paste // there is a high level assert for all clipboard in commandmanager.cs if (This.AcceptsRichContent && SecurityHelper.CheckUnmanagedCodePermission()) { object pastedData = GetPasteData(dataObjectToApply, DataFormats.Rtf); // Convert rtf to xaml text to paste rtf data into the target. if (pastedData != null) { MemoryStream memoryStream = ConvertRtfToXaml(pastedData.ToString()); if (memoryStream != null) { TextElement textElement = WpfPayload.LoadElement(memoryStream) as TextElement; if ((textElement is Section || textElement is Span) && PasteTextElement(This, textElement)) { return true; } } } } // Fall to plain text: dataObjectToApply = dataObject; // go back to source data object if (dataObjectToApply.GetDataPresent(DataFormats.UnicodeText)) { formatToApply = DataFormats.UnicodeText; } else if (dataObjectToApply.GetDataPresent(DataFormats.Text)) { formatToApply = DataFormats.Text; } } if (formatToApply == DataFormats.UnicodeText) { object pastedData = GetPasteData(dataObjectToApply, DataFormats.UnicodeText); if (pastedData == null) { if (dataObjectToApply.GetDataPresent(DataFormats.Text)) { formatToApply = DataFormats.Text; // fall to plain text dataObjectToApply = dataObject; // go back to source data object } } else { // Dont attempt to recover if pasting Unicode text fails because our only fallback is mbcs text, // which will either evaluate identically (at best) or // produce a string with unexpected text (worse!) from WideCharToMultiByte conversion. return PastePlainText(This, pastedData.ToString()); } } if (formatToApply == DataFormats.Text) { object pastedData = GetPasteData(dataObjectToApply, DataFormats.Text); if (pastedData != null && PastePlainText(This, pastedData.ToString())) { return true; } } return false; }
internal static void Copy(TextEditor This, bool userInitiated) { if (userInitiated) { // Fail silently if the app explicitly denies clipboard access. try { new UIPermission(UIPermissionClipboard.OwnClipboard).Demand(); } catch (SecurityException) { return; } } else if (!SecurityHelper.CallerHasAllClipboardPermission()) { // Fail silently if we don't have clipboard permission. return; } TextEditorTyping._FlushPendingInputItems(This); TextEditorTyping._BreakTypingSequence(This); if (This.Selection != null && !This.Selection.IsEmpty) { // Note: _CreateDataObject raises a public event which might throw a recoverable exception. DataObject dataObject = TextEditorCopyPaste._CreateDataObject(This, /*isDragDrop:*/false); if (dataObject != null) { try { // The copy command was not terminated by application // One of reason should be the opening fail of Clipboard by the destroyed hwnd. Clipboard.CriticalSetDataObject(dataObject, true); } catch (ExternalException) { // Clipboard is failed to set the data object. return; } } } // Do not clear springload formatting }
/// <summary> /// Attach TextEditor to Document, if supports text. /// </summary> private void AttachTextEditor() { AnnotationService service = AnnotationService.GetService(this); ITextContainer textContainer; // This method is called when Document is changing, so need // to clear old TextEditor data. if (_textEditor != null) { _textEditor.OnDetach(); _textEditor = null; if (_textView.TextContainer.TextView == _textView) { _textView.TextContainer.TextView = null; } _textView = null; } if (service != null) { // Must be enabled - otherwise it won't be on the tree service.Disable(); } // If new Document supports TextEditor, create one. // If the Document is already attached to TextEditor (TextSelection != null), // do not create TextEditor for this instance of the viewer. (This situation may happen // when the same instance of Document is attached to more than one viewer). textContainer = this.TextContainer; if (textContainer != null && this.TextEditorRenderScope != null && textContainer.TextSelection == null) { _textView = new MultiPageTextView(this, this.TextEditorRenderScope, textContainer); _textEditor = new TextEditor(textContainer, this, false); _textEditor.IsReadOnly = !IsEditingEnabled; _textEditor.TextView = _textView; textContainer.TextView = _textView; } // Re-enable the service in order to register on the new TextView if (service != null) { service.Enable(service.Store); } }
// Attaches this control to a new TextContainer. private void InitializeTextContainer(PasswordTextContainer textContainer) { Invariant.Assert(textContainer != null); // Uninitialize previous TextEditor if (_textContainer != null) { Invariant.Assert(_textEditor != null); Invariant.Assert(_textEditor.TextContainer == _textContainer); // Detach existing editor from VisualTree DetachFromVisualTree(); // Discard TextEditor - must release text container _textEditor.OnDetach(); } // Save text container _textContainer = textContainer; // ((ITextContainer)_textContainer).Changed += new TextContainerChangedEventHandler(OnTextContainerChanged); // Create a text editor, initialize undo manager for it, and link it to text container _textEditor = new TextEditor(_textContainer, this, true); }
// Paste xaml content into the current text selection // Returns false if pasting was not successful - assuming that the caller will choose another format for pasting private static bool PasteXaml(TextEditor This, string pasteXaml) { bool success; if (pasteXaml.Length == 0) { success = false; } else { try { // Parse the fragment into a separate subtree object xamlObject = XamlReader.Load(new XmlTextReader(new System.IO.StringReader(pasteXaml))); TextElement flowContent = xamlObject as TextElement; success = flowContent == null ? false : PasteTextElement(This, flowContent); } catch (XamlParseException e) { // Clipboard data can have the invalid xaml content that will throw // the XamlParseException. // In case of XamlParseException, we shouldn't paste anything and quiet. // Xaml invalid character range is from 0x00 to 0x20. (e.g. �x03) // Invariant.Assert(e != null); //to make compiler happy about not using a variable e. This variable is useful in debugging process though - to see a reason of a parsing failure success = false; } } return success; }
// Paste flow content into the current text selection // Returns false if pasting was not successful - assuming that the caller will choose another format for pasting private static bool PasteTextElement(TextEditor This, TextElement sectionOrSpan) { bool success = false; This.Selection.BeginChange(); try { ((TextRange)This.Selection).SetXmlVirtual(sectionOrSpan); // Merge new Lists with surrounding Lists. TextRangeEditLists.MergeListsAroundNormalizedPosition((TextPointer)This.Selection.Start); TextRangeEditLists.MergeListsAroundNormalizedPosition((TextPointer)This.Selection.End); // Merge flow direction of the new content if it matches its surroundings. TextRangeEdit.MergeFlowDirection((TextPointer)This.Selection.Start); TextRangeEdit.MergeFlowDirection((TextPointer)This.Selection.End); success = true; } finally { This.Selection.EndChange(); } return success; }
internal static void _OnApplyProperty(TextEditor This, DependencyProperty formattingProperty, object propertyValue, bool applyToParagraphs) { _OnApplyProperty(This, formattingProperty, propertyValue, applyToParagraphs, PropertyValueAction.SetValue); }
// Helper for plain text filtering when pasted into rich or plain destination private static bool PastePlainText(TextEditor This, string pastedText) { pastedText = This._FilterText(pastedText, This.Selection); if (pastedText.Length > 0) { if (This.AcceptsRichContent && This.Selection.Start is TextPointer) { // Clear selection content This.Selection.Text = String.Empty; // Ensure that text is insertable at current selection TextPointer start = TextRangeEditTables.EnsureInsertionPosition((TextPointer)This.Selection.Start); // Store boundaries of inserted text start = start.GetPositionAtOffset(0, LogicalDirection.Backward); TextPointer end = start.GetPositionAtOffset(0, LogicalDirection.Forward); // For rich text we need to remove control characters and // replace linebreaks by paragraphs int currentLineStart = 0; for (int i = 0; i < pastedText.Length; i++) { if (pastedText[i] == '\r' || pastedText[i] == '\n') { end.InsertTextInRun(pastedText.Substring(currentLineStart, i - currentLineStart)); if (!This.AcceptsReturn) { return true; // All lined except for the first one are ignored when TextBox does not accept Return key } if (end.HasNonMergeableInlineAncestor) { // We cannot split a Hyperlink or other non-mergeable Inline element, // so insert a space character instead (similar to embedded object). // Note that this means, Paste operation would loose // paragraph break information in this case. end.InsertTextInRun(" "); } else { end = end.InsertParagraphBreak(); } if (pastedText[i] == '\r' && i + 1 < pastedText.Length && pastedText[i + 1] == '\n') { i++; } currentLineStart = i + 1; } } end.InsertTextInRun(pastedText.Substring(currentLineStart, pastedText.Length - currentLineStart)); // Select all pasted content This.Selection.Select(start, end); } else { // For plain text we insert the content as is (including control characters) This.Selection.Text = pastedText; } return true; } return false; }
internal static void Paste(TextEditor This) { // Don't try anything if the caller doesn't have the rights to read from the clipboard... if (!SecurityHelper.CallerHasAllClipboardPermission()) { return; } if (This.Selection.IsTableCellRange) { // return; } TextEditorTyping._FlushPendingInputItems(This); TextEditorTyping._BreakTypingSequence(This); // Get DataObject from the Clipboard IDataObject dataObject; try { dataObject = Clipboard.GetDataObject(); } catch (ExternalException) { // Clipboard is failed to get the data object. // One of reason should be the opening fail of Clipboard by the destroyed hwnd. dataObject = null; // } bool forceLayoutUpdate = This.Selection.CoversEntireContent; if (dataObject != null) { using (This.Selection.DeclareChangeBlock()) { // Forget previously suggested horizontal position TextEditorSelection._ClearSuggestedX(This); // _DoPaste raises a public event -- could raise recoverable exception. if (TextEditorCopyPaste._DoPaste(This, dataObject, /*isDragDrop:*/false)) { // Collapse selection to the end // Use backward direction to stay oriented towards pasted content This.Selection.SetCaretToPosition(This.Selection.End, LogicalDirection.Backward, /*allowStopAtLineEnd:*/false, /*allowStopNearSpace:*/true); // Clear springload formatting if (This.Selection is TextSelection) { ((TextSelection)This.Selection).ClearSpringloadFormatting(); } } } // PUBLIC EVENT RAISED HERE AS CHANGEBLOCK CLOSES! } // If we replaced the entire document content, background layout will // kick in. Force it to complete now. if (forceLayoutUpdate) { This.Selection.ValidateLayout(); } }
//------------------------------------------------------ // // Internal Methods // //------------------------------------------------------ #region Internal Methods // Attaches this control to a new TextContainer. internal void InitializeTextContainer(TextContainer textContainer) { Invariant.Assert(textContainer != null); Invariant.Assert(textContainer.TextSelection == null); // Uninitialize previous TextEditor if (_textContainer != null) { Invariant.Assert(_textEditor != null); Invariant.Assert(_textEditor.TextContainer == _textContainer); Invariant.Assert(_textEditor.TextContainer.TextSelection == _textEditor.Selection); // Detach existing editor from VisualTree DetachFromVisualTree(); // Discard TextEditor - must release text container _textEditor.OnDetach(); } // Save text container _textContainer = textContainer; _textContainer.Changed += new TextContainerChangedEventHandler(OnTextContainerChanged); // Create a text editor, initialize undo manager for it, and link it to text container _textEditor = new TextEditor(_textContainer, this, true); _textEditor.Selection.Changed += new EventHandler(OnSelectionChangedInternal); // Init a default undo limit. UndoManager undoManager = UndoManager.GetUndoManager(this); if (undoManager != null) { undoManager.UndoLimit = this.UndoLimit; } // Delay raising automation events until the automation subsystem is activated by a client. // ISSUE-2005/01/23-vsmirnov - Adding an event listener to AutomationProvider apparently // causes memory leaks because TextBoxBase is never released. I comment it out for now just // to fix the build break (perf DRT failure). Need to find a right fix later. // AutomationProvider.Activated += new AutomationActivatedEventHandler(OnAutomationActivated); }
internal static bool _DoPaste(TextEditor This, IDataObject dataObject, bool isDragDrop) { // Don't try anything if the caller doesn't have the rights to read from the clipboard... // if (!SecurityHelper.CallerHasAllClipboardPermission()) return false; Invariant.Assert(dataObject != null); // Choose what format we are going to paste string formatToApply; bool pasted; pasted = false; // Get the default paste content applying format formatToApply = GetPasteApplyFormat(This, dataObject); DataObjectPastingEventArgs dataObjectPastingEventArgs; try { // Let the application to participate in Paste process dataObjectPastingEventArgs = new DataObjectPastingEventArgs(dataObject, isDragDrop, formatToApply); } catch (ArgumentException) { // Clipboard can be changed by set new or empty data during creating // DataObjectPastingEvent that check the representing of the // formatToApply. Do nothing if we encounter AgrumentException. return pasted; } // Public event call - could raise recoverable exception. This.UiScope.RaiseEvent(dataObjectPastingEventArgs); if (!dataObjectPastingEventArgs.CommandCancelled) { // When custom handler decides to suggest its own data, // it must create a new instance of DataObject and put it // into DataObjectPastingEventArgs.DataObject property. // Exisiting DataObject is on global Clipboard and can not be changed. // Here we need to get this potentially changed instance // of DataObject IDataObject dataObjectToApply = dataObjectPastingEventArgs.DataObject; formatToApply = dataObjectPastingEventArgs.FormatToApply; // Paste the content data(Text, Unicode, Xaml and Rtf) to the current text selection pasted = PasteContentData(This, dataObject, dataObjectToApply, formatToApply); } return pasted; }
internal static ITextRange Find(FindToolBar findToolBar, TextEditor textEditor, ITextView textView, ITextView masterPageTextView) { string searchText; FindFlags findFlags; ITextContainer textContainer; ITextRange textSelection; ITextPointer contentStart; ITextPointer contentEnd; ITextPointer startPointer = null; ITextRange findResult = null; Invariant.Assert(findToolBar != null); Invariant.Assert(textEditor != null); // Set up our FindOptions from the options in the Find Toolbar. findFlags = FindFlags.None; findFlags |= (findToolBar.SearchUp ? FindFlags.FindInReverse : FindFlags.None); findFlags |= (findToolBar.MatchCase ? FindFlags.MatchCase : FindFlags.None); findFlags |= (findToolBar.MatchWholeWord ? FindFlags.FindWholeWordsOnly : FindFlags.None); findFlags |= (findToolBar.MatchDiacritic ? FindFlags.MatchDiacritics : FindFlags.None); findFlags |= (findToolBar.MatchKashida ? FindFlags.MatchKashida : FindFlags.None); findFlags |= (findToolBar.MatchAlefHamza ? FindFlags.MatchAlefHamza : FindFlags.None); // Get the text container for our content. textContainer = textEditor.TextContainer; textSelection = textEditor.Selection; // Initialize other Find parameters searchText = findToolBar.SearchText; CultureInfo cultureInfo = GetDocumentCultureInfo(textContainer); // The find behavior below is defined in section 2.2.3 of this spec: // http://d2/DRX/Development%20Documents/02.01.00%20-%20UI%20Design.DocumentViewer.mht // Determine if we have a starting selection if (textSelection.IsEmpty) { if (textView != null && !textView.IsValid) { textView = null; } // Determine if the IP/Selection is in view. if (textView != null && textView.Contains(textSelection.Start)) { // Case 1: Selection is empty and IP is currently visible. // Search from this IP to the start/end of the document. //We treat the start of the selection as the IP. contentStart = findToolBar.SearchUp ? textContainer.Start : textSelection.Start; contentEnd = findToolBar.SearchUp ? textSelection.Start : textContainer.End; } else { // Case 4: Selection is empty and IP is not currently visible. // Search from the top of the current TextView to the end of the document, // if searching down. If searchind up, search from the start of the document // to the end position of the current TextView. if (masterPageTextView != null && masterPageTextView.IsValid) { foreach (TextSegment textSegment in masterPageTextView.TextSegments) { if (textSegment.IsNull) { continue; } if (startPointer == null) { // Set initial masterPointer value. startPointer = !findToolBar.SearchUp ? textSegment.Start : textSegment.End; } else { if (!findToolBar.SearchUp) { if (textSegment.Start.CompareTo(startPointer) < 0) { // Start is before the current masterPointer startPointer = textSegment.Start; } } else { // end is after than the current masterPointer if (textSegment.End.CompareTo(startPointer) > 0) { startPointer = textSegment.End; } } } } } if (startPointer != null) { // Now build the content range from that pointer to the start/end of the document. // Set content start/end pointer to the content of the find document contentStart = findToolBar.SearchUp ? textContainer.Start : startPointer; contentEnd = findToolBar.SearchUp ? startPointer : textContainer.End; } else { // We were unable to determine the viewing area (form TextView), // just use the entire TextContainer. contentStart = textContainer.Start; contentEnd = textContainer.End; } } } else { // Determine if the search text is already selected in the document. findResult = TextFindEngine.Find(textSelection.Start, textSelection.End, searchText, findFlags, cultureInfo); // To see if our Text ranges are the same, we will verify that // their start and end points are the same. if ((findResult != null) && (findResult.Start != null) && (findResult.Start.CompareTo(textSelection.Start) == 0) && (findResult.End.CompareTo(textSelection.End) == 0)) { // Case 2: Selection exists and it matches the search text. // Search from the end of the given selection. contentStart = findToolBar.SearchUp ? textSelection.Start : textSelection.End; contentEnd = findToolBar.SearchUp ? textContainer.Start : textContainer.End; } else { // Case 3: Selection exists and it does not match the search text. // Search from the beginning of the given selection to the end of the document. contentStart = findToolBar.SearchUp ? textSelection.End : textSelection.Start; contentEnd = findToolBar.SearchUp ? textContainer.Start : textContainer.End; } } // We should have content. Try to find something. findResult = null; if (contentStart != null && contentEnd != null && contentStart.CompareTo(contentEnd) != 0) { // We might legimately have crossed start/end given our logic above. // It's easier to untangle the range here. if (contentStart.CompareTo(contentEnd) > 0) { ITextPointer temp = contentStart; contentStart = contentEnd; contentEnd = temp; } findResult = TextFindEngine.Find(contentStart, contentEnd, searchText, findFlags, cultureInfo); if ((findResult != null) && (!findResult.IsEmpty)) { textSelection.Select(findResult.Start, findResult.End); } } return findResult; }
// Get the default paste content applying format internal static string GetPasteApplyFormat(TextEditor This, IDataObject dataObject) { string formatToApply; // Currently we won't allow DataFormats.Xaml on the partial trust. // GetDataPresent(DataFormats.Xaml)have a chance to register Xaml format // by calling the unmanaged code which is RegisterClipboardFormat. bool hasUnmanagedCodePermission = SecurityHelper.CheckUnmanagedCodePermission(); if (This.AcceptsRichContent && hasUnmanagedCodePermission && dataObject.GetDataPresent(DataFormats.XamlPackage)) { formatToApply = DataFormats.XamlPackage; } else if (This.AcceptsRichContent && dataObject.GetDataPresent(DataFormats.Xaml)) { formatToApply = DataFormats.Xaml; } else if (This.AcceptsRichContent && hasUnmanagedCodePermission && dataObject.GetDataPresent(DataFormats.Rtf)) { formatToApply = DataFormats.Rtf; } else if (dataObject.GetDataPresent(DataFormats.UnicodeText)) { formatToApply = DataFormats.UnicodeText; } else if (dataObject.GetDataPresent(DataFormats.Text)) { formatToApply = DataFormats.Text; } else if (This.AcceptsRichContent && hasUnmanagedCodePermission && dataObject is DataObject && ((DataObject)dataObject).ContainsImage()) { formatToApply = DataFormats.Bitmap; } else { // Even if we do not see any recognizable formats, // we continue the process because application custom // paste needs it and may do something useful. formatToApply = String.Empty; } return formatToApply; }