4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 // Copyright (c) 2007 Novell, Inc.
26 // Rolf Bjarne Kvinge (RKvinge@novell.com)
32 using System.Collections;
33 using System.ComponentModel;
35 using System.Drawing.Design;
36 using System.Globalization;
37 using System.Runtime.InteropServices;
38 using System.Security.Permissions;
39 using System.Windows.Forms;
41 namespace System.Windows.Forms
43 [ClassInterface (ClassInterfaceType.AutoDispatch)]
45 [DefaultProperty ("Mask")]
46 [DefaultEvent ("MaskInputRejected")]
47 [Designer ("System.Windows.Forms.Design.MaskedTextBoxDesigner, " + Consts.AssemblySystem_Design)]
48 [DefaultBindingProperty ("Text")]
49 public class MaskedTextBox : TextBoxBase
52 private MaskedTextProvider provider;
53 private bool beep_on_error;
54 private IFormatProvider format_provider;
55 private bool hide_prompt_on_leave;
56 private InsertKeyMode insert_key_mode;
57 private bool insert_key_overwriting;
58 private bool reject_input_on_first_failure;
59 private HorizontalAlignment text_align;
60 private MaskFormat cut_copy_mask_format;
61 private bool use_system_password_char;
62 private Type validating_type;
63 private bool is_empty_mask;
64 private bool setting_text;
68 static object AcceptsTabChangedEvent = new object ();
69 static object IsOverwriteModeChangedEvent = new object ();
70 static object MaskChangedEvent = new object ();
71 static object MaskInputRejectedEvent = new object ();
72 static object MultilineChangedEvent = new object ();
73 static object TextAlignChangedEvent = new object ();
74 static object TypeValidationCompletedEvent = new object ();
76 // This event is never raised by MaskedTextBox.
77 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
79 [EditorBrowsable (EditorBrowsableState.Never)]
80 public new event EventHandler AcceptsTabChanged {
81 add { Events.AddHandler (AcceptsTabChangedEvent, value);}
82 remove { Events.RemoveHandler (AcceptsTabChangedEvent, value);}
85 public event EventHandler IsOverwriteModeChanged {
86 add { Events.AddHandler (IsOverwriteModeChangedEvent, value); }
87 remove { Events.RemoveHandler (IsOverwriteModeChangedEvent, value); }
90 public event EventHandler MaskChanged {
91 add { Events.AddHandler (MaskChangedEvent, value); }
92 remove { Events.RemoveHandler (MaskChangedEvent, value); }
95 public event MaskInputRejectedEventHandler MaskInputRejected {
96 add { Events.AddHandler (MaskInputRejectedEvent, value); }
97 remove { Events.RemoveHandler (MaskInputRejectedEvent, value); }
100 // This event is never raised by MaskedTextBox.
101 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
103 [EditorBrowsable (EditorBrowsableState.Never)]
104 public new event EventHandler MultilineChanged {
105 add { Events.AddHandler (MultilineChangedEvent, value); }
106 remove { Events.RemoveHandler (MultilineChangedEvent, value); }
109 public event EventHandler TextAlignChanged {
110 add { Events.AddHandler (TextAlignChangedEvent, value); }
111 remove { Events.RemoveHandler (TextAlignChangedEvent, value); }
114 public event TypeValidationEventHandler TypeValidationCompleted {
115 add { Events.AddHandler (TypeValidationCompletedEvent, value); }
116 remove { Events.RemoveHandler (TypeValidationCompletedEvent, value); }
121 public MaskedTextBox ()
123 provider = new MaskedTextProvider ("<>", CultureInfo.CurrentCulture);
124 is_empty_mask = true;
128 public MaskedTextBox (MaskedTextProvider maskedTextProvider)
130 if (maskedTextProvider == null) {
131 throw new ArgumentNullException ();
133 provider = maskedTextProvider;
134 is_empty_mask = false;
138 public MaskedTextBox (string mask)
141 throw new ArgumentNullException ();
143 provider = new MaskedTextProvider (mask, CultureInfo.CurrentCulture);
144 is_empty_mask = false;
150 BackColor = SystemColors.Window;
151 cut_copy_mask_format = MaskFormat.IncludeLiterals;
152 insert_key_overwriting = false;
153 UpdateVisibleText ();
157 #region Public and protected methods
158 [EditorBrowsable (EditorBrowsableState.Never)]
159 public new void ClearUndo ()
161 // Do nothing, not supported by MTB
164 [EditorBrowsable (EditorBrowsableState.Advanced)]
165 [UIPermission (SecurityAction.InheritanceDemand, Window = UIPermissionWindow.AllWindows)]
166 protected override void CreateHandle ()
168 base.CreateHandle ();
171 public override char GetCharFromPosition (Point pt)
173 return base.GetCharFromPosition (pt);
176 public override int GetCharIndexFromPosition (Point pt)
178 return base.GetCharIndexFromPosition (pt);
181 [EditorBrowsable (EditorBrowsableState.Never)]
182 public new int GetFirstCharIndexFromLine (int lineNumber)
187 [EditorBrowsable (EditorBrowsableState.Never)]
188 public new int GetFirstCharIndexOfCurrentLine ()
193 [EditorBrowsable (EditorBrowsableState.Never)]
194 public override int GetLineFromCharIndex (int index)
199 public override Point GetPositionFromCharIndex (int index)
201 return base.GetPositionFromCharIndex (index);
204 protected override bool IsInputKey (Keys keyData)
206 return base.IsInputKey (keyData);
209 protected override void OnBackColorChanged (EventArgs e)
211 base.OnBackColorChanged (e);
214 protected override void OnHandleCreated (EventArgs e)
216 base.OnHandleCreated (e);
219 [EditorBrowsable (EditorBrowsableState.Advanced)]
220 protected virtual void OnIsOverwriteModeChanged (EventArgs e)
222 EventHandler eh = (EventHandler) Events [IsOverwriteModeChangedEvent];
227 protected override void OnKeyDown (KeyEventArgs e)
229 // Only handle Delete or Insert here
231 if (e.KeyCode == Keys.Insert && insert_key_mode == InsertKeyMode.Default) {
232 // switch the internal overwriting mode, not the public one
233 insert_key_overwriting = !insert_key_overwriting;
234 OnIsOverwriteModeChanged (EventArgs.Empty);
239 if (e.KeyCode != Keys.Delete || is_empty_mask) {
244 int testPosition, endSelection;
245 MaskedTextResultHint resultHint;
248 // Use a slightly different approach than the one used for backspace
249 endSelection = SelectionLength == 0 ? SelectionStart : SelectionStart + SelectionLength - 1;
250 result = provider.RemoveAt (SelectionStart, endSelection, out testPosition, out resultHint);
252 PostprocessKeyboardInput (result, testPosition, testPosition, resultHint);
257 protected override void OnKeyPress (KeyPressEventArgs e)
264 int testPosition, editPosition;
265 MaskedTextResultHint resultHint;
268 if (e.KeyChar == '\b') {
269 if (SelectionLength == 0)
270 result = provider.RemoveAt (SelectionStart - 1, SelectionStart - 1, out testPosition, out resultHint);
272 result = provider.RemoveAt (SelectionStart, SelectionStart + SelectionLength - 1, out testPosition, out resultHint);
274 editPosition = testPosition;
275 } else if (IsOverwriteMode || SelectionLength > 0) { // Replace
276 int start = provider.FindEditPositionFrom (SelectionStart, true);
277 int end = SelectionLength > 0 ? SelectionStart + SelectionLength - 1 : start;
278 result = provider.Replace (e.KeyChar, start, end, out testPosition, out resultHint);
280 editPosition = testPosition + 1;
282 // Move chars to the right
283 result = provider.InsertAt (e.KeyChar, SelectionStart, out testPosition, out resultHint);
284 editPosition = testPosition + 1;
287 PostprocessKeyboardInput (result, editPosition, testPosition, resultHint);
292 void PostprocessKeyboardInput (bool result, int newPosition, int testPosition, MaskedTextResultHint resultHint)
295 OnMaskInputRejected (new MaskInputRejectedEventArgs (testPosition, resultHint));
297 if (newPosition != MaskedTextProvider.InvalidIndex)
298 SelectionStart = newPosition;
300 SelectionStart = provider.Length;
302 UpdateVisibleText ();
306 protected override void OnKeyUp (KeyEventArgs e)
311 [EditorBrowsable (EditorBrowsableState.Advanced)]
312 protected virtual void OnMaskChanged (EventArgs e)
314 EventHandler eh = (EventHandler) Events [MaskChangedEvent];
319 private void OnMaskInputRejected (MaskInputRejectedEventArgs e)
321 MaskInputRejectedEventHandler eh = (MaskInputRejectedEventHandler) Events [MaskInputRejectedEvent];
326 [EditorBrowsable (EditorBrowsableState.Never)]
327 protected override void OnMultilineChanged (EventArgs e)
329 EventHandler eh = (EventHandler)Events [MultilineChangedEvent];
334 protected virtual void OnTextAlignChanged (EventArgs e)
336 EventHandler eh = (EventHandler)Events [TextAlignChangedEvent];
341 protected override void OnTextChanged (EventArgs e)
343 base.OnTextChanged (e);
346 [EditorBrowsable (EditorBrowsableState.Advanced)]
347 protected override void OnValidating (CancelEventArgs e)
349 base.OnValidating (e);
352 //[SecurityPermission (SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
353 protected override bool ProcessCmdKey (ref Message msg, Keys keyData)
355 return base.ProcessCmdKey (ref msg, keyData);
358 //[SecurityPermission (SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
359 protected internal override bool ProcessKeyMessage (ref Message m)
361 return base.ProcessKeyMessage (ref m);
364 [EditorBrowsable (EditorBrowsableState.Never)]
365 public new void ScrollToCaret ()
367 // MSDN: this method is overridden to perform no actions.
370 public override string ToString ()
372 return base.ToString () + ", Text: " + provider.ToString (false, false);
375 [EditorBrowsable (EditorBrowsableState.Never)]
376 public new void Undo ()
378 // Do nothing, not supported by MTB.
381 public object ValidateText ()
383 throw new NotImplementedException ();
386 //[SecurityPermission (SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
387 protected override void WndProc (ref Message m)
389 switch ((Msg) m.Msg) {
391 base.WndProc (ref m);
398 [EditorBrowsable (EditorBrowsableState.Never)]
399 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
401 public new bool AcceptsTab {
409 [DefaultValue (true)]
410 public bool AllowPromptAsInput {
412 return provider.AllowPromptAsInput;
415 provider = new MaskedTextProvider (provider.Mask, provider.Culture, value, provider.PromptChar, provider.PasswordChar, provider.AsciiOnly);
416 UpdateVisibleText ();
420 [RefreshProperties (RefreshProperties.Repaint)]
421 [DefaultValue (false)]
422 public bool AsciiOnly {
424 return provider.AsciiOnly;
427 provider = new MaskedTextProvider (provider.Mask, provider.Culture, provider.AllowPromptAsInput, provider.PromptChar, provider.PasswordChar, value);
428 UpdateVisibleText ();
432 [DefaultValue (false)]
433 public bool BeepOnError {
435 return beep_on_error;
438 beep_on_error = value;
443 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
444 [EditorBrowsable (EditorBrowsableState.Never)]
445 public new bool CanUndo {
451 protected override CreateParams CreateParams {
452 //[SecurityPermission (SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
454 return base.CreateParams;
458 [RefreshProperties (RefreshProperties.Repaint)]
459 public CultureInfo Culture {
461 return provider.Culture;
464 provider = new MaskedTextProvider (provider.Mask, value, provider.AllowPromptAsInput, provider.PromptChar, provider.PasswordChar, provider.AsciiOnly);
465 UpdateVisibleText ();
469 [RefreshProperties (RefreshProperties.Repaint)]
470 [DefaultValue (MaskFormat.IncludeLiterals)]
471 public MaskFormat CutCopyMaskFormat {
473 return cut_copy_mask_format;
476 if (!Enum.IsDefined (typeof (MaskFormat), value)) {
477 throw new InvalidEnumArgumentException ("value", (int)value, typeof (MaskFormat));
479 cut_copy_mask_format = value;
483 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
485 public IFormatProvider FormatProvider {
487 return format_provider;
490 format_provider = value;
494 [RefreshProperties (RefreshProperties.Repaint)]
495 [DefaultValue (false)]
496 public bool HidePromptOnLeave {
498 return hide_prompt_on_leave;
501 hide_prompt_on_leave = value;
505 [DefaultValue (InsertKeyMode.Default)]
506 public InsertKeyMode InsertKeyMode {
508 return insert_key_mode;
511 if (!Enum.IsDefined (typeof (InsertKeyMode), value)) {
512 throw new InvalidEnumArgumentException ("value", (int)value, typeof (InsertKeyMode));
514 insert_key_mode = value;
519 public bool IsOverwriteMode {
521 if (insert_key_mode == InsertKeyMode.Default) {
522 return insert_key_overwriting;
524 return insert_key_mode == InsertKeyMode.Overwrite;
529 [EditorBrowsable (EditorBrowsableState.Never)]
530 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
532 public new string [] Lines {
535 if (text == null || text == string.Empty)
536 return new string [] {};
538 return Text.Split (new string [] {"\r\n", "\r", "\n"}, StringSplitOptions.None);
541 // Do nothing, not supported by MTB.
546 [Editor ("System.Windows.Forms.Design.MaskPropertyEditor, " + Consts.AssemblySystem_Design, typeof (UITypeEditor))]
547 [RefreshProperties (RefreshProperties.Repaint)]
548 [MergablePropertyAttribute (false)]
555 return provider.Mask;
558 is_empty_mask = (value == string.Empty || value == null);
563 provider = new MaskedTextProvider (value, provider.Culture, provider.AllowPromptAsInput, provider.PromptChar, provider.PasswordChar, provider.AsciiOnly);
564 ReCalculatePasswordChar ();
565 UpdateVisibleText ();
570 public bool MaskCompleted {
572 return provider.MaskCompleted;
577 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
578 public MaskedTextProvider MaskedTextProvider {
583 return provider.Clone () as MaskedTextProvider;
588 public bool MaskFull {
590 return provider.MaskFull;
594 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
596 [EditorBrowsable (EditorBrowsableState.Never)]
597 public override int MaxLength {
599 return base.MaxLength;
602 // Do nothing, MTB doesn't support this.
606 [EditorBrowsable (EditorBrowsableState.Never)]
608 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
609 public override bool Multiline {
614 // Do nothing, MTB doesn't support this.
618 [RefreshProperties (RefreshProperties.Repaint)]
619 [DefaultValue ('\0')]
620 public char PasswordChar {
622 if (use_system_password_char)
625 return provider.PasswordChar;
628 provider.PasswordChar = value;
631 provider.IsPassword = true;
633 provider.IsPassword = false;
635 ReCalculatePasswordChar (true);
636 CalculateDocument ();
638 UpdateVisibleText ();
644 [RefreshProperties (RefreshProperties.Repaint)]
645 public char PromptChar {
647 return provider.PromptChar;
650 provider.PromptChar = value;
651 UpdateVisibleText ();
655 public new bool ReadOnly {
657 return base.ReadOnly;
660 base.ReadOnly = value;
664 [DefaultValue (false)]
665 public bool RejectInputOnFirstFailure {
667 return reject_input_on_first_failure;
670 reject_input_on_first_failure = value;
674 [DefaultValue (true)]
675 public bool ResetOnPrompt {
677 return provider.ResetOnPrompt;
680 provider.ResetOnPrompt = value;
684 [DefaultValue (true)]
685 public bool ResetOnSpace {
687 return provider.ResetOnSpace;
690 provider.ResetOnSpace = value;
694 public override string SelectedText {
696 return base.SelectedText;
699 base.SelectedText = value;
700 UpdateVisibleText ();
704 [DefaultValue (true)]
705 public bool SkipLiterals {
707 return provider.SkipLiterals;
710 provider.SkipLiterals = value;
715 [Editor ("System.Windows.Forms.Design.MaskedTextBoxTextEditor, " + Consts.AssemblySystem_Design, typeof (UITypeEditor))]
717 [RefreshProperties (RefreshProperties.Repaint)]
719 public override string Text {
721 if (is_empty_mask || setting_text)
724 // The base constructor may call Text before we get to create a provider,
725 // so it may be null even though it's not an empty mask.
726 if (provider == null)
729 return provider.ToString ();
736 setting_text = false;
740 UpdateVisibleText ();
744 [DefaultValue (HorizontalAlignment.Left)]
746 public HorizontalAlignment TextAlign {
751 if (text_align != value) {
752 if (!Enum.IsDefined (typeof (HorizontalAlignment), value)) {
753 throw new InvalidEnumArgumentException ("value", (int) value, typeof (HorizontalAlignment));
756 OnTextAlignChanged (EventArgs.Empty);
762 public override int TextLength {
768 [DefaultValue (MaskFormat.IncludeLiterals)]
769 [RefreshProperties (RefreshProperties.Repaint)]
770 public MaskFormat TextMaskFormat {
772 if (provider.IncludePrompt && provider.IncludeLiterals) {
773 return MaskFormat.IncludePromptAndLiterals;
774 } else if (provider.IncludeLiterals) {
775 return MaskFormat.IncludeLiterals;
776 } else if (provider.IncludePrompt) {
777 return MaskFormat.IncludePrompt;
779 return MaskFormat.ExcludePromptAndLiterals;
783 if (!Enum.IsDefined (typeof (MaskFormat), value)) {
784 throw new InvalidEnumArgumentException ("value", (int)value, typeof (MaskFormat));
787 provider.IncludeLiterals = (value & MaskFormat.IncludeLiterals) == MaskFormat.IncludeLiterals;
788 provider.IncludePrompt = (value & MaskFormat.IncludePrompt) == MaskFormat.IncludePrompt;
792 [DefaultValue (false)]
793 [RefreshProperties (RefreshProperties.Repaint)]
794 public bool UseSystemPasswordChar {
796 return use_system_password_char;
799 if (use_system_password_char != value) {
800 use_system_password_char = value;
802 if (use_system_password_char)
803 PasswordChar = PasswordChar;
810 [DefaultValue (null)]
812 public Type ValidatingType {
814 return validating_type;
817 validating_type = value;
820 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
822 [EditorBrowsable (EditorBrowsableState.Never)]
823 public new bool WordWrap {
828 // Do nothing, not supported by MTB
832 #region Internal and private members
834 private void ReCalculatePasswordChar ()
836 ReCalculatePasswordChar (PasswordChar != '\0');
839 private void ReCalculatePasswordChar (bool using_password)
843 document.PasswordChar = PasswordChar.ToString ();
845 document.PasswordChar = string.Empty;
848 internal override void OnPaintInternal (PaintEventArgs pevent)
850 base.OnPaintInternal (pevent);
851 //pevent.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (BackColor), ClientRectangle);
852 //TextRenderer.DrawText (pevent.Graphics, Text, Font, ClientRectangle, ForeColor, TextFormatFlags.SingleLine);
853 //pevent.Handled = true;
856 internal override Color ChangeBackColor (Color backColor)
861 private void UpdateVisibleText ()
865 if (is_empty_mask || setting_text)
868 if (provider == null)
871 text = provider.ToDisplayString ();
874 if (base.Text != text) {
875 int selstart = SelectionStart;
877 SelectionStart = selstart;
879 setting_text = false;
882 private void InputText (string text)
887 MaskedTextResultHint resultHint;
890 if (RejectInputOnFirstFailure) {
891 result = provider.Set (input, out testPosition, out resultHint);
893 OnMaskInputRejected (new MaskInputRejectedEventArgs (testPosition, resultHint));
898 // Unfortunately we can't break if we reach the end of the mask, since
899 // .net iterates over _all_ the chars in the input
900 for (int i = 0; i < input.Length; i++) {
903 result = provider.InsertAt (c, testPosition, out testPosition, out resultHint);
905 testPosition++; // Move to the next free position
907 OnMaskInputRejected (new MaskInputRejectedEventArgs (testPosition, resultHint));