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