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