2007-09-28 Carlos Alberto Cortez <calberto.cortez@gmail.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / ListBox.cs
index 93449932e4cfe26ebffd18f60a454d1b68a6c740..9b4ae5f6abcb8b184df3edb448cbb85684153108 100644 (file)
@@ -35,6 +35,10 @@ using System.ComponentModel.Design.Serialization;
 using System.Reflection;
 using System.Runtime.InteropServices;
 
+#if NET_2_0
+using System.Collections.Generic;
+#endif
+
 namespace System.Windows.Forms
 {
        [DefaultProperty("Items")]
@@ -92,10 +96,15 @@ namespace System.Windows.Forms
                private Rectangle items_area;
                private int focused_item = -1;          
                private ObjectCollection items;
+#if NET_2_0
+               private IntegerCollection custom_tab_offsets;
+               private Padding padding;
+               private bool use_custom_tab_offsets;
+#endif
 
                public ListBox ()
                {
-                       border_style = BorderStyle.Fixed3D;                     
+                       InternalBorderStyle = BorderStyle.Fixed3D;                      
                        BackColor = ThemeEngine.Current.ColorWindow;
 
                        items = CreateItemCollection ();
@@ -134,6 +143,10 @@ namespace System.Windows.Forms
                        LostFocus += new EventHandler (OnLostFocus);
                        
                        SetStyle (ControlStyles.UserPaint, false);
+
+#if NET_2_0
+                       custom_tab_offsets = new IntegerCollection (this);
+#endif
                }
 
                #region Events
@@ -149,6 +162,13 @@ namespace System.Windows.Forms
                }
 
 #if NET_2_0
+               [Browsable (false)]
+               [EditorBrowsable (EditorBrowsableState.Never)]
+               public new event EventHandler BackgroundImageLayoutChanged {
+                       add { base.BackgroundImageLayoutChanged += value; }
+                       remove { base.BackgroundImageLayoutChanged -= value; }
+               }
+
                [Browsable (true)]
                [EditorBrowsable (EditorBrowsableState.Always)]
 #else
@@ -170,6 +190,22 @@ namespace System.Windows.Forms
                        remove { Events.RemoveHandler (MeasureItemEvent, value); }
                }
 
+#if NET_2_0
+               [Browsable (true)]
+               [EditorBrowsable (EditorBrowsableState.Always)]
+               public new event MouseEventHandler MouseClick {
+                       add { base.MouseClick += value; }
+                       remove { base.MouseClick -= value; }
+               }
+
+               [Browsable (false)]
+               [EditorBrowsable (EditorBrowsableState.Never)]
+               public new event EventHandler PaddingChanged {
+                       add { base.PaddingChanged += value; }
+                       remove { base.PaddingChanged -= value; }
+               }
+#endif
+
                [Browsable (false)]
                [EditorBrowsable (EditorBrowsableState.Never)]
                public new event PaintEventHandler Paint {
@@ -212,6 +248,15 @@ namespace System.Windows.Forms
                        }
                }
 
+#if NET_2_0
+               [Browsable (false)]
+               [EditorBrowsable (EditorBrowsableState.Never)]
+               public override ImageLayout BackgroundImageLayout {
+                       get { return base.BackgroundImageLayout; }
+                       set { base.BackgroundImageLayout = value; }
+               }
+#endif
+
                [DefaultValue (BorderStyle.Fixed3D)]
                [DispId(-504)]
                public BorderStyle BorderStyle {
@@ -245,6 +290,14 @@ namespace System.Windows.Forms
                        get { return base.CreateParams;}
                }
 
+#if NET_2_0
+               [Browsable (false)]
+               [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
+               public IntegerCollection CustomTabOffsets {
+                       get { return custom_tab_offsets; }
+               }
+#endif
+
                protected override Size DefaultSize {
                        get { return new Size (120, 96); }
                }
@@ -275,6 +328,13 @@ namespace System.Windows.Forms
                        }
                }
 
