Fix bug #395
[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 != ClientSize.Height) {
241                                                         ClientSize = new Size(ClientSize.Width, 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                 public int PreferredHeight {
470                         get {
471                                 if (BorderStyle != BorderStyle.None)
472                                         return Font.Height + 7;
473
474                                 // usually in borderless mode the top margin is 0, but
475                                 // try to access it, in case it was set manually, as ToolStrip* controls do
476                                 return Font.Height + TopMargin;
477                         }
478                 }
479
480                 [RefreshProperties (RefreshProperties.Repaint)] 
481                 [DefaultValue(false)]
482                 [MWFCategory("Behavior")]
483                 public bool ReadOnly {
484                         get {
485                                 return read_only;
486                         }
487
488                         set {
489                                 if (value != read_only) {
490                                         read_only = value;
491                                         if (!backcolor_set) {
492                                                 if (read_only)
493                                                         background_color = SystemColors.Control;
494                                                 else
495                                                         background_color = SystemColors.Window;
496                                         }
497                                         OnReadOnlyChanged(EventArgs.Empty);
498                                         Invalidate ();
499                                 }
500                         }
501                 }
502
503                 [Browsable(false)]
504                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
505                 public virtual string SelectedText {
506                         get {
507                                 string retval = document.GetSelection ();
508
509                                 return retval;
510                         }
511
512                         set {
513                                 if (value == null)
514                                         value = String.Empty;
515
516                                 document.ReplaceSelection(CaseAdjust(value), false);
517
518                                 ScrollToCaret();
519                                 OnTextChanged(EventArgs.Empty);
520                         }
521                 }
522
523                 [Browsable(false)]
524                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
525                 public virtual int SelectionLength {
526                         get {
527                                 int res = document.SelectionLength ();
528
529                                 return res;
530                         }
531
532                         set {
533                                 if (value < 0) {
534                                         string msg = String.Format ("'{0}' is not a valid value for 'SelectionLength'", value);
535                                         throw new ArgumentOutOfRangeException ("SelectionLength", msg);
536                                 }
537
538                                 document.InvalidateSelectionArea ();
539                                 if (value != 0) {
540                                         int     start;
541                                         Line    line;
542                                         LineTag tag;
543                                         int     pos;
544
545                                         selection_length = value;
546                                         start = document.LineTagToCharIndex (document.selection_start.line, document.selection_start.pos);
547                                         document.CharIndexToLineTag (start + value, out line, out tag, out pos);
548                                         document.SetSelectionEnd (line, pos, true);
549                                         document.PositionCaret (line, pos);
550                                 } else {
551                                         selection_length = -1;
552                                         document.SetSelectionEnd (document.selection_start.line, document.selection_start.pos, true);
553                                         document.PositionCaret (document.selection_start.line, document.selection_start.pos);
554                                 }
555                         }
556                 }
557
558                 [Browsable(false)]
559                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
560                 public int SelectionStart {
561                         get {
562                                 return document.LineTagToCharIndex(document.selection_start.line,
563                                         document.selection_start.pos);
564                         }
565
566                         set {
567                                 if (value < 0) {
568                                         string msg = String.Format ("'{0}' is not a valid value for 'SelectionStart'", value);
569                                         throw new ArgumentOutOfRangeException ("SelectionStart", msg);
570                                 }
571
572                                 // If SelectionStart has been used, we don't highlight on focus
573                                 has_been_focused = true;
574                                 
575                                 document.InvalidateSelectionArea ();
576                                 document.SetSelectionStart (value, false);
577                                 if (selection_length > -1)
578                                         document.SetSelectionEnd (value + selection_length, true);
579                                 else
580                                         document.SetSelectionEnd (value, true);
581                                 document.PositionCaret (document.selection_start.line, document.selection_start.pos);
582                                 ScrollToCaret ();
583                         }
584                 }
585
586                 [DefaultValue (true)]
587                 public virtual bool ShortcutsEnabled {
588                         get { return shortcuts_enabled; }
589                         set { shortcuts_enabled = value; }
590                 }
591
592                 [Editor ("System.ComponentModel.Design.MultilineStringEditor, " + Consts.AssemblySystem_Design,
593                          "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
594                 [Localizable(true)]
595                 public override string Text {
596                         get {
597                                 if (document == null || document.Root == null || document.Root.text == null)
598                                         return string.Empty;
599
600                                 StringBuilder sb = new StringBuilder();
601
602                                 Line line = null;
603                                 for (int i = 1; i <= document.Lines; i++) {
604                                         line = document.GetLine (i);
605                                         sb.Append(line.text.ToString ());
606                                 }
607
608                                 return sb.ToString();
609                         }
610
611                         set {
612                                 // reset to force a select all next time the box gets focus
613                                 has_been_focused = false;
614
615                                 if (value == Text)
616                                         return;
617
618                                 document.Empty ();
619                                 if ((value != null) && (value != "")) {
620                                         document.Insert (document.GetLine (1), 0, false, value);
621                                 } else {
622                                         if (IsHandleCreated) {
623                                                 document.SetSelectionToCaret (true);
624                                                 CalculateDocument ();
625                                         }
626                                 }
627                                                         
628                                 document.PositionCaret (document.GetLine (1), 0);
629                                 document.SetSelectionToCaret (true);
630
631                                 ScrollToCaret ();
632
633                                 OnTextChanged(EventArgs.Empty);
634                         }
635                 }
636
637                 [Browsable(false)]
638                 public virtual int TextLength {
639                         get {
640                                 if (document == null || document.Root == null || document.Root.text == null)
641                                         return 0;
642                                 return Text.Length;
643                         }
644                 }
645
646                 [DefaultValue(true)]
647                 [Localizable(true)]
648                 [MWFCategory("Behavior")]
649                 public bool WordWrap {
650                         get {
651                                 return word_wrap;
652                         }
653
654                         set {
655                                 if (value != word_wrap) {
656                                         if (document.multiline) {
657                                                 word_wrap = value;
658                                                 document.Wrap = value;
659                                         }
660                                         CalculateDocument ();
661                                 }
662                         }
663                 }
664
665                 [Browsable (false)]
666                 [EditorBrowsable (EditorBrowsableState.Never)]
667                 public override ImageLayout BackgroundImageLayout {
668                         get { return base.BackgroundImageLayout; } 
669                         set { base.BackgroundImageLayout = value; }
670                 }
671
672                 [Browsable (false)]
673                 [EditorBrowsable (EditorBrowsableState.Never)]
674                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
675                 public new Padding Padding {
676                         get { return base.Padding; }
677                         set { base.Padding = value; }
678                 }
679                 
680                 protected override Cursor DefaultCursor {
681                         get { return Cursors.IBeam; }
682                 }
683                 #endregion      // Public Instance Properties
684
685                 #region Protected Instance Properties
686                 protected override bool CanEnableIme {
687                         get {
688                                 if (ReadOnly || password_char != '\0')
689                                         return false;
690                                         
691                                 return true;
692                         }
693                 }
694
695                 protected override CreateParams CreateParams {
696                         get {
697                                 return base.CreateParams;
698                         }
699                 }
700
701                 protected override System.Drawing.Size DefaultSize {
702                         get {
703                                 return new Size(100, 20);
704                         }
705                 }
706
707                 // Currently our double buffering breaks our scrolling, so don't let people enable this
708                 [EditorBrowsable (EditorBrowsableState.Never)]
709                 protected override bool DoubleBuffered {
710                         get { return false; }
711                         set { }
712                 }
713
714                 #endregion      // Protected Instance Properties
715
716                 #region Public Instance Methods
717                 public void AppendText (string text)
718                 {
719                         // Save some cycles and only check the Text if we are one line
720                         bool is_empty = document.Lines == 1 && Text == String.Empty; 
721
722                         // make sure the caret begins at the end
723                         if (document.caret.line.line_no != document.Lines ||
724                              (document.caret.pos) != document.caret.line.TextLengthWithoutEnding ()) {
725                                 document.MoveCaret (CaretDirection.CtrlEnd);
726                         }
727                         document.Insert (document.caret.line, document.caret.pos, false, text, document.CaretTag);
728                         document.MoveCaret (CaretDirection.CtrlEnd);
729                         document.SetSelectionToCaret (true);
730
731                         if (!is_empty)
732                                 ScrollToCaret ();
733
734                         //
735                         // Avoid the initial focus selecting all when append text is used
736                         //
737                         has_been_focused = true;
738
739                         Modified = false;
740                         OnTextChanged(EventArgs.Empty);
741                 }
742
743                 public void Clear ()
744                 {
745                         Modified = false;
746                         Text = string.Empty;
747                 }
748
749                 public void ClearUndo ()
750                 {
751                         document.undo.Clear();
752                 }
753
754                 public void Copy ()
755                 {
756                         DataObject o;
757
758                         o = new DataObject(DataFormats.Text, SelectedText);
759                         if (this is RichTextBox)
760                                 o.SetData(DataFormats.Rtf, ((RichTextBox)this).SelectedRtf);
761                         Clipboard.SetDataObject(o);
762                 }
763
764                 public void Cut ()
765                 {
766                         DataObject      o;
767
768                         o = new DataObject(DataFormats.Text, SelectedText);
769                         if (this is RichTextBox)
770                                 o.SetData(DataFormats.Rtf, ((RichTextBox)this).SelectedRtf);
771                         Clipboard.SetDataObject (o);
772
773                         document.undo.BeginUserAction (Locale.GetText ("Cut"));
774                         document.ReplaceSelection (String.Empty, false);
775                         document.undo.EndUserAction ();
776
777                         Modified = true;
778                         OnTextChanged (EventArgs.Empty);
779                 }
780
781                 public void Paste ()
782                 {
783                         Paste (Clipboard.GetDataObject(), null, false);
784                 }
785
786                 public void ScrollToCaret ()
787                 {
788                         if (IsHandleCreated)
789                                 CaretMoved (this, EventArgs.Empty);
790                 }
791
792                 public void Select(int start, int length)
793                 {
794                         SelectionStart = start;
795                         SelectionLength = length;
796                 }
797
798                 public void SelectAll ()
799                 {
800                         Line    last;
801
802                         last = document.GetLine(document.Lines);
803                         document.SetSelectionStart(document.GetLine(1), 0, false);
804                         document.SetSelectionEnd(last, last.text.Length, true);
805                         document.PositionCaret (document.selection_end.line, document.selection_end.pos);
806                         selection_length = -1;
807
808                         CaretMoved (this, null);
809
810                         document.DisplayCaret ();
811                 }
812
813                 internal void SelectAllNoScroll ()
814                 {
815                         Line last;
816
817                         last = document.GetLine(document.Lines);
818                         document.SetSelectionStart(document.GetLine(1), 0, false);
819                         document.SetSelectionEnd(last, last.text.Length, false);
820                         document.PositionCaret (document.selection_end.line, document.selection_end.pos);
821                         selection_length = -1;
822
823                         document.DisplayCaret ();
824                 }
825
826                 public override string ToString ()
827                 {
828                         return String.Concat (base.ToString (), ", Text: ", Text);
829                 }
830
831                 [MonoInternalNote ("Deleting is classed as Typing, instead of its own Undo event")]
832                 public void Undo ()
833                 {
834                         if (document.undo.Undo ()) {
835                                 Modified = true;
836                                 OnTextChanged (EventArgs.Empty);
837                         }
838                 }
839
840                 public void DeselectAll ()
841                 {
842                         SelectionLength = 0;
843                 }
844
845                 public virtual char GetCharFromPosition (Point pt)
846                 {
847                         return GetCharFromPositionInternal (pt);
848                 }
849                 
850                 internal virtual char GetCharFromPositionInternal (Point p)
851                 {
852                         int index;
853                         LineTag tag = document.FindCursor (p.X, p.Y, out index);
854                         if (tag == null)
855                                 return (char) 0; // Shouldn't happen
856
857                         if (index >= tag.Line.text.Length) {
858                                 
859                                 if (tag.Line.ending == LineEnding.Wrap) {
860                                         // If we have wrapped text, we return the first char of the next line
861                                         Line line = document.GetLine (tag.Line.line_no + 1);
862                                         if (line != null)
863                                                 return line.text [0];
864
865                                 }
866
867                                 if (tag.Line.line_no == document.Lines) {
868                                         // Last line returns the last char
869                                         return tag.Line.text [tag.Line.text.Length - 1];
870                                 }
871
872                                 // This really shouldn't happen
873                                 return (char) 0;
874                         }
875                         return tag.Line.text [index];
876                 }
877
878                 public virtual int GetCharIndexFromPosition (Point pt)
879                 {
880                         int line_index;
881                         LineTag tag = document.FindCursor (pt.X, pt.Y, out line_index);
882                         if (tag == null)
883                                 return 0;
884
885                         if (line_index >= tag.Line.text.Length) {
886
887                                 if (tag.Line.ending == LineEnding.Wrap) {
888                                         // If we have wrapped text, we return the first char of the next line
889                                         Line line = document.GetLine (tag.Line.line_no + 1);
890                                         if (line != null)
891                                                 return document.LineTagToCharIndex (line, 0);
892                                 }
893
894                                 if (tag.Line.line_no == document.Lines) {
895                                         // Last line returns the last char
896                                         return document.LineTagToCharIndex (tag.Line, tag.Line.text.Length - 1);
897                                 }
898
899                                 return 0;
900                         }
901
902                         return document.LineTagToCharIndex (tag.Line, line_index);
903                 }
904
905                 public virtual Point GetPositionFromCharIndex (int index)
906                 {
907                         int pos;
908                         Line line;
909                         LineTag tag;
910
911                         document.CharIndexToLineTag (index, out line, out tag, out pos);
912
913                         return new Point ((int) (line.widths [pos] +
914                                                           line.X + document.viewport_x),
915                                         line.Y + document.viewport_y + tag.Shift);
916                 }
917
918                 public int GetFirstCharIndexFromLine (int lineNumber)
919                 {
920                         Line line = document.GetLine (lineNumber + 1);
921                         if (line == null)
922                                 return -1;
923                                         
924                         return document.LineTagToCharIndex (line, 0);
925                 }
926
927                 public int GetFirstCharIndexOfCurrentLine ()
928                 {
929                         return document.LineTagToCharIndex (document.caret.line, 0);
930                 }
931                 #endregion      // Public Instance Methods
932
933                 #region Protected Instance Methods
934                 protected override void CreateHandle ()
935                 {
936                         CalculateDocument ();
937                         base.CreateHandle ();
938                         document.AlignCaret();
939                         ScrollToCaret();
940                 }
941
942                 internal virtual void HandleLinkClicked (LinkRectangle link_clicked)
943                 {
944                 }
945
946                 protected override bool IsInputKey (Keys keyData)
947                 {
948                         if ((keyData & Keys.Alt) != 0)
949                                 return base.IsInputKey(keyData);
950
951                         switch (keyData & Keys.KeyCode) {
952                                 case Keys.Enter: {
953                                         return (accepts_return && document.multiline);
954                                 }
955
956                                 case Keys.Tab: {
957                                         if (accepts_tab && document.multiline)
958                                                 if ((keyData & Keys.Control) == 0)
959                                                         return true;
960                                         return false;
961                                 }
962
963                                 case Keys.Left:
964                                 case Keys.Right:
965                                 case Keys.Up:
966                                 case Keys.Down:
967                                 case Keys.PageUp:
968                                 case Keys.PageDown:
969                                 case Keys.Home:
970                                 case Keys.End: {
971                                         return true;
972                                 }
973                         }
974                         return false;
975                 }
976
977                 protected virtual void OnAcceptsTabChanged(EventArgs e)
978                 {
979                         EventHandler eh = (EventHandler)(Events [AcceptsTabChangedEvent]);
980                         if (eh != null)
981                                 eh (this, e);
982                 }
983
984                 protected virtual void OnBorderStyleChanged (EventArgs e)
985                 {
986                         EventHandler eh = (EventHandler)(Events [BorderStyleChangedEvent]);
987                         if (eh != null)
988                                 eh (this, e);
989                 }
990
991                 protected override void OnFontChanged (EventArgs e)
992                 {
993                         base.OnFontChanged (e);
994
995                         if (auto_size && !document.multiline) {
996                                 if (PreferredHeight != ClientSize.Height) {
997                                         Height = PreferredHeight;
998                                 }
999                         }
1000                 }
1001
1002                 protected override void OnHandleCreated (EventArgs e)
1003                 {
1004                         base.OnHandleCreated (e);
1005                         FixupHeight ();
1006                 }
1007
1008                 protected override void OnHandleDestroyed (EventArgs e)
1009                 {
1010                         base.OnHandleDestroyed (e);
1011                 }
1012
1013                 protected virtual void OnHideSelectionChanged (EventArgs e)
1014                 {
1015                         EventHandler eh = (EventHandler)(Events [HideSelectionChangedEvent]);
1016                         if (eh != null)
1017                                 eh (this, e);
1018                 }
1019
1020                 protected virtual void OnModifiedChanged (EventArgs e)
1021                 {
1022                         EventHandler eh = (EventHandler)(Events [ModifiedChangedEvent]);
1023                         if (eh != null)
1024                                 eh (this, e);
1025                 }
1026
1027                 protected virtual void OnMultilineChanged (EventArgs e)
1028                 {
1029                         EventHandler eh = (EventHandler)(Events [MultilineChangedEvent]);
1030                         if (eh != null)
1031                                 eh (this, e);
1032                 }
1033
1034                 protected override void OnPaddingChanged (EventArgs e)
1035                 {
1036                         base.OnPaddingChanged (e);
1037                 }
1038
1039                 protected virtual void OnReadOnlyChanged (EventArgs e)
1040                 {
1041                         EventHandler eh = (EventHandler)(Events [ReadOnlyChangedEvent]);
1042                         if (eh != null)
1043                                 eh (this, e);
1044                 }
1045
1046                 protected override bool ProcessCmdKey (ref Message msg, Keys keyData)
1047                 {
1048                         return base.ProcessCmdKey (ref msg, keyData);
1049                 }
1050                 protected override bool ProcessDialogKey (Keys keyData)
1051                 {
1052                         // The user can use Ctrl-Tab or Ctrl-Shift-Tab to move control focus
1053                         // instead of inserting a Tab.  However, the focus-moving-tab-stuffs
1054                         // doesn't work if Ctrl is pushed, so we remove it before sending it.
1055                         if (accepts_tab && (keyData & (Keys.Control | Keys.Tab)) == (Keys.Control | Keys.Tab))
1056                                 keyData ^= Keys.Control;
1057                                 
1058                         return base.ProcessDialogKey(keyData);
1059                 }
1060
1061                 private bool ProcessKey (Keys keyData)
1062                 {
1063                         bool control;
1064                         bool shift;
1065
1066                         control = (Control.ModifierKeys & Keys.Control) != 0;
1067                         shift = (Control.ModifierKeys & Keys.Shift) != 0;
1068
1069                         if (shortcuts_enabled) {
1070                                 switch (keyData & Keys.KeyCode) {
1071                                 case Keys.X:
1072                                         if (control && read_only == false) {
1073                                                 Cut();
1074                                                 return true;
1075                                         }
1076                                         return false;
1077
1078                                 case Keys.C:
1079                                         if (control) {
1080                                                 Copy();
1081                                                 return true;
1082                                         }
1083                                         return false;
1084
1085                                 case Keys.V:
1086                                         if (control && read_only == false) {
1087                                                 return Paste(Clipboard.GetDataObject(), null, true);
1088                                         }
1089                                         return false;
1090
1091                                 case Keys.Z:
1092                                         if (control && read_only == false) {
1093                                                 Undo ();
1094                                                 return true;
1095                                         }
1096                                         return false;
1097
1098                                 case Keys.A:
1099                                         if (control) {
1100                                                 SelectAll();
1101                                                 return true;
1102                                         }
1103                                         return false;
1104
1105                                 case Keys.Insert:
1106
1107                                         if (read_only == false) {
1108                                                 if (shift) {
1109                                                         Paste (Clipboard.GetDataObject (), null, true);
1110                                                         return true;
1111                                                 }
1112
1113                                                 if (control) {
1114                                                         Copy ();
1115                                                         return true;
1116                                                 }
1117                                         }
1118
1119                                         return false;
1120
1121                                 case Keys.Delete:
1122
1123                                         if (read_only)
1124                                                 break;
1125
1126                                         if (shift && read_only == false) {
1127                                                 Cut ();
1128                                                 return true;
1129                                         }
1130
1131                                         if (document.selection_visible) {
1132                                                 document.ReplaceSelection("", false);
1133                                         } else {
1134                                                 // DeleteChar only deletes on the line, doesn't do the combine
1135                                                 if (document.CaretPosition >= document.CaretLine.TextLengthWithoutEnding ()) {
1136                                                         if (document.CaretLine.LineNo < document.Lines) {
1137                                                                 Line    line;
1138
1139                                                                 line = document.GetLine(document.CaretLine.LineNo + 1);
1140
1141                                                                 // this line needs to be invalidated before it is combined
1142                                                                 // because once it is combined, all it's coordinates will
1143                                                                 // have changed
1144                                                                 document.Invalidate (line, 0, line, line.text.Length);
1145                                                                 document.Combine(document.CaretLine, line);
1146
1147                                                                 document.UpdateView(document.CaretLine,
1148                                                                                 document.Lines, 0);
1149
1150                                                         }
1151                                                 } else {
1152                                                         if (!control) {
1153                                                                 document.DeleteChar(document.CaretTag.Line, document.CaretPosition, true);
1154                                                         } else {
1155                                                                 int end_pos;
1156
1157                                                                 end_pos = document.CaretPosition;
1158
1159                                                                 while ((end_pos < document.CaretLine.Text.Length) && !Document.IsWordSeparator(document.CaretLine.Text[end_pos])) {
1160                                                                         end_pos++;
1161                                                                 }
1162
1163                                                                 if (end_pos < document.CaretLine.Text.Length) {
1164                                                                         end_pos++;
1165                                                                 }
1166                                                                 document.DeleteChars(document.CaretTag.Line, document.CaretPosition, end_pos - document.CaretPosition);
1167                                                         }
1168                                                 }
1169                                         }
1170
1171                                         document.AlignCaret();
1172                                         document.UpdateCaret();
1173                                         CaretMoved(this, null);
1174
1175                                         Modified = true;
1176                                         OnTextChanged (EventArgs.Empty);
1177                 
1178                                         return true;
1179                                 }
1180                         }
1181
1182                         switch (keyData & Keys.KeyCode) {
1183                                 case Keys.Left: {
1184                                         if (control) {
1185                                                 document.MoveCaret(CaretDirection.WordBack);
1186                                         } else {
1187                                                 if (!document.selection_visible || shift) {
1188                                                         document.MoveCaret(CaretDirection.CharBack);
1189                                                 } else {
1190                                                         document.MoveCaret(CaretDirection.SelectionStart);
1191                                                 }
1192                                         }
1193                                         
1194                                         if (!shift) {
1195                                                 document.SetSelectionToCaret(true);
1196                                         } else {
1197                                                 document.SetSelectionToCaret(false);
1198                                         }
1199
1200                                         CaretMoved(this, null);
1201                                         return true;
1202                                 }
1203
1204                                 case Keys.Right: {
1205                                         if (control) {
1206                                                 document.MoveCaret(CaretDirection.WordForward);
1207                                         } else {
1208                                                 if (!document.selection_visible || shift) {
1209                                                         document.MoveCaret(CaretDirection.CharForward);
1210                                                 } else {
1211                                                         document.MoveCaret(CaretDirection.SelectionEnd);
1212                                                 }
1213                                         }
1214                                         if (!shift) {
1215                                                 document.SetSelectionToCaret(true);
1216                                         } else {
1217                                                 document.SetSelectionToCaret(false);
1218                                         }
1219
1220                                         CaretMoved(this, null);
1221                                         return true;
1222                                 }
1223
1224                                 case Keys.Up: {
1225                                         if (control) {
1226                                                 if (document.CaretPosition == 0) {
1227                                                         document.MoveCaret(CaretDirection.LineUp);
1228                                                 } else {
1229                                                         document.MoveCaret(CaretDirection.Home);
1230                                                 }
1231                                         } else {
1232                                                 document.MoveCaret(CaretDirection.LineUp);
1233                                         }
1234
1235                                         if ((Control.ModifierKeys & Keys.Shift) == 0) {
1236                                                 document.SetSelectionToCaret(true);
1237                                         } else {
1238                                                 document.SetSelectionToCaret(false);
1239                                         }
1240
1241                                         CaretMoved(this, null);
1242                                         return true;
1243                                 }
1244
1245                                 case Keys.Down: {
1246                                         if (control) {
1247                                                 if (document.CaretPosition == document.CaretLine.Text.Length) {
1248                                                         document.MoveCaret(CaretDirection.LineDown);
1249                                                 } else {
1250                                                         document.MoveCaret(CaretDirection.End);
1251                                                 }
1252                                         } else {
1253                                                 document.MoveCaret(CaretDirection.LineDown);
1254                                         }
1255
1256                                         if ((Control.ModifierKeys & Keys.Shift) == 0) {
1257                                                 document.SetSelectionToCaret(true);
1258                                         } else {
1259                                                 document.SetSelectionToCaret(false);
1260                                         }
1261
1262                                         CaretMoved(this, null);
1263                                         return true;
1264                                 }
1265
1266                                 case Keys.Home: {
1267                                         if ((Control.ModifierKeys & Keys.Control) != 0) {
1268                                                 document.MoveCaret(CaretDirection.CtrlHome);
1269                                         } else {
1270                                                 document.MoveCaret(CaretDirection.Home);
1271                                         }
1272
1273                                         if ((Control.ModifierKeys & Keys.Shift) == 0) {
1274                                                 document.SetSelectionToCaret(true);
1275                                         } else {
1276                                                 document.SetSelectionToCaret(false);
1277                                         }
1278
1279                                         CaretMoved(this, null);
1280                                         return true;
1281                                 }
1282
1283                                 case Keys.End: {
1284                                         if ((Control.ModifierKeys & Keys.Control) != 0) {
1285                                                 document.MoveCaret(CaretDirection.CtrlEnd);
1286                                         } else {
1287                                                 document.MoveCaret(CaretDirection.End);
1288                                         }
1289
1290                                         if ((Control.ModifierKeys & Keys.Shift) == 0) {
1291                                                 document.SetSelectionToCaret(true);
1292                                         } else {
1293                                                 document.SetSelectionToCaret(false);
1294                                         }
1295
1296                                         CaretMoved(this, null);
1297                                         return true;
1298                                 }
1299
1300                                 //case Keys.Enter: {
1301                                 //        // ignoring accepts_return, fixes bug #76355
1302                                 //        if (!read_only && document.multiline && (accepts_return || (FindForm() != null && FindForm().AcceptButton == null) || ((Control.ModifierKeys & Keys.Control) != 0))) {
1303                                 //                Line  line;
1304
1305                                 //                if (document.selection_visible) {
1306                                 //                        document.ReplaceSelection("\n", false);
1307                                 //                }
1308
1309                                 //                line = document.CaretLine;
1310
1311                                 //                document.Split (document.CaretLine, document.CaretTag, document.CaretPosition);
1312                                 //                line.ending = LineEnding.Rich;
1313                                 //                document.InsertString (line, line.text.Length,
1314                                 //                                                document.LineEndingToString (line.ending));
1315                                 //                OnTextChanged(EventArgs.Empty);
1316
1317                                 //                document.UpdateView (line, document.Lines - line.line_no, 0);
1318                                 //                CaretMoved(this, null);
1319                                 //                return true;
1320                                 //        }
1321                                 //        break;
1322                                 //}
1323
1324                                 case Keys.Tab: {
1325                                         if (!read_only && accepts_tab && document.multiline) {
1326                                                 document.InsertCharAtCaret ('\t', true);
1327
1328                                                 CaretMoved(this, null);
1329                                                 Modified = true;
1330                                                 OnTextChanged (EventArgs.Empty);
1331
1332                                                 return true;
1333                                         }
1334                                         break;
1335                                 }
1336
1337                                 case Keys.PageUp: {
1338                                         if ((Control.ModifierKeys & Keys.Control) != 0) {
1339                                                 document.MoveCaret(CaretDirection.CtrlPgUp);
1340                                         } else {
1341                                                 document.MoveCaret(CaretDirection.PgUp);
1342                                         }
1343                                         document.DisplayCaret ();
1344                                         return true;
1345                                 }
1346
1347                                 case Keys.PageDown: {
1348                                         if ((Control.ModifierKeys & Keys.Control) != 0) {
1349                                                 document.MoveCaret(CaretDirection.CtrlPgDn);
1350                                         } else {
1351                                                 document.MoveCaret(CaretDirection.PgDn);
1352                                         }
1353                                         document.DisplayCaret ();
1354                                         return true;
1355                                 }
1356                         }
1357
1358                         return false;
1359                 }
1360
1361                 internal virtual void RaiseSelectionChanged ()
1362                 {
1363                         // Do nothing, overridden in RTB
1364                 }
1365                 
1366                 private void HandleBackspace (bool control)
1367                 {
1368                         bool    fire_changed;
1369
1370                         fire_changed = false;
1371
1372                         // delete only deletes on the line, doesn't do the combine
1373                         if (document.selection_visible) {
1374                                 document.undo.BeginUserAction (Locale.GetText ("Delete"));
1375                                 document.ReplaceSelection("", false);
1376                                 document.undo.EndUserAction ();
1377                                 fire_changed = true;
1378                                 document.SetSelectionToCaret (true);
1379                         } else {
1380                         document.SetSelectionToCaret (true);
1381
1382                         if (document.CaretPosition == 0) {
1383                                 if (document.CaretLine.LineNo > 1) {
1384                                         Line    line;
1385                                         int     new_caret_pos;
1386
1387                                         line = document.GetLine(document.CaretLine.LineNo - 1);
1388                                         new_caret_pos = line.TextLengthWithoutEnding ();
1389
1390                                         // Invalidate the old line position before we do the combine
1391                                         document.Invalidate (line, 0, line, line.text.Length);
1392                                         document.Combine(line, document.CaretLine);
1393
1394                                         document.UpdateView(line, document.Lines - line.LineNo, 0);
1395                                         document.PositionCaret(line, new_caret_pos);
1396                                         document.SetSelectionToCaret (true);
1397                                         document.UpdateCaret();
1398                                         fire_changed = true;
1399                                 }
1400                         } else {
1401                                 if (!control || document.CaretPosition == 0) {
1402
1403                                         // Move before we delete because the delete will change positions around
1404                                         // if we cross a wrap border
1405                                         LineTag tag = document.CaretTag;
1406                                         int pos = document.CaretPosition;
1407                                         document.MoveCaret (CaretDirection.CharBack);
1408                                         document.DeleteChar (tag.Line, pos, false);
1409                                         document.SetSelectionToCaret (true);
1410                                 } else {
1411                                         int start_pos;
1412
1413                                         
1414                                         start_pos = document.CaretPosition - 1;
1415                                         while ((start_pos > 0) && !Document.IsWordSeparator(document.CaretLine.Text[start_pos - 1])) {
1416                                                 start_pos--;
1417                                         }
1418
1419                                         document.undo.BeginUserAction (Locale.GetText ("Delete"));
1420                                         document.DeleteChars(document.CaretTag.Line, start_pos, document.CaretPosition - start_pos);
1421                                         document.undo.EndUserAction ();
1422                                         document.PositionCaret(document.CaretLine, start_pos);
1423                                         document.SetSelectionToCaret (true);
1424                                 }
1425                                 document.UpdateCaret();
1426                                 fire_changed = true;
1427                                 }
1428                         }
1429
1430                         CaretMoved (this, null);
1431
1432                         if (fire_changed) {
1433                                 Modified = true;
1434                                 OnTextChanged(EventArgs.Empty);
1435                         }
1436                 }
1437
1438                 private void HandleEnter ()
1439                 {
1440                         // ignoring accepts_return, fixes bug #76355
1441                         if (!read_only && document.multiline && (accepts_return || (FindForm() != null && FindForm().AcceptButton == null) || ((Control.ModifierKeys & Keys.Control) != 0))) {
1442                                 Line    line;
1443
1444                                 if (document.selection_visible)
1445                                         document.ReplaceSelection ("", false);
1446
1447                                 line = document.CaretLine;
1448
1449                                 document.Split (document.CaretLine, document.CaretTag, document.CaretPosition);
1450                                 line.ending = document.StringToLineEnding (Environment.NewLine);
1451                                 document.InsertString (line, line.text.Length, document.LineEndingToString (line.ending));
1452                                 
1453                                 document.UpdateView (line, document.Lines - line.line_no, 0);
1454                                 CaretMoved (this, null);
1455                                 Modified = true;
1456                                 OnTextChanged (EventArgs.Empty);
1457                         }
1458                 }
1459                 
1460                 protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
1461                 {
1462                         // Make sure we don't get sized bigger than we want to be
1463
1464                         if (!richtext) {
1465                                 if (!document.multiline) {
1466                                         if (height != PreferredHeight) {
1467                                                 // If the specified has Height, we need to store that in the
1468                                                 // ExplicitBounds because we are going to override it
1469                                                 if ((specified & BoundsSpecified.Height) != 0) {
1470                                                         Rectangle r = ExplicitBounds;
1471                                                         r.Height = height;
1472                                                         ExplicitBounds = r;
1473                                                         specified &= ~BoundsSpecified.Height;
1474                                                 }
1475                                                 
1476                                                 height = PreferredHeight;
1477                                         }
1478                                 }
1479                         }
1480
1481                         base.SetBoundsCore (x, y, width, height, specified);
1482                 }
1483
1484                 protected override void WndProc (ref Message m)
1485                 {
1486                         switch ((Msg)m.Msg) {
1487                         case Msg.WM_KEYDOWN: {
1488                                 if (ProcessKeyMessage(ref m) || ProcessKey((Keys)m.WParam.ToInt32() | XplatUI.State.ModifierKeys)) {
1489                                         m.Result = IntPtr.Zero;
1490                                         return;
1491                                 }
1492                                 DefWndProc (ref m);
1493                                 return;
1494                         }
1495
1496                         case Msg.WM_CHAR: {
1497                                 int     ch;
1498
1499                                 if (ProcessKeyMessage(ref m)) {
1500                                         m.Result = IntPtr.Zero;
1501                                         return;
1502                                 }
1503
1504                                 if (read_only) {
1505                                         return;
1506                                 }
1507
1508                                 m.Result = IntPtr.Zero;
1509
1510                                 ch = m.WParam.ToInt32();
1511
1512                                 if (ch == 127) {
1513                                         HandleBackspace(true);
1514                                 } else if (ch >= 32) {
1515                                         if (document.selection_visible) {
1516                                                 document.ReplaceSelection("", false);
1517                                         }
1518
1519                                         char c = (char)m.WParam;
1520                                         switch (character_casing) {
1521                                         case CharacterCasing.Upper:
1522                                                 c = Char.ToUpper((char) m.WParam);
1523                                                 break;
1524                                         case CharacterCasing.Lower:
1525                                                 c = Char.ToLower((char) m.WParam);
1526                                                 break;
1527                                         }
1528
1529                                         if (document.Length < max_length) {
1530                                                 document.InsertCharAtCaret(c, true);
1531                                                 OnTextUpdate ();
1532                                                 CaretMoved (this, null);
1533                                                 Modified = true;
1534                                                 OnTextChanged(EventArgs.Empty);
1535
1536                                         } else {
1537                                                 XplatUI.AudibleAlert(AlertType.Default);
1538                                         }
1539                                         return;
1540                                 } else if (ch == 8) {
1541                                         HandleBackspace(false);
1542                                 } else if (ch == 13)
1543                                         HandleEnter ();
1544
1545                                 return;
1546                         }
1547
1548                         case Msg.WM_SETFOCUS:
1549                                 base.WndProc(ref m);
1550                                 document.CaretHasFocus ();
1551                                 break;
1552
1553                         case Msg.WM_KILLFOCUS:
1554                                 base.WndProc(ref m);
1555                                 document.CaretLostFocus ();
1556                                 break;
1557
1558                         case Msg.WM_NCPAINT:
1559                                 if (!ThemeEngine.Current.TextBoxBaseHandleWmNcPaint (this, ref m))
1560                                         base.WndProc(ref m);
1561                                 break;
1562
1563                         default:
1564                                 base.WndProc(ref m);
1565                                 return;
1566                         }
1567                 }
1568
1569                 #endregion      // Protected Instance Methods
1570
1571                 #region Events
1572                 static object AcceptsTabChangedEvent = new object ();
1573                 static object AutoSizeChangedEvent = new object ();
1574                 static object BorderStyleChangedEvent = new object ();
1575                 static object HideSelectionChangedEvent = new object ();
1576                 static object ModifiedChangedEvent = new object ();
1577                 static object MultilineChangedEvent = new object ();
1578                 static object ReadOnlyChangedEvent = new object ();
1579                 static object HScrolledEvent = new object ();
1580                 static object VScrolledEvent = new object ();
1581
1582                 public event EventHandler AcceptsTabChanged {
1583                         add { Events.AddHandler (AcceptsTabChangedEvent, value); }
1584                         remove { Events.RemoveHandler (AcceptsTabChangedEvent, value); }
1585                 }
1586
1587                 [Browsable (false)]
1588                 [EditorBrowsable (EditorBrowsableState.Never)]
1589                 public new event EventHandler AutoSizeChanged {
1590                         add { Events.AddHandler (AutoSizeChangedEvent, value); }
1591                         remove { Events.RemoveHandler (AutoSizeChangedEvent, value); }
1592                 }
1593
1594                 public event EventHandler BorderStyleChanged {
1595                         add { Events.AddHandler (BorderStyleChangedEvent, value); }
1596                         remove { Events.RemoveHandler (BorderStyleChangedEvent, value); }
1597                 }
1598
1599                 public event EventHandler HideSelectionChanged {
1600                         add { Events.AddHandler (HideSelectionChangedEvent, value); }
1601                         remove { Events.RemoveHandler (HideSelectionChangedEvent, value); }
1602                 }
1603
1604                 public event EventHandler ModifiedChanged {
1605                         add { Events.AddHandler (ModifiedChangedEvent, value); }
1606                         remove { Events.RemoveHandler (ModifiedChangedEvent, value); }
1607                 }
1608
1609                 public event EventHandler MultilineChanged {
1610                         add { Events.AddHandler (MultilineChangedEvent, value); }
1611                         remove { Events.RemoveHandler (MultilineChangedEvent, value); }
1612                 }
1613
1614                 public event EventHandler ReadOnlyChanged {
1615                         add { Events.AddHandler (ReadOnlyChangedEvent, value); }
1616                         remove { Events.RemoveHandler (ReadOnlyChangedEvent, value); }
1617                 }
1618
1619                 internal event EventHandler HScrolled {
1620                         add { Events.AddHandler (HScrolledEvent, value); }
1621                         remove { Events.RemoveHandler (HScrolledEvent, value); }
1622                 }
1623
1624                 internal event EventHandler VScrolled {
1625                         add { Events.AddHandler (VScrolledEvent, value); }
1626                         remove { Events.RemoveHandler (VScrolledEvent, value); }
1627                 }
1628
1629                 [Browsable(false)]
1630                 [EditorBrowsable(EditorBrowsableState.Never)]
1631                 public new event EventHandler BackgroundImageChanged {
1632                         add { base.BackgroundImageChanged += value; }
1633                         remove { base.BackgroundImageChanged -= value; }
1634                 }
1635
1636                 [Browsable (false)]
1637                 [EditorBrowsable (EditorBrowsableState.Never)]
1638                 public new event EventHandler BackgroundImageLayoutChanged {
1639                         add { base.BackgroundImageLayoutChanged += value; }
1640                         remove { base.BackgroundImageLayoutChanged -= value; }
1641                 }
1642
1643                 [Browsable (true)]
1644                 [EditorBrowsable (EditorBrowsableState.Always)]
1645                 public new event MouseEventHandler MouseClick {
1646                         add { base.MouseClick += value; }
1647                         remove { base.MouseClick -= value; }
1648                 }
1649
1650                 [Browsable (false)]
1651                 [EditorBrowsable (EditorBrowsableState.Never)]
1652                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
1653                 public new event EventHandler PaddingChanged {
1654                         add { base.PaddingChanged += value; }
1655                         remove { base.PaddingChanged -= value; }
1656                 }
1657
1658                 [Browsable (true)]
1659                 [EditorBrowsable (EditorBrowsableState.Always)]
1660                 public new event EventHandler Click {
1661                         add { base.Click += value; }
1662                         remove { base.Click -= value; }
1663                 }
1664
1665                 // XXX should this not manipulate base.Paint?
1666                 [Browsable(false)]
1667                 [EditorBrowsable(EditorBrowsableState.Never)]
1668                 public new event PaintEventHandler Paint;
1669                 #endregion      // Events
1670
1671                 #region Private Methods
1672                 internal Document Document {
1673                         get {
1674                                 return document;
1675                         }
1676
1677                         set {
1678                                 document = value;
1679                         }
1680                 }
1681
1682                 internal bool EnableLinks {
1683                         get { return enable_links; }
1684                         set {
1685                                 enable_links = value;
1686
1687                                 document.EnableLinks = value;
1688                         }
1689                 }
1690
1691                 internal override bool ScaleChildrenInternal {
1692                         get { return false; }
1693                 }
1694
1695                 internal bool ShowSelection {
1696                         get {
1697                                 if (show_selection || !hide_selection) {
1698                                         return true;
1699                                 }
1700
1701                                 return has_focus;
1702                         }
1703
1704                         set {
1705                                 if (show_selection == value)
1706                                         return;
1707
1708                                 show_selection = value;
1709                                 // Currently InvalidateSelectionArea is commented out so do a full invalidate
1710                                 document.InvalidateSelectionArea();
1711                         }
1712                 }
1713
1714                 internal int TopMargin {
1715                         get {
1716                                 return document.top_margin;
1717                         }
1718                         set {
1719                                 document.top_margin = value;
1720                         }
1721                 }
1722
1723                 #region UIA Framework Properties
1724
1725                 internal ScrollBar UIAHScrollBar {
1726                         get { return hscroll; }
1727                 }
1728
1729                 internal ScrollBar UIAVScrollBar {
1730                         get { return vscroll; }
1731                 }
1732
1733                 #endregion UIA Framework Properties
1734
1735                 internal Graphics CreateGraphicsInternal ()
1736                 {
1737                         if (IsHandleCreated)
1738                                 return base.CreateGraphics();
1739                                 
1740                         return DeviceContext;
1741                 }
1742
1743                 internal override void OnPaintInternal (PaintEventArgs pevent)
1744                 {
1745                         Draw (pevent.Graphics, pevent.ClipRectangle);
1746
1747                         //
1748                         // OnPaint does not get raised on MS (see bug #80639)
1749                         // 
1750                         pevent.Handled = true;
1751                 }
1752
1753                 internal void Draw (Graphics g, Rectangle clippingArea)
1754                 {
1755                         ThemeEngine.Current.TextBoxBaseFillBackground (this, g, clippingArea);
1756                         
1757                         // Draw the viewable document
1758                         document.Draw(g, clippingArea);
1759                 }
1760
1761                 private void FixupHeight ()
1762                 {
1763                         if (!richtext) {
1764                                 if (!document.multiline) {
1765                                         if (PreferredHeight != ClientSize.Height) {
1766                                                 ClientSize = new Size (ClientSize.Width, PreferredHeight);
1767                                         }
1768                                 }
1769                         }
1770                 }
1771
1772                 private bool IsDoubleClick (MouseEventArgs e)
1773                 {
1774                         TimeSpan interval = DateTime.Now - click_last;
1775                         if (interval.TotalMilliseconds > SystemInformation.DoubleClickTime)
1776                                 return false;
1777                         Size dcs = SystemInformation.DoubleClickSize;
1778                         if (e.X < click_point_x - dcs.Width / 2 || e.X > click_point_x + dcs.Width / 2)
1779                                 return false;
1780                         if (e.Y < click_point_y - dcs.Height / 2 || e.Y > click_point_y + dcs.Height / 2)
1781                                 return false;
1782                         return true;
1783                 }
1784
1785                 private void TextBoxBase_MouseDown (object sender, MouseEventArgs e)
1786                 {
1787                         bool dbliclick = false;
1788
1789                         if (e.Button == MouseButtons.Left) {
1790
1791                                 // Special case when shift key is pressed and
1792                                 // left mouse is clicked.. set selection from
1793                                 // current cursor to mouse
1794                                 if ((Control.ModifierKeys & Keys.Shift) > 0) {
1795                                         document.PositionCaret (e.X + document.ViewPortX, e.Y + document.ViewPortY);
1796                                         document.SetSelectionToCaret (false);
1797                                         document.DisplayCaret ();
1798                                         return;
1799                                 }
1800
1801                                 dbliclick = IsDoubleClick (e);
1802
1803                                 if (current_link != null) {
1804                                         HandleLinkClicked (current_link);
1805                                         return;
1806                                 }
1807
1808                                 //ensure nothing is selected anymore BEFORE we
1809                                 //position the caret, so the caret is recreated
1810                                 //(caret is only visible when nothing is selected)
1811                                 if (document.selection_visible && dbliclick == false) {
1812                                         document.SetSelectionToCaret (true);
1813                                         click_mode = CaretSelection.Position;
1814                                 }
1815
1816                                 document.PositionCaret(e.X + document.ViewPortX, e.Y + document.ViewPortY);
1817
1818                                 if (dbliclick) {
1819                                         switch (click_mode) {
1820                                         case CaretSelection.Position:
1821                                                 SelectWord ();
1822                                                 click_mode = CaretSelection.Word;
1823                                                 break;
1824                                         case CaretSelection.Word:
1825
1826                                                 if (this is TextBox) {
1827                                                         document.SetSelectionToCaret (true);
1828                                                         click_mode = CaretSelection.Position;
1829                                                         break;
1830                                                 }
1831
1832                                                 document.ExpandSelection (CaretSelection.Line, false);
1833                                                 click_mode = CaretSelection.Line;
1834                                                 break;
1835                                         case CaretSelection.Line:
1836
1837                                                 // Gotta do this first because Exanding to a word
1838                                                 // from a line doesn't really work
1839                                                 document.SetSelectionToCaret (true);
1840
1841                                                 SelectWord ();
1842                                                 click_mode = CaretSelection.Word;
1843                                                 break;
1844                                         }
1845                                 } else {
1846                                         document.SetSelectionToCaret (true);
1847                                         click_mode = CaretSelection.Position;
1848                                 }
1849
1850                                 click_point_x = e.X;
1851                                 click_point_y = e.Y;
1852                                 click_last = DateTime.Now;
1853                         }
1854
1855                         if ((e.Button == MouseButtons.Middle) && XplatUI.RunningOnUnix) {
1856                                 Document.Marker marker;
1857
1858                                 marker.tag = document.FindCursor(e.X + document.ViewPortX, e.Y + document.ViewPortY, out marker.pos);
1859                                 marker.line = marker.tag.Line;
1860                                 marker.height = marker.tag.Height;
1861
1862                                 document.SetSelection(marker.line, marker.pos, marker.line, marker.pos);
1863                                 Paste (Clipboard.GetDataObject (true), null, true);
1864                         }
1865                 }
1866
1867                 private void TextBoxBase_MouseUp (object sender, MouseEventArgs e)
1868                 {
1869                         if (e.Button == MouseButtons.Left) {
1870                                 if (click_mode == CaretSelection.Position) {
1871                                         document.SetSelectionToCaret(false);
1872                                         document.DisplayCaret();
1873                                         
1874                                         // Only raise if there is text.
1875                                         if (Text.Length > 0)
1876                                                 RaiseSelectionChanged ();
1877                                 }
1878
1879                                 if (scroll_timer != null) {
1880                                         scroll_timer.Enabled = false;
1881                                 }
1882                                 return;
1883                         }
1884                 }
1885
1886                 private void SizeControls ()
1887                 {
1888                         if (hscroll.Visible) {
1889                                 //vscroll.Maximum += hscroll.Height;
1890                                 canvas_height = ClientSize.Height - hscroll.Height;
1891                         } else {
1892                                 canvas_height = ClientSize.Height;
1893                         }
1894
1895                         if (vscroll.Visible) {
1896                                 //hscroll.Maximum += vscroll.Width;
1897                                 canvas_width = ClientSize.Width - vscroll.Width;
1898
1899                                 if (GetInheritedRtoL () == RightToLeft.Yes) {
1900                                         document.OffsetX = vscroll.Width;
1901                                 } else {
1902                                         document.OffsetX = 0;
1903                                 }
1904
1905                         } else {
1906                                 canvas_width = ClientSize.Width;
1907                                 document.OffsetX = 0;
1908                         }
1909
1910                         document.ViewPortWidth = canvas_width;
1911                         document.ViewPortHeight = canvas_height;
1912                 }
1913
1914                 private void PositionControls ()
1915                 {
1916                         if (canvas_height < 1 || canvas_width < 1)
1917                                 return;
1918
1919                         int hmod = vscroll.Visible ? vscroll.Width : 0;
1920                         int vmod = hscroll.Visible ? hscroll.Height : 0;
1921
1922                         if (GetInheritedRtoL () == RightToLeft.Yes) {
1923                                 hscroll.Bounds = new Rectangle (ClientRectangle.Left + hmod, 
1924                                         Math.Max(0, ClientRectangle.Height - hscroll.Height), 
1925                                         ClientSize.Width, 
1926                                         hscroll.Height);
1927
1928                                 vscroll.Bounds = new Rectangle (ClientRectangle.Left, 
1929                                         ClientRectangle.Top, 
1930                                         vscroll.Width, 
1931                                         Math.Max(0, ClientSize.Height - (vmod)));
1932                         } else {
1933                                 hscroll.Bounds = new Rectangle (ClientRectangle.Left, 
1934                                         Math.Max(0, ClientRectangle.Height - hscroll.Height), 
1935                                         Math.Max(0, ClientSize.Width - hmod), 
1936                                         hscroll.Height);
1937
1938                                 vscroll.Bounds = new Rectangle (
1939                                         Math.Max(0, ClientRectangle.Right - vscroll.Width), 
1940                                         ClientRectangle.Top, 
1941                                         vscroll.Width, 
1942                                         Math.Max(0, ClientSize.Height - vmod));
1943                         }
1944                 }
1945
1946                 internal RightToLeft GetInheritedRtoL ()
1947                 {
1948                         for (Control c = this; c != null; c = c.Parent)
1949                                 if (c.RightToLeft != RightToLeft.Inherit)
1950                                         return c.RightToLeft;
1951                         return RightToLeft.No;
1952                 }
1953
1954                 private void TextBoxBase_SizeChanged (object sender, EventArgs e)
1955                 {
1956                         if (IsHandleCreated)
1957                                 CalculateDocument ();
1958                 }
1959
1960                 private void TextBoxBase_RightToLeftChanged (object o, EventArgs e)
1961                 {
1962                         if (IsHandleCreated)
1963                                 CalculateDocument ();
1964                 }
1965
1966                 private void TextBoxBase_MouseWheel (object sender, MouseEventArgs e)
1967                 {
1968                         if (!vscroll.Enabled)
1969                                 return;
1970
1971                         if (e.Delta < 0)
1972                                 vscroll.Value = Math.Min (vscroll.Value + SystemInformation.MouseWheelScrollLines * 5,
1973                                                 Math.Max (0, vscroll.Maximum - document.ViewPortHeight + 1));
1974                         else
1975                                 vscroll.Value = Math.Max (0, vscroll.Value - SystemInformation.MouseWheelScrollLines * 5);
1976                 }
1977
1978                 internal virtual void SelectWord ()
1979                 {
1980                         StringBuilder s = document.caret.line.text;
1981                         int start = document.caret.pos;
1982                         int end = document.caret.pos;
1983
1984                         if (s.Length < 1) {
1985                                 if (document.caret.line.line_no >= document.Lines)
1986                                         return;
1987                                 Line line = document.GetLine (document.caret.line.line_no + 1);
1988                                 document.PositionCaret (line, 0);
1989                                 return;
1990                         }
1991
1992                         if (start > 0) {
1993                                 start--;
1994                                 end--;
1995                         }
1996
1997                         // skip whitespace until we hit a word
1998                         while (start > 0 && s [start] == ' ')
1999                                 start--;
2000                         if (start > 0) {
2001                                 while (start > 0 && (s [start] != ' '))
2002                                         start--;
2003                                 if (s [start] == ' ')
2004                                         start++;
2005                         }
2006
2007                         if (s [end] == ' ') {
2008                                 while (end < s.Length && s [end] == ' ')
2009                                         end++;
2010                         } else {
2011                                 while (end < s.Length && s [end] != ' ')
2012                                         end++;
2013                                 while (end < s.Length && s [end] == ' ')
2014                                         end++;
2015                         }
2016
2017                         document.SetSelection (document.caret.line, start, document.caret.line, end);
2018                         document.PositionCaret (document.selection_end.line, document.selection_end.pos);
2019                         document.DisplayCaret();
2020                 }
2021
2022                 internal void CalculateDocument()
2023                 {
2024                         CalculateScrollBars ();
2025                         document.RecalculateDocument (CreateGraphicsInternal ());
2026
2027
2028                         if (document.caret.line != null && document.caret.line.Y < document.ViewPortHeight) {
2029                                 // The window has probably been resized, making the entire thing visible, so
2030                                 // we need to set the scroll position back to zero.
2031                                 vscroll.Value = 0;
2032                         }
2033
2034                         Invalidate();
2035                 }
2036
2037                 internal void CalculateScrollBars ()
2038                 {
2039                         // FIXME - need separate calculations for center and right alignment
2040                         SizeControls ();
2041
2042                         if (document.Width >= document.ViewPortWidth) {
2043                                 hscroll.SetValues (0, Math.Max (1, document.Width), -1,
2044                                                 document.ViewPortWidth < 0 ? 0 : document.ViewPortWidth);
2045                                 if (document.multiline)
2046                                         hscroll.Enabled = true;
2047                         } else {
2048                                 hscroll.Enabled = false;
2049                                 hscroll.Maximum = document.ViewPortWidth;
2050                         }
2051
2052                         if (document.Height >= document.ViewPortHeight) {
2053                                 vscroll.SetValues (0, Math.Max (1, document.Height), -1,
2054                                                 document.ViewPortHeight < 0 ? 0 : document.ViewPortHeight);
2055                                 if (document.multiline)
2056                                         vscroll.Enabled = true;
2057                         } else {
2058                                 vscroll.Enabled = false;
2059                                 vscroll.Maximum = document.ViewPortHeight;
2060                         }
2061
2062                         if (!WordWrap) {
2063                                 switch (scrollbars) {
2064                                 case RichTextBoxScrollBars.Both:
2065                                 case RichTextBoxScrollBars.Horizontal:
2066                                         if (richtext)
2067                                                 hscroll.Visible = hscroll.Enabled;
2068                                         else
2069                                                 hscroll.Visible = this.Multiline;
2070                                         break;
2071                                 case RichTextBoxScrollBars.ForcedBoth:
2072                                 case RichTextBoxScrollBars.ForcedHorizontal:
2073                                         hscroll.Visible = true;
2074                                         break;
2075                                 default:
2076                                         hscroll.Visible = false;
2077                                         break;
2078                                 }
2079                         } else {
2080                                 hscroll.Visible = false;
2081                         }
2082
2083                         switch (scrollbars) {
2084                         case RichTextBoxScrollBars.Both:
2085                         case RichTextBoxScrollBars.Vertical:
2086                                 if (richtext)
2087                                         vscroll.Visible = vscroll.Enabled;
2088                                 else 
2089                                         vscroll.Visible = this.Multiline;
2090                                 break;
2091                         case RichTextBoxScrollBars.ForcedBoth:
2092                         case RichTextBoxScrollBars.ForcedVertical:
2093                                 vscroll.Visible = true;
2094                                 break;
2095                         default:
2096                                 vscroll.Visible = false;
2097                                 break;
2098                         }
2099
2100                         PositionControls ();
2101
2102                         SizeControls (); //Update sizings now we've decided whats visible
2103                 }
2104
2105                 private void document_WidthChanged (object sender, EventArgs e)
2106                 {
2107                         CalculateScrollBars();
2108                 }
2109
2110                 private void document_HeightChanged (object sender, EventArgs e)
2111                 {
2112                         CalculateScrollBars();
2113                 }
2114
2115                 private void ScrollLinks (int xChange, int yChange)
2116                 {
2117                         foreach (LinkRectangle link in list_links)
2118                                 link.Scroll (xChange, yChange);
2119                 }
2120
2121                 private void hscroll_ValueChanged (object sender, EventArgs e)
2122                 {
2123                         int old_viewport_x;
2124
2125                         old_viewport_x = document.ViewPortX;
2126                         document.ViewPortX = this.hscroll.Value;
2127
2128                         //
2129                         // Before scrolling we want to destroy the caret, then draw a new one after the scroll
2130                         // the reason for this is that scrolling changes the coordinates of the caret, and we
2131                         // will get tracers if we don't 
2132                         //
2133                         if (Focused)
2134                                 document.CaretLostFocus ();
2135
2136                         if (vscroll.Visible) {
2137                                 if (GetInheritedRtoL () == RightToLeft.Yes) {
2138                                         XplatUI.ScrollWindow (this.Handle, new Rectangle (vscroll.Width, 0, ClientSize.Width - vscroll.Width, ClientSize.Height), old_viewport_x - this.hscroll.Value, 0, false);
2139                                 } else {
2140                                         XplatUI.ScrollWindow (this.Handle, new Rectangle (0, 0, ClientSize.Width - vscroll.Width, ClientSize.Height), old_viewport_x - this.hscroll.Value, 0, false);
2141                                 }
2142                         } else {
2143                                 XplatUI.ScrollWindow(this.Handle, ClientRectangle, old_viewport_x - this.hscroll.Value, 0, false);
2144                         }
2145
2146                         ScrollLinks (old_viewport_x - this.hscroll.Value, 0);
2147
2148                         if (Focused)
2149                                 document.CaretHasFocus ();
2150
2151                         EventHandler eh = (EventHandler)(Events [HScrolledEvent]);
2152                         if (eh != null)
2153                                 eh (this, EventArgs.Empty);
2154                 }
2155
2156                 private void vscroll_ValueChanged (object sender, EventArgs e)
2157                 {
2158                         int old_viewport_y;
2159
2160                         old_viewport_y = document.ViewPortY;
2161                         document.ViewPortY = this.vscroll.Value;
2162
2163                         //
2164                         // Before scrolling we want to destroy the caret, then draw a new one after the scroll
2165                         // the reason for this is that scrolling changes the coordinates of the caret, and we
2166                         // will get tracers if we don't 
2167                         //
2168                         if (Focused)
2169                                 document.CaretLostFocus ();
2170
2171                         if (hscroll.Visible) {
2172                                 XplatUI.ScrollWindow(this.Handle, new Rectangle(0, 0, ClientSize.Width, ClientSize.Height - hscroll.Height), 0, old_viewport_y - this.vscroll.Value, false);
2173                         } else {
2174                                 XplatUI.ScrollWindow(this.Handle, ClientRectangle, 0, old_viewport_y - this.vscroll.Value, false);
2175                         }
2176
2177                         ScrollLinks (0, old_viewport_y - this.vscroll.Value);
2178
2179                         if (Focused)
2180                                 document.CaretHasFocus ();
2181
2182                         EventHandler eh = (EventHandler)(Events [VScrolledEvent]);
2183                         if (eh != null)
2184                                 eh (this, EventArgs.Empty);
2185                 }
2186
2187                 private void TextBoxBase_MouseMove (object sender, MouseEventArgs e)
2188                 {
2189                         // FIXME - handle auto-scrolling if mouse is to the right/left of the window
2190                         if (e.Button == MouseButtons.Left && Capture) {
2191                                 if (!ClientRectangle.Contains (e.X, e.Y)) {
2192                                         if (scroll_timer == null) {
2193                                                 scroll_timer = new Timer ();
2194                                                 scroll_timer.Interval = 100;
2195                                                 scroll_timer.Tick += new EventHandler (ScrollTimerTickHandler);
2196                                         }
2197
2198                                         if (!scroll_timer.Enabled) {
2199                                                 scroll_timer.Start ();
2200
2201                                                 // Force the first tick
2202                                                 ScrollTimerTickHandler (null, EventArgs.Empty);
2203                                         }
2204                                 }
2205
2206                                 document.PositionCaret(e.X + document.ViewPortX, e.Y + document.ViewPortY);
2207                                 if (click_mode == CaretSelection.Position) {
2208                                         document.SetSelectionToCaret(false);
2209                                         document.DisplayCaret();
2210                                 }
2211                         }
2212
2213                         //search through link boxes to see if the mouse is over one of them
2214
2215                         bool found_link = false;
2216                         foreach (LinkRectangle link in list_links) {
2217                                 if (link.LinkAreaRectangle.Contains (e.X, e.Y)) {
2218                                         XplatUI.SetCursor (window.Handle, Cursors.Hand.handle);
2219
2220                                         found_link = true;
2221                                         current_link = link;
2222                                         break;
2223                                 }
2224                         }
2225
2226                         if (found_link == false) {
2227                                 XplatUI.SetCursor (window.Handle, DefaultCursor.handle);
2228                                 current_link = null;
2229                         }
2230                 }
2231
2232                 private void TextBoxBase_FontOrColorChanged (object sender, EventArgs e)
2233                 {
2234                         Line    line;
2235
2236                         document.SuspendRecalc ();
2237                         // Font changes apply to the whole document
2238                         for (int i = 1; i <= document.Lines; i++) {
2239                                 line = document.GetLine(i);
2240                                 if (LineTag.FormatText(line, 1, line.text.Length, Font, ForeColor,
2241                                                 Color.Empty, FormatSpecified.Font | FormatSpecified.Color))
2242                                         document.RecalculateDocument (CreateGraphicsInternal (), line.LineNo, line.LineNo, false);
2243                         }
2244                         document.ResumeRecalc (false);
2245
2246                         // Make sure the caret height is matching the new font height
2247                         document.AlignCaret();
2248                 }
2249
2250                 private void ScrollTimerTickHandler (object sender, EventArgs e)
2251                 {
2252                         Point pt = Cursor.Position;
2253
2254                         pt = PointToClient (pt);
2255
2256                         if (pt.X < ClientRectangle.Left) {
2257                                 document.MoveCaret(CaretDirection.CharBackNoWrap);
2258                                 document.SetSelectionToCaret(false);
2259                                 
2260                                 CaretMoved(this, null);
2261                         } else if (pt.X > ClientRectangle.Right) {
2262                                 document.MoveCaret(CaretDirection.CharForwardNoWrap);
2263                                 document.SetSelectionToCaret(false);
2264                                 
2265                                 CaretMoved(this, null);
2266                         } else if (pt.Y > ClientRectangle.Bottom) {
2267                                 document.MoveCaret(CaretDirection.LineDown);
2268                                 document.SetSelectionToCaret(false);
2269                                 
2270                                 CaretMoved(this, null);
2271                         } else if (pt.Y < ClientRectangle.Top) {
2272                                 document.MoveCaret(CaretDirection.LineUp);
2273                                 document.SetSelectionToCaret(false);
2274                                 
2275                                 CaretMoved(this, null);
2276                         }
2277                 }
2278
2279                 /// <summary>Ensure the caret is always visible</summary>
2280                 internal void CaretMoved (object sender, EventArgs e)
2281                 {
2282                         Point   pos;
2283                         int     height;
2284
2285                         if (!IsHandleCreated || canvas_width < 1 || canvas_height < 1)
2286                                 return;
2287
2288                         document.MoveCaretToTextTag ();
2289                         pos = document.Caret;
2290
2291                         //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);
2292
2293
2294                         // Horizontal scrolling:
2295                         // If the caret moves to the left outside the visible area, we jump the document into view, not just one
2296                         // character, but 1/3 of the width of the document
2297                         // If the caret moves to the right outside the visible area, we scroll just enough to keep the caret visible
2298
2299                         // Handle horizontal scrolling
2300                         if (document.CaretLine.alignment == HorizontalAlignment.Left) {
2301                                 // Check if we moved out of view to the left
2302                                 if (pos.X < (document.ViewPortX)) {
2303                                         do {
2304                                                 if ((hscroll.Value - document.ViewPortWidth / 3) >= hscroll.Minimum) {
2305                                                         hscroll.SafeValueSet (hscroll.Value - document.ViewPortWidth / 3);
2306                                                 } else {
2307                                                         hscroll.Value = hscroll.Minimum;
2308                                                 }
2309                                         } while (hscroll.Value > pos.X);
2310                                 }
2311
2312                                 // Check if we moved out of view to the right
2313                                 if ((pos.X >= (document.ViewPortWidth + document.ViewPortX)) && (hscroll.Value != hscroll.Maximum)) {
2314                                         if ((pos.X - document.ViewPortWidth + 1) <= hscroll.Maximum) {
2315                                                 if (pos.X - document.ViewPortWidth >= 0) {
2316                                                         hscroll.SafeValueSet (pos.X - document.ViewPortWidth + 1);
2317                                                 } else {
2318                                                         hscroll.Value = 0;
2319                                                 }
2320                                         } else {
2321                                                 hscroll.Value = hscroll.Maximum;
2322                                         }
2323                                 }
2324                         } else if (document.CaretLine.alignment == HorizontalAlignment.Right) {
2325 //                              hscroll.Value = pos.X;
2326
2327 //                              if ((pos.X > (this.canvas_width + document.ViewPortX)) && (hscroll.Enabled && (hscroll.Value != hscroll.Maximum))) {
2328 //                                      hscroll.Value = hscroll.Maximum;
2329 //                              }
2330                         } else {
2331                                 // FIXME - implement center cursor alignment
2332                         }
2333
2334                         if (Text.Length > 0)
2335                                 RaiseSelectionChanged ();
2336                         
2337                         if (!document.multiline)
2338                                 return;
2339
2340                         // Handle vertical scrolling
2341                         height = document.CaretLine.Height + 1;
2342
2343                         if (pos.Y < document.ViewPortY)
2344                                 vscroll.SafeValueSet (pos.Y);
2345                         if ((pos.Y + height) > (document.ViewPortY + canvas_height))
2346                                 vscroll.Value = Math.Min (vscroll.Maximum, pos.Y - canvas_height + height);
2347                 }
2348
2349                 internal bool Paste (IDataObject clip, DataFormats.Format format, bool obey_length)
2350                 {
2351                         string          s;
2352
2353                         if (clip == null)
2354                                 return false;
2355
2356                         if (format == null) {
2357                                 if ((this is RichTextBox) && clip.GetDataPresent(DataFormats.Rtf)) {
2358                                         format = DataFormats.GetFormat(DataFormats.Rtf);
2359                                 } else if ((this is RichTextBox) && clip.GetDataPresent (DataFormats.Bitmap)) {
2360                                         format = DataFormats.GetFormat (DataFormats.Bitmap);
2361                                 } else if (clip.GetDataPresent(DataFormats.UnicodeText)) {
2362                                         format = DataFormats.GetFormat(DataFormats.UnicodeText);
2363                                 } else if (clip.GetDataPresent(DataFormats.Text)) {
2364                                         format = DataFormats.GetFormat(DataFormats.Text);
2365                                 } else {
2366                                         return false;
2367                                 }
2368                         } else {
2369                                 if ((format.Name == DataFormats.Rtf) && !(this is RichTextBox)) {
2370                                         return false;
2371                                 }
2372
2373                                 if (!clip.GetDataPresent(format.Name)) {
2374                                         return false;
2375                                 }
2376                         }
2377
2378                         if (format.Name == DataFormats.Rtf) {
2379                                 document.undo.BeginUserAction (Locale.GetText ("Paste"));
2380                                 ((RichTextBox)this).SelectedRtf = (string)clip.GetData(DataFormats.Rtf);
2381                                 document.undo.EndUserAction ();
2382                                 Modified = true;
2383                                 return true;
2384                         } else if (format.Name == DataFormats.Bitmap) {
2385                                 document.undo.BeginUserAction (Locale.GetText ("Paste"));
2386                                 //      document.InsertImage (document.caret.line, document.caret.pos, (Image) clip.GetData (DataFormats.Bitmap));
2387                                 document.MoveCaret (CaretDirection.CharForward);
2388                                 document.undo.EndUserAction ();
2389                                 return true;
2390                         } else if (format.Name == DataFormats.UnicodeText) {
2391                                 s = (string)clip.GetData(DataFormats.UnicodeText);
2392                         } else if (format.Name == DataFormats.Text) {
2393                                 s = (string)clip.GetData(DataFormats.Text);
2394                         } else {
2395                                 return false;
2396                         }
2397
2398                         if (!obey_length) {
2399                                 document.undo.BeginUserAction (Locale.GetText ("Paste"));
2400                                 this.SelectedText = s;
2401                                 document.undo.EndUserAction ();
2402                         } else {
2403                                 if ((s.Length + (document.Length - SelectedText.Length)) < max_length) {
2404                                         document.undo.BeginUserAction (Locale.GetText ("Paste"));
2405                                         this.SelectedText = s;
2406                                         document.undo.EndUserAction ();
2407                                 } else if ((document.Length - SelectedText.Length) < max_length) {
2408                                         document.undo.BeginUserAction (Locale.GetText ("Paste"));
2409                                         this.SelectedText = s.Substring (0, max_length - (document.Length - SelectedText.Length));
2410                                         document.undo.EndUserAction ();
2411                                 }
2412                         }
2413
2414                         Modified = true;
2415                         return true;
2416                 }
2417
2418                 internal virtual Color ChangeBackColor (Color backColor)
2419                 {
2420                         return backColor;
2421                 }
2422
2423                 internal override bool IsInputCharInternal (char charCode)
2424                 {
2425                         return true;
2426                 }
2427                 #endregion      // Private Methods
2428
2429                 #region Private Classes
2430                 internal class LinkRectangle {
2431                         private Rectangle link_area_rectangle;
2432                         private LineTag link_tag;
2433
2434                         public LinkRectangle (Rectangle rect)
2435                         {
2436                                 link_tag = null;
2437                                 link_area_rectangle = rect;
2438                         }
2439
2440                         public Rectangle LinkAreaRectangle {
2441                                 get { return link_area_rectangle; }
2442                                 set { link_area_rectangle = value; }
2443                         }
2444
2445                         public LineTag LinkTag {
2446                                 get { return link_tag; }
2447                                 set { link_tag = value; }
2448                         }
2449
2450                         public void Scroll (int x_change, int y_change)
2451                         {
2452                                 link_area_rectangle.X += x_change;
2453                                 link_area_rectangle.Y += y_change;
2454                         }
2455                 }
2456                 #endregion
2457
2458                 // This is called just before OnTextChanged is called.
2459                 internal virtual void OnTextUpdate ()
2460                 {
2461                 }
2462                 
2463                 protected override void OnTextChanged (EventArgs e)
2464                 {
2465                         base.OnTextChanged (e);
2466                 }
2467
2468                 public virtual int GetLineFromCharIndex (int index)
2469                 {
2470                         Line line_out;
2471                         LineTag tag_out;
2472                         int pos;
2473                         
2474                         document.CharIndexToLineTag (index, out line_out, out tag_out, out pos);
2475
2476                         return line_out.LineNo;
2477                 }
2478
2479                 protected override void OnMouseUp (MouseEventArgs mevent)
2480                 {
2481                         base.OnMouseUp (mevent);
2482                 }
2483         }
2484 }