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