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