2009-02-16 Carlos Alberto Cortez <calberto.cortez@gmail.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / TextBox.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:
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 //     Daniel Nauck    (dna(at)mono-project(dot)de)
25 //
26
27 // NOT COMPLETE
28
29 using System;
30 using System.Collections;
31 using System.ComponentModel;
32 using System.ComponentModel.Design;
33 using System.Drawing;
34 #if NET_2_0
35 using System.Collections.Generic;
36 using System.Runtime.InteropServices;
37 #endif
38
39 namespace System.Windows.Forms {
40
41 #if NET_2_0
42         [ComVisible(true)]
43         [ClassInterface (ClassInterfaceType.AutoDispatch)]
44         [Designer ("System.Windows.Forms.Design.TextBoxDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
45 #endif
46         public class TextBox : TextBoxBase {
47                 #region Variables
48                 private ContextMenu     menu;
49                 private MenuItem        undo;
50                 private MenuItem        cut;
51                 private MenuItem        copy;
52                 private MenuItem        paste;
53                 private MenuItem        delete;
54                 private MenuItem        select_all;
55
56 #if NET_2_0
57                 private bool use_system_password_char;
58                 private AutoCompleteStringCollection auto_complete_custom_source;
59                 private AutoCompleteMode auto_complete_mode = AutoCompleteMode.None;
60                 private AutoCompleteSource auto_complete_source = AutoCompleteSource.None;
61                 private AutoCompleteListBox auto_complete_listbox;
62                 private string auto_complete_original_text;
63                 private int auto_complete_selected_index = -1;
64                 private List<string> auto_complete_matches;
65                 private ComboBox auto_complete_cb_source;
66 #endif
67                 #endregion      // Variables
68
69                 #region Public Constructors
70                 public TextBox() {
71
72                         scrollbars = RichTextBoxScrollBars.None;
73                         alignment = HorizontalAlignment.Left;
74                         this.LostFocus +=new EventHandler(TextBox_LostFocus);
75                         this.RightToLeftChanged += new EventHandler (TextBox_RightToLeftChanged);
76 #if NET_2_0
77                         MouseWheel += new MouseEventHandler (TextBox_MouseWheel);
78 #endif
79
80                         BackColor = SystemColors.Window;
81                         ForeColor = SystemColors.WindowText;
82                         backcolor_set = false;
83
84                         SetStyle (ControlStyles.StandardClick | ControlStyles.StandardDoubleClick, false);
85                         SetStyle (ControlStyles.FixedHeight, true);
86
87                         undo = new MenuItem(Locale.GetText("&Undo"));
88                         cut = new MenuItem(Locale.GetText("Cu&t"));
89                         copy = new MenuItem(Locale.GetText("&Copy"));
90                         paste = new MenuItem(Locale.GetText("&Paste"));
91                         delete = new MenuItem(Locale.GetText("&Delete"));
92                         select_all = new MenuItem(Locale.GetText("Select &All"));
93
94                         menu = new ContextMenu(new MenuItem[] { undo, new MenuItem("-"), cut, copy, paste, delete, new MenuItem("-"), select_all});
95                         ContextMenu = menu;
96
97                         menu.Popup += new EventHandler(menu_Popup);
98                         undo.Click += new EventHandler(undo_Click);
99                         cut.Click += new EventHandler(cut_Click);
100                         copy.Click += new EventHandler(copy_Click);
101                         paste.Click += new EventHandler(paste_Click);
102                         delete.Click += new EventHandler(delete_Click);
103                         select_all.Click += new EventHandler(select_all_Click);
104
105                         document.multiline = false;
106                 }
107
108                 #endregion      // Public Constructors
109
110                 #region Private & Internal Methods
111
112                 void TextBox_RightToLeftChanged (object sender, EventArgs e)
113                 {
114                         UpdateAlignment ();
115                 }
116
117                 private void TextBox_LostFocus (object sender, EventArgs e) {
118                         if (hide_selection)
119                                 document.InvalidateSelectionArea ();
120 #if NET_2_0
121                         if (auto_complete_listbox != null && auto_complete_listbox.Visible)
122                                 auto_complete_listbox.HideListBox (false);
123 #endif
124                 }
125
126 #if NET_2_0
127                 private void TextBox_MouseWheel (object o, MouseEventArgs args)
128                 {
129                         if (auto_complete_listbox == null || !auto_complete_listbox.Visible)
130                                 return;
131
132                         int lines = args.Delta / 120;
133                         auto_complete_listbox.Scroll (-lines);
134                 }
135
136                 private void ShowAutoCompleteListBox (bool is_backspace)
137                 {
138                         // 
139                         // We only support CustomSource by now
140                         //
141
142                         IList source;
143                         if (auto_complete_cb_source == null)
144                                 source = auto_complete_custom_source;
145                         else
146                                 source = auto_complete_cb_source.Items;
147
148                         if (source == null || source.Count == 0)
149                                 return;
150
151                         bool append = auto_complete_mode == AutoCompleteMode.Append || auto_complete_mode == AutoCompleteMode.SuggestAppend;
152                         bool suggest = auto_complete_mode == AutoCompleteMode.Suggest || auto_complete_mode == AutoCompleteMode.SuggestAppend;
153
154                         if (Text.Length == 0) {
155                                 if (auto_complete_listbox != null)
156                                         auto_complete_listbox.HideListBox (false);
157                                 return;
158                         }
159
160                         if (auto_complete_matches == null)
161                                 auto_complete_matches = new List<string> ();
162
163                         string text = Text;
164                         auto_complete_matches.Clear ();
165
166                         for (int i = 0; i < source.Count; i++) {
167                                 string item_text = auto_complete_cb_source == null ? auto_complete_custom_source [i] :
168                                         auto_complete_cb_source.GetItemText (auto_complete_cb_source.Items [i]);
169                                 if (item_text.StartsWith (text, StringComparison.CurrentCultureIgnoreCase))
170                                         auto_complete_matches.Add (item_text);
171                         }
172
173                         auto_complete_matches.Sort ();
174
175                         // Return if we have a single exact match
176                         if ((auto_complete_matches.Count == 0) || (auto_complete_matches.Count == 1 && 
177                                                 auto_complete_matches [0].Equals (text, StringComparison.CurrentCultureIgnoreCase))) {
178
179                                 if (auto_complete_listbox != null && auto_complete_listbox.Visible)
180                                         auto_complete_listbox.HideListBox (false);
181                                 return;
182                         }
183
184                         auto_complete_selected_index = suggest ? -1 : 0;
185
186                         if (suggest) {
187                                 if (auto_complete_listbox == null)
188                                         auto_complete_listbox = new AutoCompleteListBox (this);
189
190                                 // Show or update auto complete listbox contents
191                                 auto_complete_listbox.Location = PointToScreen (new Point (0, Height));
192                                 auto_complete_listbox.ShowListBox ();
193                         }
194
195                         if (append && !is_backspace)
196                                 AppendAutoCompleteMatch (0);
197
198                         document.MoveCaret (CaretDirection.End);
199                 }
200
201                 internal void HideAutoCompleteList ()
202                 {
203                         if (auto_complete_listbox != null)
204                                 auto_complete_listbox.HideListBox (false);
205                 }
206
207                 bool IsAutoCompleteAvailable {
208                         get {
209                                 if (auto_complete_source == AutoCompleteSource.None || auto_complete_mode == AutoCompleteMode.None)
210                                         return false;
211
212                                 // We only support CustomSource by now
213                                 if (auto_complete_source != AutoCompleteSource.CustomSource || auto_complete_custom_source == null ||
214                                                 auto_complete_custom_source.Count == 0)
215                                         return false;
216
217                                 return true;
218                         }
219                 }
220
221                 internal ComboBox AutoCompleteInternalSource {
222                         get {
223                                 return auto_complete_cb_source;
224                         }
225                         set {
226                                 auto_complete_cb_source = value;
227                         }
228                 }
229
230                 internal bool CanNavigateAutoCompleteList {
231                         get {
232                                 if (auto_complete_mode == AutoCompleteMode.None)
233                                         return false;
234                                 if (auto_complete_matches == null || auto_complete_matches.Count == 0)
235                                         return false;
236
237                                 bool suggest_window_visible = auto_complete_listbox != null && auto_complete_listbox.Visible;
238                                 if (auto_complete_mode == AutoCompleteMode.Suggest && !suggest_window_visible)
239                                         return false;
240
241                                 return true;
242                         }
243                 }
244
245                 bool NavigateAutoCompleteList (Keys key)
246                 {
247                         if (auto_complete_matches == null || auto_complete_matches.Count == 0)
248                                 return false;
249
250                         bool suggest_window_visible = auto_complete_listbox != null && auto_complete_listbox.Visible;
251                         if (!suggest_window_visible && auto_complete_mode == AutoCompleteMode.Suggest)
252                                 return false;
253
254                         int index = auto_complete_selected_index;
255
256                         switch (key) {
257                                 case Keys.Up:
258                                         index -= 1;
259                                         if (index < -1)
260                                                 index = auto_complete_matches.Count - 1;
261                                         break;
262                                 case Keys.Down:
263                                         index += 1;
264                                         if (index >= auto_complete_matches.Count)
265                                                 index = -1;
266                                         break;
267                                 case Keys.PageUp:
268                                         if (auto_complete_mode == AutoCompleteMode.Append || !suggest_window_visible)
269                                                 goto case Keys.Up;
270
271                                         if (index == -1)
272                                                 index = auto_complete_matches.Count - 1;
273                                         else if (index == 0)
274                                                 index = -1;
275                                         else {
276                                                 index -= auto_complete_listbox.page_size - 1;
277                                                 if (index < 0)
278                                                         index = 0;
279                                         }
280                                         break;
281                                 case Keys.PageDown:
282                                         if (auto_complete_mode == AutoCompleteMode.Append || !suggest_window_visible)
283                                                 goto case Keys.Down;
284
285                                         if (index == -1)
286                                                 index = 0;
287                                         else if (index == auto_complete_matches.Count - 1)
288                                                 index = -1;
289                                         else {
290                                                 index += auto_complete_listbox.page_size - 1;
291                                                 if (index >= auto_complete_matches.Count)
292                                                         index = auto_complete_matches.Count - 1;
293                                         }
294                                         break;
295                                 default:
296                                         break;
297                         }
298
299                         // In SuggestAppend mode the navigation mode depends on the visibility of the suggest lb.
300                         bool suggest = auto_complete_mode == AutoCompleteMode.Suggest || auto_complete_mode == AutoCompleteMode.SuggestAppend;
301                         if (suggest && suggest_window_visible) {
302                                 Text = index == -1 ? auto_complete_original_text : auto_complete_matches [index];
303                                 auto_complete_listbox.HighlightedIndex = index;
304                         } else
305                                 // Append only, not suggest at all
306                                 AppendAutoCompleteMatch (index < 0 ? 0 : index);
307                                 
308                         auto_complete_selected_index = index;
309                         document.MoveCaret (CaretDirection.End);
310
311                         return true;
312                 }
313
314                 void AppendAutoCompleteMatch (int index)
315                 {
316                         Text = auto_complete_original_text + auto_complete_matches [index].Substring (auto_complete_original_text.Length);
317                         SelectionStart = auto_complete_original_text.Length;
318                         SelectionLength = auto_complete_matches [index].Length - auto_complete_original_text.Length;
319                 }
320
321 #endif
322
323                 private void UpdateAlignment ()
324                 {
325                         HorizontalAlignment new_alignment = alignment;
326                         RightToLeft rtol = GetInheritedRtoL ();
327
328                         if (rtol == RightToLeft.Yes) {
329                                 if (new_alignment == HorizontalAlignment.Left)
330                                         new_alignment = HorizontalAlignment.Right;
331                                 else if (new_alignment == HorizontalAlignment.Right)
332                                         new_alignment = HorizontalAlignment.Left;
333                         }
334
335                         document.alignment = new_alignment;
336
337                         // MS word-wraps if alignment isn't left
338                         if (Multiline) {
339                                 if (alignment != HorizontalAlignment.Left) {
340                                         document.Wrap = true;
341                                 } else {
342                                         document.Wrap = word_wrap;
343                                 }
344                         }
345
346                         for (int i = 1; i <= document.Lines; i++) {
347                                 document.GetLine (i).Alignment = new_alignment;
348                         }
349
350                         document.RecalculateDocument (CreateGraphicsInternal ());
351
352                         Invalidate ();  // Make sure we refresh
353                 }
354
355                 internal override Color ChangeBackColor (Color backColor)
356                 {
357                         if (backColor == Color.Empty) {
358 #if NET_2_0
359                                 if (!ReadOnly)
360                                         backColor = SystemColors.Window;
361 #else
362                                 backColor = SystemColors.Window;
363 #endif
364                                 backcolor_set = false;
365                         }
366                         return backColor;
367                 }
368
369 #if NET_2_0
370                 void OnAutoCompleteCustomSourceChanged(object sender, CollectionChangeEventArgs e) {
371                         if(auto_complete_source == AutoCompleteSource.CustomSource) {
372                                 //FIXME: handle add, remove and refresh events in AutoComplete algorithm.
373                         }
374                 }
375 #endif
376                 #endregion      // Private & Internal Methods
377
378                 #region Public Instance Properties
379 #if NET_2_0
380                 [MonoTODO("AutoCompletion algorithm is currently not implemented.")]
381                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
382                 [Browsable (true)]
383                 [EditorBrowsable (EditorBrowsableState.Always)]
384                 [Localizable (true)]
385                 [Editor ("System.Windows.Forms.Design.ListControlStringCollectionEditor, " + Consts.AssemblySystem_Design,
386                  "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
387                 public AutoCompleteStringCollection AutoCompleteCustomSource { 
388                         get {
389                                 if(auto_complete_custom_source == null) {
390                                         auto_complete_custom_source = new AutoCompleteStringCollection ();
391                                         auto_complete_custom_source.CollectionChanged += new CollectionChangeEventHandler (OnAutoCompleteCustomSourceChanged);
392                                 }
393                                 return auto_complete_custom_source;
394                         }
395                         set {
396                                 if(auto_complete_custom_source == value)
397                                         return;
398
399                                 if(auto_complete_custom_source != null) //remove eventhandler from old collection
400                                         auto_complete_custom_source.CollectionChanged -= new CollectionChangeEventHandler (OnAutoCompleteCustomSourceChanged);
401
402                                 auto_complete_custom_source = value;
403
404                                 if(auto_complete_custom_source != null)
405                                         auto_complete_custom_source.CollectionChanged += new CollectionChangeEventHandler (OnAutoCompleteCustomSourceChanged);
406                         }
407                 }
408
409                 [MonoTODO("AutoCompletion algorithm is currently not implemented.")]
410                 [Browsable (true)]
411                 [EditorBrowsable (EditorBrowsableState.Always)]
412                 [DefaultValue (AutoCompleteMode.None)]
413                 public AutoCompleteMode AutoCompleteMode {
414                         get { return auto_complete_mode; }
415                         set {
416                                 if(auto_complete_mode == value)
417                                         return;
418
419                                 if((value < AutoCompleteMode.None) || (value > AutoCompleteMode.SuggestAppend))
420                                         throw new InvalidEnumArgumentException (Locale.GetText ("Enum argument value '{0}' is not valid for AutoCompleteMode", value));
421
422                                 auto_complete_mode = value;
423                         }
424                 }
425
426                 [MonoTODO("AutoCompletion algorithm is currently not implemented.")]
427                 [Browsable (true)]
428                 [EditorBrowsable (EditorBrowsableState.Always)]
429                 [DefaultValue (AutoCompleteSource.None)]
430                 [TypeConverter (typeof (TextBoxAutoCompleteSourceConverter))]
431                 public AutoCompleteSource AutoCompleteSource {
432                         get { return auto_complete_source; }
433                         set {
434                                 if(auto_complete_source == value)
435                                         return;
436
437                                 if(!Enum.IsDefined (typeof (AutoCompleteSource), value))
438                                         throw new InvalidEnumArgumentException (Locale.GetText ("Enum argument value '{0}' is not valid for AutoCompleteSource", value));
439
440                                 auto_complete_source = value;
441                         }
442                 }
443
444                 [DefaultValue(false)]
445                 [RefreshProperties (RefreshProperties.Repaint)]
446                 public bool UseSystemPasswordChar {
447                         get {
448                                 return use_system_password_char;
449                         }
450
451                         set {
452                                 if (use_system_password_char != value) {
453                                         use_system_password_char = value;
454                                         
455                                         if (!Multiline)
456                                                 document.PasswordChar = PasswordChar.ToString ();
457                                         else
458                                                 document.PasswordChar = string.Empty;
459                                         Invalidate ();
460                                 }
461                         }
462                 }
463 #endif
464
465                 [DefaultValue(false)]
466                 [MWFCategory("Behavior")]
467                 public bool AcceptsReturn {
468                         get {
469                                 return accepts_return;
470                         }
471
472                         set {
473                                 if (value != accepts_return) {
474                                         accepts_return = value;
475                                 }
476                         }
477                 }
478
479                 [DefaultValue(CharacterCasing.Normal)]
480                 [MWFCategory("Behavior")]
481                 public CharacterCasing CharacterCasing {
482                         get {
483                                 return character_casing;
484                         }
485
486                         set {
487                                 if (value != character_casing) {
488                                         character_casing = value;
489                                 }
490                         }
491                 }
492
493                 [Localizable(true)]
494                 [DefaultValue('\0')]
495                 [MWFCategory("Behavior")]
496 #if NET_2_0
497                 [RefreshProperties (RefreshProperties.Repaint)]
498 #endif
499                 public char PasswordChar {
500                         get {
501 #if NET_2_0
502                                 if (use_system_password_char) {
503                                         return '*';
504                                 }
505 #endif
506                                 return password_char;
507                         }
508
509                         set {
510                                 if (value != password_char) {
511                                         password_char = value;
512                                         if (!Multiline) {
513                                                 document.PasswordChar = PasswordChar.ToString ();
514                                         } else {
515                                                 document.PasswordChar = string.Empty;
516                                         }
517                                         this.CalculateDocument();
518                                 }
519                         }
520                 }
521
522                 [DefaultValue(ScrollBars.None)]
523                 [Localizable(true)]
524                 [MWFCategory("Appearance")]
525                 public ScrollBars ScrollBars {
526                         get {
527                                 return (ScrollBars)scrollbars;
528                         }
529
530                         set {
531                                 if (!Enum.IsDefined (typeof (ScrollBars), value))
532                                         throw new InvalidEnumArgumentException ("value", (int) value,
533                                                 typeof (ScrollBars));
534
535                                 if (value != (ScrollBars)scrollbars) {
536                                         scrollbars = (RichTextBoxScrollBars)value;
537                                         base.CalculateScrollBars();
538                                 }
539                         }
540                 }
541
542 #if ONLY_1_1
543                 [Browsable(false)]
544                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
545                 public override int SelectionLength {
546                         get {
547                                 return base.SelectionLength;
548                         }
549                         set {
550                                 base.SelectionLength = value;
551                         }
552                 }
553 #endif
554
555                 public override string Text {
556                         get {
557                                 return base.Text;
558                         }
559
560                         set {
561                                 base.Text = value;
562                         }
563                 }
564
565                 [DefaultValue(HorizontalAlignment.Left)]
566                 [Localizable(true)]
567                 [MWFCategory("Appearance")]
568                 public HorizontalAlignment TextAlign {
569                         get {
570                                 return alignment;
571                         }
572
573                         set {
574                                 if (value != alignment) {
575                                         alignment = value;
576
577                                         UpdateAlignment ();
578
579                                         OnTextAlignChanged(EventArgs.Empty);
580                                 }
581                         }
582                 }
583                 #endregion      // Public Instance Properties
584
585 #if NET_2_0
586                 public void Paste (string text)
587                 {
588                         document.ReplaceSelection (CaseAdjust (text), false);
589
590                         ScrollToCaret();
591                         OnTextChanged(EventArgs.Empty);
592                 }
593 #endif
594                 #region Protected Instance Methods
595                 protected override CreateParams CreateParams {
596                         get {
597                                 return base.CreateParams;
598                         }
599                 }
600
601 #if ONLY_1_1
602                 protected override ImeMode DefaultImeMode {
603                         get {
604                                 return base.DefaultImeMode;
605                         }
606                 }
607 #endif
608 #if NET_2_0
609                 protected override void Dispose (bool disposing)
610                 {
611                         base.Dispose (disposing);
612                 }
613 #endif
614
615                 protected override bool IsInputKey (Keys keyData)
616                 {
617                         return base.IsInputKey (keyData);
618                 }
619
620                 protected override void OnGotFocus (EventArgs e)
621                 {
622                         base.OnGotFocus (e);
623                         if (selection_length == -1 && !has_been_focused)
624                                 SelectAllNoScroll ();
625                         has_been_focused = true;
626                 }
627
628                 protected override void OnHandleCreated (EventArgs e)
629                 {
630                         base.OnHandleCreated (e);
631                 }
632
633 #if ONLY_1_1
634                 protected override void OnMouseUp(MouseEventArgs mevent)
635                 {
636                         base.OnMouseUp (mevent);
637                 }
638 #endif
639
640                 protected virtual void OnTextAlignChanged (EventArgs e)
641                 {
642                         EventHandler eh = (EventHandler)(Events [TextAlignChangedEvent]);
643                         if (eh != null)
644                                 eh (this, e);
645                 }
646
647                 protected override void WndProc (ref Message m)
648                 {
649                         switch ((Msg)m.Msg) {
650 #if NET_2_0
651                                 case Msg.WM_KEYDOWN:
652                                         if (!IsAutoCompleteAvailable)
653                                                 break;
654
655                                         Keys key_data = (Keys)m.WParam.ToInt32 ();
656                                         switch (key_data) {
657                                                 case Keys.Down:
658                                                 case Keys.Up:
659                                                 case Keys.PageDown:
660                                                 case Keys.PageUp:
661                                                         if (NavigateAutoCompleteList (key_data)) {
662                                                                 m.Result = IntPtr.Zero;
663                                                                 return;
664                                                         }
665                                                         break;
666                                                 case Keys.Enter:
667                                                         if (auto_complete_listbox != null && auto_complete_listbox.Visible)
668                                                                 auto_complete_listbox.HideListBox (false);
669                                                         SelectAll ();
670                                                         break;
671                                                 case Keys.Escape:
672                                                         if (auto_complete_listbox != null && auto_complete_listbox.Visible)
673                                                                 auto_complete_listbox.HideListBox (false);
674                                                         break;
675                                                 default:
676                                                         break;
677                                         }
678                                         break;
679                                 case Msg.WM_CHAR:
680                                         if (!IsAutoCompleteAvailable)
681                                                 break;
682
683                                         bool is_backspace = m.WParam.ToInt32 () == 8;
684                                         if (!Char.IsLetterOrDigit ((char)m.WParam) && !is_backspace) {
685                                                 // Update Text and save it before returning
686                                                 base.WndProc (ref m);
687                                                 auto_complete_original_text = Text;
688                                                 return;
689                                         }
690                                         
691                                         if (!is_backspace)
692                                                 Text = auto_complete_original_text;
693
694                                         document.MoveCaret (CaretDirection.End);
695
696                                         // Need to call base.WndProc before to have access to
697                                         // the updated Text property value
698                                         base.WndProc (ref m);
699                                         auto_complete_original_text = Text;
700                                         ShowAutoCompleteListBox (is_backspace);
701                                         return;
702 #endif
703                                 case Msg.WM_LBUTTONDOWN:
704                                         // When the textbox gets focus by LBUTTON (but not by middle or right)
705                                         // it does not do the select all / scroll thing.
706                                         has_been_focused = true;
707                                         FocusInternal (true);
708                                         break;
709                         }
710
711                         base.WndProc(ref m);
712                 }
713                 #endregion      // Protected Instance Methods
714
715                 #region Events
716                 static object TextAlignChangedEvent = new object ();
717
718                 public event EventHandler TextAlignChanged {
719                         add { Events.AddHandler (TextAlignChangedEvent, value); }
720                         remove { Events.RemoveHandler (TextAlignChangedEvent, value); }
721                 }
722                 #endregion      // Events
723
724                 #region Private Methods
725
726                 internal override ContextMenu ContextMenuInternal {
727                         get {
728                                 ContextMenu res = base.ContextMenuInternal;
729                                 if (res == menu)
730                                         return null;
731                                 return res;
732                         }
733                         set {
734                                 base.ContextMenuInternal = value;
735                         }
736                 }
737
738                 internal void RestoreContextMenu ()
739                 {
740                         ContextMenuInternal = menu;
741                 }
742
743                 private void menu_Popup(object sender, EventArgs e) {
744                         if (SelectionLength == 0) {
745                                 cut.Enabled = false;
746                                 copy.Enabled = false;
747                         } else {
748                                 cut.Enabled = true;
749                                 copy.Enabled = true;
750                         }
751
752                         if (SelectionLength == TextLength) {
753                                 select_all.Enabled = false;
754                         } else {
755                                 select_all.Enabled = true;
756                         }
757
758                         if (!CanUndo) {
759                                 undo.Enabled = false;
760                         } else {
761                                 undo.Enabled = true;
762                         }
763
764                         if (ReadOnly) {
765                                 undo.Enabled = cut.Enabled = paste.Enabled = delete.Enabled = false;
766                         }
767                 }
768
769                 private void undo_Click(object sender, EventArgs e) {
770                         Undo();
771                 }
772
773                 private void cut_Click(object sender, EventArgs e) {
774                         Cut();
775                 }
776
777                 private void copy_Click(object sender, EventArgs e) {
778                         Copy();
779                 }
780
781                 private void paste_Click(object sender, EventArgs e) {
782                         Paste();
783                 }
784
785                 private void delete_Click(object sender, EventArgs e) {
786                         SelectedText = string.Empty;
787                 }
788
789                 private void select_all_Click(object sender, EventArgs e) {
790                         SelectAll();
791                 }
792                 #endregion      // Private Methods
793
794 #if NET_2_0
795                 public override bool Multiline {
796                         get {
797                                 return base.Multiline;
798                         }
799
800                         set {
801                                 base.Multiline = value;
802                         }
803                 }
804
805                 protected override void OnBackColorChanged (EventArgs e)
806                 {
807                         base.OnBackColorChanged (e);
808                 }
809                 
810                 protected override void OnFontChanged (EventArgs e)
811                 {
812                         base.OnFontChanged (e);
813                 }
814
815                 protected override void OnHandleDestroyed (EventArgs e)
816                 {
817                         base.OnHandleDestroyed (e);
818                 }
819
820                 class AutoCompleteListBox : Control
821                 {
822                         TextBox owner;
823                         VScrollBar vscroll;
824                         int top_item;
825                         int last_item;
826                         internal int page_size;
827                         int item_height;
828                         int highlighted_index = -1;
829                         bool user_defined_size;
830                         bool resizing;
831                         Rectangle resizer_bounds;
832
833                         const int DefaultDropDownItems = 7;
834
835                         public AutoCompleteListBox (TextBox tb)
836                         {
837                                 owner = tb;
838                                 item_height = FontHeight + 2;
839
840                                 vscroll = new VScrollBar ();
841                                 vscroll.ValueChanged += VScrollValueChanged;
842                                 Controls.Add (vscroll);
843
844                                 is_visible = false;
845                                 InternalBorderStyle = BorderStyle.FixedSingle;
846                         }
847
848                         protected override CreateParams CreateParams {
849                                 get {
850                                         CreateParams cp = base.CreateParams;
851
852                                         cp.Style ^= (int)WindowStyles.WS_CHILD;
853                                         cp.Style ^= (int)WindowStyles.WS_VISIBLE;
854                                         cp.Style |= (int)WindowStyles.WS_POPUP;
855                                         cp.ExStyle |= (int)WindowExStyles.WS_EX_TOPMOST | (int)WindowExStyles.WS_EX_TOOLWINDOW;
856                                         return cp;
857                                 }
858                         }
859
860                         public int HighlightedIndex {
861                                 get {
862                                         return highlighted_index;
863                                 }
864                                 set {
865                                         if (value == highlighted_index)
866                                                 return;
867
868                                         if (highlighted_index != -1)
869                                                 Invalidate (GetItemBounds (highlighted_index));
870                                         highlighted_index = value;
871                                         if (highlighted_index != -1)
872                                                 Invalidate (GetItemBounds (highlighted_index));
873
874                                         if (highlighted_index != -1)
875                                                 EnsureVisible (highlighted_index);
876                                 }
877                         }
878
879                         public void Scroll (int lines)
880                         {
881                                 int max = vscroll.Maximum - page_size + 1;
882                                 int val = vscroll.Value + lines;
883                                 if (val > max)
884                                         val = max;
885                                 else if (val < vscroll.Minimum)
886                                         val = vscroll.Minimum;
887
888                                 vscroll.Value = val;
889                         }
890
891                         public void EnsureVisible (int index)
892                         {
893                                 if (index < top_item) {
894                                         vscroll.Value = index;
895                                 } else {
896                                         int max = vscroll.Maximum - page_size + 1;
897                                         int rows = Height / item_height;
898                                         if (index > top_item + rows - 1) {
899                                                 index = index - rows + 1;
900                                                 vscroll.Value = index > max ? max : index;
901                                         }
902                                 }
903                         }
904
905                         internal override bool ActivateOnShow {
906                                 get {
907                                         return false;
908                                 }
909                         }
910
911                         void VScrollValueChanged (object o, EventArgs args)
912                         {
913                                 if (top_item == vscroll.Value)
914                                         return;
915
916                                 top_item = vscroll.Value;
917                                 last_item = GetLastVisibleItem ();
918                                 Invalidate ();
919                         }
920
921                         int GetLastVisibleItem ()
922                         {
923                                 int top_y = Height;
924
925                                 for (int i = top_item; i < owner.auto_complete_matches.Count; i++) {
926                                         int pos = i - top_item; // relative to visible area
927                                         if ((pos * item_height) + item_height >= top_y)
928                                                 return i;
929                                 }
930
931                                 return owner.auto_complete_matches.Count - 1;
932                         }
933
934                         Rectangle GetItemBounds (int index)
935                         {
936                                 int pos = index - top_item;
937                                 Rectangle bounds = new Rectangle (0, pos * item_height, Width, item_height);
938                                 if (vscroll.Visible)
939                                         bounds.Width -= vscroll.Width;
940
941                                 return bounds;
942                         }
943
944                         int GetItemAt (Point loc)
945                         {
946                                 if (loc.Y > (last_item - top_item) * item_height + item_height)
947                                         return -1;
948
949                                 int retval = loc.Y / item_height;
950                                 retval += top_item;
951
952                                 return retval;
953                         }
954
955                         void LayoutListBox ()
956                         {
957                                 int total_height = owner.auto_complete_matches.Count * item_height;
958                                 page_size = Math.Max (Height / item_height, 1);
959                                 last_item = GetLastVisibleItem ();
960
961                                 if (Height < total_height) {
962                                         vscroll.Visible = true;
963                                         vscroll.Maximum = owner.auto_complete_matches.Count - 1;
964                                         vscroll.LargeChange = page_size;
965                                         vscroll.Location = new Point (Width - vscroll.Width, 0);
966                                         vscroll.Height = Height - item_height;
967                                 } else
968                                         vscroll.Visible = false;
969
970                                 resizer_bounds = new Rectangle (Width - item_height, Height - item_height,
971                                                 item_height, item_height);
972                         }
973
974                         public void HideListBox (bool set_text)
975                         {
976                                 if (set_text)
977                                         owner.Text = owner.auto_complete_matches [HighlightedIndex];
978
979                                 Capture = false;
980                                 Hide ();
981                         }
982
983                         public void ShowListBox ()
984                         {
985                                 if (!user_defined_size) {
986                                         // This should call the Layout routine for us
987                                         int height = owner.auto_complete_matches.Count > DefaultDropDownItems ? 
988                                                 DefaultDropDownItems * item_height : (owner.auto_complete_matches.Count + 1) * item_height;
989                                         Size = new Size (owner.Width, height);
990                                 } else
991                                         LayoutListBox ();
992
993                                 vscroll.Value = 0;
994                                 HighlightedIndex = -1;
995
996                                 Show ();
997                                 Invalidate ();
998                         }
999
1000                         protected override void OnResize (EventArgs args)
1001                         {
1002                                 base.OnResize (args);
1003
1004                                 LayoutListBox ();
1005                                 Refresh ();
1006                         }
1007
1008                         protected override void OnMouseDown (MouseEventArgs args)
1009                         {
1010                                 base.OnMouseDown (args);
1011
1012                                 if (!resizer_bounds.Contains (args.Location))
1013                                         return;
1014
1015                                 user_defined_size = true;
1016                                 resizing = true;
1017                                 Capture = true;
1018                         }
1019
1020                         protected override void OnMouseMove (MouseEventArgs args)
1021                         {
1022                                 base.OnMouseMove (args);
1023
1024                                 if (resizing) {
1025                                         Point mouse_loc = Control.MousePosition;
1026                                         Point ctrl_loc = PointToScreen (Point.Empty);
1027
1028                                         Size new_size = new Size (mouse_loc.X - ctrl_loc.X, mouse_loc.Y - ctrl_loc.Y);
1029                                         if (new_size.Height < item_height)
1030                                                 new_size.Height = item_height;
1031                                         if (new_size.Width < item_height)
1032                                                 new_size.Width = item_height;
1033
1034                                         Size = new_size;
1035                                         return;
1036                                 }
1037
1038                                 Cursor = resizer_bounds.Contains (args.Location) ? Cursors.SizeNWSE : Cursors.Default;
1039
1040                                 int item_idx = GetItemAt (args.Location);
1041                                 if (item_idx != -1)
1042                                         HighlightedIndex = item_idx;
1043                         }
1044
1045                         protected override void OnMouseUp (MouseEventArgs args)
1046                         {
1047                                 base.OnMouseUp (args);
1048
1049                                 int item_idx = GetItemAt (args.Location);
1050                                 if (item_idx != -1 && !resizing)
1051                                         HideListBox (true);
1052
1053                                 resizing = false;
1054                                 Capture = false;
1055                         }
1056
1057                         internal override void OnPaintInternal (PaintEventArgs args)
1058                         {
1059                                 Graphics g = args.Graphics;
1060                                 Brush brush = ThemeEngine.Current.ResPool.GetSolidBrush (ForeColor);
1061
1062                                 int highlighted_idx = HighlightedIndex;
1063
1064                                 int y = 0;
1065                                 int last = GetLastVisibleItem ();
1066                                 for (int i = top_item; i <= last; i++) {
1067                                         Rectangle item_bounds = GetItemBounds (i);
1068                                         if (!item_bounds.IntersectsWith (args.ClipRectangle))
1069                                                 continue;
1070
1071                                         if (i == highlighted_idx) {
1072                                                 g.FillRectangle (SystemBrushes.Highlight, item_bounds);
1073                                                 g.DrawString (owner.auto_complete_matches [i], Font, SystemBrushes.HighlightText, item_bounds);
1074                                         } else 
1075                                                 g.DrawString (owner.auto_complete_matches [i], Font, brush, item_bounds);
1076
1077                                         y += item_height;
1078                                 }
1079
1080                                 ThemeEngine.Current.CPDrawSizeGrip (g, SystemColors.Control, resizer_bounds);
1081                         }
1082                 }
1083 #endif
1084         }
1085         
1086 #if NET_2_0
1087         internal class TextBoxAutoCompleteSourceConverter : EnumConverter
1088         {
1089                 public TextBoxAutoCompleteSourceConverter(Type type)
1090                         : base(type)
1091                 { }
1092
1093                 public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
1094                 {
1095                         StandardValuesCollection stdv = base.GetStandardValues(context);
1096                         AutoCompleteSource[] arr = new AutoCompleteSource[stdv.Count];
1097                         stdv.CopyTo(arr, 0);
1098                         AutoCompleteSource[] arr2 = Array.FindAll(arr, delegate (AutoCompleteSource value) {
1099                                 // No "ListItems" in a TextBox.
1100                                 return value != AutoCompleteSource.ListItems;
1101                         });
1102                         return new StandardValuesCollection(arr2);
1103                 }
1104         }
1105 #endif
1106 }