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