2005-05-11 Jordi Mas i Hernandez <jordi@ximian.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)]\r
86                 public CheckedListBox.CheckedIndexCollection CheckedIndices {
87                         get {return checked_indices; }
88                 }
89                                 
90                 [Browsable (false)]
91                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]\r
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)]\r
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                 \r
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.Checked);
189                 }
190                 \r
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 (check_onclick) {
209                                 if (focused_item != -1) {
210                                         SetItemChecked (focused_item, !GetItemChecked (focused_item));
211                                 }
212                         }
213                         
214                         if (Click != null)                      
215                                 Click (this, EventArgs.Empty);
216                 }
217                 \r
218                 protected override void OnDrawItem (DrawItemEventArgs e)
219                 {
220                         ThemeEngine.Current.DrawCheckedListBoxItem (this, e);
221                 }
222
223                 protected override void OnFontChanged (EventArgs e)
224                 {
225                         base.OnFontChanged (e);
226                 }
227
228                 protected override void OnHandleCreated (EventArgs e)
229                 {
230                         base.OnHandleCreated (e);
231                 }
232
233                 protected virtual void OnItemCheck (ItemCheckEventArgs ice)
234                 {
235                         if (ItemCheck != null)
236                                 ItemCheck (this, ice);
237                 }
238
239                 protected override void OnKeyPress (KeyPressEventArgs e)
240                 {
241                         base.OnKeyPress (e);
242                         
243                         if (e.KeyChar == ' ') { // Space should check focused item                              
244                                 if (focused_item != -1) {
245                                         SetItemChecked (focused_item, !GetItemChecked (focused_item));
246                                 }
247                         }
248                 }
249
250                 protected override void OnMeasureItem (MeasureItemEventArgs e)
251                 {
252                         if (MeasureItem != null)
253                                 MeasureItem (this, e);
254                 }
255
256                 protected override void OnSelectedIndexChanged (EventArgs e)
257                 {
258                         base.OnSelectedIndexChanged (e);
259                 }
260
261                 public void SetItemChecked (int index, bool value)
262                 {
263                         SetItemCheckState (index, value ? CheckState.Checked : CheckState.Unchecked);
264                 }
265
266                 public void SetItemCheckState (int index, CheckState value)
267                 {
268                         if (index < 0 || index >= Items.Count)
269                                 throw new ArgumentOutOfRangeException ("Index of out range");
270
271                         if (!Enum.IsDefined (typeof (CheckState), value))
272                                 throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for CheckState", value));
273
274                         CheckState old_value = (Items.GetListBoxItem (index)).State;
275                         
276                         if (old_value == value)
277                                 return;
278                         
279                         (Items.GetListBoxItem (index)).State = value;
280
281                         Rectangle invalidate = GetItemDisplayRectangle (index, LBoxInfo.top_item);
282
283                         switch (value) {
284                                 case CheckState.Checked:
285                                         checked_indices.AddIndex (index);
286                                         checked_items.AddObject (Items[index]);
287                                         break;
288                                 case CheckState.Unchecked:
289                                         checked_indices.RemoveIndex (index);
290                                         checked_items.RemoveObject (Items[index]);
291                                         break;
292                                 case CheckState.Indeterminate:
293                                 default:
294                                         break;
295                         }
296
297                         OnItemCheck (new ItemCheckEventArgs (index, value, old_value));
298
299                         if (ClientRectangle.Contains (invalidate))
300                                 Invalidate (invalidate);
301                 }
302
303                 protected override void WmReflectCommand (ref Message m)
304                 {
305                         base.WmReflectCommand (ref m);
306                 }
307
308                 protected override void WndProc (ref Message m)
309                 {
310                         base.WndProc (ref m);
311                 }
312
313                 #endregion Public Methods
314
315                 #region Private Methods
316
317                 internal override void OnMouseDownLB (object sender, MouseEventArgs e)
318                 {
319                         base.OnMouseDownLB (sender, e);
320                         
321                         Rectangle hit_rect, item_rect;
322                         CheckState value =  CheckState.Checked;
323                         bool set_value = false;
324                         int index = IndexFromPointDisplayRectangle (e.X, e.Y);
325
326                         if (index == -1)
327                                 return;
328                         
329                         /* CheckBox hit */
330                         hit_rect = item_rect = GetItemDisplayRectangle (index, LBoxInfo.top_item); // Full item rect
331                         hit_rect.X += ThemeEngine.Current.CheckedListBoxCheckRectangle().X;
332                         hit_rect.Y += ThemeEngine.Current.CheckedListBoxCheckRectangle().Y;
333                         hit_rect.Width = ThemeEngine.Current.CheckedListBoxCheckRectangle().Width;
334                         hit_rect.Height = ThemeEngine.Current.CheckedListBoxCheckRectangle().Height;
335                         
336                         if ((Items.GetListBoxItem (index)).State == CheckState.Checked)
337                                         value = CheckState.Unchecked;
338
339                         if (hit_rect.Contains (e.X, e.Y) == true)  {                            
340                                 set_value = true;
341
342                         } else {
343                                 if (item_rect.Contains (e.X, e.Y) == true) {
344                                         if (!check_onclick) {
345                                                 if ((Items.GetListBoxItem (index)).Selected == true)
346                                                         set_value = true;
347                                         }
348                                 }
349                         }
350
351                         if (set_value)
352                                 SetItemCheckState (index, value);
353                         
354                 }
355
356                 internal override void UpdateItemInfo (UpdateOperation operation, int first, int last)
357                 {
358                         base.UpdateItemInfo (operation, first, last);
359                         CheckedItems.ReCreate ();
360                         CheckedIndices.ReCreate ();
361                 }
362
363                 #endregion Private Methods
364
365                 public class ObjectCollection : ListBox.ObjectCollection
366                 {               
367                         public ObjectCollection (CheckedListBox owner) : base (owner)
368                         {
369                                 
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                         \r
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                                 return cnt;
389                         }
390                 }
391
392                 /*
393                         CheckedListBox.CheckedIndexCollection
394                 */
395                 public class CheckedIndexCollection : IList, ICollection, IEnumerable
396                 {
397                         private CheckedListBox owner;
398                         private ArrayList indices = new ArrayList ();
399
400                         internal CheckedIndexCollection (CheckedListBox owner)
401                         {
402                                 this.owner = owner;
403                         }
404
405                         #region Public Properties
406                         public virtual int Count {
407                                 get { return indices.Count; }
408                         }
409
410                         public virtual bool IsReadOnly {
411                                 get { return true;}
412                         }
413
414                         bool ICollection.IsSynchronized {
415                                 get { return false; }
416                         }
417
418                         bool IList.IsFixedSize{
419                                 get { return true; }
420                         }
421
422                         object ICollection.SyncRoot {
423                                 get { return this; }
424                         }
425
426                         [Browsable (false)]
427                         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
428                         public int this[int index] {
429                                 get {
430                                         if (index < 0 || index >= Count)
431                                                 throw new ArgumentOutOfRangeException ("Index of out range");
432
433                                         return (int) indices[index];
434                                 }
435                         }
436                         #endregion Public Properties
437
438                         public bool Contains (int index)
439                         {
440                                 return indices.Contains (index);
441                         }
442
443
444                         public virtual void CopyTo (Array dest, int index)
445                         {
446                                 indices.CopyTo (dest, index);
447                         }
448
449                         public virtual IEnumerator GetEnumerator ()
450                         {
451                                 return indices.GetEnumerator ();
452                         }
453
454                         int IList.Add (object value)
455                         {
456                                 throw new NotSupportedException ();
457                         }
458
459                         void IList.Clear ()
460                         {
461                                 throw new NotSupportedException ();
462                         }
463
464                         bool IList.Contains (object index)
465                         {
466                                 return Contains ((int)index);
467                         }
468
469                         int IList.IndexOf (object index)
470                         {
471                                 return IndexOf ((int) index);
472                         }
473
474                         void IList.Insert (int index, object value)
475                         {
476                                 throw new NotSupportedException ();
477                         }
478
479                         void IList.Remove (object value)
480                         {
481                                 throw new NotSupportedException ();
482                         }
483
484                         void IList.RemoveAt (int index)
485                         {
486                                 throw new NotSupportedException ();
487                         }
488
489                         object IList.this[int index]{
490                                 get {return indices[index]; }
491                                 set {throw new NotImplementedException (); }
492                         }
493
494                         public int IndexOf (int index)
495                         {
496                                 return indices.IndexOf (index);
497                         }
498
499                         #region Private Methods
500
501                         internal void AddIndex (int index)
502                         {
503                                 indices.Add (index);
504                         }
505
506                         internal void ClearIndices ()
507                         {
508                                 indices.Clear ();
509                         }
510
511                         internal void RemoveIndex (int index)
512                         {
513                                 indices.Remove (index);
514                         }
515
516                         internal void ReCreate ()
517                         {
518                                 indices.Clear ();
519
520                                 for (int i = 0; i < owner.Items.Count; i++) {
521                                         ListBox.ListBoxItem item = owner.Items.GetListBoxItem (i);
522
523                                         if (item.State == CheckState.Checked)
524                                                 indices.Add (item.Index);
525                                 }
526                         }
527
528                         #endregion Private Methods
529                 }
530
531                 /*
532                         CheckedItemCollection
533                 */
534                 public class CheckedItemCollection : IList, ICollection, IEnumerable
535                 {
536                         private CheckedListBox owner;
537                         private ArrayList object_items = new ArrayList ();
538
539                         internal CheckedItemCollection (CheckedListBox owner)
540                         {
541                                 this.owner = owner;
542                         }
543
544                         #region Public Properties
545                         public virtual int Count {
546                                 get { return object_items.Count; }
547                         }
548
549                         public virtual bool IsReadOnly {
550                                 get { return true; }
551                         }
552
553                         [Browsable (false)]
554                         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
555                         public virtual object this [int index] {
556                                 get {
557                                         if (index < 0 || index >= Count)
558                                                 throw new ArgumentOutOfRangeException ("Index of out range");
559
560                                         return object_items[index];
561                                 }
562                                 set {throw new NotSupportedException ();}
563                         }
564
565                         bool ICollection.IsSynchronized {
566                                 get { return true; }
567                         }
568
569                         object ICollection.SyncRoot {
570                                 get { return this; }
571                         }
572
573                         bool IList.IsFixedSize {
574                                 get { return true; }
575                         }
576
577                         object IList.this[int index] {
578                                 get { return object_items[index]; }
579                                 set { throw new NotSupportedException (); }
580                         }
581
582                         #endregion Public Properties
583
584                         #region Public Methods
585                         public virtual bool Contains (object selectedObject)
586                         {
587                                 return object_items.Contains (selectedObject);
588                         }
589
590                         public virtual void CopyTo (Array dest, int index)
591                         {
592                                 object_items.CopyTo (dest, index);
593                         }
594
595                         int IList.Add (object value)
596                         {
597                                 throw new NotSupportedException ();
598                         }
599
600                         void IList.Clear ()
601                         {
602                                 throw new NotSupportedException ();
603                         }
604
605                         bool IList.Contains (object selectedIndex)
606                         {
607                                 throw new NotImplementedException ();
608                         }
609                                 \r
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         \r
625                         public int IndexOf (object item)
626                         {
627                                 return object_items.IndexOf (item);
628                         }
629
630                         public virtual IEnumerator GetEnumerator ()
631                         {
632                                 return object_items.GetEnumerator ();
633                         }
634
635                         #endregion Public Methods
636
637                         #region Private Methods
638                         internal void AddObject (object obj)
639                         {
640                                 object_items.Add (obj);
641                         }
642
643                         internal void ClearObjects ()
644                         {
645                                 object_items.Clear ();
646                         }
647
648                         internal void ReCreate ()
649                         {
650                                 object_items.Clear ();
651
652                                 for (int i = 0; i < owner.Items.Count; i++) {
653                                         ListBox.ListBoxItem item = owner.Items.GetListBoxItem (i);
654
655                                         if (item.State == CheckState.Checked)
656                                                 object_items.Add (owner.Items[item.Index]);
657                                 }
658                         }
659
660                         internal void RemoveObject (object obj)
661                         {
662                                 object_items.Remove (obj);
663                         }
664                         #endregion Private Methods
665                 }
666         }
667 }
668