+#if NET_2_0
+               public override Font Font {
+                       get { return base.Font; }
+                       set { base.Font = value; }
+               }
+#endif
+
                public override Color ForeColor {
                        get { return base.ForeColor; }
                        set {
@@ -334,7 +394,7 @@ namespace System.Windows.Forms
                public virtual int ItemHeight {
                        get {
                                if (item_height == -1) {
-                                       SizeF sz = DeviceContext.MeasureString ("The quick brown Fox", Font);
+                                       SizeF sz = TextRenderer.MeasureString ("The quick brown Fox", Font);
                                        item_height = (int) sz.Height;
                                }
                                return item_height;
@@ -379,6 +439,16 @@ namespace System.Windows.Forms
                        }
                }
 
+#if NET_2_0
+               [Browsable (false)]
+               [EditorBrowsable (EditorBrowsableState.Never)]
+               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+               public new Padding Padding {
+                       get { return padding; }
+                       set { padding = value; }
+               }
+#endif
+
                [Browsable (false)]
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                [EditorBrowsable (EditorBrowsableState.Advanced)]
@@ -444,8 +514,7 @@ namespace System.Windows.Forms
                                else if (SelectionMode == SelectionMode.One)
                                        UnSelectItem (selected_index, true);
 
-                               if (value < top_index)
-                               {
+                               if (value != -1 && value < top_index) {
                                        top_index = value;
                                        UpdateTopItem ();
                                } else {
@@ -582,6 +651,19 @@ namespace System.Windows.Forms
                        }
                }
 
+#if NET_2_0
+               [Browsable (false)]
+               [DefaultValue (false)]
+               public bool UseCustomTabOffsets {
+                       get { return use_custom_tab_offsets; }
+                       set { 
+                               if (use_custom_tab_offsets != value) {
+                                       use_custom_tab_offsets = value;
+                                       CalculateTabStops ();
+                               }
+                        }
+               }
+#endif
                [DefaultValue (true)]
                public bool UseTabStops {
                        get { return use_tabstops; }
@@ -590,12 +672,9 @@ namespace System.Windows.Forms
                                if (use_tabstops == value)
                                        return;
 
-                               use_tabstops = value;                                   
-                               if (use_tabstops)
-                                       StringFormat.SetTabStops (0, new float [] {(float)(Font.Height * 3.7)});
-                               else
-                                       StringFormat.SetTabStops (0, new float [0]);
-                               base.Refresh ();
+                               use_tabstops = value;
+                               
+                               CalculateTabStops ();
                        }
                }
 
@@ -758,9 +837,41 @@ namespace System.Windows.Forms
                                }                               
                        }
 
+                       if (this is CheckedListBox)
+                               rect.Width += 15;
+                               
                        return rect;
                }
 
