diff options
Diffstat (limited to 'mcs/class/Managed.Windows.Forms/System.Windows.Forms/DomainUpDown.cs')
-rw-r--r-- | mcs/class/Managed.Windows.Forms/System.Windows.Forms/DomainUpDown.cs | 572 |
1 files changed, 572 insertions, 0 deletions
diff --git a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/DomainUpDown.cs b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/DomainUpDown.cs new file mode 100644 index 00000000000..06d8c3d61b3 --- /dev/null +++ b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/DomainUpDown.cs @@ -0,0 +1,572 @@ +// 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 +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// 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> +// + +// COMPLETE + +using System; +using System.Collections; +using System.ComponentModel; +using System.Drawing; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Windows.Forms; + +namespace System.Windows.Forms +{ + [DefaultProperty("Items")] + [DefaultEvent("SelectedItemChanged")] + [MonoTODO("Figure out what to do with the DomainItemAccessibleObject and DomainUpDownAccessibleObject classes")] + public class DomainUpDown : UpDownBase { + #region Local Variables + private DomainUpDownItemCollection items; + private int selected_index = -1; + private bool sorted; + private bool wrap; + private int typed_to_index = -1; + #endregion // Local Variables + + #region DomainUpDownAccessibleObject sub-class + [ComVisible(true)] + public class DomainItemAccessibleObject : AccessibleObject { + #region DomainItemAccessibleObject Local Variables + private AccessibleObject parent; + #endregion // DomainItemAccessibleObject Local Variables + + #region DomainItemAccessibleObject Constructors + public DomainItemAccessibleObject(string name, AccessibleObject parent) { + this.name = name; + this.parent = parent; + } + #endregion // DomainItemAccessibleObject Constructors + + #region DomainItemAccessibleObject Properties + public override string Name { + get { + return base.Name; + } + + set { + base.Name = value; + } + } + + public override AccessibleObject Parent { + get { + return parent; + } + } + + public override AccessibleRole Role { + get { + return base.Role; + } + } + + public override AccessibleStates State { + get { + return base.State; + } + } + + public override string Value { + get { + return base.Value; + } + } + #endregion // DomainItemAccessibleObject Properties + } + #endregion // DomainItemAccessibleObject sub-class + + #region DomainUpDownAccessibleObject sub-class + [ComVisible(true)] + public class DomainUpDownAccessibleObject : ControlAccessibleObject { + #region DomainUpDownAccessibleObject Local Variables + private Control owner; + #endregion // DomainUpDownAccessibleObject Local Variables + + #region DomainUpDownAccessibleObject Constructors + public DomainUpDownAccessibleObject(Control owner) : base(owner) { + this.owner = owner; + } + #endregion // DomainUpDownAccessibleObject Constructors + + #region DomainUpDownAccessibleObject Properties + public override AccessibleRole Role { + get { + return base.Role; + } + } + #endregion // DomainUpDownAccessibleObject Properties + + #region DomainUpDownAccessibleObject Methods + public override AccessibleObject GetChild(int index) { + return base.GetChild (index); + } + + public override int GetChildCount() { + return base.GetChildCount (); + } + #endregion // DomainUpDownAccessibleObject Methods + } + #endregion // DomainUpDownAccessibleObject sub-class + + #region DomainUpDownItemCollection sub-class + public class DomainUpDownItemCollection : ArrayList { + internal ArrayList string_cache = new ArrayList(); + + #region Local Variables + #endregion // Local Variables + + #region Constructors + internal DomainUpDownItemCollection() {} + #endregion // Constructors + + #region Public Instance Properties + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public override object this[int index] { + get { + return base[index]; + } + + set { + if (value == null) { + throw new ArgumentNullException("value", "Cannot add null values to a DomainUpDownItemCollection"); + } + + base[index] = value; + string_cache[index] = value.ToString(); + OnCollectionChanged(index, 0); + } + } + #endregion // Public Instance Properties + + #region Public Instance Methods + public override int Add(object value) { + if (value == null) + throw new ArgumentNullException("value", "Cannot add null values to a DomainUpDownItemCollection"); + + int ret = base.Add(value); + string_cache.Add(value.ToString()); + OnCollectionChanged(Count - 1, +1); + return ret; + } + + public override void Insert(int index, object value) { + if (value == null) + throw new ArgumentNullException("value", "Cannot add null values to a DomainUpDownItemCollection"); + + base.Insert(index, value); + string_cache.Insert(index, value.ToString()); + OnCollectionChanged(index, +1); + } + + public override void Remove(object obj) { + int index = IndexOf(obj); + + if (index >= 0) + RemoveAt(index); + } + + public override void RemoveAt(int index) { + base.RemoveAt(index); + string_cache.RemoveAt(index); + OnCollectionChanged(index, -1); + } + #endregion // Public Instance Methods + + #region Internal Methods and Events + internal void OnCollectionChanged(int index, int size_delta) { + CollectionChangedEventHandler handler = CollectionChanged; + + if (handler != null) { + handler(index, size_delta); + } + } + + internal void PrivSort() { + PrivSort(0, Count, Comparer.Default); + } + + internal void PrivSort(int index, int count, IComparer comparer) { + object[] base_items = null; // this will refer to the base ArrayList private _items member + object[] string_cache_items = null; // and this will refer to that of the string_cache + + FieldInfo items_field = null; + + try { + items_field = typeof(ArrayList).GetField("_items", BindingFlags.NonPublic | BindingFlags.Instance); + } + catch {} // security exceptions, perhaps... + + if (items_field != null) { + base_items = items_field.GetValue(this) as object[]; + string_cache_items = items_field.GetValue(string_cache) as object[]; + } + + if ((base_items == null) || (string_cache_items == null)) { + // oh poop =/ guess we have to completely repopulate the string cache + base.Sort(index, count, comparer); + + for (int i=0; i < count; i++) + string_cache[i + index] = base[i + index].ToString(); + } + else { + // yay, this will be much faster than creating a whole bunch more items + Array.Sort(string_cache_items, base_items, index, count, comparer); + + OnCollectionChanged(-1, 0); + } + } + + internal void PrivSort(IComparer comparer) { + PrivSort(0, Count, comparer); + } + + internal event CollectionChangedEventHandler CollectionChanged; + #endregion // Internal Methods and Events + } + #endregion // DomainUpDownItemCollection sub-class + + #region Private Methods + // normally I'd use an EventArgs class, but I don't want to create spurious objects here + internal delegate void CollectionChangedEventHandler(int index, int size_delta); + + internal void items_CollectionChanged(int index, int size_delta) { + bool new_item = false; + + if ((index == selected_index) && (size_delta <= 0)) + new_item = true; + else if (index <= selected_index) + selected_index += size_delta; + + if (sorted && (index >= 0)) // index < 0 means it is already sorting + items.PrivSort(); + + UpdateEditText(); + + if (new_item) { + OnSelectedItemChanged(this, EventArgs.Empty); + } + } + + void go_to_user_input() { + UserEdit = false; + + if (typed_to_index >= 0) { + selected_index = typed_to_index; + OnSelectedItemChanged(this, EventArgs.Empty); + } + } + + private void TextBoxLostFocus(object source, EventArgs e) { + Select(base.txtView.SelectionStart + base.txtView.SelectionLength, 0); + } + + private void TextBoxKeyDown(object source, KeyPressEventArgs e) { + if (!UserEdit) { + base.txtView.SelectionLength = 0; + typed_to_index = -1; + } + + if (base.txtView.SelectionLength == 0) { + base.txtView.SelectionStart = 0; + } + + if (base.txtView.SelectionStart != 0) { + return; + } + + if (e.KeyChar == '\b') { // backspace + if (base.txtView.SelectionLength > 0) { + string prefix = base.txtView.SelectedText.Substring(0, base.txtView.SelectionLength - 1); + + bool found = false; + + if (typed_to_index < 0) { + typed_to_index = 0; + } + + if (sorted) { + for (int i=typed_to_index; i >= 0; i--) { + int difference = string.Compare(prefix, 0, items.string_cache[i].ToString(), 0, prefix.Length, true); + + if (difference == 0) { + found = true; + typed_to_index = i; + } + + if (difference > 0) { // since it is sorted, no strings after this point will match + break; + } + } + } else { + for (int i=0; i < items.Count; i++) { + if (0 == string.Compare(prefix, 0, items.string_cache[i].ToString(), 0, prefix.Length, true)) { + found = true; + typed_to_index = i; + break; + } + } + } + + ChangingText = true; + + if (found) + Text = items.string_cache[typed_to_index].ToString(); + else + Text = prefix; + + Select(0, prefix.Length); + + UserEdit = true; + + e.Handled = true; + } + } + else { + char key_char = e.KeyChar; + + if (char.IsLetterOrDigit(key_char) + || char.IsNumber(key_char) + || char.IsPunctuation(key_char) + || char.IsSymbol(key_char) + || char.IsWhiteSpace(key_char)) { + string prefix = base.txtView.SelectedText + key_char; + + bool found = false; + + if (typed_to_index < 0) { + typed_to_index = 0; + } + + if (sorted) { + for (int i=typed_to_index; i < items.Count; i++) { + int difference = string.Compare(prefix, 0, items.string_cache[i].ToString(), 0, prefix.Length, true); + + if (difference == 0) { + found = true; + typed_to_index = i; + } + + if (difference <= 0) { // since it is sorted, no strings after this point will match + break; + } + } + } else { + for (int i=0; i < items.Count; i++) { + if (0 == string.Compare(prefix, 0, items.string_cache[i].ToString(), 0, prefix.Length, true)) { + found = true; + typed_to_index = i; + break; + } + } + } + + ChangingText = true; + + if (found) { + Text = items.string_cache[typed_to_index].ToString(); + } else { + Text = prefix; + } + + Select(0, prefix.Length); + + UserEdit = true; + + e.Handled = true; + } + } + } + #endregion // Private Methods + + #region Public Constructors + public DomainUpDown() { + selected_index = -1; + sorted = false; + wrap = false; + typed_to_index = -1; + + items = new DomainUpDownItemCollection(); + items.CollectionChanged += new CollectionChangedEventHandler(items_CollectionChanged); + + this.txtView.LostFocus +=new EventHandler(TextBoxLostFocus); + this.txtView.KeyPress += new KeyPressEventHandler(TextBoxKeyDown); + } + #endregion // Public Constructors + + #region Public Instance Properties + [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] + [Editor("System.Windows.Forms.Design.StringCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] + [Localizable(true)] + public DomainUpDownItemCollection Items { + get { + return items; + } + } + + [Browsable(false)] + [DefaultValue(-1)] + public int SelectedIndex { + get { + return selected_index; + } + set { + object before = (selected_index >= 0) ? items[selected_index] : null; + + selected_index = value; + UpdateEditText(); + + object after = (selected_index >= 0) ? items[selected_index] : null; + + if (!ReferenceEquals(before, after)) { + OnSelectedItemChanged(this, EventArgs.Empty); + } + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public object SelectedItem { + get { + if (selected_index >= 0) { + return items[selected_index]; + } else { + return null; + } + } + + set { + SelectedIndex = items.IndexOf(value); + } + } + + [DefaultValue(false)] + public bool Sorted { + get { + return sorted; + } + set { + sorted = value; + + if (sorted) + items.PrivSort(); + } + } + + [DefaultValue(false)] + [Localizable(true)] + public bool Wrap { + get { + return wrap; + } + set { + wrap = value; + } + } + #endregion // Public Instance Properties + + #region Public Instance Methods + public override void DownButton() { + if (UserEdit) + go_to_user_input(); + + int new_index = selected_index + 1; + + if (new_index >= items.Count) { + if (!wrap) + return; + + new_index = 0; + } + + SelectedIndex = new_index; + } + + public override string ToString() { + return base.ToString() + ", Items.Count: " + items.Count + ", SelectedIndex: " + selected_index; + } + + public override void UpButton() { + if (UserEdit) + go_to_user_input(); + + int new_index = selected_index - 1; + + if (new_index < 0) { + if (!wrap) { + return; + } + + new_index = items.Count - 1; + } + + SelectedIndex = new_index; + } + #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 OnChanged(object source, EventArgs e) { + base.OnChanged (source, e); + } + + protected void OnSelectedItemChanged(object source, EventArgs e) { + EventHandler handler = SelectedItemChanged; + + if (handler != null) + handler(source, e); + } + + protected override void UpdateEditText() { + if ((selected_index >= 0) && (selected_index < items.Count)) { + ChangingText = true; + Text = items.string_cache[selected_index].ToString(); + } + } + + protected override void OnTextBoxKeyDown(object source, KeyEventArgs e) { + base.OnTextBoxKeyDown (source, e); + } + + #endregion // Protected Instance Methods + + #region Events + public event EventHandler SelectedItemChanged; + #endregion // Events + } +} |