Merge pull request #2057 from directhex/monolite-on-jenkins
[mono.git] / mcs / class / System.Windows.Forms / System.Windows.Forms / NumericUpDown.cs
index 7566db4ee93ee52eb6fcfbd18dfcc4e41e8a4fdf..856137cb17e051cd2f72513bbc16b7ea7c2ea4ac 100644 (file)
@@ -1,15 +1,3 @@
-//
-// System.Windows.Forms.NumericUpDown.cs
-//
-// Author:
-//   stubbed out by Paul Osman (paul.osman@sympatico.ca)
-//     Dennis Hayes (dennish@raytek.com)
-//     Alexandre Pigolkine (pigolkine@gxm.de)
-//
-// (C) 2002/3 Ximian, Inc
-//
-
-//
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
 // "Software"), to deal in the Software without restriction, including
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
+// Copyright (c) 2005 Novell, Inc.
+//
+// Authors:
+//     Jonathan Gilbert        <logic@deltaq.org>
+//
+// Integration into MWF:
+//     Peter Bartok            <pbartok@novell.com>
+//
+
+using System;
+using System.Collections;
 using System.ComponentModel;
+using System.Drawing;
+using System.Globalization;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Windows.Forms;
+
 namespace System.Windows.Forms {
+       [DefaultEvent("ValueChanged")]
+       [DefaultProperty("Value")]
+       [DefaultBindingProperty ("Value")]
+       [ClassInterface (ClassInterfaceType.AutoDispatch)]
+       [ComVisible (true)]
+       public class NumericUpDown : UpDownBase, ISupportInitialize {
+               #region Local Variables
+               private bool    suppress_validation;
+               private int     decimal_places;
+               private bool    hexadecimal;
+               private decimal increment;
+               private decimal maximum;
+               private decimal minimum;
+               private bool    thousands_separator;
+               private decimal dvalue;
+               
+
+               NumericUpDownAccelerationCollection accelerations;
+//             private long buttonPressedTicks;
+               //private bool isSpinning;
+               #endregion      // Local Variables
+
+               #region UIA FrameWork Events
+               static object UIAMinimumChangedEvent = new object ();
 
-       // <summary>
-       //
-       // </summary>
-
-    public class NumericUpDown : UpDownBase, ISupportInitialize {
-
-               private decimal Value_ = 0;
-       private int DecimalPlaces_;
-       private bool Hexadecimal_ = false;
-       private decimal Increment_ = 1;
-       private decimal Maximum_ = 100;
-       private decimal Minimum_ = 0;
-               //
-               //  --- Constructor
-               //
-               [MonoTODO]
-               public NumericUpDown()
+               internal event EventHandler UIAMinimumChanged {
+                       add { Events.AddHandler (UIAMinimumChangedEvent, value); }
+                       remove { Events.RemoveHandler (UIAMinimumChangedEvent, value); }
+               }
+
+               internal void OnUIAMinimumChanged (EventArgs e)
                {
-                       
+                       EventHandler eh = (EventHandler) Events [UIAMinimumChangedEvent];
+                       if (eh != null)
+                               eh (this, e);
                }
 
-               public override void DownButton(){
-                       if( Value_ > Minimum_) {
-                               Value = Math.Max(Value_ - Increment_, Minimum_);
-                       }
+               static object UIAMaximumChangedEvent = new object ();
+
+               internal event EventHandler UIAMaximumChanged {
+                       add { Events.AddHandler (UIAMaximumChangedEvent, value); }
+                       remove { Events.RemoveHandler (UIAMaximumChangedEvent, value); }
+               }
+
+               internal void OnUIAMaximumChanged (EventArgs e)
+               {
+                       EventHandler eh = (EventHandler) Events [UIAMaximumChangedEvent];
+                       if (eh != null)
+                               eh (this, e);
+               }
+
+               static object UIASmallChangeChangedEvent = new object ();
+
+               internal event EventHandler UIASmallChangeChanged {
+                       add { Events.AddHandler (UIASmallChangeChangedEvent, value); }
+                       remove { Events.RemoveHandler (UIASmallChangeChangedEvent, value); }
+               }
+
+               internal void OnUIASmallChangeChanged (EventArgs e)
+               {
+                       EventHandler eh = (EventHandler) Events [UIASmallChangeChangedEvent];
+                       if (eh != null)
+                               eh (this, e);
                }
+               #endregion
 
-               //
-               //  --- Public Properties
-               //
+               #region Public Constructors
+               public NumericUpDown() {
+                       suppress_validation = false;
+                       decimal_places = 0;
+                       hexadecimal = false;
+                       increment = 1M;
+                       maximum = 100M;
+                       minimum = 0M;
+                       thousands_separator = false;
 
-               [MonoTODO]
-               public int DecimalPlaces  {
+                       Text = "0";
+               }
+               #endregion      // Public Constructors
+
+               #region Public Instance Properties
+
+               [Browsable (false)]
+               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+               public NumericUpDownAccelerationCollection Accelerations {
+                       get {
+                               if (accelerations == null)
+                                       accelerations = new NumericUpDownAccelerationCollection ();
+                               return accelerations;
+                       }
+               }
+
+               [DefaultValue(0)]
+               public int DecimalPlaces {
                        get {
-                               return DecimalPlaces_;
+                               return decimal_places;
                        }
+
                        set {
-                               //FIXME:
-                               DecimalPlaces_ = value;
+                               decimal_places = value;
+                               UpdateEditText();
                        }
                }
 
-               [MonoTODO]
-               public bool Hexadecimal  {
+               [DefaultValue(false)]
+               public bool Hexadecimal {
                        get {
-                               return Hexadecimal_;
+                               return hexadecimal;
                        }
+
                        set {
-                               //FIXME:
-                               Hexadecimal_ = value;
+                               hexadecimal = value;
+                               UpdateEditText();
                        }
                }
 
                public decimal Increment {
                        get {
-                               return Increment_;
-                       } 
+
+                               return increment;
+                       }
+
                        set {
-                               Increment_ = value;
+                               if (value < 0) {
+                                       throw new ArgumentOutOfRangeException("value", value, "NumericUpDown increment cannot be negative");
+                               }
+
+                               increment = value;
+
+                               // UIA Framework Event: SmallChange Changed
+                               OnUIASmallChangeChanged (EventArgs.Empty);
                        }
                }
-               
-               [MonoTODO]
-               public decimal Maximum  {
+
+               [RefreshProperties(RefreshProperties.All)]
+               public decimal Maximum {
                        get {
-                               return Maximum_;
+                               return maximum;
                        }
+
                        set {
-                               //FIXME:
-                               if( Maximum_ != value) {
-                                       Maximum_ = value;
-                                       Minimum = Math.Min(Maximum_,Minimum_);
-                                       Value = Math.Min(Value_,Minimum_);
-                               }
+                               maximum = value;
+
+                               if (minimum > maximum)
+                                       minimum = maximum;
+
+                               if (dvalue > maximum)
+                                       Value = maximum;
+
+                               // UIA Framework Event: Maximum Changed
+                               OnUIAMaximumChanged (EventArgs.Empty);
                        }
                }
 
-               [MonoTODO]
-               public decimal Minimum  {
+               [RefreshProperties(RefreshProperties.All)]
+               public decimal Minimum {
                        get {
-                               return Minimum_;
+                               return minimum;
                        }
+
                        set {
-                               //FIXME:
-                               if( Minimum_ != value) {
-                                       Minimum_ = value;
-                                       Maximum = Math.Max(Maximum_,Minimum_);
-                                       Value = Math.Max(Value_,Minimum_);
-                               }
+                               minimum = value;
+
+                               if (maximum < minimum)
+                                       maximum = minimum;
+
+                               if (dvalue < minimum)
+                                       Value = minimum;
+
+                               // UIA Framework Event: Minimum Changed
+                               OnUIAMinimumChanged (EventArgs.Empty);
                        }
                }
 
-               [MonoTODO]
-               public override string Text  {
-                       //FIXME: just to get it to run
+               [Browsable (false)]
+               [EditorBrowsable (EditorBrowsableState.Never)]
+               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+               public new Padding Padding {
+                       get { return Padding.Empty; }
+                       set { }
+               }
+
+               [Bindable(false)]
+               [Browsable(false)]
+               [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
+               [EditorBrowsable(EditorBrowsableState.Never)]
+               public override string Text {
                        get {
-                               return Value_.ToString();
+                               return base.Text;
                        }
+
                        set {
-                               Value = Decimal.Parse(value);
+                               base.Text = value;
                        }
                }
 
-               [MonoTODO]
-               public bool ThousandsSeparator  {
+               [DefaultValue(false)]
+               [Localizable(true)]
+               public bool ThousandsSeparator {
                        get {
-                               throw new NotImplementedException ();
+                               return thousands_separator;
                        }
+
                        set {
-                               //FIXME:
+                               thousands_separator = value;
+                               UpdateEditText();
                        }
                }
 
-               [MonoTODO]
-               public decimal Value  {
+               [Bindable(true)]
+               public decimal Value {
                        get {
-                               return Value_;
+                               if (UserEdit)
+                                       ValidateEditText ();
+                               return dvalue;
                        }
+
                        set {
-                               //FIXME:
-                               if( Value_ != value) {
-                                       Value_ = value;
-                                       UpdateEditText();
+                               if (value != dvalue) {
+                                       if (!suppress_validation && ((value < minimum) || (value > maximum))) {
+                                               throw new ArgumentOutOfRangeException ("value", "NumericUpDown.Value must be within the specified Minimum and Maximum values");
+                                       }
+
+                                       dvalue = value;
+                                       OnValueChanged (EventArgs.Empty);
+                                       UpdateEditText ();
                                }
                        }
                }
+               #endregion      // Public Instance Properties
+
+               #region Public Instance Methods
+               public void BeginInit() {
+                       suppress_validation = true;
+               }
 
-               //
-               //  --- Public Methods
-               //
+               public void EndInit() {
+                       suppress_validation = false;
+                       Value = Check (dvalue);
+                       UpdateEditText ();
+               }
 
-               [MonoTODO]
-               public override string ToString()
-               {
-                       //FIXME:
-                       return base.ToString();
+               public override string ToString() {
+                       return string.Format("{0}, Minimum = {1}, Maximum = {2}", base.ToString(), minimum, maximum);
                }
 
-               [MonoTODO]
-               public override void UpButton()
-               {
-                       if( Value_ != Maximum_) {
-                               Value = Math.Min(Value_ + Increment_, Maximum_);
+               public override void DownButton() {
+                       if (UserEdit) {
+                               ParseEditText ();
                        }
+
+                       Value = Math.Max (minimum, unchecked (dvalue - increment));
+
+                       // UIA Framework Event: DownButton Click
+                       OnUIADownButtonClick (EventArgs.Empty);
                }
 
-               //
-               //  --- Public Events
-               //
+               public override void UpButton() {
+                       if (UserEdit) {
+                               ParseEditText ();
+                       }
 
-               public event EventHandler ValueChanged;
+                       Value = Math.Min (maximum, unchecked (dvalue + increment));
 
-               //
-               //  --- Protected Methods
-               //
-               [MonoTODO]
-               protected override AccessibleObject CreateAccessibilityInstance() 
-               {
-                       //FIXME:
-                       return base.CreateAccessibilityInstance();
+                       // UIA Framework Event: UpButton Click
+                       OnUIAUpButtonClick (EventArgs.Empty);
                }
+               #endregion      // Public Instance Methods
+
+               #region Protected Instance Methods
+               protected override AccessibleObject CreateAccessibilityInstance() {
+                       AccessibleObject        acc;
+
+                       acc = new AccessibleObject(this);
+                       acc.role = AccessibleRole.SpinButton;
+
+                       return acc;
+               }
+
+               protected override void OnTextBoxKeyPress(object source, KeyPressEventArgs e) {
+                       if ((ModifierKeys & ~Keys.Shift) != Keys.None) {
+                               return;
+                       }
+
+                       NumberFormatInfo nfi = CultureInfo.CurrentCulture.NumberFormat;
+                       string pressedKey = e.KeyChar.ToString ();
+
+                       if ((pressedKey != nfi.NegativeSign) && (pressedKey != nfi.NumberDecimalSeparator) && 
+                               (pressedKey != nfi.NumberGroupSeparator)) {
+                               string acceptable = hexadecimal ? "\b0123456789abcdefABCDEF" : "\b0123456789";
+                               if (acceptable.IndexOf (e.KeyChar) == -1) {
+                                       // FIXME: produce beep to signal that "invalid" key was pressed
+                                       // prevent the key from reaching the text box
+                                       e.Handled = true;
+                               }
+                       }
 
-               [MonoTODO]
-               protected override void OnTextBoxKeyPress(object source, KeyPressEventArgs e)
-               {
-                       //FIXME:
                        base.OnTextBoxKeyPress(source, e);
                }
 
-               [MonoTODO]
-               protected virtual void OnValueChanged(EventArgs e) 
-               {
-                       //FIXME:
+               protected virtual void OnValueChanged(EventArgs e) {
+                       EventHandler eh = (EventHandler)(Events [ValueChangedEvent]);
+                       if (eh != null)
+                               eh (this, e);
                }
 
-               [MonoTODO]
-               protected void ParseEditText() 
+               protected void ParseEditText () {
+                       try {
+                               if (!hexadecimal) {
+                                       Value = Check (decimal.Parse (Text, CultureInfo.CurrentCulture));
+                               } else {
+                                       Value = Check (Convert.ToDecimal (Convert.ToInt32 (Text, 16)));
+                               }
+                       }
+                       catch { }
+                       finally {
+                               UserEdit = false;
+                       }
+               }
+
+               private decimal Check (decimal val)
                {
-                       //FIXME:
+                       decimal ret = val;
+                       if (ret < minimum) {
+                               ret = minimum;
+                       }
+
+                       if (ret > maximum) {
+                               ret = maximum;
+                       }
+
+                       return ret;
                }
 
-               [MonoTODO]
-               protected override void UpdateEditText() 
+               protected override void UpdateEditText () {
+                       if (suppress_validation)
+                               return;
+
+                       if (UserEdit)
+                               ParseEditText ();
+
+                       ChangingText = true;
+                       if (!hexadecimal) {
+                               // "N" and "F" differ only in that "N" includes commas
+                               // every 3 digits to the left of the decimal and "F"
+                               // does not.
+
+                               string format_string;
+
+                               if (thousands_separator) {
+                                       format_string = "N";
+                               } else {
+                                       format_string = "F";
+                               }
+
+                               format_string += decimal_places;
+
+                               Text = dvalue.ToString (format_string, CultureInfo.CurrentCulture);
+
+                       } else {
+                               // Cast to Int64 to be able to use the "X" formatter.
+                               // If the value is below Int64.MinValue or above Int64.MaxValue,
+                               // then an OverflowException will be thrown, as with .NET.
+                               Text = ((Int64)dvalue).ToString("X", CultureInfo.CurrentCulture);
+                       }
+               }
+
+
+               protected override void ValidateEditText() {
+                       ParseEditText ();
+                       UpdateEditText ();
+               }
+
+               protected override void OnLostFocus(EventArgs e) {
+                       base.OnLostFocus(e);
+                       if (UserEdit)
+                               UpdateEditText();
+               }
+
+               protected override void OnKeyUp (KeyEventArgs e)
                {
-                       //FIXME:
-                       base.Text = Value_.ToString();
+//                     isSpinning = false;
+                       base.OnKeyUp (e);
                }
 
-               [MonoTODO]
-               protected override void ValidateEditText() 
+               protected override void OnKeyDown (KeyEventArgs e)
                {
-                       //FIXME:
-                       base.ValidateEditText();
+//                     buttonPressedTicks = DateTime.Now.Ticks;
+//                     isSpinning = true;
+                       base.OnKeyDown (e);
                }
+               #endregion      // Protected Instance Methods
 
-               void ISupportInitialize.BeginInit(){
-                       //FIXME:
+               #region Events
+               [Browsable (false)]
+               [EditorBrowsable (EditorBrowsableState.Never)]
+               public new event EventHandler PaddingChanged {
+                       add { base.PaddingChanged += value; }
+                       remove { base.PaddingChanged -= value; }
                }
 
-               void ISupportInitialize.EndInit(){
-                       //FIXME:
+               static object ValueChangedEvent = new object ();
+
+               public event EventHandler ValueChanged {
+                       add { Events.AddHandler (ValueChangedEvent, value); }
+                       remove { Events.RemoveHandler (ValueChangedEvent, value); }
                }
 
+               [Browsable(false)]
+               [EditorBrowsable(EditorBrowsableState.Never)]
+               public new event EventHandler TextChanged {
+                       add { base.TextChanged += value; }
+                       remove { base.TextChanged -= value; }
+               }
+               #endregion      // Events
        }
 }