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