+#if NET_2_0
+               [EditorBrowsable (EditorBrowsableState.Advanced)]
+               protected override Rectangle GetScaledBounds (Rectangle bounds, SizeF factor, BoundsSpecified specified)
+               {
+                       // For some reason, it always uses the control's Height instead of
+                       // the Height passed in
+                       bounds.Height = this.bounds.Height;
+
+                       if ((specified & BoundsSpecified.X) == BoundsSpecified.X)
+                               bounds.X = (int)Math.Round (bounds.Left * factor.Width);
+                       if ((specified & BoundsSpecified.Y) == BoundsSpecified.Y)
+                               bounds.Y = (int)Math.Round (bounds.Top * factor.Height);
+                       
+                       if ((specified & BoundsSpecified.Width) == BoundsSpecified.Width && !GetStyle (ControlStyles.FixedWidth))
+                               bounds.Width = (int)Math.Round (bounds.Width * factor.Width);
+                       if ((specified & BoundsSpecified.Height) == BoundsSpecified.Height && !GetStyle (ControlStyles.FixedHeight))
+                               bounds.Height = (int)Math.Round (bounds.Height * factor.Height);
+
+                       Size size = ClientSizeFromSize (bounds.Size);
+
+                       if ((specified & BoundsSpecified.Width) == BoundsSpecified.Width && !GetStyle (ControlStyles.FixedWidth))
+                               bounds.Width -= (int)((bounds.Width - size.Width) * (factor.Width - 1));
+                       if ((specified & BoundsSpecified.Height) == BoundsSpecified.Height && !GetStyle (ControlStyles.FixedHeight))
+                               bounds.Height -= (int)((bounds.Height - size.Height) * (factor.Height - 1));
+
+                       return bounds;
+               }
+#endif
+
                public bool GetSelected (int index)
                {
                        if (index < 0 || index >= Items.Count)
@@ -846,7 +957,7 @@ namespace System.Windows.Forms
                        if (explicit_item_height) {
                                base.Refresh ();
                        } else {
-                               SizeF sz = DeviceContext.MeasureString ("The quick brown Fox", Font);
+                               SizeF sz = TextRenderer.MeasureString ("The quick brown Fox", Font);
                                item_height = (int) sz.Height;
                                if (IntegralHeight)
                                        UpdateListBoxBounds ();
@@ -918,6 +1029,32 @@ namespace System.Windows.Forms
                                item_heights.Remove (Items [index]);
                }
 
+#if NET_2_0
+               protected override void RefreshItems ()
+               {
+                       for (int i = 0; i < Items.Count; i++) {
+                               RefreshItem (i);
+                       }
+               }
+
+               public override void ResetBackColor ()
+               {
+                       base.ResetBackColor ();
+               }
+
+               public override void ResetForeColor ()
+               {
+                       base.ResetForeColor ();
+               }
+
+               protected override void ScaleControl (SizeF factor, BoundsSpecified specified)
+               {
+                       Rectangle new_bounds = GetScaledBounds (new Rectangle (Location, new Size (Width, Height)), factor, specified);
+
+                       SetBounds (new_bounds.X, new_bounds.Y, new_bounds.Width, new_bounds.Height, specified);
+               }
+#endif
+               
                protected override void SetBoundsCore (int x,  int y, int width, int height, BoundsSpecified specified)
                {
                        if ((specified & BoundsSpecified.Height) == BoundsSpecified.Height)
@@ -1006,6 +1143,25 @@ namespace System.Windows.Forms
 
                #region Private Methods
 
+               private void CalculateTabStops ()
+               {
+                       if (use_tabstops) {
+#if NET_2_0
+                               if (use_custom_tab_offsets) {
+                                       float[] f = new float[custom_tab_offsets.Count];
+                                       custom_tab_offsets.CopyTo (f, 0);
+                                       StringFormat.SetTabStops (0, f);
+                               }
+                               else
+#endif
+                                       StringFormat.SetTabStops (0, new float[] { (float)(Font.Height * 3.7) });
+                       }       
+                       else
+                               StringFormat.SetTabStops (0, new float[0]);
+                               
+                       this.Invalidate ();
+               }
+
                private Size canvas_size;
 
                private void LayoutListBox ()
@@ -1045,9 +1201,14 @@ namespace System.Windows.Forms
                                height = Items.Count * ItemHeight;
                                width = 0;
                                for (int i = 0; i < Items.Count; i++) {
-                                       SizeF sz = DeviceContext.MeasureString (GetItemText (Items[i]), Font);
-                                       if ((int) sz.Width > width)
-                                               width = (int) sz.Width;
+                                       SizeF sz = TextRenderer.MeasureString (GetItemText (Items[i]), Font);
+                                       int t = (int)sz.Width;
+                                       
+                                       if (this is CheckedListBox)
+                                               t += 15;
+                                               
+                                       if (t > width)
+                                               width = t;
                                }
                                break;
                        }
@@ -1123,6 +1284,19 @@ namespace System.Windows.Forms
                        return item_rect;
                }
 
+               internal override int HeightInternal {
+                       get { 
+                               if (requested_height > -1)
+                                       return requested_height;
+                               else
+                                       return bounds.Height;
+                       }
+                       set {
+                               base.HeightInternal = value;
+                               requested_height = value;
+                       }
+               }
+
                // Value Changed
                private void HorizontalScrollEvent (object sender, EventArgs e)
                {
@@ -1172,6 +1346,11 @@ namespace System.Windows.Forms
                        return -1;
                }
 
+               internal override bool IsInputCharInternal (char charCode)
+               {
+                       return true;
+               }
+
                private int LastVisibleItem ()
                {
                        Rectangle item_rect;
@@ -1480,6 +1659,8 @@ namespace System.Windows.Forms
 
                internal void InvalidateItem (int index)
                {
+                       if (!IsHandleCreated)
+                               return;
                        Rectangle bounds = GetItemDisplayRectangle (index, top_index);
                        if (ClientRectangle.IntersectsWith (bounds))
                                Invalidate (bounds);
@@ -1808,8 +1989,7 @@ namespace System.Windows.Forms
                                                string_format.Alignment = StringAlignment.Far;
                                        else
                                                string_format.Alignment = StringAlignment.Near;
-                                       if (use_tabstops)
-                                               string_format.SetTabStops (0, new float [] {(float)(Font.Height * 3.7)});
+                                       CalculateTabStops ();
                                }
                                return string_format;
                        }
@@ -1840,7 +2020,7 @@ namespace System.Windows.Forms
                        if (requested_height == -1)
                                return;
 
