Merge pull request #1275 from ranma42/fix-lib64
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / CheckedListBox.cs
1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
8 //
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 //
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 //
20 // Copyright (c) 2004-2006 Novell, Inc.
21 //
22 // Authors:
23 //      Jordi Mas i Hernandez, jordi@ximian.com
24 //      Mike Kestner  <mkestner@novell.com>
25 //
26 //
27
28 using System;
29 using System.Drawing;
30 using System.Collections;
31 using System.ComponentModel;
32 using System.Reflection;
33 using System.Runtime.InteropServices;
34
35 namespace System.Windows.Forms
36 {
37         [ClassInterface (ClassInterfaceType.AutoDispatch)]
38         [ComVisible (true)]
39         [LookupBindingPropertiesAttribute ()]
40         public class CheckedListBox : ListBox
41         {
42                 private CheckedIndexCollection checked_indices;
43                 private CheckedItemCollection checked_items;
44                 private Hashtable check_states = new Hashtable ();
45                 private bool check_onclick = false;
46                 private bool three_dcheckboxes = false;
47                 
48                 public CheckedListBox ()
49                 {
50                         checked_indices = new CheckedIndexCollection (this);
51                         checked_items = new CheckedItemCollection (this);
52                         SetStyle (ControlStyles.ResizeRedraw, true);
53                 }
54
55                 #region events
56                 static object ItemCheckEvent = new object ();
57
58                 [Browsable (true)]
59                 [EditorBrowsable (EditorBrowsableState.Always)]
60                 public new event EventHandler Click {
61                         add { base.Click += value; }
62                         remove { base.Click -= value; }
63                 }
64                 
65                 [Browsable (false)]
66                 [EditorBrowsable (EditorBrowsableState.Never)]
67                 public new event EventHandler DataSourceChanged {
68                         add { base.DataSourceChanged += value; }
69                         remove { base.DataSourceChanged -= value; }
70                 }
71                 
72                 [Browsable (false)]
73                 [EditorBrowsable (EditorBrowsableState.Never)]
74                 public new event EventHandler DisplayMemberChanged {
75                         add { base.DisplayMemberChanged += value; }
76                         remove { base.DisplayMemberChanged -= value; }
77                 }
78                 
79                 [Browsable (false)]
80                 [EditorBrowsable (EditorBrowsableState.Never)]
81                 public new event DrawItemEventHandler DrawItem {
82                         add { base.DrawItem += value; }
83                         remove { base.DrawItem -= value; }
84                 }
85
86                 [Browsable (false)]
87                 [EditorBrowsable (EditorBrowsableState.Never)]
88                 public new event MeasureItemEventHandler MeasureItem {
89                         add { base.MeasureItem += value; }
90                         remove { base.MeasureItem -= value; }
91                 }
92                 
93                 [Browsable (false)]
94                 [EditorBrowsable (EditorBrowsableState.Never)]
95                 public new event EventHandler ValueMemberChanged {
96                         add { base.ValueMemberChanged += value; }
97                         remove { base.ValueMemberChanged -= value; }
98                 }
99
100                 public event ItemCheckEventHandler ItemCheck {
101                         add { Events.AddHandler (ItemCheckEvent, value); }
102                         remove { Events.RemoveHandler (ItemCheckEvent, value); }
103                 }
104                 
105                 [Browsable (true)]
106                 [EditorBrowsable (EditorBrowsableState.Always)]
107                 public new event MouseEventHandler MouseClick {
108                         add { base.MouseClick += value; }
109                         remove { base.MouseClick -= value; }
110                 }
111                 #endregion Events
112
113                 #region Public Properties
114                 
115                 [Browsable (false)]
116                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
117                 public CheckedListBox.CheckedIndexCollection CheckedIndices {
118                         get {return checked_indices; }
119                 }
120                                 
121                 [Browsable (false)]
122                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
123                 public CheckedListBox.CheckedItemCollection CheckedItems {
124                         get {return checked_items; }
125                 }
126
127                 [DefaultValue (false)]
128                 public bool CheckOnClick {
129                         get { return check_onclick; }
130                         set { check_onclick = value; }
131                 }
132
133                 protected override CreateParams CreateParams {
134                         get { return base.CreateParams;}
135                 }
136                 
137                 [EditorBrowsable (EditorBrowsableState.Never)]
138                 [Browsable (false)]
139                 public new object DataSource {
140                         get { return base.DataSource; }
141                         // FIXME: docs say you can't use a DataSource with this subclass
142                         set { base.DataSource = value; }
143                 }
144
145                 [EditorBrowsable (EditorBrowsableState.Never)]
146                 [Browsable (false)]
147                 public new string DisplayMember {
148                         get { return base.DisplayMember; }
149                         set { base.DisplayMember = value; }
150                 }
151
152                 [Browsable (false)]
153                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
154                 [EditorBrowsable (EditorBrowsableState.Never)]
155                 public override DrawMode DrawMode {
156                         get { return DrawMode.Normal; }
157                         set { /* Not an exception, but has no effect. */ }
158                 }
159
160                 [Browsable (false)]
161                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
162                 [EditorBrowsable (EditorBrowsableState.Never)]
163                 public override int ItemHeight {
164                         get { return base.ItemHeight; }
165                         set { /* Not an exception, but has no effect. */ }
166                 }
167
168                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
169                 [Localizable (true)]
170                 [Editor ("System.Windows.Forms.Design.ListControlStringCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
171                 public new CheckedListBox.ObjectCollection Items {
172                         get { return (CheckedListBox.ObjectCollection) base.Items; }
173                 }
174
175                 public override SelectionMode SelectionMode {
176                         get { return base.SelectionMode; }
177                         set {
178                                 if (!Enum.IsDefined (typeof (SelectionMode), value))
179                                         throw new InvalidEnumArgumentException ("value", (int) value, typeof (SelectionMode));
180
181                                 if (value == SelectionMode.MultiSimple || value == SelectionMode.MultiExtended)
182                                         throw new ArgumentException ("Multi selection not supported on CheckedListBox");
183
184                                 base.SelectionMode = value;
185                         }
186                 }
187
188                 [DefaultValue (false)]
189                 public bool ThreeDCheckBoxes {
190                         get { return three_dcheckboxes; }
191                         set {
192                                 if (three_dcheckboxes == value)
193                                         return;
194
195                                 three_dcheckboxes = value;
196                                 Refresh ();
197                         }
198                 }
199
200                 [Browsable (false)]
201                 [EditorBrowsable (EditorBrowsableState.Never)]
202                 public new string ValueMember {
203                         get { return base.ValueMember; }
204                         set { base.ValueMember = value; }                       
205                 }
206                 
207                 [Browsable (false)]
208                 [EditorBrowsable (EditorBrowsableState.Never)]
209                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
210                 public new Padding Padding {
211                         get { return base.Padding; }
212                         set { base.Padding = value; }
213                 }
214                 #endregion Public Properties
215
216                 #region Public Methods
217
218                 protected override AccessibleObject CreateAccessibilityInstance ()
219                 {
220                         return base.CreateAccessibilityInstance ();
221                 }
222                 
223                 protected override ListBox.ObjectCollection CreateItemCollection ()
224                 {
225                         return new ObjectCollection (this);
226                 }
227
228                 public bool GetItemChecked (int index)
229                 {
230                         return check_states.Contains (Items [index]);
231                 }
232                 
233                 public CheckState GetItemCheckState (int index)
234                 {
235                         if (index < 0 || index >= Items.Count)
236                                 throw new ArgumentOutOfRangeException ("Index of out range");
237
238                         object o = Items [index];
239                         if (check_states.Contains (o))
240                                 return (CheckState) check_states [o];
241                         else
242                                 return CheckState.Unchecked;
243                 }
244
245                 protected override void OnBackColorChanged (EventArgs e)
246                 {
247                         base.OnBackColorChanged (e);
248                 }
249
250                 protected override void OnClick (EventArgs e)
251                 {
252                         base.OnClick (e);
253                 }
254                 
255                 protected override void OnDrawItem (DrawItemEventArgs e)
256                 {
257                         if (check_states.Contains (Items [e.Index])) {
258                                 DrawItemState state = e.State | DrawItemState.Checked;
259                                 if (((CheckState) check_states [Items [e.Index]]) == CheckState.Indeterminate)
260                                         state |= DrawItemState.Inactive;
261                                 e = new DrawItemEventArgs (e.Graphics, e.Font, e.Bounds, e.Index, state, e.ForeColor, e.BackColor);
262                         }
263                         ThemeEngine.Current.DrawCheckedListBoxItem (this, e);
264                 }
265
266                 protected override void OnFontChanged (EventArgs e)
267                 {
268                         base.OnFontChanged (e);
269                 }
270
271                 protected override void OnHandleCreated (EventArgs e)
272                 {
273                         base.OnHandleCreated (e);
274                 }
275
276                 protected virtual void OnItemCheck (ItemCheckEventArgs ice)
277                 {
278                         ItemCheckEventHandler eh = (ItemCheckEventHandler)(Events [ItemCheckEvent]);
279                         if (eh != null)
280                                 eh (this, ice);
281                 }
282
283                 protected override void OnKeyPress (KeyPressEventArgs e)
284                 {
285                         base.OnKeyPress (e);
286                         
287                         if (e.KeyChar == ' ' && FocusedItem != -1)
288                                 SetItemChecked (FocusedItem, !GetItemChecked (FocusedItem));
289                 }
290
291                 protected override void OnMeasureItem (MeasureItemEventArgs e)
292                 {
293                         base.OnMeasureItem (e);
294                 }
295
296                 protected override void OnSelectedIndexChanged (EventArgs e)
297                 {
298                         base.OnSelectedIndexChanged (e);
299                 }
300
301                 protected override void RefreshItems ()
302                 {
303                         base.RefreshItems ();
304                 }
305
306                 public void SetItemChecked (int index, bool value)
307                 {
308                         SetItemCheckState (index, value ? CheckState.Checked : CheckState.Unchecked);
309                 }
310
311                 public void SetItemCheckState (int index, CheckState value)
312                 {
313                         if (index < 0 || index >= Items.Count)
314                                 throw new ArgumentOutOfRangeException ("Index of out range");
315
316                         if (!Enum.IsDefined (typeof (CheckState), value))
317                                 throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for CheckState", value));
318
319                         CheckState old_value = GetItemCheckState (index);
320                         
321                         if (old_value == value)
322                                 return;
323
324                         ItemCheckEventArgs icea = new ItemCheckEventArgs (index, value, old_value);
325                         OnItemCheck (icea);
326
327                         switch (icea.NewValue) {
328                         case CheckState.Checked:
329                         case CheckState.Indeterminate:
330                                 check_states[Items[index]] = icea.NewValue;
331                                 break;
332                         case CheckState.Unchecked:
333                                 check_states.Remove (Items[index]);
334                                 break;
335                         default:
336                                 break;
337                         }
338
339                         UpdateCollections ();
340
341                         InvalidateCheckbox (index);
342                 }
343
344                 protected override void WmReflectCommand (ref Message m)
345                 {
346                         base.WmReflectCommand (ref m);
347                 }
348
349                 protected override void WndProc (ref Message m)
350                 {
351                         base.WndProc (ref m);
352                 }
353
354                 #endregion Public Methods
355
356                 #region Private Methods
357
358                 int last_clicked_index = -1;
359
360                 internal override void OnItemClick (int index)
361                 {                       
362                         if ((CheckOnClick || last_clicked_index == index) && index > -1) {
363                                 if (GetItemChecked (index))
364                                         SetItemCheckState (index, CheckState.Unchecked);
365                                 else
366                                         SetItemCheckState (index, CheckState.Checked);
367                         }
368                         
369                         last_clicked_index = index;
370                         base.OnItemClick (index);
371                 }
372
373                 internal override void CollectionChanged ()
374                 {
375                         base.CollectionChanged ();
376                         UpdateCollections ();
377                 }
378
379                 private void InvalidateCheckbox (int index)
380                 {
381                         Rectangle area = GetItemDisplayRectangle (index, TopIndex);
382                         area.X += 2;
383                         area.Y += (area.Height - 11) / 2;
384                         area.Width = 11;
385                         area.Height = 11;
386                         Invalidate (area);
387                 }
388
389                 private void UpdateCollections ()
390                 {
391                         CheckedItems.Refresh ();
392                         CheckedIndices.Refresh ();
393                 }
394
395                 #endregion Private Methods
396
397                 public new class ObjectCollection : ListBox.ObjectCollection
398                 {               
399                         private CheckedListBox owner;
400
401                         public ObjectCollection (CheckedListBox owner) : base (owner)
402                         {
403                                 this.owner = owner;                             
404                         }
405
406                         public int Add (object item, bool isChecked)
407                         {
408                                 return Add (item, isChecked ? CheckState.Checked : CheckState.Unchecked);
409                         }
410                         
411                         public int Add (object item, CheckState check)
412                         {
413                                 int idx = Add (item);
414
415                                 ItemCheckEventArgs icea = new ItemCheckEventArgs (idx, check, CheckState.Unchecked);
416                                 
417                                 if (check == CheckState.Checked)
418                                         owner.OnItemCheck (icea);
419                                         
420                                 if (icea.NewValue != CheckState.Unchecked)
421                                         owner.check_states[item] = icea.NewValue;
422                                         
423                                 owner.UpdateCollections ();
424                                 return idx;
425                         }
426                 }
427
428                 public class CheckedIndexCollection : IList, ICollection, IEnumerable
429                 {
430                         private CheckedListBox owner;
431                         private ArrayList indices = new ArrayList ();
432
433                         internal CheckedIndexCollection (CheckedListBox owner)
434                         {
435                                 this.owner = owner;
436                         }
437
438                         #region Public Properties
439                         public int Count {
440                                 get { return indices.Count; }
441                         }
442
443                         public bool IsReadOnly {
444                                 get { return true;}
445                         }
446
447                         bool ICollection.IsSynchronized {
448                                 get { return false; }
449                         }
450
451                         bool IList.IsFixedSize{
452                                 get { return true; }
453                         }
454
455                         object ICollection.SyncRoot {
456                                 get { return this; }
457                         }
458
459                         [Browsable (false)]
460                         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
461                         public int this[int index] {
462                                 get {
463                                         if (index < 0 || index >= Count)
464                                                 throw new ArgumentOutOfRangeException ("Index of out range");
465
466                                         return (int) indices[index];
467                                 }
468                         }
469                         #endregion Public Properties
470
471                         public bool Contains (int index)
472                         {
473                                 return indices.Contains (index);
474                         }
475
476
477                         public void CopyTo (Array dest, int index)
478                         {
479                                 indices.CopyTo (dest, index);
480                         }
481
482                         public IEnumerator GetEnumerator ()
483                         {
484                                 return indices.GetEnumerator ();
485                         }
486
487                         int IList.Add (object value)
488                         {
489                                 throw new NotSupportedException ();
490                         }
491
492                         void IList.Clear ()
493                         {
494                                 throw new NotSupportedException ();
495                         }
496
497                         bool IList.Contains (object index)
498                         {
499                                 return Contains ((int)index);
500                         }
501
502                         int IList.IndexOf (object index)
503                         {
504                                 return IndexOf ((int) index);
505                         }
506
507                         void IList.Insert (int index, object value)
508                         {
509                                 throw new NotSupportedException ();
510                         }
511
512                         void IList.Remove (object value)
513                         {
514                                 throw new NotSupportedException ();
515                         }
516
517                         void IList.RemoveAt (int index)
518                         {
519                                 throw new NotSupportedException ();
520                         }
521
522                         object IList.this[int index]{
523                                 get {return indices[index]; }
524                                 set {throw new NotImplementedException (); }
525                         }
526
527                         public int IndexOf (int index)
528                         {
529                                 return indices.IndexOf (index);
530                         }
531
532                         #region Private Methods
533                         internal void Refresh ()
534                         {
535                                 indices.Clear ();
536                                 for (int i = 0; i < owner.Items.Count; i++)
537                                         if (owner.check_states.Contains (owner.Items [i]))
538                                                 indices.Add (i);
539                         }
540                         #endregion Private Methods
541
542                 }
543
544                 public class CheckedItemCollection : IList, ICollection, IEnumerable
545                 {
546                         private CheckedListBox owner;
547                         private ArrayList list = new ArrayList ();
548
549                         internal CheckedItemCollection (CheckedListBox owner)
550                         {
551                                 this.owner = owner;
552                         }
553
554                         #region Public Properties
555                         public int Count {
556                                 get { return list.Count; }
557                         }
558
559                         public bool IsReadOnly {
560                                 get { return true; }
561                         }
562
563                         [Browsable (false)]
564                         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
565                         public object this [int index] {
566                                 get {
567                                         if (index < 0 || index >= Count)
568                                                 throw new ArgumentOutOfRangeException ("Index of out range");
569
570                                         return list[index];
571                                 }
572                                 set {throw new NotSupportedException ();}
573                         }
574
575                         bool ICollection.IsSynchronized {
576                                 get { return true; }
577                         }
578
579                         object ICollection.SyncRoot {
580                                 get { return this; }
581                         }
582
583                         bool IList.IsFixedSize {
584                                 get { return true; }
585                         }
586
587                         #endregion Public Properties
588
589                         #region Public Methods
590                         public bool Contains (object item)
591                         {
592                                 return list.Contains (item);
593                         }
594
595                         public void CopyTo (Array dest, int index)
596                         {
597                                 list.CopyTo (dest, index);
598                         }
599
600                         int IList.Add (object value)
601                         {
602                                 throw new NotSupportedException ();
603                         }
604
605                         void IList.Clear ()
606                         {
607                                 throw new NotSupportedException ();
608                         }
609
610                         void IList.Insert (int index, object value)
611                         {
612                                 throw new NotSupportedException ();
613                         }
614
615                         void IList.Remove (object value)
616                         {
617                                 throw new NotSupportedException ();
618                         }
619
620                         void IList.RemoveAt (int index)
621                         {
622                                 throw new NotSupportedException ();
623                         }
624         
625                         public int IndexOf (object item)
626                         {
627                                 return list.IndexOf (item);
628                         }
629
630                         public IEnumerator GetEnumerator ()
631                         {
632                                 return list.GetEnumerator ();
633                         }
634
635                         #endregion Public Methods
636
637                         #region Private Methods
638                         internal void Refresh ()
639                         {
640                                 list.Clear ();
641                                 for (int i = 0; i < owner.Items.Count; i++)
642                                         if (owner.check_states.Contains (owner.Items [i]))
643                                                 list.Add (owner.Items[i]);
644                         }
645                         #endregion Private Methods
646                 }
647                 [DefaultValue (false)]
648                 public bool UseCompatibleTextRendering {
649                         get { return use_compatible_text_rendering; }
650                         set { use_compatible_text_rendering = value; }
651                 }
652         }
653 }
654