System.Drawing: added email to icon and test file headers
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / TextBoxBase.cs
1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:c
8 //
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 //
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 //
20 // Copyright (c) 2004-2006 Novell, Inc. (http://www.novell.com)
21 //
22 // Authors:
23 //      Peter Bartok    pbartok@novell.com
24 //
25 //
26
27 // NOT COMPLETE
28 #undef Debug
29 #undef DebugClick
30
31 using System.ComponentModel;
32 using System.ComponentModel.Design;
33 using System.Drawing;
34 using System.Drawing.Text;
35 using System.Text;
36 using System.Runtime.InteropServices;
37 using System.Collections;
38
39 namespace System.Windows.Forms
40 {
41         [ComVisible (true)]
42         [DefaultBindingProperty ("Text")]
43         [ClassInterface (ClassInterfaceType.AutoDispatch)]
44         [DefaultEvent("TextChanged")]
45         [Designer("System.Windows.Forms.Design.TextBoxBaseDesigner, " + Consts.AssemblySystem_Design)]
46         public abstract class TextBoxBase : Control
47         {
48                 #region Local Variables
49                 internal HorizontalAlignment    alignment;
50                 internal bool                   accepts_tab;
51                 internal bool                   accepts_return;
52                 internal bool                   auto_size;
53                 internal bool                   backcolor_set;
54                 internal CharacterCasing        character_casing;
55                 internal bool                   hide_selection;
56                 int                             max_length;
57                 internal bool                   modified;
58                 internal char                   password_char;
59                 internal bool                   read_only;
60                 internal bool                   word_wrap;
61                 internal Document               document;
62                 internal LineTag                caret_tag;              // tag our cursor is in
63                 internal int                    caret_pos;              // position on the line our cursor is in (can be 0 = beginning of line)
64                 internal ImplicitHScrollBar     hscroll;
65                 internal ImplicitVScrollBar     vscroll;
66                 internal RichTextBoxScrollBars  scrollbars;
67                 internal Timer                  scroll_timer;
68                 internal bool                   richtext;
69                 internal bool                   show_selection;         // set to true to always show selection, even if no focus is set
70                 internal ArrayList              list_links;             // currently showing links
71                 private LinkRectangle           current_link;           // currently hovering link
72                 private bool                    enable_links;           // whether links are enabled
73                 
74                 internal bool has_been_focused;
75
76                 internal int                    selection_length = -1;  // set to the user-specified selection length, or -1 if none
77                 internal bool show_caret_w_selection;  // TextBox shows the caret when the selection is visible
78                 internal int                    canvas_width;
79                 internal int                    canvas_height;
80                 static internal int             track_width = 2;        //
81                 static internal int             track_border = 5;       //
82                 internal DateTime               click_last;
83                 internal int                    click_point_x;
84                 internal int                    click_point_y;
85                 internal CaretSelection         click_mode;
86                 internal BorderStyle actual_border_style;
87                 internal bool shortcuts_enabled = true;
88                 #if Debug
89                 internal static bool    draw_lines = false;
90                 #endif
91
92                 #endregion      // Local Variables
93
94                 #region Internal Constructor
95                 // Constructor will go when complete, only for testing - pdb
96                 internal TextBoxBase ()
97                 {
98                         alignment = HorizontalAlignment.Left;
99                         accepts_return = false;
100                         accepts_tab = false;
101                         auto_size = true;
102                         InternalBorderStyle = BorderStyle.Fixed3D;
103                         actual_border_style = BorderStyle.Fixed3D;
104                         character_casing = CharacterCasing.Normal;
105                         hide_selection = true;
106                         max_length = short.MaxValue;
107                         password_char = '\0';
108                         read_only = false;
109                         word_wrap = true;
110                         richtext = false;
111                         show_selection = false;
112                         enable_links = false;
113                         list_links = new ArrayList ();
114                         current_link = null;
115                         show_caret_w_selection = (this is TextBox);
116                         document = new Document(this);
117                         document.WidthChanged += new EventHandler(document_WidthChanged);
118                         document.HeightChanged += new EventHandler(document_HeightChanged);
119                         //document.CaretMoved += new EventHandler(CaretMoved);
120                         document.Wrap = false;
121                         click_last = DateTime.Now;
122                         click_mode = CaretSelection.Position;
123
124                         MouseDown += new MouseEventHandler(TextBoxBase_MouseDown);
125                         MouseUp += new MouseEventHandler(TextBoxBase_MouseUp);
126                         MouseMove += new MouseEventHandler(TextBoxBase_MouseMove);
127                         SizeChanged += new EventHandler(TextBoxBase_SizeChanged);
128                         FontChanged += new EventHandler(TextBoxBase_FontOrColorChanged);
129                         ForeColorChanged += new EventHandler(TextBoxBase_FontOrColorChanged);
130                         MouseWheel += new MouseEventHandler(TextBoxBase_MouseWheel);
131                         RightToLeftChanged += new EventHandler (TextBoxBase_RightToLeftChanged);
132                         
133                         scrollbars = RichTextBoxScrollBars.None;
134
135                         hscroll = new ImplicitHScrollBar();
136                         hscroll.ValueChanged += new EventHandler(hscroll_ValueChanged);
137                         hscroll.SetStyle (ControlStyles.Selectable, false);
138                         hscroll.Enabled = false;
139                         hscroll.Visible = false;
140                         hscroll.Maximum = Int32.MaxValue;
141
142                         vscroll = new ImplicitVScrollBar();
143                         vscroll.ValueChanged += new EventHandler(vscroll_ValueChanged);
144                         vscroll.SetStyle (ControlStyles.Selectable, false);
145                         vscroll.Enabled = false;
146                         vscroll.Visible = false;
147                         vscroll.Maximum = Int32.MaxValue;
148
149                         SuspendLayout ();
150                         this.Controls.AddImplicit (hscroll);
151                         this.Controls.AddImplicit (vscroll);
152                         ResumeLayout ();
153                         
154                         SetStyle(ControlStyles.UserPaint | ControlStyles.StandardClick, false);
155                         SetStyle(ControlStyles.UseTextForAccessibility, false);
156                         
157                         base.SetAutoSizeMode (AutoSizeMode.GrowAndShrink);
158
159                         canvas_width = ClientSize.Width;
160                         canvas_height = ClientSize.Height;
161                         document.ViewPortWidth = canvas_width;
162                         document.ViewPortHeight = canvas_height;
163
164                         Cursor = Cursors.IBeam;
165                 }
166                 #endregion      // Internal Constructor
167
168                 #region Private and Internal Methods
169                 internal string CaseAdjust (string s)
170                 {
171                         if (character_casing == CharacterCasing.Normal)
172                                 return s;
173                         if (character_casing == CharacterCasing.Lower)
174                                 return s.ToLower();
175                         return s.ToUpper();
176                 }
177
178                 internal override Size GetPreferredSizeCore (Size proposedSize)
179                 {
180                         return new Size (Width, Height);
181                 }
182
183                 internal override void HandleClick (int clicks, MouseEventArgs me)
184                 {
185                         // MS seems to fire the click event in spite of the styles they set
186                         bool click_set = GetStyle (ControlStyles.StandardClick);
187                         bool doubleclick_set = GetStyle (ControlStyles.StandardDoubleClick);
188
189                         // so explicitly set them to true first
190                         SetStyle (ControlStyles.StandardClick | ControlStyles.StandardDoubleClick, true);
191
192                         base.HandleClick (clicks, me);
193
194                         // then revert to our previous state
195                         if (!click_set)
196                                 SetStyle (ControlStyles.StandardClick, false);
197                         if (!doubleclick_set)
198                                 SetStyle (ControlStyles.StandardDoubleClick, false);
199                 }
200
201                 internal override void PaintControlBackground (PaintEventArgs pevent)
202                 {
203                         if (!ThemeEngine.Current.TextBoxBaseShouldPaintBackground (this))
204                                 return;
205                         base.PaintControlBackground (pevent);
206                 }
207                 #endregion      // Private and Internal Methods
208
209                 #region Public Instance Properties
210                 [DefaultValue(false)]
211                 [MWFCategory("Behavior")]
212                 public bool AcceptsTab {
213                         get {
214                                 return accepts_tab;
215                         }
216
217                         set {
218                                 if (value != accepts_tab) {
219                                         accepts_tab = value;
220                                         OnAcceptsTabChanged(EventArgs.Empty);
221                                 }
222                         }
223                 }
224
225                 [Browsable (false)]
226                 [EditorBrowsable (EditorBrowsableState.Never)]
227                 [DefaultValue(true)]
228                 [Localizable(true)]
229                 [RefreshProperties(RefreshProperties.Repaint)]
230                 [MWFCategory("Behavior")]
231                 public override bool AutoSize {
232                         get {
233                                 return auto_size;
234                         }
235
236                         set {
237                                 if (value != auto_size) {
238                                         auto_size = value;
239                                         if (auto_size) {
240                                                 if (PreferredHeight != Height) {
241                                                         Height = PreferredHeight;
242                                                 }
243                                         }
244                                 }
245                         }
246                 }
247
248                 [DispId(-501)]
249                 public override System.Drawing.Color BackColor {
250                         get {
251                                 return base.BackColor;
252                         }
253                         set {
254                                 backcolor_set = true;
255                                 base.BackColor = ChangeBackColor (value);
256                         }
257                 }
258
259                 [Browsable(false)]
260                 [EditorBrowsable(EditorBrowsableState.Never)]
261                 public override System.Drawing.Image BackgroundImage {
262                         get {
263                                 return base.BackgroundImage;
264                         }
265                         set {
266                                 base.BackgroundImage = value;
267                         }
268                 }
269
270                 [DefaultValue(BorderStyle.Fixed3D)]
271                 [DispId(-504)]
272                 [MWFCategory("Appearance")]
273                 public BorderStyle BorderStyle {
274                         get { return actual_border_style; }
275                         set {
276                                 if (value == actual_border_style)
277                                         return;
278
279                                 if (actual_border_style != BorderStyle.Fixed3D || value != BorderStyle.Fixed3D)
280                                         Invalidate ();
281
282                                 actual_border_style = value;
283                                 document.UpdateMargins ();
284
285                                 if (value != BorderStyle.Fixed3D)
286                                         value = BorderStyle.None;
287
288                                 InternalBorderStyle = value; 
289                                 OnBorderStyleChanged(EventArgs.Empty);
290                         }
291                 }
292
293                 [Browsable(false)]
294                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
295                 public bool CanUndo {
296                         get {
297                                 return document.undo.CanUndo;
298                         }
299                 }
300
301                 [DispId(-513)]
302                 public override System.Drawing.Color ForeColor {
303                         get {
304                                 return base.ForeColor;
305                         }
306                         set {
307                                 base.ForeColor = value;
308                         }
309                 }
310
311                 [DefaultValue(true)]
312                 [MWFCategory("Behavior")]
313                 public bool HideSelection {
314                         get {
315                                 return hide_selection;
316                         }
317
318                         set {
319                                 if (value != hide_selection) {
320                                         hide_selection = value;
321                                         OnHideSelectionChanged(EventArgs.Empty);
322                                 }
323                                 document.selection_visible = !hide_selection;
324                                 document.InvalidateSelectionArea();
325                         }
326                 }
327
328                 [MergableProperty (false)]
329                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
330                 [Editor("System.Windows.Forms.Design.StringArrayEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))]
331                 [Localizable(true)]
332                 [MWFCategory("Appearance")]
333                 public string[] Lines {
334                         get {
335                                 int count;
336                                 ArrayList lines;
337
338                                 count = document.Lines;
339
340                                 // Handle empty document
341                                 if ((count == 1) && (document.GetLine (1).text.Length == 0)) {
342                                         return new string [0];
343                                 }
344
345                                 lines = new ArrayList ();
346
347                                 int i = 1;
348                                 while (i <= count) {
349                                         Line line;
350                                         StringBuilder lt = new StringBuilder ();
351
352                                         do {
353                                                 line = document.GetLine (i++);
354                                                 lt.Append (line.TextWithoutEnding ());
355                                         } while (line.ending == LineEnding.Wrap && i <= count);
356
357                                         lines.Add (lt.ToString ());     
358                                 }
359
360                                 return (string []) lines.ToArray (typeof (string));
361                         }
362
363                         set {
364                                 StringBuilder sb = new StringBuilder ();
365                         
366                                 for (int i = 0; i < value.Length; i++) {
367                                         // Don't add the last line if it is just an empty line feed
368                                         // the line feed is reflected in the previous line's ending 
369                                         if (i == value.Length - 1 && value[i].Length == 0)
370                                                 break;
371                                                 
372                                         sb.Append (value[i] + Environment.NewLine);
373                                 }
374
375                                 int newline_length = Environment.NewLine.Length;
376
377                                 // We want to remove the final new line character
378                                 if (sb.Length >= newline_length)
379                                         sb.Remove (sb.Length - newline_length, newline_length);
380
381                                 Text = sb.ToString ();
382                         }
383                 }
384
385                 [DefaultValue(32767)]
386                 [Localizable(true)]
387                 [MWFCategory("Behavior")]
388                 public virtual int MaxLength {
389                         get {
390                                 if (max_length == (int.MaxValue - 1)) { // We don't distinguish between single and multi-line limits
391                                         return 0;
392                                 }
393                                 return max_length;
394                         }
395
396                         set {
397                                 if (value != max_length) {
398                                         if (value == 0)
399                                                 value = int.MaxValue - 1;
400
401                                         max_length = value;
402                                 }
403                         }
404                 }
405
406                 [Browsable(false)]
407                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
408                 public bool Modified {
409                         get {
410                                 return modified;
411                         }
412
413                         set {
414                                 if (value != modified) {
415                                         modified = value;
416                                         OnModifiedChanged(EventArgs.Empty);
417                                 }
418                         }
419                 }
420
421                 [DefaultValue(false)]
422                 [Localizable(true)]
423                 [RefreshProperties(RefreshProperties.All)]
424                 [MWFCategory("Behavior")]
425                 public virtual bool Multiline {
426                         get {
427                                 return document.multiline;
428                         }
429
430                         set {
431                                 if (value != document.multiline) {
432                                         document.multiline = value;
433
434                                         if (this is TextBox)
435                                                 SetStyle (ControlStyles.FixedHeight, !value);
436
437                                         // SetBoundsCore overrides the Height for multiline if it needs to,
438                                         // so we don't need to worry about it here.
439                                         SetBoundsCore (Left, Top, Width, ExplicitBounds.Height, BoundsSpecified.None);
440                                         
441                                         if (Parent != null)
442                                                 Parent.PerformLayout ();
443
444                                         OnMultilineChanged(EventArgs.Empty);
445                                 }
446
447                                 if (document.multiline) {
448                                         document.Wrap = word_wrap;
449                                         document.PasswordChar = "";
450
451                                 } else {
452                                         document.Wrap = false;
453                                         if (this.password_char != '\0') {
454                                                 if (this is TextBox)
455                                                         document.PasswordChar = (this as TextBox).PasswordChar.ToString ();
456                                         } else {
457                                                 document.PasswordChar = "";
458                                         }
459                                 }
460
461                                 if (IsHandleCreated)
462                                         CalculateDocument ();
463                         }
464                 }
465
466                 [Browsable(false)]
467                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
468                 [EditorBrowsable(EditorBrowsableState.Advanced)]
469                 // This returns the preferred outer height, not the client height.
470                 public int PreferredHeight {
471                         get {
472                                 int clientDelta = Height - ClientSize.Height;
473                                 if (BorderStyle != BorderStyle.None)
474                                         return Font.Height + 7 + clientDelta;
475
476                                 // usually in borderless mode the top margin is 0, but
477                                 // try to access it, in case it was set manually, as ToolStrip* controls do
478                                 return Font.Height + TopMargin + clientDelta;
479                         }
480                 }
481
482                 [RefreshProperties (RefreshProperties.Repaint)] 
483                 [DefaultValue(false)]
484                 [MWFCategory("Behavior")]
485                 public bool ReadOnly {
486                         get {
487                                 return read_only;
488                         }
489
490                         set {
491                                 if (value != read_only) {
492                                         read_only = value;
493                                         if (!backcolor_set) {
494                                                 if (read_only)
495                                                         background_color = SystemColors.Control;
496                                                 else
497                                                         background_color = SystemColors.Window;
498                                         }
499                                         OnReadOnlyChanged(EventArgs.Empty);
500                                         Invalidate ();
501                                 }
502                         }
503                 }
504
505                 [Browsable(false)]
506                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
507                 public virtual string SelectedText {
508                         get {
509                                 string retval = document.GetSelection ();
510
511                                 return retval;
512                         }
513
514                         set {
515                                 if (value == null)
516                                         value = String.Empty;
517
518                                 document.ReplaceSelection(CaseAdjust(value), false);
519
520                                 ScrollToCaret();
521                                 OnTextChanged(EventArgs.Empty);
522                         }
523                 }
524
525                 [Browsable(false)]
526                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
527                 public virtual int SelectionLength {
528                         get {
529                                 int res = document.SelectionLength ();
530
531                                 return res;
532                         }
533
534                         set {
535                                 if (value < 0) {
536                                         string msg = String.Format ("'{0}' is not a valid value for 'SelectionLength'", value);
537                                         throw new ArgumentOutOfRangeException ("SelectionLength", msg);
538                                 }
539
540                                 document.InvalidateSelectionArea ();
541                                 if (value != 0) {
542                                         int     start;
543                                         Line    line;
544                                         LineTag tag;
545                                         int     pos;
546
547                                         selection_length = value;
548                                         start = document.LineTagToCharIndex (document.selection_start.line, document.selection_start.pos);
549                                         document.CharIndexToLineTag (start + value, out line, out tag, out pos);
550                                         document.SetSelectionEnd (line, pos, true);
551                                         document.PositionCaret (line, pos);
552                                 } else {
553                                         selection_length = -1;
554                                         document.SetSelectionEnd (document.selection_start.line, document.selection_start.pos, true);
555                                         document.PositionCaret (document.selection_start.line, document.selection_start.pos);
556                                 }
557                         }
558                 }
559
560                 [Browsable(false)]
561                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
562                 public int SelectionStart {
563                         get {
564                                 return document.LineTagToCharIndex(document.selection_start.line,
565                                         document.selection_start.pos);
566                         }
567
568                         set {
569                                 if (value < 0) {
570                                         string msg = String.Format ("'{0}' is not a valid value for 'SelectionStart'", value);
571                                         throw new ArgumentOutOfRangeException ("SelectionStart", msg);
572                                 }
573
574                                 // If SelectionStart has been used, we don't highlight on focus
575                                 has_been_focused = true;
576                                 
577                                 document.InvalidateSelectionArea ();
578                                 document.SetSelectionStart (value, false);
579                                 if (selection_length > -1)
580                                         document.SetSelectionEnd (value + selection_length, true);
581                                 else
582                                         document.SetSelectionEnd (value, true);
583                                 document.PositionCaret (document.selection_start.line, document.selection_start.pos);
584                                 ScrollToCaret ();
585                         }
586                 }
587
588                 [DefaultValue (true)]
589                 public virtual bool ShortcutsEnabled {
590                         get { return shortcuts_enabled; }
591                         set { shortcuts_enabled = value; }
592                 }
593
594                 [Editor ("System.ComponentModel.Design.MultilineStringEditor, " + Consts.AssemblySystem_Design,
595                          "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
596                 [Localizable(true)]
597                 public override string Text {
598                         get {
599                                 if (document == null || document.Root == null || document.Root.text == null)
600                                         return string.Empty;
601
602                                 StringBuilder sb = new StringBuilder();
603
604                                 Line line = null;
605                                 for (int i = 1; i <= document.Lines; i++) {
606                                         line = document.GetLine (i);
607                                         sb.Append(line.text.ToString ());
608                                 }
609
610                                 return sb.ToString();
611                         }
612
613                         set {
614                                 // reset to force a select all next time the box gets focus
615                                 has_been_focused = false;
616
617                                 if (value == Text)
618                                         return;
619
620                                 document.Empty ();
621                                 if ((value != null) && (value != "")) {
622                                         document.Insert (document.GetLine (1), 0, false, value);
623                                 } else {
624                                         if (IsHandleCreated) {
625                                                 document.SetSelectionToCaret (true);
626                                                 CalculateDocument ();
627                                         }
628                                 }
629                                                         
630                                 document.PositionCaret (document.GetLine (1), 0);
631                                 document.SetSelectionToCaret (true);
632
633                                 ScrollToCaret ();
634
635                                 OnTextChanged(EventArgs.Empty);
636                         }
637                 }
638
639                 [Browsable(false)]
640                 public virtual int TextLength {
641                         get {
642                                 if (document == null || document.Root == null || document.Root.text == null)
643                                         return 0;
644                                 return Text.Length;
645                         }
646                 }
647
648                 [DefaultValue(true)]
649                 [Localizable(true)]
650                 [MWFCategory("Behavior")]
651                 public bool WordWrap {
652                         get {
653                                 return word_wrap;
654                         }
655
656                         set {
657                                 if (value != word_wrap) {
658                                         if (document.multiline) {
659                                                 word_wrap = value;
660                                                 document.Wrap = value;
661                                         }
662                                         CalculateDocument ();
663                                 }
664                         }
665                 }
666
667                 [Browsable (false)]
668                 [EditorBrowsable (EditorBrowsableState.Never)]
669                 public override ImageLayout BackgroundImageLayout {
670                         get { return base.BackgroundImageLayout; } 
671                         set { base.BackgroundImageLayout = value; }
672                 }
673
674                 [Browsable (false)]
675                 [EditorBrowsable (EditorBrowsableState.Never)]
676                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
677                 public new Padding Padding {
678                         get { return base.Padding; }
679                         set { base.Padding = value; }
680                 }
681                 
682                 protected override Cursor DefaultCursor {
683                         get { return Cursors.IBeam; }
684                 }
685                 #endregion      // Public Instance Properties
686
687                 #region Protected Instance Properties
688                 protected override bool CanEnableIme {
689                         get {
690                                 if (ReadOnly || password_char != '\0')
691                                         return false;
692                                         
693                                 return true;
694                         }
695                 }
696
697                 protected override CreateParams CreateParams {
698                         get {
699                                 return base.CreateParams;
700                         }
701                 }
702
703                 protected override System.Drawing.Size DefaultSize {
704                         get {
705                                 return new Size(100, 20);
706                         }
707                 }
708
709                 // Currently our double buffering breaks our scrolling, so don't let people enable this
710                 [EditorBrowsable (EditorBrowsableState.Never)]
711                 protected override bool DoubleBuffered {
712                         get { return false; }
713                         set { }
714                 }
715
716                 #endregion      // Protected Instance Properties
717
718                 #region Public Instance Methods
719                 public void AppendText (string text)
720                 {
721                         // Save some cycles and only check the Text if we are one line
722                         bool is_empty = document.Lines == 1 && Text == String.Empty; 
723
724                         // make sure the caret begins at the end
725                         if (document.caret.line.line_no != document.Lines ||
726                              (document.caret.pos) != document.caret.line.TextLengthWithoutEnding ()) {
727                                 document.MoveCaret (CaretDirection.CtrlEnd);
728                         }
729                         document.Insert (document.caret.line, document.caret.pos, false, text, document.CaretTag);
730                         document.MoveCaret (CaretDirection.CtrlEnd);
731                         document.SetSelectionToCaret (true);
732
733                         if (!is_empty)
734                                 ScrollToCaret ();
735
736                         //
737                         // Avoid the initial focus selecting all when append text is used
738                         //
739                         has_been_focused = true;
740
741                         Modified = false;
742                         OnTextChanged(EventArgs.Empty);
743                 }
744
745                 public void Clear ()
746                 {
747                         Modified = false;
748                         Text = string.Empty;
749                 }
750
751                 public void ClearUndo ()
752                 {
753                         document.undo.Clear();
754                 }
755
756                 public void Copy ()
757                 {
758                         DataObject o;
759
760                         o = new DataObject(DataFormats.Text, SelectedText);
761                         if (this is RichTextBox)
762                                 o.SetData(DataFormats.Rtf, ((RichTextBox)this).SelectedRtf);
763                         Clipboard.SetDataObject(o);
764                 }
765
766                 public void Cut ()
767                 {
768                         DataObject      o;
769
770                         o = new DataObject(DataFormats.Text, SelectedText);
771                         if (this is RichTextBox)
772                                 o.SetData(DataFormats.Rtf, ((RichTextBox)this).SelectedRtf);
773                         Clipboard.SetDataObject (o);
774
775                         document.undo.BeginUserAction (Locale.GetText ("Cut"));
776                         document.ReplaceSelection (String.Empty, false);
777                         document.undo.EndUserAction ();
778
779                         Modified = true;
780                         OnTextChanged (EventArgs.Empty);
781                 }
782
783                 public void Paste ()
784                 {
785                         Paste (Clipboard.GetDataObject(), null, false);
786                 }
787
788                 public void ScrollToCaret ()
789                 {
790                         if (IsHandleCreated)
791                                 CaretMoved (this, EventArgs.Empty);
792                 }
793
794                 public void Select(int start, int length)
795                 {
796                         SelectionStart = start;
797                         SelectionLength = length;
798                 }
799
800                 public void SelectAll ()
801                 {
802                         Line    last;
803
804                         last = document.GetLine(document.Lines);
805                         document.SetSelectionStart(document.GetLine(1), 0, false);
806                         document.SetSelectionEnd(last, last.text.Length, true);
807                         document.PositionCaret (document.selection_end.line, document.selection_end.pos);
808                         selection_length = -1;
809
810                         CaretMoved (this, null);
811
812                         document.DisplayCaret ();
813                 }
814
815                 internal void SelectAllNoScroll ()
816                 {
817                         Line last;
818
819                         last = document.GetLine(document.Lines);
820                         document.SetSelectionStart(document.GetLine(1), 0, false);
821                         document.SetSelectionEnd(last, last.text.Length, false);
822                         document.PositionCaret (document.selection_end.line, document.selection_end.pos);
823                         selection_length = -1;
824
825                         document.DisplayCaret ();
826                 }
827
828                 public override string ToString ()
829                 {
830                         return String.Concat (base.ToString (), ", Text: ", Text);
831                 }
832
833                 [MonoInternalNote ("Deleting is classed as Typing, instead of its own Undo event")]
834                 public void Undo ()
835                 {
836                         if (document.undo.Undo ()) {
837                                 Modified = true;
838                                 OnTextChanged (EventArgs.Empty);
839                         }
840                 }
841
842                 public void DeselectAll ()
843                 {
844                         SelectionLength = 0;
845                 }
846
847                 public virtual char GetCharFromPosition (Point pt)
848                 {
849                         return GetCharFromPositionInternal (pt);
850                 }
851                 
852                 internal virtual char GetCharFromPositionInternal (Point p)
853                 {
854                         int index;
855                         LineTag tag = document.FindCursor (p.X, p.Y, out index);
856                         if (tag == null)
857                                 return (char) 0; // Shouldn't happen
858
859                         if (index >= tag.Line.text.Length) {
860                                 
861                                 if (tag.Line.ending == LineEnding.Wrap) {
862                                         // If we have wrapped text, we return the first char of the next line
863                                         Line line = document.GetLine (tag.Line.line_no + 1);
864                                         if (line != null)
865                                                 return line.text [0];
866
867                                 }
868
869                                 if (tag.Line.line_no == document.Lines) {
870                                         // Last line returns the last char
871                                         return tag.Line.text [tag.Line.text.Length - 1];
872                                 }
873
874                                 // This really shouldn't happen
875                                 return (char) 0;
876                         }
877                         return tag.Line.text [index];
878                 }
879
880                 public virtual int GetCharIndexFromPosition (Point pt)
881                 {
882                         int line_index;
883                         LineTag tag = document.FindCursor (pt.X, pt.Y, out line_index);
884                         if (tag == null)
885                                 return 0;
886
887                         if (line_index >= tag.Line.text.Length) {
888
889                                 if (tag.Line.ending == LineEnding.Wrap) {
890                                         // If we have wrapped text, we return the first char of the next line
891                                         Line line = document.GetLine (tag.Line.line_no + 1);
892                                         if (line != null)
893                                                 return document.LineTagToCharIndex (line, 0);
894                                 }
895
896                                 if (tag.Line.line_no == document.Lines) {
897                                         // Last line returns the last char
898                                         return document.LineTagToCharIndex (tag.Line, tag.Line.text.Length - 1);
899                                 }
900
901                                 return 0;
902                         }
903
904                         return document.LineTagToCharIndex (tag.Line, line_index);
905                 }
906
907                 public virtual Point GetPositionFromCharIndex (int index)
908                 {
909                         int pos;
910                         Line line;
911                         LineTag tag;
912
913                         document.CharIndexToLineTag (index, out line, out tag, out pos);
914
915                         return new Point ((int) (line.widths [pos] +
916                                                           line.X + document.viewport_x),
917                                         line.Y + document.viewport_y + tag.Shift);
918                 }
919
920                 public int GetFirstCharIndexFromLine (int lineNumber)
921                 {
922                         Line line = document.GetLine (lineNumber + 1);
923                         if (line == null)
924                                 return -1;
925                                         
926                         return document.LineTagToCharIndex (line, 0);
927                 }
928
929                 public int GetFirstCharIndexOfCurrentLine ()
930                 {
931                         return document.LineTagToCharIndex (document.caret.line, 0);
932                 }
933                 #endregion      // Public Instance Methods
934
935                 #region Protected Instance Methods
936                 protected override void CreateHandle ()
937                 {
938                         CalculateDocument ();
939                         base.CreateHandle ();
940                         document.AlignCaret();
941                         ScrollToCaret();
942                 }
943
944                 internal virtual void HandleLinkClicked (LinkRectangle link_clicked)
945                 {
946                 }
947
948                 protected override bool IsInputKey (Keys keyData)
949                 {
950                         if ((keyData & Keys.Alt) != 0)
951                                 return base.IsInputKey(keyData);
952
953                         switch (keyData & Keys.KeyCode) {
954                                 case Keys.Enter: {
955                                         return (accepts_return && document.multiline);
956                                 }
957
958                                 case Keys.Tab: {
959                                         if (accepts_tab && document.multiline)
960                                                 if ((keyData & Keys.Control) == 0)
961                                                         return true;
962                                         return false;
963                                 }
964
965                                 case Keys.Left:
966                                 case Keys.Right:
967                                 case Keys.Up:
968                                 case Keys.Down:
969                                 case Keys.PageUp:
970                                 case Keys.PageDown:
971                                 case Keys.Home:
972                                 case Keys.End: {
973                                         return true;
974                                 }
975                         }
976                         return false;
977                 }
978
979                 protected virtual void OnAcceptsTabChanged(EventArgs e)
980                 {
981                         EventHandler eh = (EventHandler)(Events [AcceptsTabChangedEvent]);
982                         if (eh != null)
983                                 eh (this, e);
984                 }
985
986                 protected virtual void OnBorderStyleChanged (EventArgs e)
987                 {
988                         EventHandler eh = (EventHandler)(Events [BorderStyleChangedEvent]);
989                         if (eh != null)
990                                 eh (this, e);
991                 }
992
993                 protected override void OnFontChanged (EventArgs e)
994                 {
995                         base.OnFontChanged (e);
996
997                         if (auto_size && !document.multiline) {
998                                 if (PreferredHeight != Height) {
999                                         Height = PreferredHeight;
1000                                 }
1001                         }
1002                 }
1003
1004                 protected override void OnHandleCreated (EventArgs e)
1005                 {
1006                         base.OnHandleCreated (e);
1007                         FixupHeight ();
1008                 }
1009
1010                 protected override void OnHandleDestroyed (EventArgs e)
1011                 {
1012                         base.OnHandleDestroyed (e);
1013                 }
1014
1015                 protected virtual void OnHideSelectionChanged (EventArgs e)
1016                 {
1017                         EventHandler eh = (EventHandler)(Events [HideSelectionChangedEvent]);
1018                         if (eh != null)
1019                                 eh (this, e);
1020                 }
1021
1022                 protected virtual void OnModifiedChanged (EventArgs e)
1023                 {
1024                         EventHandler eh = (EventHandler)(Events [ModifiedChangedEvent]);
1025                         if (eh != null)
1026                                 eh (this, e);
1027                 }
1028
1029                 protected virtual void OnMultilineChanged (EventArgs e)
1030                 {
1031                         EventHandler eh = (EventHandler)(Events [MultilineChangedEvent]);
1032                         if (eh != null)
1033                                 eh (this, e);
1034                 }
1035
1036                 protected override void OnPaddingChanged (EventArgs e)
1037                 {
1038                         base.OnPaddingChanged (e);
1039                 }
1040
1041                 protected virtual void OnReadOnlyChanged (EventArgs e)
1042                 {
1043                         EventHandler eh = (EventHandler)(Events [ReadOnlyChangedEvent]);
1044                         if (eh != null)
1045                                 eh (this, e);
1046                 }
1047
1048                 protected override bool ProcessCmdKey (ref Message msg, Keys keyData)
1049                 {
1050                         return base.ProcessCmdKey (ref msg, keyData);
1051                 }
1052                 protected override bool ProcessDialogKey (Keys keyData)
1053                 {
1054                         // The user can use Ctrl-Tab or Ctrl-Shift-Tab to move control focus
1055                         // instead of inserting a Tab.  However, the focus-moving-tab-stuffs
1056                         // doesn't work if Ctrl is pushed, so we remove it before sending it.
1057                         if (accepts_tab && (keyData & (Keys.Control | Keys.Tab)) == (Keys.Control | Keys.Tab))
1058                                 keyData ^= Keys.Control;
1059                                 
1060                         return base.ProcessDialogKey(keyData);
1061                 }
1062
1063                 private bool ProcessKey (Keys keyData)
1064                 {
1065                         bool control;
1066                         bool shift;
1067
1068                         control = (Control.ModifierKeys & Keys.Control) != 0;
1069                         shift = (Control.ModifierKeys & Keys.Shift) != 0;
1070
1071                         if (shortcuts_enabled) {
1072                                 switch (keyData & Keys.KeyCode) {
1073                                 case Keys.X:
1074                                         if (control && read_only == false) {
1075                                                 Cut();
1076                                                 return true;
1077                                         }
1078                                         return false;
1079
1080                                 case Keys.C:
1081                                         if (control) {
1082                                                 Copy();
1083                                                 return true;
1084                                         }
1085                                         return false;
1086
1087                                 case Keys.V:
1088                                         if (control && read_only == false) {
1089                                                 return Paste(Clipboard.GetDataObject(), null, true);
1090                                         }
1091                                         return false;
1092
1093                                 case Keys.Z:
1094                                         if (control && read_only == false) {
1095                                                 Undo ();
1096                                                 return true;
1097                                         }
1098                                         return false;
1099
1100                                 case Keys.A:
1101                                         if (control) {
1102                                                 SelectAll();
1103                                                 return true;
1104                                         }
1105                                         return false;
1106
1107                                 case Keys.Insert:
1108
1109                                         if (read_only == false) {
1110                                                 if (shift) {
1111                                                         Paste (Clipboard.GetDataObject (), null, true);
1112                                                         return true;
1113                                                 }
1114
1115                                                 if (control) {
1116                                                         Copy ();
1117                                                         return true;
1118                                                 }
1119                                         }
1120
1121                                         return false;
1122
1123                                 case Keys.Delete:
1124
1125                                         if (read_only)
1126                                                 break;
1127
1128                                         if (shift && read_only == false) {
1129                                                 Cut ();
1130                                                 return true;
1131                                         }
1132
1133                                         if (document.selection_visible) {
1134                                                 document.ReplaceSelection("", false);
1135                                         } else {
1136                                                 // DeleteChar only deletes on the line, doesn't do the combine
1137                                                 if (document.CaretPosition >= document.CaretLine.TextLengthWithoutEnding ()) {
1138                                                         if (document.CaretLine.LineNo < document.Lines) {
1139                                                                 Line    line;
1140
1141                                                                 line = document.GetLine(document.CaretLine.LineNo + 1);
1142
1143                                                                 // this line needs to be invalidated before it is combined
1144                                                                 // because once it is combined, all it's coordinates will
1145                                                                 // have changed
1146                                                                 document.Invalidate (line, 0, line, line.text.Length);
1147                                                                 document.Combine(document.CaretLine, line);
1148
1149                                                                 document.UpdateView(document.CaretLine,
1150                                                                                 document.Lines, 0);
1151
1152                                                         }
1153                                                 } else {
1154                                                         if (!control) {
1155                                                                 document.DeleteChar(document.CaretTag.Line, document.CaretPosition, true);
1156                                                         } else {
1157                                                                 int end_pos;
1158
1159                                                                 end_pos = document.CaretPosition;
1160
1161                                                                 while ((end_pos < document.CaretLine.Text.Length) && !Document.IsWordSeparator(document.CaretLine.Text[end_pos])) {
1162                                                                         end_pos++;
1163                                                                 }
1164
1165                                                                 if (end_pos < document.CaretLine.Text.Length) {
1166                                                                         end_pos++;
1167                                                                 }
1168                                                                 document.DeleteChars(document.CaretTag.Line, document.CaretPosition, end_pos - document.CaretPosition);
1169                                                         }
1170                                                 }
1171                                         }
1172
1173                                         document.AlignCaret();
1174                                         document.UpdateCaret();
1175                                         CaretMoved(this, null);
1176
1177                                         Modified = true;
1178                                         OnTextChanged (EventArgs.Empty);
1179                 
1180                                         return true;
1181                                 }
1182                         }
1183
1184                         switch (keyData & Keys.KeyCode) {
1185                                 case Keys.Left: {
1186                                         if (control) {
1187                                                 document.MoveCaret(CaretDirection.WordBack);
1188                                         } else {
1189                                                 if (!document.selection_visible || shift) {
1190                                                         document.MoveCaret(CaretDirection.CharBack);
1191                                                 } else {
1192                                                         document.MoveCaret(CaretDirection.SelectionStart);
1193                                                 }
1194                                         }
1195                                         
1196                                         if (!shift) {
1197                                                 document.SetSelectionToCaret(true);
1198                                         } else {
1199                                                 document.SetSelectionToCaret(false);
1200                                         }
1201
1202                                         CaretMoved(this, null);
1203                                         return true;
1204                                 }
1205
1206                                 case Keys.Right: {
1207                                         if (control) {
1208                                                 document.MoveCaret(CaretDirection.WordForward);
1209                                         } else {
1210                                                 if (!document.selection_visible || shift) {
1211                                                         document.MoveCaret(CaretDirection.CharForward);
1212                                                 } else {
1213                                                         document.MoveCaret(CaretDirection.SelectionEnd);
1214                                                 }
1215                                         }
1216                                         if (!shift) {
1217                                                 document.SetSelectionToCaret(true);
1218                                         } else {
1219                                                 document.SetSelectionToCaret(false);
1220                                         }
1221
1222                                         CaretMoved(this, null);
1223                                         return true;
1224                                 }
1225
1226                                 case Keys.Up: {
1227                                         if (control) {
1228                                                 if (document.CaretPosition == 0) {
1229                                                         document.MoveCaret(CaretDirection.LineUp);
1230                                                 } else {
1231                                                         document.MoveCaret(CaretDirection.Home);
1232                                                 }
1233                                         } else {
1234                                                 document.MoveCaret(CaretDirection.LineUp);
1235                                         }
1236
1237                                         if ((Control.ModifierKeys & Keys.Shift) == 0) {
1238                                                 document.SetSelectionToCaret(true);
1239                                         } else {
1240                                                 document.SetSelectionToCaret(false);
1241                                         }
1242
1243                                         CaretMoved(this, null);
1244                                         return true;
1245                                 }
1246
1247                                 case Keys.Down: {
1248                                         if (control) {
1249                                                 if (document.CaretPosition == document.CaretLine.Text.Length) {
1250                                                         document.MoveCaret(CaretDirection.LineDown);
1251                                                 } else {
1252                                                         document.MoveCaret(CaretDirection.End);
1253                                                 }
1254                                         } else {
1255                                                 document.MoveCaret(CaretDirection.LineDown);
1256                                         }
1257
1258                                         if ((Control.ModifierKeys & Keys.Shift) == 0) {
1259                                                 document.SetSelectionToCaret(true);
1260                                         } else {
1261                                                 document.SetSelectionToCaret(false);
1262                                         }
1263
1264                                         CaretMoved(this, null);
1265                                         return true;
1266                                 }
1267
1268                                 case Keys.Home: {
1269                                         if ((Control.ModifierKeys & Keys.Control) != 0) {
1270                                                 document.MoveCaret(CaretDirection.CtrlHome);
1271                                         } else {
1272                                                 document.MoveCaret(CaretDirection.Home);
1273                                         }
1274
1275                                         if ((Control.ModifierKeys & Keys.Shift) == 0) {
1276                                                 document.SetSelectionToCaret(true);
1277                                         } else {
1278                                                 document.SetSelectionToCaret(false);
1279                                         }
1280
1281                                         CaretMoved(this, null);
1282                                         return true;
1283                                 }
1284
1285                                 case Keys.End: {
1286                                         if ((Control.ModifierKeys & Keys.Control) != 0) {
1287                                                 document.MoveCaret(CaretDirection.CtrlEnd);
1288                                         } else {
1289                                                 document.MoveCaret(CaretDirection.End);
1290                                         }
1291
1292                                         if ((Control.ModifierKeys & Keys.Shift) == 0) {
1293                                                 document.SetSelectionToCaret(true);
1294                                         } else {
1295                                                 document.SetSelectionToCaret(false);
1296                                         }
1297
1298                                         CaretMoved(this, null);
1299                                         return true;
1300                                 }
1301
1302                                 //case Keys.Enter: {
1303                                 //        // ignoring accepts_return, fixes bug #76355
1304                                 //        if (!read_only && document.multiline && (accepts_return || (FindForm() != null && FindForm().AcceptButton == null) || ((Control.ModifierKeys & Keys.Control) != 0))) {
1305                                 //                Line  line;
1306
1307                                 //                if (document.selection_visible) {
1308                                 //                        document.ReplaceSelection("\n", false);
1309                                 //                }
1310
1311                                 //                line = document.CaretLine;
1312
1313                                 //                document.Split (document.CaretLine, document.CaretTag, document.CaretPosition);
1314                                 //                line.ending = LineEnding.Rich;
1315                                 //                document.InsertString (line, line.text.Length,
1316                                 //                                                document.LineEndingToString (line.ending));
1317                                 //                OnTextChanged(EventArgs.Empty);
1318
1319                                 //                document.UpdateView (line, document.Lines - line.line_no, 0);
1320                                 //                CaretMoved(this, null);
1321                                 //                return true;
1322                                 //        }
1323                                 //        break;
1324                                 //}
1325
1326                                 case Keys.Tab: {
1327                                         if (!read_only && accepts_tab && document.multiline) {
1328                                                 document.InsertCharAtCaret ('\t', true);
1329
1330                                                 CaretMoved(this, null);
1331                                                 Modified = true;
1332                                                 OnTextChanged (EventArgs.Empty);
1333
1334                                                 return true;
1335                                         }
1336                                         break;
1337                                 }
1338
1339                                 case Keys.PageUp: {
1340                                         if ((Control.ModifierKeys & Keys.Control) != 0) {
1341                                                 document.MoveCaret(CaretDirection.CtrlPgUp);
1342                                         } else {
1343                                                 document.MoveCaret(CaretDirection.PgUp);
1344                                         }
1345                                         document.DisplayCaret ();
1346                                         return true;
1347                                 }
1348
1349                                 case Keys.PageDown: {
1350                                         if ((Control.ModifierKeys & Keys.Control) != 0) {
1351                                                 document.MoveCaret(CaretDirection.CtrlPgDn);
1352                                         } else {
1353                                                 document.MoveCaret(CaretDirection.PgDn);
1354                                         }
1355                                         document.DisplayCaret ();
1356                                         return true;
1357                                 }
1358                         }
1359
1360                         return false;
1361                 }
1362
1363                 internal virtual void RaiseSelectionChanged ()
1364                 {
1365                         // Do nothing, overridden in RTB
1366                 }
1367                 
1368                 private void HandleBackspace (bool control)
1369                 {
1370                         bool    fire_changed;
1371
1372                         fire_changed = false;
1373
1374                         // delete only deletes on the line, doesn't do the combine
1375                         if (document.selection_visible) {
1376                                 document.undo.BeginUserAction (Locale.GetText ("Delete"));
1377                                 document.ReplaceSelection("", false);
1378                                 document.undo.EndUserAction ();
1379                                 fire_changed = true;
1380                                 document.SetSelectionToCaret (true);
1381                         } else {
1382                         document.SetSelectionToCaret (true);
1383
1384                         if (document.CaretPosition == 0) {
1385                                 if (document.CaretLine.LineNo > 1) {
1386                                         Line    line;
1387                                         int     new_caret_pos;
1388
1389                                         line = document.GetLine(document.CaretLine.LineNo - 1);
1390                                         new_caret_pos = line.TextLengthWithoutEnding ();
1391
1392                                         // Invalidate the old line position before we do the combine
1393                                         document.Invalidate (line, 0, line, line.text.Length);
1394                                         document.Combine(line, document.CaretLine);
1395
1396                                         document.UpdateView(line, document.Lines - line.LineNo, 0);
1397                                         document.PositionCaret(line, new_caret_pos);
1398                                         document.SetSelectionToCaret (true);
1399                                         document.UpdateCaret();
1400                                         fire_changed = true;
1401                                 }
1402                         } else {
1403                                 if (!control || document.CaretPosition == 0) {
1404
1405                                         // Move before we delete because the delete will change positions around
1406                                         // if we cross a wrap border
1407                                         LineTag tag = document.CaretTag;
1408                                         int pos = document.CaretPosition;
1409                                         document.MoveCaret (CaretDirection.CharBack);
1410                                         document.DeleteChar (tag.Line, pos, false);
1411                                         document.SetSelectionToCaret (true);
1412                                 } else {
1413                                         int start_pos;
1414
1415                                         
1416                                         start_pos = document.CaretPosition - 1;
1417                                         while ((start_pos > 0) && !Document.IsWordSeparator(document.CaretLine.Text[start_pos - 1])) {
1418                                                 start_pos--;
1419                                         }
1420
1421                                         document.undo.BeginUserAction (Locale.GetText ("Delete"));
1422                                         document.DeleteChars(document.CaretTag.Line, start_pos, document.CaretPosition - start_pos);
1423                                         document.undo.EndUserAction ();
1424                                         document.PositionCaret(document.CaretLine, start_pos);
1425                                         document.SetSelectionToCaret (true);
1426                                 }
1427                                 document.UpdateCaret();
1428                                 fire_changed = true;
1429                                 }
1430                         }
1431
1432                         CaretMoved (this, null);
1433
1434                         if (fire_changed) {
1435                                 Modified = true;
1436                                 OnTextChanged(EventArgs.Empty);
1437                         }
1438                 }
1439
1440                 private void HandleEnter ()
1441                 {
1442                         // ignoring accepts_return, fixes bug #76355
1443                         if (!read_only && document.multiline && (accepts_return || (FindForm() != null && FindForm().AcceptButton == null) || ((Control.ModifierKeys & Keys.Control) != 0))) {
1444                                 Line    line;
1445
1446                                 if (document.selection_visible)
1447                                         document.ReplaceSelection ("", false);
1448
1449                                 line = document.CaretLine;
1450
1451                                 document.Split (document.CaretLine, document.CaretTag, document.CaretPosition);
1452                                 line.ending = document.StringToLineEnding (Environment.NewLine);
1453                                 document.InsertString (line, line.text.Length, document.LineEndingToString (line.ending));
1454                                 
1455                                 document.UpdateView (line, document.Lines - line.line_no, 0);
1456                                 CaretMoved (this, null);
1457                                 Modified = true;
1458                                 OnTextChanged (EventArgs.Empty);
1459                         }
1460                 }
1461                 
1462                 protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
1463                 {
1464                         // Make sure we don't get sized bigger than we want to be
1465
1466                         if (!richtext) {
1467                                 if (!document.multiline) {
1468                                         if (height != PreferredHeight) {
1469                                                 // If the specified has Height, we need to store that in the
1470                                                 // ExplicitBounds because we are going to override it
1471                                                 if ((specified & BoundsSpecified.Height) != 0) {
1472                                                         Rectangle r = ExplicitBounds;
1473                                                         r.Height = height;
1474                                                         ExplicitBounds = r;
1475                                                         specified &= ~BoundsSpecified.Height;
1476                                                 }
1477                                                 
1478                                                 height = PreferredHeight;
1479                                         }
1480                                 }
1481                         }
1482
1483                         base.SetBoundsCore (x, y, width, height, specified);
1484                 }
1485
1486                 protected override void WndProc (ref Message m)
1487                 {
1488                         switch ((Msg)m.Msg) {
1489                         case Msg.WM_KEYDOWN: {
1490                                 if (ProcessKeyMessage(ref m) || ProcessKey((Keys)m.WParam.ToInt32() | XplatUI.State.ModifierKeys)) {
1491                                         m.Result = IntPtr.Zero;
1492                                         return;
1493                                 }
1494                                 DefWndProc (ref m);
1495                                 return;
1496                         }
1497
1498                         case Msg.WM_CHAR: {
1499                                 int     ch;
1500
1501                                 if (ProcessKeyMessage(ref m)) {
1502                                         m.Result = IntPtr.Zero;
1503                                         return;
1504                                 }
1505
1506                                 if (read_only) {
1507                                         return;
1508                                 }
1509
1510                                 m.Result = IntPtr.Zero;
1511
1512                                 ch = m.WParam.ToInt32();
1513
1514                                 if (ch == 127) {
1515                                         HandleBackspace(true);
1516                                 } else if (ch >= 32) {
1517                                         if (document.selection_visible) {
1518                                                 document.ReplaceSelection("", false);
1519                                         }
1520
1521                                         char c = (char)m.WParam;
1522                                         switch (character_casing) {
1523                                         case CharacterCasing.Upper:
1524                                                 c = Char.ToUpper((char) m.WParam);
1525                                                 break;
1526                                         case CharacterCasing.Lower:
1527                                                 c = Char.ToLower((char) m.WParam);
1528                                                 break;
1529                                         }
1530
1531                                         if (document.Length < max_length) {
1532                                                 document.InsertCharAtCaret(c, true);
1533                                                 OnTextUpdate ();
1534                                                 CaretMoved (this, null);
1535                                                 Modified = true;
1536                                                 OnTextChanged(EventArgs.Empty);
1537
1538                                         } else {
1539                                                 XplatUI.AudibleAlert(AlertType.Default);
1540                                         }
1541                                         return;
1542                                 } else if (ch == 8) {
1543                                         HandleBackspace(false);
1544                                 } else if (ch == 13)
1545                                         HandleEnter ();
1546
1547                                 return;
1548                         }
1549
1550                         case Msg.WM_SETFOCUS:
1551                                 base.WndProc(ref m);
1552                                 document.CaretHasFocus ();
1553                                 break;
1554
1555                         case Msg.WM_KILLFOCUS:
1556                                 base.WndProc(ref m);
1557                                 document.CaretLostFocus ();
1558                                 break;
1559
1560                         case Msg.WM_NCPAINT:
1561                                 if (!ThemeEngine.Current.TextBoxBaseHandleWmNcPaint (this, ref m))
1562                                         base.WndProc(ref m);
1563                                 break;
1564
1565                         default:
1566                                 base.WndProc(ref m);
1567                                 return;
1568                         }
1569                 }
1570
1571                 #endregion      // Protected Instance Methods
1572
1573                 #region Events
1574                 static object AcceptsTabChangedEvent = new object ();
1575                 static object AutoSizeChangedEvent = new object ();
1576                 static object BorderStyleChangedEvent = new object ();
1577                 static object HideSelectionChangedEvent = new object ();
1578                 static object ModifiedChangedEvent = new object ();
1579                 static object MultilineChangedEvent = new object ();
1580                 static object ReadOnlyChangedEvent = new object ();
1581                 static object HScrolledEvent = new object ();
1582                 static object VScrolledEvent = new object ();
1583
1584                 public event EventHandler AcceptsTabChanged {
1585                         add { Events.AddHandler (AcceptsTabChangedEvent, value); }
1586                         remove { Events.RemoveHandler (AcceptsTabChangedEvent, value); }
1587                 }
1588
1589                 [Browsable (false)]
1590                 [EditorBrowsable (EditorBrowsableState.Never)]
1591                 public new event EventHandler AutoSizeChanged {
1592                         add { Events.AddHandler (AutoSizeChangedEvent, value); }
1593                         remove { Events.RemoveHandler (AutoSizeChangedEvent, value); }
1594                 }
1595
1596                 public event EventHandler BorderStyleChanged {
1597                         add { Events.AddHandler (BorderStyleChangedEvent, value); }
1598                         remove { Events.RemoveHandler (BorderStyleChangedEvent, value); }
1599                 }
1600
1601                 public event EventHandler HideSelectionChanged {
1602                         add { Events.AddHandler (HideSelectionChangedEvent, value); }
1603                         remove { Events.RemoveHandler (HideSelectionChangedEvent, value); }
1604                 }
1605
1606                 public event EventHandler ModifiedChanged {
1607                         add { Events.AddHandler (ModifiedChangedEvent, value); }
1608                         remove { Events.RemoveHandler (ModifiedChangedEvent, value); }
1609                 }
1610
1611                 public event EventHandler MultilineChanged {
1612                         add { Events.AddHandler (MultilineChangedEvent, value); }
1613                         remove { Events.RemoveHandler (MultilineChangedEvent, value); }
1614                 }
1615
1616                 public event EventHandler ReadOnlyChanged {
1617                         add { Events.AddHandler (ReadOnlyChangedEvent, value); }
1618                         remove { Events.RemoveHandler (ReadOnlyChangedEvent, value); }
1619                 }
1620
1621                 internal event EventHandler HScrolled {
1622                         add { Events.AddHandler (HScrolledEvent, value); }
1623                         remove { Events.RemoveHandler (HScrolledEvent, value); }
1624                 }
1625
1626                 internal event EventHandler VScrolled {
1627                         add { Events.AddHandler (VScrolledEvent, value); }
1628                         remove { Events.RemoveHandler (VScrolledEvent, value); }
1629                 }
1630
1631                 [Browsable(false)]
1632                 [EditorBrowsable(EditorBrowsableState.Never)]
1633                 public new event EventHandler BackgroundImageChanged {
1634                         add { base.BackgroundImageChanged += value; }
1635                         remove { base.BackgroundImageChanged -= value; }
1636                 }
1637
1638                 [Browsable (false)]
1639                 [EditorBrowsable (EditorBrowsableState.Never)]
1640                 public new event EventHandler BackgroundImageLayoutChanged {
1641                         add { base.BackgroundImageLayoutChanged += value; }
1642                         remove { base.BackgroundImageLayoutChanged -= value; }
1643                 }
1644
1645                 [Browsable (true)]
1646                 [EditorBrowsable (EditorBrowsableState.Always)]
1647                 public new event MouseEventHandler MouseClick {
1648                         add { base.MouseClick += value; }
1649                         remove { base.MouseClick -= value; }
1650                 }
1651
1652                 [Browsable (false)]
1653                 [EditorBrowsable (EditorBrowsableState.Never)]
1654                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
1655                 public new event EventHandler PaddingChanged {
1656                         add { base.PaddingChanged += value; }
1657                         remove { base.PaddingChanged -= value; }
1658                 }
1659
1660                 [Browsable (true)]
1661                 [EditorBrowsable (EditorBrowsableState.Always)]
1662                 public new event EventHandler Click {
1663                         add { base.Click += value; }
1664                         remove { base.Click -= value; }
1665                 }
1666
1667                 // XXX should this not manipulate base.Paint?
1668                 [Browsable(false)]
1669                 [EditorBrowsable(EditorBrowsableState.Never)]
1670                 public new event PaintEventHandler Paint;
1671                 #endregion      // Events
1672
1673                 #region Private Methods
1674                 internal Document Document {
1675                         get {
1676                                 return document;
1677                         }
1678
1679                         set {
1680                                 document = value;
1681                         }
1682                 }
1683
1684                 internal bool EnableLinks {
1685                         get { return enable_links; }
1686                         set {
1687                                 enable_links = value;
1688
1689                                 document.EnableLinks = value;
1690                         }
1691                 }
1692
1693                 internal override bool ScaleChildrenInternal {
1694                         get { return false; }
1695                 }
1696
1697                 internal bool ShowSelection {
1698                         get {
1699                                 if (show_selection || !hide_selection) {
1700                                         return true;
1701                                 }
1702
1703                                 return has_focus;
1704                         }
1705
1706                         set {
1707                                 if (show_selection == value)
1708                                         return;
1709
1710                                 show_selection = value;
1711                                 // Currently InvalidateSelectionArea is commented out so do a full invalidate
1712                                 document.InvalidateSelectionArea();
1713                         }
1714                 }
1715
1716                 internal int TopMargin {
1717                         get {
1718                                 return document.top_margin;
1719                         }
1720                         set {
1721                                 document.top_margin = value;
1722                         }
1723                 }
1724
1725                 #region UIA Framework Properties
1726
1727                 internal ScrollBar UIAHScrollBar {
1728                         get { return hscroll; }
1729                 }
1730
1731                 internal ScrollBar UIAVScrollBar {
1732                         get { return vscroll; }
1733                 }
1734
1735                 #endregion UIA Framework Properties
1736
1737                 internal Graphics CreateGraphicsInternal ()
1738                 {
1739                         if (IsHandleCreated)
1740                                 return base.CreateGraphics();
1741                                 
1742                         return DeviceContext;
1743                 }
1744
1745                 internal override void OnPaintInternal (PaintEventArgs pevent)
1746                 {
1747                         Draw (pevent.Graphics, pevent.ClipRectangle);
1748
1749                         //
1750                         // OnPaint does not get raised on MS (see bug #80639)
1751                         // 
1752                         pevent.Handled = true;
1753                 }
1754
1755                 internal void Draw (Graphics g, Rectangle clippingArea)
1756                 {
1757                         ThemeEngine.Current.TextBoxBaseFillBackground (this, g, clippingArea);
1758                         
1759                         // Draw the viewable document
1760                         document.Draw(g, clippingArea);
1761                 }
1762
1763                 private void FixupHeight ()
1764                 {
1765                         if (!richtext) {
1766                                 if (!document.multiline) {
1767                                         if (PreferredHeight != Height) {
1768                                                 Height = PreferredHeight;
1769                                         }
1770                                 }
1771                         }
1772                 }
1773
1774                 private bool IsDoubleClick (MouseEventArgs e)
1775                 {
1776                         TimeSpan interval = DateTime.Now - click_last;
1777                         if (interval.TotalMilliseconds > SystemInformation.DoubleClickTime)
1778                                 return false;
1779                         Size dcs = SystemInformation.DoubleClickSize;
1780                         if (e.X < click_point_x - dcs.Width / 2 || e.X > click_point_x + dcs.Width / 2)
1781                                 return false;
1782                         if (e.Y < click_point_y - dcs.Height / 2 || e.Y > click_point_y + dcs.Height / 2)
1783                                 return false;
1784                         return true;
1785                 }
1786
1787                 private void TextBoxBase_MouseDown (object sender, MouseEventArgs e)
1788                 {
1789                         bool dbliclick = false;
1790
1791                         if (e.Button == MouseButtons.Left) {
1792
1793                                 // Special case when shift key is pressed and
1794                                 // left mouse is clicked.. set selection from
1795                                 // current cursor to mouse
1796                                 if ((Control.ModifierKeys & Keys.Shift) > 0) {
1797                                         document.PositionCaret (e.X + document.ViewPortX, e.Y + document.ViewPortY);
1798                                         document.SetSelectionToCaret (false);
1799                                         document.DisplayCaret ();
1800                                         return;
1801                                 }
1802
1803                                 dbliclick = IsDoubleClick (e);
1804
1805                                 if (current_link != null) {
1806                                         HandleLinkClicked (current_link);
1807                                         return;
1808                                 }
1809
1810                                 //ensure nothing is selected anymore BEFORE we
1811                                 //position the caret, so the caret is recreated
1812                                 //(caret is only visible when nothing is selected)
1813                                 if (document.selection_visible && dbliclick == false) {
1814                                         document.SetSelectionToCaret (true);
1815                                         click_mode = CaretSelection.Position;
1816                                 }
1817
1818                                 document.PositionCaret(e.X + document.ViewPortX, e.Y + document.ViewPortY);
1819
1820                                 if (dbliclick) {
1821                                         switch (click_mode) {
1822                                         case CaretSelection.Position:
1823                                                 SelectWord ();
1824                                                 click_mode = CaretSelection.Word;
1825                                                 break;
1826                                         case CaretSelection.Word:
1827
1828                                                 if (this is TextBox) {
1829                                                         document.SetSelectionToCaret (true);
1830                                                         click_mode = CaretSelection.Position;
1831                                                         break;
1832                                                 }
1833
1834                                                 document.ExpandSelection (CaretSelection.Line, false);
1835                                                 click_mode = CaretSelection.Line;
1836                                                 break;
1837                                         case CaretSelection.Line:
1838
1839                                                 // Gotta do this first because Exanding to a word
1840                                                 // from a line doesn't really work
1841                                                 document.SetSelectionToCaret (true);
1842
1843                                                 SelectWord ();
1844                                                 click_mode = CaretSelection.Word;
1845                                                 break;
1846                                         }
1847                                 } else {
1848                                         document.SetSelectionToCaret (true);
1849                                         click_mode = CaretSelection.Position;
1850                                 }
1851
1852                                 click_point_x = e.X;
1853                                 click_point_y = e.Y;
1854                                 click_last = DateTime.Now;
1855                         }
1856
1857                         if ((e.Button == MouseButtons.Middle) && XplatUI.RunningOnUnix) {
1858                                 Document.Marker marker;
1859
1860                                 marker.tag = document.FindCursor(e.X + document.ViewPortX, e.Y + document.ViewPortY, out marker.pos);
1861                                 marker.line = marker.tag.Line;
1862                                 marker.height = marker.tag.Height;
1863
1864                                 document.SetSelection(marker.line, marker.pos, marker.line, marker.pos);
1865                                 Paste (Clipboard.GetDataObject (true), null, true);
1866                         }
1867                 }
1868
1869                 private void TextBoxBase_MouseUp (object sender, MouseEventArgs e)
1870                 {
1871                         if (e.Button == MouseButtons.Left) {
1872                                 if (click_mode == CaretSelection.Position) {
1873                                         document.SetSelectionToCaret(false);
1874                                         document.DisplayCaret();
1875                                         
1876                                         // Only raise if there is text.
1877                                         if (Text.Length > 0)
1878                                                 RaiseSelectionChanged ();
1879                                 }
1880
1881                                 if (scroll_timer != null) {
1882                                         scroll_timer.Enabled = false;
1883                                 }
1884                                 return;
1885                         }
1886                 }
1887
1888                 private void SizeControls ()
1889                 {
1890                         if (hscroll.Visible) {
1891                                 //vscroll.Maximum += hscroll.Height;
1892                                 canvas_height = ClientSize.Height - hscroll.Height;
1893                         } else {
1894                                 canvas_height = ClientSize.Height;
1895                         }
1896
1897                         if (vscroll.Visible) {
1898                                 //hscroll.Maximum += vscroll.Width;
1899                                 canvas_width = ClientSize.Width - vscroll.Width;
1900
1901                                 if (GetInheritedRtoL () == RightToLeft.Yes) {
1902                                         document.OffsetX = vscroll.Width;
1903                                 } else {
1904                                         document.OffsetX = 0;
1905                                 }
1906
1907                         } else {
1908                                 canvas_width = ClientSize.Width;
1909                                 document.OffsetX = 0;
1910                         }
1911
1912                         document.ViewPortWidth = canvas_width;
1913                         document.ViewPortHeight = canvas_height;
1914                 }
1915
1916                 private void PositionControls ()
1917                 {
1918                         if (canvas_height < 1 || canvas_width < 1)
1919                                 return;
1920
1921                         int hmod = vscroll.Visible ? vscroll.Width : 0;
1922                         int vmod = hscroll.Visible ? hscroll.Height : 0;
1923
1924                         if (GetInheritedRtoL () == RightToLeft.Yes) {
1925                                 hscroll.Bounds = new Rectangle (ClientRectangle.Left + hmod, 
1926                                         Math.Max(0, ClientRectangle.Height - hscroll.Height), 
1927                                         ClientSize.Width, 
1928                                         hscroll.Height);
1929
1930                                 vscroll.Bounds = new Rectangle (ClientRectangle.Left, 
1931                                         ClientRectangle.Top, 
1932                                         vscroll.Width, 
1933                                         Math.Max(0, ClientSize.Height - (vmod)));
1934                         } else {
1935                                 hscroll.Bounds = new Rectangle (ClientRectangle.Left, 
1936                                         Math.Max(0, ClientRectangle.Height - hscroll.Height), 
1937                                         Math.Max(0, ClientSize.Width - hmod), 
1938                                         hscroll.Height);
1939
1940                                 vscroll.Bounds = new Rectangle (
1941                                         Math.Max(0, ClientRectangle.Right - vscroll.Width), 
1942                                         ClientRectangle.Top, 
1943                                         vscroll.Width, 
1944                                         Math.Max(0, ClientSize.Height - vmod));
1945                         }
1946                 }
1947
1948                 internal RightToLeft GetInheritedRtoL ()
1949                 {
1950                         for (Control c = this; c != null; c = c.Parent)
1951                                 if (c.RightToLeft != RightToLeft.Inherit)
1952                                         return c.RightToLeft;
1953                         return RightToLeft.No;
1954                 }
1955
1956                 private void TextBoxBase_SizeChanged (object sender, EventArgs e)
1957                 {
1958                         if (IsHandleCreated)
1959                                 CalculateDocument ();
1960                 }
1961
1962                 private void TextBoxBase_RightToLeftChanged (object o, EventArgs e)
1963                 {
1964                         if (IsHandleCreated)
1965                                 CalculateDocument ();
1966                 }
1967
1968                 private void TextBoxBase_MouseWheel (object sender, MouseEventArgs e)
1969                 {
1970                         if (!vscroll.Enabled)
1971                                 return;
1972
1973                         if (e.Delta < 0)
1974                                 vscroll.Value = Math.Min (vscroll.Value + SystemInformation.MouseWheelScrollLines * 5,
1975                                                 Math.Max (0, vscroll.Maximum - document.ViewPortHeight + 1));
1976                         else
1977                                 vscroll.Value = Math.Max (0, vscroll.Value - SystemInformation.MouseWheelScrollLines * 5);
1978                 }
1979
1980                 internal virtual void SelectWord ()
1981                 {
1982                         StringBuilder s = document.caret.line.text;
1983                         int start = document.caret.pos;
1984                         int end = document.caret.pos;
1985
1986                         if (s.Length < 1) {
1987                                 if (document.caret.line.line_no >= document.Lines)
1988                                         return;
1989                                 Line line = document.GetLine (document.caret.line.line_no + 1);
1990                                 document.PositionCaret (line, 0);
1991                                 return;
1992                         }
1993
1994                         if (start > 0) {
1995                                 start--;
1996                                 end--;
1997                         }
1998
1999                         // skip whitespace until we hit a word
2000                         while (start > 0 && s [start] == ' ')
2001                                 start--;
2002                         if (start > 0) {
2003                                 while (start > 0 && (s [start] != ' '))
2004                                         start--;
2005                                 if (s [start] == ' ')
2006                                         start++;
2007                         }
2008
2009                         if (s [end] == ' ') {
2010                                 while (end < s.Length && s [end] == ' ')
2011                                         end++;
2012                         } else {
2013                                 while (end < s.Length && s [end] != ' ')
2014                                         end++;
2015                                 while (end < s.Length && s [end] == ' ')
2016                                         end++;
2017                         }
2018
2019                         document.SetSelection (document.caret.line, start, document.caret.line, end);
2020                         document.PositionCaret (document.selection_end.line, document.selection_end.pos);
2021                         document.DisplayCaret();
2022                 }
2023
2024                 internal void CalculateDocument()
2025                 {
2026                         CalculateScrollBars ();
2027                         document.RecalculateDocument (CreateGraphicsInternal ());
2028
2029
2030                         if (document.caret.line != null && document.caret.line.Y < document.ViewPortHeight) {
2031                                 // The window has probably been resized, making the entire thing visible, so
2032                                 // we need to set the scroll position back to zero.
2033                                 vscroll.Value = 0;
2034                         }
2035
2036                         Invalidate();
2037                 }
2038
2039                 internal void CalculateScrollBars ()
2040                 {
2041                         // FIXME - need separate calculations for center and right alignment
2042                         SizeControls ();
2043
2044                         if (document.Width >= document.ViewPortWidth) {
2045                                 hscroll.SetValues (0, Math.Max (1, document.Width), -1,
2046                                                 document.ViewPortWidth < 0 ? 0 : document.ViewPortWidth);
2047                                 if (document.multiline)
2048                                         hscroll.Enabled = true;
2049                         } else {
2050                                 hscroll.Enabled = false;
2051                                 hscroll.Maximum = document.ViewPortWidth;
2052                         }
2053
2054                         if (document.Height >= document.ViewPortHeight) {
2055                                 vscroll.SetValues (0, Math.Max (1, document.Height), -1,
2056                                                 document.ViewPortHeight < 0 ? 0 : document.ViewPortHeight);
2057                                 if (document.multiline)
2058                                         vscroll.Enabled = true;
2059                         } else {
2060                                 vscroll.Enabled = false;
2061                                 vscroll.Maximum = document.ViewPortHeight;
2062                         }
2063
2064                         if (!WordWrap) {
2065                                 switch (scrollbars) {
2066                                 case RichTextBoxScrollBars.Both:
2067                                 case RichTextBoxScrollBars.Horizontal:
2068                                         if (richtext)
2069                                                 hscroll.Visible = hscroll.Enabled;
2070                                         else
2071                                                 hscroll.Visible = this.Multiline;
2072                                         break;
2073                                 case RichTextBoxScrollBars.ForcedBoth:
2074                                 case RichTextBoxScrollBars.ForcedHorizontal:
2075                                         hscroll.Visible = true;
2076                                         break;
2077                                 default:
2078                                         hscroll.Visible = false;
2079                                         break;
2080                                 }
2081                         } else {
2082                                 hscroll.Visible = false;
2083                         }
2084
2085                         switch (scrollbars) {
2086                         case RichTextBoxScrollBars.Both:
2087                         case RichTextBoxScrollBars.Vertical:
2088                                 if (richtext)
2089                                         vscroll.Visible = vscroll.Enabled;
2090                                 else 
2091                                         vscroll.Visible = this.Multiline;
2092                                 break;
2093                         case RichTextBoxScrollBars.ForcedBoth:
2094                         case RichTextBoxScrollBars.ForcedVertical:
2095                                 vscroll.Visible = true;
2096                                 break;
2097                         default:
2098                                 vscroll.Visible = false;
2099                                 break;
2100                         }
2101
2102                         PositionControls ();
2103
2104                         SizeControls (); //Update sizings now we've decided whats visible
2105                 }
2106
2107                 private void document_WidthChanged (object sender, EventArgs e)
2108                 {
2109                         CalculateScrollBars();
2110                 }
2111
2112                 private void document_HeightChanged (object sender, EventArgs e)
2113                 {
2114                         CalculateScrollBars();
2115                 }
2116
2117                 private void ScrollLinks (int xChange, int yChange)
2118                 {
2119                         foreach (LinkRectangle link in list_links)
2120                                 link.Scroll (xChange, yChange);
2121                 }
2122
2123                 private void hscroll_ValueChanged (object sender, EventArgs e)
2124                 {
2125                         int old_viewport_x;
2126
2127                         old_viewport_x = document.ViewPortX;
2128                         document.ViewPortX = this.hscroll.Value;
2129
2130                         //
2131                         // Before scrolling we want to destroy the caret, then draw a new one after the scroll
2132                         // the reason for this is that scrolling changes the coordinates of the caret, and we
2133                         // will get tracers if we don't 
2134                         //
2135                         if (Focused)
2136                                 document.CaretLostFocus ();
2137
2138                         if (vscroll.Visible) {
2139                                 if (GetInheritedRtoL () == RightToLeft.Yes) {
2140                                         XplatUI.ScrollWindow (this.Handle, new Rectangle (vscroll.Width, 0, ClientSize.Width - vscroll.Width, ClientSize.Height), old_viewport_x - this.hscroll.Value, 0, false);
2141                                 } else {
2142                                         XplatUI.ScrollWindow (this.Handle, new Rectangle (0, 0, ClientSize.Width - vscroll.Width, ClientSize.Height), old_viewport_x - this.hscroll.Value, 0, false);
2143                                 }
2144                         } else {
2145                                 XplatUI.ScrollWindow(this.Handle, ClientRectangle, old_viewport_x - this.hscroll.Value, 0, false);
2146                         }
2147
2148                         ScrollLinks (old_viewport_x - this.hscroll.Value, 0);
2149
2150                         if (Focused)
2151                                 document.CaretHasFocus ();
2152
2153                         EventHandler eh = (EventHandler)(Events [HScrolledEvent]);
2154                         if (eh != null)
2155                                 eh (this, EventArgs.Empty);
2156                 }
2157
2158                 private void vscroll_ValueChanged (object sender, EventArgs e)
2159                 {
2160                         int old_viewport_y;
2161
2162                         old_viewport_y = document.ViewPortY;
2163                         document.ViewPortY = this.vscroll.Value;
2164
2165                         //
2166                         // Before scrolling we want to destroy the caret, then draw a new one after the scroll
2167                         // the reason for this is that scrolling changes the coordinates of the caret, and we
2168                         // will get tracers if we don't 
2169                         //
2170                         if (Focused)
2171                                 document.CaretLostFocus ();
2172
2173                         if (hscroll.Visible) {
2174                                 XplatUI.ScrollWindow(this.Handle, new Rectangle(0, 0, ClientSize.Width, ClientSize.Height - hscroll.Height), 0, old_viewport_y - this.vscroll.Value, false);
2175                         } else {
2176                                 XplatUI.ScrollWindow(this.Handle, ClientRectangle, 0, old_viewport_y - this.vscroll.Value, false);
2177                         }
2178
2179                         ScrollLinks (0, old_viewport_y - this.vscroll.Value);
2180
2181                         if (Focused)
2182                                 document.CaretHasFocus ();
2183
2184                         EventHandler eh = (EventHandler)(Events [VScrolledEvent]);
2185                         if (eh != null)
2186                                 eh (this, EventArgs.Empty);
2187                 }
2188
2189                 private void TextBoxBase_MouseMove (object sender, MouseEventArgs e)
2190                 {
2191                         // FIXME - handle auto-scrolling if mouse is to the right/left of the window
2192                         if (e.Button == MouseButtons.Left && Capture) {
2193                                 if (!ClientRectangle.Contains (e.X, e.Y)) {
2194                                         if (scroll_timer == null) {
2195                                                 scroll_timer = new Timer ();
2196                                                 scroll_timer.Interval = 100;
2197                                                 scroll_timer.Tick += new EventHandler (ScrollTimerTickHandler);
2198                                         }
2199
2200                                         if (!scroll_timer.Enabled) {
2201                                                 scroll_timer.Start ();
2202
2203                                                 // Force the first tick
2204                                                 ScrollTimerTickHandler (null, EventArgs.Empty);
2205                                         }
2206                                 }
2207
2208                                 document.PositionCaret(e.X + document.ViewPortX, e.Y + document.ViewPortY);
2209                                 if (click_mode == CaretSelection.Position) {
2210                                         document.SetSelectionToCaret(false);
2211                                         document.DisplayCaret();
2212                                 }
2213                         }
2214
2215                         //search through link boxes to see if the mouse is over one of them
2216
2217                         bool found_link = false;
2218                         foreach (LinkRectangle link in list_links) {
2219                                 if (link.LinkAreaRectangle.Contains (e.X, e.Y)) {
2220                                         XplatUI.SetCursor (window.Handle, Cursors.Hand.handle);
2221
2222                                         found_link = true;
2223                                         current_link = link;
2224                                         break;
2225                                 }
2226                         }
2227
2228                         if (found_link == false) {
2229                                 XplatUI.SetCursor (window.Handle, DefaultCursor.handle);
2230                                 current_link = null;
2231                         }
2232                 }
2233
2234                 private void TextBoxBase_FontOrColorChanged (object sender, EventArgs e)
2235                 {
2236                         Line    line;
2237
2238                         document.SuspendRecalc ();
2239                         // Font changes apply to the whole document
2240                         for (int i = 1; i <= document.Lines; i++) {
2241                                 line = document.GetLine(i);
2242                                 if (LineTag.FormatText(line, 1, line.text.Length, Font, ForeColor,
2243                                                 Color.Empty, FormatSpecified.Font | FormatSpecified.Color))
2244                                         document.RecalculateDocument (CreateGraphicsInternal (), line.LineNo, line.LineNo, false);
2245                         }
2246                         document.ResumeRecalc (false);
2247
2248                         // Make sure the caret height is matching the new font height
2249                         document.AlignCaret();
2250                 }
2251
2252                 private void ScrollTimerTickHandler (object sender, EventArgs e)
2253                 {
2254                         Point pt = Cursor.Position;
2255
2256                         pt = PointToClient (pt);
2257
2258                         if (pt.X < ClientRectangle.Left) {
2259                                 document.MoveCaret(CaretDirection.CharBackNoWrap);
2260                                 document.SetSelectionToCaret(false);
2261                                 
2262                                 CaretMoved(this, null);
2263                         } else if (pt.X > ClientRectangle.Right) {
2264                                 document.MoveCaret(CaretDirection.CharForwardNoWrap);
2265                                 document.SetSelectionToCaret(false);
2266                                 
2267                                 CaretMoved(this, null);
2268                         } else if (pt.Y > ClientRectangle.Bottom) {
2269                                 document.MoveCaret(CaretDirection.LineDown);
2270                                 document.SetSelectionToCaret(false);
2271                                 
2272                                 CaretMoved(this, null);
2273                         } else if (pt.Y < ClientRectangle.Top) {
2274                                 document.MoveCaret(CaretDirection.LineUp);
2275                                 document.SetSelectionToCaret(false);
2276                                 
2277                                 CaretMoved(this, null);
2278                         }
2279                 }
2280
2281                 /// <summary>Ensure the caret is always visible</summary>
2282                 internal void CaretMoved (object sender, EventArgs e)
2283                 {
2284                         Point   pos;
2285                         int     height;
2286
2287                         if (!IsHandleCreated || canvas_width < 1 || canvas_height < 1)
2288                                 return;
2289
2290                         document.MoveCaretToTextTag ();
2291                         pos = document.Caret;
2292
2293                         //Console.WriteLine("Caret now at {0} (Thumb: {1}x{2}, Canvas: {3}x{4}, Document {5}x{6})", pos, hscroll.Value, vscroll.Value, canvas_width, canvas_height, document.Width, document.Height);
2294
2295
2296                         // Horizontal scrolling:
2297                         // If the caret moves to the left outside the visible area, we jump the document into view, not just one
2298                         // character, but 1/3 of the width of the document
2299                         // If the caret moves to the right outside the visible area, we scroll just enough to keep the caret visible
2300
2301                         // Handle horizontal scrolling
2302                         if (document.CaretLine.alignment == HorizontalAlignment.Left) {
2303                                 // Check if we moved out of view to the left
2304                                 if (pos.X < (document.ViewPortX)) {
2305                                         do {
2306                                                 if ((hscroll.Value - document.ViewPortWidth / 3) >= hscroll.Minimum) {
2307                                                         hscroll.SafeValueSet (hscroll.Value - document.ViewPortWidth / 3);
2308                                                 } else {
2309                                                         hscroll.Value = hscroll.Minimum;
2310                                                 }
2311                                         } while (hscroll.Value > pos.X);
2312                                 }
2313
2314                                 // Check if we moved out of view to the right
2315                                 if ((pos.X >= (document.ViewPortWidth + document.ViewPortX)) && (hscroll.Value != hscroll.Maximum)) {
2316                                         if ((pos.X - document.ViewPortWidth + 1) <= hscroll.Maximum) {
2317                                                 if (pos.X - document.ViewPortWidth >= 0) {
2318                                                         hscroll.SafeValueSet (pos.X - document.ViewPortWidth + 1);
2319                                                 } else {
2320                                                         hscroll.Value = 0;
2321                                                 }
2322                                         } else {
2323                                                 hscroll.Value = hscroll.Maximum;
2324                                         }
2325                                 }
2326                         } else if (document.CaretLine.alignment == HorizontalAlignment.Right) {
2327 //                              hscroll.Value = pos.X;
2328
2329 //                              if ((pos.X > (this.canvas_width + document.ViewPortX)) && (hscroll.Enabled && (hscroll.Value != hscroll.Maximum))) {
2330 //                                      hscroll.Value = hscroll.Maximum;
2331 //                              }
2332                         } else {
2333                                 // FIXME - implement center cursor alignment
2334                         }
2335
2336                         if (Text.Length > 0)
2337                                 RaiseSelectionChanged ();
2338                         
2339                         if (!document.multiline)
2340                                 return;
2341
2342                         // Handle vertical scrolling
2343                         height = document.CaretLine.Height + 1;
2344
2345                         if (pos.Y < document.ViewPortY)
2346                                 vscroll.SafeValueSet (pos.Y);
2347                         if ((pos.Y + height) > (document.ViewPortY + canvas_height))
2348                                 vscroll.Value = Math.Min (vscroll.Maximum, pos.Y - canvas_height + height);
2349                 }
2350
2351                 internal bool Paste (IDataObject clip, DataFormats.Format format, bool obey_length)
2352                 {
2353                         string          s;
2354
2355                         if (clip == null)
2356                                 return false;
2357
2358                         if (format == null) {
2359                                 if ((this is RichTextBox) && clip.GetDataPresent(DataFormats.Rtf)) {
2360                                         format = DataFormats.GetFormat(DataFormats.Rtf);
2361                                 } else if ((this is RichTextBox) && clip.GetDataPresent (DataFormats.Bitmap)) {
2362                                         format = DataFormats.GetFormat (DataFormats.Bitmap);
2363                                 } else if (clip.GetDataPresent(DataFormats.UnicodeText)) {
2364                                         format = DataFormats.GetFormat(DataFormats.UnicodeText);
2365                                 } else if (clip.GetDataPresent(DataFormats.Text)) {
2366                                         format = DataFormats.GetFormat(DataFormats.Text);
2367                                 } else {
2368                                         return false;
2369                                 }
2370                         } else {
2371                                 if ((format.Name == DataFormats.Rtf) && !(this is RichTextBox)) {
2372                                         return false;
2373                                 }
2374
2375                                 if (!clip.GetDataPresent(format.Name)) {
2376                                         return false;
2377                                 }
2378                         }
2379
2380                         if (format.Name == DataFormats.Rtf) {
2381                                 document.undo.BeginUserAction (Locale.GetText ("Paste"));
2382                                 ((RichTextBox)this).SelectedRtf = (string)clip.GetData(DataFormats.Rtf);
2383                                 document.undo.EndUserAction ();
2384                                 Modified = true;
2385                                 return true;
2386                         } else if (format.Name == DataFormats.Bitmap) {
2387                                 document.undo.BeginUserAction (Locale.GetText ("Paste"));
2388                                 //      document.InsertImage (document.caret.line, document.caret.pos, (Image) clip.GetData (DataFormats.Bitmap));
2389                                 document.MoveCaret (CaretDirection.CharForward);
2390                                 document.undo.EndUserAction ();
2391                                 return true;
2392                         } else if (format.Name == DataFormats.UnicodeText) {
2393                                 s = (string)clip.GetData(DataFormats.UnicodeText);
2394                         } else if (format.Name == DataFormats.Text) {
2395                                 s = (string)clip.GetData(DataFormats.Text);
2396                         } else {
2397                                 return false;
2398                         }
2399
2400                         if (!obey_length) {
2401                                 document.undo.BeginUserAction (Locale.GetText ("Paste"));
2402                                 this.SelectedText = s;
2403                                 document.undo.EndUserAction ();
2404                         } else {
2405                                 if ((s.Length + (document.Length - SelectedText.Length)) < max_length) {
2406                                         document.undo.BeginUserAction (Locale.GetText ("Paste"));
2407                                         this.SelectedText = s;
2408                                         document.undo.EndUserAction ();
2409                                 } else if ((document.Length - SelectedText.Length) < max_length) {
2410                                         document.undo.BeginUserAction (Locale.GetText ("Paste"));
2411                                         this.SelectedText = s.Substring (0, max_length - (document.Length - SelectedText.Length));
2412                                         document.undo.EndUserAction ();
2413                                 }
2414                         }
2415
2416                         Modified = true;
2417                         return true;
2418                 }
2419
2420                 internal virtual Color ChangeBackColor (Color backColor)
2421                 {
2422                         return backColor;
2423                 }
2424
2425                 internal override bool IsInputCharInternal (char charCode)
2426                 {
2427                         return true;
2428                 }
2429                 #endregion      // Private Methods
2430
2431                 #region Private Classes
2432                 internal class LinkRectangle {
2433                         private Rectangle link_area_rectangle;
2434                         private LineTag link_tag;
2435
2436                         public LinkRectangle (Rectangle rect)
2437                         {
2438                                 link_tag = null;
2439                                 link_area_rectangle = rect;
2440                         }
2441
2442                         public Rectangle LinkAreaRectangle {
2443                                 get { return link_area_rectangle; }
2444                                 set { link_area_rectangle = value; }
2445                         }
2446
2447                         public LineTag LinkTag {
2448                                 get { return link_tag; }
2449                                 set { link_tag = value; }
2450                         }
2451
2452                         public void Scroll (int x_change, int y_change)
2453                         {
2454                                 link_area_rectangle.X += x_change;
2455                                 link_area_rectangle.Y += y_change;
2456                         }
2457                 }
2458                 #endregion
2459
2460                 // This is called just before OnTextChanged is called.
2461                 internal virtual void OnTextUpdate ()
2462                 {
2463                 }
2464                 
2465                 protected override void OnTextChanged (EventArgs e)
2466                 {
2467                         base.OnTextChanged (e);
2468                 }
2469
2470                 public virtual int GetLineFromCharIndex (int index)
2471                 {
2472                         Line line_out;
2473                         LineTag tag_out;
2474                         int pos;
2475                         
2476                         document.CharIndexToLineTag (index, out line_out, out tag_out, out pos);
2477
2478                         return line_out.LineNo;
2479                 }
2480
2481                 protected override void OnMouseUp (MouseEventArgs mevent)
2482                 {
2483                         base.OnMouseUp (mevent);
2484                 }
2485         }
2486 }