-                       SetBounds(0, 0, 0, requested_height, BoundsSpecified.Height);
+                       SetBounds(bounds.X, bounds.Y, bounds.Width, requested_height, BoundsSpecified.None);
                }
 
                private void UpdateScrollBars ()
@@ -1881,7 +2061,7 @@ namespace System.Windows.Forms
                        } else if (canvas_size.Width > ClientRectangle.Width && HorizontalScrollbar) {
                                show = true;                                    
                                hscrollbar.Maximum = canvas_size.Width;
-                               hscrollbar.LargeChange = items_area.Width;
+                               hscrollbar.LargeChange = Math.Max (0, items_area.Width);
                        }
 
                        hbar_offset = hscrollbar.Value;
@@ -1933,6 +2113,173 @@ namespace System.Windows.Forms
 
                #endregion Private Methods
 
+#if NET_2_0
+               public class IntegerCollection : IList, ICollection, IEnumerable
+               {
+                       private ListBox owner;
+                       private List<int> list;
+                       
+                       #region Public Constructor
+                       public IntegerCollection (ListBox owner)
+                       {
+                               this.owner = owner;
+                               list = new List<int> ();
+                       }
+                       #endregion
+
+                       #region Public Properties
+                       [Browsable (false)]
+                       public int Count {
+                               get { return list.Count; }
+                       }
+                       
+                       public int this [int index] {
+                               get { return list[index]; }
+                               set { list[index] = value; owner.CalculateTabStops (); }
+                       }
+                       #endregion
+
+                       #region Public Methods
+                       public int Add (int item)
+                       {
+                               // This collection does not allow duplicates
+                               if (!list.Contains (item)) {
+                                       list.Add (item);
+                                       list.Sort ();
+                                       owner.CalculateTabStops ();
+                               }
+                               
+                               return list.IndexOf (item);
+                       }
+                       
+                       public void AddRange (int[] items)
+                       {
+                               foreach (int i in items)
+                                       if (!list.Contains (i))
+                                               list.Add (i);
+                                               
+                               list.Sort ();
+                       }
+                       
+                       public void AddRange (IntegerCollection value)
+                       {
+                               foreach (int i in value)
+                                       if (!list.Contains (i))
+                                               list.Add (i);
+
+                               list.Sort ();
+                       }
+                       
+                       public void Clear ()
+                       {
+                               list.Clear ();
+                               owner.CalculateTabStops ();
+                       }
+                       
+                       public bool Contains (int item)
+                       {
+                               return list.Contains (item);
+                       }
+                       
+                       public void CopyTo (Array destination, int index)
+                       {
+                               for (int i = index; i < list.Count; i++)
+                                       destination.SetValue (list[i], i);
+                       }
+                       
+                       public int IndexOf (int item)
+                       {
+                               return list.IndexOf (item);
+                       }
+                       
+                       public void Remove (int item)
+                       {
+                               list.Remove (item);
+                               list.Sort ();
+                               owner.CalculateTabStops ();
+                       }
+                       
+                       public void RemoveAt (int index)
+                       {
+                               list.RemoveAt (index);
+                               list.Sort ();
+                               owner.CalculateTabStops ();
+                       }
+                       #endregion
+
+                       #region IEnumerable Members
+                       IEnumerator IEnumerable.GetEnumerator ()
+                       {
+                               return list.GetEnumerator ();
+                       }
+                       #endregion
+
+                       #region IList Members
+                       int IList.Add (object value)
+                       {
+                               return Add ((int)value);
+                       }
+
+                       void IList.Clear ()
+                       {
+                               Clear ();
+                       }
+
+                       bool IList.Contains (object value)
+                       {
+                               return Contains ((int)value);
+                       }
+
+                       int IList.IndexOf (object value)
+                       {
+                               return IndexOf ((int)value);
+                       }
+
+                       void IList.Insert (int index, object value)
+                       {
+                               throw new Exception ("The method or operation is not implemented.");
+                       }
+
+                       bool IList.IsFixedSize
+                       {
+                               get { return false; }
+                       }
+
+                       bool IList.IsReadOnly
+                       {
+                               get { return false; }
+                       }
+
+                       void IList.Remove (object value)
+                       {
+                               Remove ((int)value);
+                       }
+
+                       void IList.RemoveAt (int index)
+                       {
+                               RemoveAt (index);
+                       }
+
+                       object IList.this[int index] {
+                               get { return this[index]; }
+                               set { this[index] = (int)value; }
+                       }
+                       #endregion
+
+                       #region ICollection Members
+                       bool ICollection.IsSynchronized
+                       {
+                               get { throw new Exception ("The method or operation is not implemented."); }
+                       }
+
+                       object ICollection.SyncRoot
+                       {
+                               get { throw new Exception ("The method or operation is not implemented."); }
+                       }
+                       #endregion
+               }
+#endif
+
                [ListBindable (false)]
                public class ObjectCollection : IList, ICollection, IEnumerable
                {
@@ -2021,6 +2368,9 @@ namespace System.Windows.Forms
 
                        public void AddRange (object[] items)
                        {
+                               if (items == null)
+                                       throw new ArgumentNullException ("items");
+
                                foreach (object mi in items)
                                        AddItem (mi);
 
@@ -2029,6 +2379,9 @@ namespace System.Windows.Forms
 
                        public void AddRange (ObjectCollection col)
                        {
+                               if (col == null)
+                                       throw new ArgumentNullException ("col");
+
                                foreach (object mi in col)
                                        AddItem (mi);
 
@@ -2051,6 +2404,9 @@ namespace System.Windows.Forms
                        }
                        public bool Contains (object obj)
                        {
+                               if (obj == null)
+                                       throw new ArgumentNullException ("obj");
+
                                return object_items.Contains (obj);
                        }
 
@@ -2076,6 +2432,9 @@ namespace System.Windows.Forms
 
                        public int IndexOf (object value)
                        {
+                               if (value == null)
+                                       throw new ArgumentNullException ("value");
+
                                return object_items.IndexOf (value);
                        }
 
@@ -2083,6 +2442,8 @@ namespace System.Windows.Forms
                        {
                                if (index < 0 || index > Count)
                                        throw new ArgumentOutOfRangeException ("Index of out range");
+                               if (item == null)
+                                       throw new ArgumentNullException ("item");
                                        
                                owner.BeginUpdate ();
                                object_items.Insert (index, item);
@@ -2092,6 +2453,9 @@ namespace System.Windows.Forms
 
                        public void Remove (object value)
                        {                               
+                               if (value == null)
+                                       return;
+
                                RemoveAt (IndexOf (value));                             
                        }
 
@@ -2168,6 +2532,24 @@ namespace System.Windows.Forms
                        #endregion Public Properties
 
                        #region Public Methods
+#if NET_2_0
+                       public void Add (int index)
+                       {
+                               object item = owner.items[index];
+                               
+                               if (!owner.selection.Contains (item)) {
+                                       owner.selection.Add (item);
+                                       owner.CollectionChanged ();
+                               }
+                       }
+
+                       public void Clear ()
+                       {
+                               owner.selection.Clear ();
+                               owner.CollectionChanged ();
+                       }
+#endif
+
                        public bool Contains (int selectedIndex)
                        {
                                foreach (object o in owner.selection)
@@ -2192,6 +2574,19 @@ namespace System.Windows.Forms
                                return indices.GetEnumerator ();
                        }
 
+#if NET_2_0
+                       public void Remove (int index)
+                       {
+                               object value = owner.items[index];
+                               
+                               if (value == null)
+                                       return;
+
+                               owner.selection.Remove (value);
+                               owner.CollectionChanged ();
+                       }
+#endif
+
                        int IList.Add (object obj)
                        {
                                throw new NotSupportedException ();
@@ -2287,6 +2682,22 @@ namespace System.Windows.Forms
                        #endregion Public Properties
 
                        #region Public Methods
+#if NET_2_0
+                       public void Add (object item)
+                       {
+                               if (!owner.selection.Contains (item)) {
+                                       owner.selection.Add (item);
+                                       owner.CollectionChanged ();
+                               }
+                       }
+
+                       public void Clear ()
+                       {
+                               owner.selection.Clear ();
+                               owner.CollectionChanged ();
+                       }
+#endif
+
                        public bool Contains (object selectedObject)
                        {
                                return owner.selection.Contains (selectedObject);
@@ -2297,6 +2708,17 @@ namespace System.Windows.Forms
                                owner.selection.CopyTo (dest, index);
                        }
 
+#if NET_2_0
+                       public void Remove (object value)
+                       {
+                               if (value == null)
+                                       return;
+
+                               owner.selection.Remove (value);
+                               owner.CollectionChanged ();
+                       }
+#endif
+
                        int IList.Add (object value)
                        {
                                throw new NotSupportedException ();