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)
31 using System.Collections;
32 using System.ComponentModel;
34 using System.Drawing.Design;
35 using System.Globalization;
36 using System.Runtime.InteropServices;
37 using System.Security.Permissions;
38 using System.Windows.Forms;
40 namespace System.Windows.Forms
42 [ClassInterface (ClassInterfaceType.AutoDispatch)]
44 [DefaultProperty ("Mask")]
45 [DefaultEvent ("MaskInputRejected")]
46 [Designer ("System.Windows.Forms.Design.MaskedTextBoxDesigner, " + Consts.AssemblySystem_Design)]
47 [DefaultBindingProperty ("Text")]
48 public class MaskedTextBox : TextBoxBase
51 private MaskedTextProvider provider;
52 private bool beep_on_error;
53 private IFormatProvider format_provider;
54 private bool hide_prompt_on_leave;
55 private InsertKeyMode insert_key_mode;
56 private bool insert_key_overwriting;
57 private bool reject_input_on_first_failure;
58 private HorizontalAlignment text_align;
59 private MaskFormat cut_copy_mask_format;
60 private bool use_system_password_char;
61 private Type validating_type;
62 private bool is_empty_mask;
63 private bool setting_text;
67 static object AcceptsTabChangedEvent = new object ();
68 static object IsOverwriteModeChangedEvent = new object ();
69 static object MaskChangedEvent = new object ();
70 static object MaskInputRejectedEvent = new object ();
71 static object MultilineChangedEvent = new object ();
72 static object TextAlignChangedEvent = new object ();
73 static object TypeValidationCompletedEvent = new object ();
75 // This event is never raised by MaskedTextBox.
76 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
78 [EditorBrowsable (EditorBrowsableState.Never)]
79 public new event EventHandler AcceptsTabChanged {
80 add { Events.AddHandler (AcceptsTabChangedEvent, value);}
81 remove { Events.RemoveHandler (AcceptsTabChangedEvent, value);}
84 public event EventHandler IsOverwriteModeChanged {
85 add { Events.AddHandler (IsOverwriteModeChangedEvent, value); }
86 remove { Events.RemoveHandler (IsOverwriteModeChangedEvent, value); }
89 public event EventHandler MaskChanged {
90 add { Events.AddHandler (MaskChangedEvent, value); }
91 remove { Events.RemoveHandler (MaskChangedEvent, value); }
94 public event MaskInputRejectedEventHandler MaskInputRejected {
95 add { Events.AddHandler (MaskInputRejectedEvent, value); }
96 remove { Events.RemoveHandler (MaskInputRejectedEvent, value); }
99 // This event is never raised by MaskedTextBox.
100 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
102 [EditorBrowsable (EditorBrowsableState.Never)]
103 public new event EventHandler MultilineChanged {
104 add { Events.AddHandler (MultilineChangedEvent, value); }
105 remove { Events.RemoveHandler (MultilineChangedEvent, value); }
108 public event EventHandler TextAlignChanged {
109 add { Events.AddHandler (TextAlignChangedEvent, value); }
110 remove { Events.RemoveHandler (TextAlignChangedEvent, value); }
113 public event TypeValidationEventHandler TypeValidationCompleted {
114 add { Events.AddHandler (TypeValidationCompletedEvent, value); }
115 remove { Events.RemoveHandler (TypeValidationCompletedEvent, value); }
120 public MaskedTextBox ()
122 provider = new MaskedTextProvider ("<>", CultureInfo.CurrentCulture);
123 is_empty_mask = true;
127 public MaskedTextBox (MaskedTextProvider maskedTextProvider)
129 if (maskedTextProvider == null) {
130 throw new ArgumentNullException ();
132 provider = maskedTextProvider;
133 is_empty_mask = false;
137 public MaskedTextBox (string mask)
140 throw new ArgumentNullException ();
142 provider = new MaskedTextProvider (mask, CultureInfo.CurrentCulture);
143 is_empty_mask = false;
149 BackColor = SystemColors.Window;
150 cut_copy_mask_format = MaskFormat.IncludeLiterals;
151 insert_key_overwriting = false;
152 UpdateVisibleText ();
156 #region Public and protected methods
157 [EditorBrowsable (EditorBrowsableState.Never)]
158 public new void ClearUndo ()
160 // Do nothing, not supported by MTB
163 [EditorBrowsable (EditorBrowsableState.Advanced)]
164 [UIPermission (SecurityAction.InheritanceDemand, Window = UIPermissionWindow.AllWindows)]
165 protected override void CreateHandle ()
167 base.CreateHandle ();
170 public override char GetCharFromPosition (Point pt)
172 return base.GetCharFromPosition (pt);
175 public override int GetCharIndexFromPosition (Point pt)
177 return base.GetCharIndexFromPosition (pt);
180 [EditorBrowsable (EditorBrowsableState.Never)]
181 public new int GetFirstCharIndexFromLine (int lineNumber)
186 [EditorBrowsable (EditorBrowsableState.Never)]
187 public new int GetFirstCharIndexOfCurrentLine ()
192 [EditorBrowsable (EditorBrowsableState.Never)]
193 public override int GetLineFromCharIndex (int index)
198 public override Point GetPositionFromCharIndex (int index)
200 return base.GetPositionFromCharIndex (index);
203 protected override bool IsInputKey (Keys keyData)
205 return base.IsInputKey (keyData);
208 protected override void OnBackColorChanged (EventArgs e)
210 base.OnBackColorChanged (e);
213 protected override void OnHandleCreated (EventArgs e)
215 base.OnHandleCreated (e);
218 [EditorBrowsable (EditorBrowsableState.Advanced)]
219 protected virtual void OnIsOverwriteModeChanged (EventArgs e)
221 EventHandler eh = (EventHandler) Events [IsOverwriteModeChangedEvent];
226 protected override void OnKeyDown (KeyEventArgs e)
228 // Only handle Delete or Insert here
230 if (e.KeyCode == Keys.Insert && insert_key_mode == InsertKeyMode.Default) {
231 // switch the internal overwriting mode, not the public one
232 insert_key_overwriting = !insert_key_overwriting;
233 OnIsOverwriteModeChanged (EventArgs.Empty);
238 if (e.KeyCode != Keys.Delete || is_empty_mask) {
243 int testPosition, endSelection;
244 MaskedTextResultHint resultHint;
247 // Use a slightly different approach than the one used for backspace
248 endSelection = SelectionLength == 0 ? SelectionStart : SelectionStart + SelectionLength - 1;
249 result = provider.RemoveAt (SelectionStart, endSelection, out testPosition, out resultHint);
251 PostprocessKeyboardInput (result, testPosition, testPosition, resultHint);
256 protected override void OnKeyPress (KeyPressEventArgs e)
263 int testPosition, editPosition;
264 MaskedTextResultHint resultHint;
267 if (e.KeyChar == '\b') {
268 if (SelectionLength == 0)
269 result = provider.RemoveAt (SelectionStart - 1, SelectionStart - 1, out testPosition, out resultHint);
271 result = provider.RemoveAt (SelectionStart, SelectionStart + SelectionLength - 1, out testPosition, out resultHint);
273 editPosition = testPosition;
274 } else if (IsOverwriteMode || SelectionLength > 0) { // Replace
275 int start = provider.FindEditPositionFrom (SelectionStart, true);
276 int end = SelectionLength > 0 ? SelectionStart + SelectionLength - 1 : start;
277 result = provider.Replace (e.KeyChar, start, end, out testPosition, out resultHint);
279 editPosition = testPosition + 1;
281 // Move chars to the right
282 result = provider.InsertAt (e.KeyChar, SelectionStart, out testPosition, out resultHint);
283 editPosition = testPosition + 1;
286 PostprocessKeyboardInput (result, editPosition, testPosition, resultHint);
291 void PostprocessKeyboardInput (bool result, int newPosition, int testPosition, MaskedTextResultHint resultHint)
294 OnMaskInputRejected (new MaskInputRejectedEventArgs (testPosition, resultHint));
296 if (newPosition != MaskedTextProvider.InvalidIndex)
297 SelectionStart = newPosition;
299 SelectionStart = provider.Length;
301 UpdateVisibleText ();
305 protected override void OnKeyUp (KeyEventArgs e)
310 [EditorBrowsable (EditorBrowsableState.Advanced)]
311 protected virtual void OnMaskChanged (EventArgs e)
313 EventHandler eh = (EventHandler) Events [MaskChangedEvent];
318 private void OnMaskInputRejected (MaskInputRejectedEventArgs e)
320 MaskInputRejectedEventHandler eh = (MaskInputRejectedEventHandler) Events [MaskInputRejectedEvent];
325 [EditorBrowsable (EditorBrowsableState.Never)]
326 protected override void OnMultilineChanged (EventArgs e)
328 EventHandler eh = (EventHandler)Events [MultilineChangedEvent];
333 protected virtual void OnTextAlignChanged (EventArgs e)
335 EventHandler eh = (EventHandler)Events [TextAlignChangedEvent];
340 protected override void OnTextChanged (EventArgs e)
342 base.OnTextChanged (e);
345 [EditorBrowsable (EditorBrowsableState.Advanced)]
346 protected override void OnValidating (CancelEventArgs e)
348 base.OnValidating (e);
351 //[SecurityPermission (SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
352 protected override bool ProcessCmdKey (ref Message msg, Keys keyData)
354 return base.ProcessCmdKey (ref msg, keyData);
357 //[SecurityPermission (SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
358 protected internal override bool ProcessKeyMessage (ref Message m)
360 return base.ProcessKeyMessage (ref m);
363 [EditorBrowsable (EditorBrowsableState.Never)]
364 public new void ScrollToCaret ()
366 // MSDN: this method is overridden to perform no actions.
369 public override string ToString ()
371 return base.ToString () + ", Text: " + provider.ToString (false, false);
374 [EditorBrowsable (EditorBrowsableState.Never)]
375 public new void Undo ()
377 // Do nothing, not supported by MTB.
380 public object ValidateText ()
382 throw new NotImplementedException ();
385 //[SecurityPermission (SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
386 protected override void WndProc (ref Message m)
388 switch ((Msg) m.Msg) {
390 base.WndProc (ref m);
397 [EditorBrowsable (EditorBrowsableState.Never)]
398 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
400 public new bool AcceptsTab {
408 [DefaultValue (true)]
409 public bool AllowPromptAsInput {
411 return provider.AllowPromptAsInput;
414 provider = new MaskedTextProvider (provider.Mask, provider.Culture, value, provider.PromptChar, provider.PasswordChar, provider.AsciiOnly);
415 UpdateVisibleText ();
419 [RefreshProperties (RefreshProperties.Repaint)]
420 [DefaultValue (false)]
421 public bool AsciiOnly {
423 return provider.AsciiOnly;
426 provider = new MaskedTextProvider (provider.Mask, provider.Culture, provider.AllowPromptAsInput, provider.PromptChar, provider.PasswordChar, value);
427 UpdateVisibleText ();
431 [DefaultValue (false)]
432 public bool BeepOnError {
434 return beep_on_error;
437 beep_on_error = value;
442 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
443 [EditorBrowsable (EditorBrowsableState.Never)]
444 public new bool CanUndo {
450 protected override CreateParams CreateParams {
451 //[SecurityPermission (SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
453 return base.CreateParams;
457 [RefreshProperties (RefreshProperties.Repaint)]
458 public CultureInfo Culture {
460 return provider.Culture;
463 provider = new MaskedTextProvider (provider.Mask, value, provider.AllowPromptAsInput, provider.PromptChar, provider.PasswordChar, provider.AsciiOnly);
464 UpdateVisibleText ();
468 [RefreshProperties (RefreshProperties.Repaint)]
469 [DefaultValue (MaskFormat.IncludeLiterals)]
470 public MaskFormat CutCopyMaskFormat {
472 return cut_copy_mask_format;
475 if (!Enum.IsDefined (typeof (MaskFormat), value)) {
476 throw new InvalidEnumArgumentException ("value", (int)value, typeof (MaskFormat));
478 cut_copy_mask_format = value;
482 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
484 public IFormatProvider FormatProvider {
486 return format_provider;
489 format_provider = value;
493 [RefreshProperties (RefreshProperties.Repaint)]
494 [DefaultValue (false)]
495 public bool HidePromptOnLeave {
497 return hide_prompt_on_leave;
500 hide_prompt_on_leave = value;
504 [DefaultValue (InsertKeyMode.Default)]
505 public InsertKeyMode InsertKeyMode {
507 return insert_key_mode;
510 if (!Enum.IsDefined (typeof (InsertKeyMode), value)) {
511 throw new InvalidEnumArgumentException ("value", (int)value, typeof (InsertKeyMode));
513 insert_key_mode = value;
518 public bool IsOverwriteMode {
520 if (insert_key_mode == InsertKeyMode.Default) {
521 return insert_key_overwriting;
523 return insert_key_mode == InsertKeyMode.Overwrite;
528 [EditorBrowsable (EditorBrowsableState.Never)]
529 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
531 public new string [] Lines {
534 if (text == null || text == string.Empty)
535 return new string [] {};
537 return Text.Split (new string [] {"\r\n", "\r", "\n"}, StringSplitOptions.None);
540 // Do nothing, not supported by MTB.
545 [Editor ("System.Windows.Forms.Design.MaskPropertyEditor, " + Consts.AssemblySystem_Design, typeof (UITypeEditor))]
546 [RefreshProperties (RefreshProperties.Repaint)]
547 [MergablePropertyAttribute (false)]
554 return provider.Mask;
557 is_empty_mask = (value == string.Empty || value == null);
562 provider = new MaskedTextProvider (value, provider.Culture, provider.AllowPromptAsInput, provider.PromptChar, provider.PasswordChar, provider.AsciiOnly);
563 ReCalculatePasswordChar ();
564 UpdateVisibleText ();
569 public bool MaskCompleted {
571 return provider.MaskCompleted;
576 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
577 public MaskedTextProvider MaskedTextProvider {
582 return provider.Clone () as MaskedTextProvider;
587 public bool MaskFull {
589 return provider.MaskFull;
593 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
595 [EditorBrowsable (EditorBrowsableState.Never)]
596 public override int MaxLength {
598 return base.MaxLength;
601 // Do nothing, MTB doesn't support this.
605 [EditorBrowsable (EditorBrowsableState.Never)]
607 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
608 public override bool Multiline {
613 // Do nothing, MTB doesn't support this.
617 [RefreshProperties (RefreshProperties.Repaint)]
618 [DefaultValue ('\0')]
619 public char PasswordChar {
621 if (use_system_password_char)
624 return provider.PasswordChar;
627 provider.PasswordChar = value;
630 provider.IsPassword = true;
632 provider.IsPassword = false;
634 ReCalculatePasswordChar (true);
635 CalculateDocument ();
637 UpdateVisibleText ();
643 [RefreshProperties (RefreshProperties.Repaint)]
644 public char PromptChar {
646 return provider.PromptChar;
649 provider.PromptChar = value;
650 UpdateVisibleText ();
654 public new bool ReadOnly {
656 return base.ReadOnly;
659 base.ReadOnly = value;
663 [DefaultValue (false)]
664 public bool RejectInputOnFirstFailure {
666 return reject_input_on_first_failure;
669 reject_input_on_first_failure = value;
673 [DefaultValue (true)]
674 public bool ResetOnPrompt {
676 return provider.ResetOnPrompt;
679 provider.ResetOnPrompt = value;
683 [DefaultValue (true)]
684 public bool ResetOnSpace {
686 return provider.ResetOnSpace;
689 provider.ResetOnSpace = value;
693 public override string SelectedText {
695 return base.SelectedText;
698 base.SelectedText = value;
699 UpdateVisibleText ();
703 [DefaultValue (true)]
704 public bool SkipLiterals {
706 return provider.SkipLiterals;
709 provider.SkipLiterals = value;
714 [Editor ("System.Windows.Forms.Design.MaskedTextBoxTextEditor, " + Consts.AssemblySystem_Design, typeof (UITypeEditor))]
716 [RefreshProperties (RefreshProperties.Repaint)]
718 public override string Text {
720 if (is_empty_mask || setting_text)
723 // The base constructor may call Text before we get to create a provider,
724 // so it may be null even though it's not an empty mask.
725 if (provider == null)
728 return provider.ToString ();
735 setting_text = false;
739 UpdateVisibleText ();
743 [DefaultValue (HorizontalAlignment.Left)]
745 public HorizontalAlignment TextAlign {
750 if (text_align != value) {
751 if (!Enum.IsDefined (typeof (HorizontalAlignment), value)) {
752 throw new InvalidEnumArgumentException ("value", (int) value, typeof (HorizontalAlignment));
755 OnTextAlignChanged (EventArgs.Empty);
761 public override int TextLength {
767 [DefaultValue (MaskFormat.IncludeLiterals)]
768 [RefreshProperties (RefreshProperties.Repaint)]
769 public MaskFormat TextMaskFormat {
771 if (provider.IncludePrompt && provider.IncludeLiterals) {
772 return MaskFormat.IncludePromptAndLiterals;
773 } else if (provider.IncludeLiterals) {
774 return MaskFormat.IncludeLiterals;
775 } else if (provider.IncludePrompt) {
776 return MaskFormat.IncludePrompt;
778 return MaskFormat.ExcludePromptAndLiterals;
782 if (!Enum.IsDefined (typeof (MaskFormat), value)) {
783 throw new InvalidEnumArgumentException ("value", (int)value, typeof (MaskFormat));
786 provider.IncludeLiterals = (value & MaskFormat.IncludeLiterals) == MaskFormat.IncludeLiterals;
787 provider.IncludePrompt = (value & MaskFormat.IncludePrompt) == MaskFormat.IncludePrompt;
791 [DefaultValue (false)]
792 [RefreshProperties (RefreshProperties.Repaint)]
793 public bool UseSystemPasswordChar {
795 return use_system_password_char;
798 if (use_system_password_char != value) {
799 use_system_password_char = value;
801 if (use_system_password_char)
802 PasswordChar = PasswordChar;
809 [DefaultValue (null)]
811 public Type ValidatingType {
813 return validating_type;
816 validating_type = value;
819 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
821 [EditorBrowsable (EditorBrowsableState.Never)]
822 public new bool WordWrap {
827 // Do nothing, not supported by MTB
831 #region Internal and private members
833 private void ReCalculatePasswordChar ()
835 ReCalculatePasswordChar (PasswordChar != '\0');
838 private void ReCalculatePasswordChar (bool using_password)
842 document.PasswordChar = PasswordChar.ToString ();
844 document.PasswordChar = string.Empty;
847 internal override void OnPaintInternal (PaintEventArgs pevent)
849 base.OnPaintInternal (pevent);
850 //pevent.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (BackColor), ClientRectangle);
851 //TextRenderer.DrawText (pevent.Graphics, Text, Font, ClientRectangle, ForeColor, TextFormatFlags.SingleLine);
852 //pevent.Handled = true;
855 internal override Color ChangeBackColor (Color backColor)
860 private void UpdateVisibleText ()
864 if (is_empty_mask || setting_text)
867 if (provider == null)
870 text = provider.ToDisplayString ();
873 if (base.Text != text) {
874 int selstart = SelectionStart;
876 SelectionStart = selstart;
878 setting_text = false;
881 private void InputText (string text)
886 MaskedTextResultHint resultHint;
889 if (RejectInputOnFirstFailure) {
890 result = provider.Set (input, out testPosition, out resultHint);
892 OnMaskInputRejected (new MaskInputRejectedEventArgs (testPosition, resultHint));
897 // Unfortunately we can't break if we reach the end of the mask, since
898 // .net iterates over _all_ the chars in the input
899 for (int i = 0; i < input.Length; i++) {
902 result = provider.InsertAt (c, testPosition, out testPosition, out resultHint);
904 testPosition++; // Move to the next free position
906 OnMaskInputRejected (new MaskInputRejectedEventArgs (testPosition, resultHint));