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