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