Mark tests as not working under TARGET_JVM
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / ListViewItem.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 Novell, Inc. (http://www.novell.com)
21 //
22 // Author:
23 //      Ravindra (rkumar@novell.com)
24 //      Mike Kestner <mkestner@novell.com>
25 //      Daniel Nauck (dna(at)mono-project(dot)de)
26
27 using System.Collections;
28 using System.ComponentModel;
29 using System.Drawing;
30 using System.Runtime.Serialization;
31
32 namespace System.Windows.Forms
33 {
34         [DefaultProperty ("Text")]
35         [DesignTimeVisible (false)]
36         [Serializable]
37         [ToolboxItem (false)]
38         [TypeConverter (typeof (ListViewItemConverter))]
39         public class ListViewItem : ICloneable, ISerializable
40         {
41                 #region Instance Variables
42                 private int image_index = -1;
43                 private bool is_checked = false;
44                 private bool is_focused = false;
45                 private int state_image_index = -1;
46                 private ListViewSubItemCollection sub_items;
47                 private object tag;
48                 private bool use_item_style = true;
49 #if NET_2_0
50                 private ListViewGroup group = null;
51                 private string name = String.Empty;
52                 private string image_key = String.Empty;
53                 int index;                      // cached index for VirtualMode
54 #endif
55                 Rectangle bounds;
56                 Rectangle checkbox_rect;        // calculated by CalcListViewItem method
57                 Rectangle icon_rect;
58                 Rectangle item_rect;
59                 Rectangle label_rect;
60                 ListView owner;
61                 Font font;
62                 bool selected;
63
64                 internal int row;
65                 internal int col;
66
67                 #endregion Instance Variables
68
69                 #region Public Constructors
70                 public ListViewItem ()
71                 {
72                         this.sub_items = new ListViewSubItemCollection (this);
73                         this.sub_items.Add ("");
74                 }
75
76                 public ListViewItem (string text) : this (text, -1)
77                 {
78                 }
79
80                 public ListViewItem (string [] items) : this (items, -1)
81                 {
82                 }
83
84                 public ListViewItem (ListViewItem.ListViewSubItem [] subItems, int imageIndex)
85                 {
86                         this.sub_items = new ListViewSubItemCollection (this);
87                         this.sub_items.AddRange (subItems);
88                         this.image_index = imageIndex;
89                 }
90
91                 public ListViewItem (string text, int imageIndex)
92                 {
93                         this.image_index = imageIndex;
94                         this.sub_items = new ListViewSubItemCollection (this);
95                         this.sub_items.Add (text);
96                 }
97
98                 public ListViewItem (string [] items, int imageIndex)
99                 {
100                         this.sub_items = new ListViewSubItemCollection (this);
101                         this.sub_items.AddRange (items);
102                         this.image_index = imageIndex;
103                 }
104
105                 public ListViewItem (string [] items, int imageIndex, Color foreColor, 
106                                      Color backColor, Font font)
107                 {
108                         this.sub_items = new ListViewSubItemCollection (this);
109                         this.sub_items.AddRange (items);
110                         this.image_index = imageIndex;
111                         ForeColor = foreColor;
112                         BackColor = backColor;
113                         this.font = font;
114                 }
115
116 #if NET_2_0
117                 public ListViewItem(string[] items, string imageKey) : this(items)
118                 {
119                         this.ImageKey = imageKey;
120                 }
121
122                 public ListViewItem(string text, string imageKey) : this(text)
123                 {
124                         this.ImageKey = imageKey;
125                 }
126
127                 public ListViewItem(ListViewSubItem[] subItems, string imageKey) : this()
128                 {
129                         this.sub_items.AddRange(subItems);
130                         this.ImageKey = imageKey;
131                 }
132
133                 public ListViewItem(string[] items, string imageKey, Color foreColor,
134                                         Color backColor, Font font) : this()
135                 {
136                         this.sub_items = new ListViewSubItemCollection(this);
137                         this.sub_items.AddRange(items);
138                         ForeColor = foreColor;
139                         BackColor = backColor;
140                         this.font = font;
141                         this.ImageKey = imageKey;
142                 }
143
144                 public ListViewItem(ListViewGroup group) : this()
145                 {
146                         this.group = group;
147                 }
148
149                 public ListViewItem(string text, ListViewGroup group) : this(text)
150                 {
151                         this.group = group;
152                 }
153
154                 public ListViewItem(string[] items, ListViewGroup group) : this(items)
155                 {
156                         this.group = group;
157                 }
158
159                 public ListViewItem(ListViewSubItem[] subItems, int imageIndex, ListViewGroup group)
160                         : this(subItems, imageIndex)
161                 {
162                         this.group = group;
163                 }
164
165                 public ListViewItem(ListViewSubItem[] subItems, string imageKey, ListViewGroup group)
166                         : this(subItems, imageKey)
167                 {
168                         this.group = group;
169                 }
170
171                 public ListViewItem(string text, int imageIndex, ListViewGroup group)
172                         : this(text, imageIndex)
173                 {
174                         this.group = group;
175                 }
176
177                 public ListViewItem(string text, string imageKey, ListViewGroup group)
178                         : this(text, imageKey)
179                 {
180                         this.group = group;
181                 }
182
183                 public ListViewItem(string[] items, int imageIndex, ListViewGroup group)
184                         : this(items, imageIndex)
185                 {
186                         this.group = group;
187                 }
188
189                 public ListViewItem(string[] items, string imageKey, ListViewGroup group)
190                         : this(items, imageKey)
191                 {
192                         this.group = group;
193                 }
194
195                 public ListViewItem(string[] items, int imageIndex, Color foreColor, Color backColor,
196                                 Font font, ListViewGroup group)
197                         : this(items, imageIndex, foreColor, backColor, font)
198                 {
199                         this.group = group;
200                 }
201
202                 public ListViewItem(string[] items, string imageKey, Color foreColor, Color backColor,
203                                 Font font, ListViewGroup group)
204                         : this(items, imageKey, foreColor, backColor, font)
205                 {
206                         this.group = group;
207                 }
208 #endif
209                 #endregion      // Public Constructors
210
211                 #region Public Instance Properties
212                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
213                 public Color BackColor {
214                         get {
215                                 if (sub_items.Count > 0)
216                                         return sub_items[0].BackColor;
217
218                                 if (owner != null)
219                                         return owner.BackColor;
220                                 
221                                 return ThemeEngine.Current.ColorWindow;
222                         }
223
224                         set { sub_items[0].BackColor = value; }
225                 }
226
227                 [Browsable (false)]
228                 public Rectangle Bounds {
229                         get {
230                                 return GetBounds (ItemBoundsPortion.Entire);
231                         }
232                 }
233
234                 [DefaultValue (false)]
235                 [RefreshProperties (RefreshProperties.Repaint)]
236                 public bool Checked {
237                         get { return is_checked; }
238                         set { 
239                                 if (is_checked == value)
240                                         return;
241                                 
242                                 if (owner != null) {
243                                         CheckState current_value = is_checked ? CheckState.Checked : CheckState.Unchecked;
244                                         CheckState new_value = value ? CheckState.Checked : CheckState.Unchecked;
245
246                                         ItemCheckEventArgs icea = new ItemCheckEventArgs (Index,
247                                                         new_value, current_value);
248                                         owner.OnItemCheck (icea);
249
250                                         if (new_value != current_value) {
251                                                 // force re-population of list
252                                                 owner.CheckedItems.Reset ();
253                                                 is_checked = new_value == CheckState.Checked;
254                                                 Invalidate ();
255
256 #if NET_2_0
257                                                 ItemCheckedEventArgs args = new ItemCheckedEventArgs (this);
258                                                 owner.OnItemChecked (args);
259 #endif
260                                         }
261                                 } else
262                                         is_checked = value;
263                         }
264                 }
265
266                 [Browsable (false)]
267                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
268                 public bool Focused {
269                         get { return is_focused; }
270                         set {   
271                                 if (is_focused == value)
272                                         return;
273
274                                 is_focused = value; 
275
276                                 Invalidate ();
277                                 if (owner != null)
278                                         Layout ();
279                                 Invalidate ();
280                         }
281                 }
282
283                 [Localizable (true)]
284                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
285                 public Font Font {
286                         get {
287                                 if (font != null)
288                                         return font;
289                                 else if (owner != null)
290                                         return owner.Font;
291
292                                 return ThemeEngine.Current.DefaultFont;
293                         }
294                         set {   
295                                 if (font == value)
296                                         return;
297
298                                 font = value; 
299
300                                 if (owner != null)
301                                         Layout ();
302                                 Invalidate ();
303                         }
304                 }
305
306                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
307                 public Color ForeColor {
308                         get {
309                                 if (sub_items.Count > 0)
310                                         return sub_items[0].ForeColor;
311
312                                 if (owner != null)
313                                         return owner.ForeColor;
314
315                                 return ThemeEngine.Current.ColorWindowText;
316                         }
317                         set { sub_items[0].ForeColor = value; }
318                 }
319
320                 [DefaultValue (-1)]
321                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
322                 [Editor ("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design,
323                          typeof (System.Drawing.Design.UITypeEditor))]
324                 [Localizable (true)]
325 #if NET_2_0
326                 [RefreshProperties (RefreshProperties.Repaint)]
327                 // [TypeConverter (typeof (NoneExcludedImageIndexConverter))]
328 #else
329                 [TypeConverter (typeof (ImageIndexConverter))]
330 #endif
331                 public int ImageIndex {
332                         get { return image_index; }
333                         set {
334                                 if (value < -1)
335                                         throw new ArgumentException ("Invalid ImageIndex. It must be greater than or equal to -1.");
336                                 
337                                 image_index = value;
338 #if NET_2_0
339                                 image_key = String.Empty;
340 #endif
341
342                                 if (owner != null)
343                                         Layout ();
344                                 Invalidate ();
345                         }
346                 }
347
348 #if NET_2_0
349                 [DefaultValue ("")]
350                 [LocalizableAttribute (true)]
351                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
352                 [Editor ("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design,
353                          typeof (System.Drawing.Design.UITypeEditor))]
354                 [RefreshProperties (RefreshProperties.Repaint)]
355                 // XXX [TypeConverter (typeof (ImageKeyConverter))
356                 public string ImageKey {
357                         get {
358                                 return image_key;
359                         }
360                         set {
361                                 image_key = value == null ? String.Empty : value;
362                                 image_index = -1;
363
364                                 if (owner != null)
365                                         Layout ();
366                                 Invalidate ();
367                         }
368                 }
369 #endif
370
371                 [Browsable (false)]
372                 public ImageList ImageList {
373                         get {
374                                 if (owner == null)
375                                         return null;
376                                 else if (owner.View == View.LargeIcon)
377                                         return owner.large_image_list;
378                                 else
379                                         return owner.small_image_list;
380                         }
381                 }
382
383                 [Browsable (false)]
384                 public int Index {
385                         get {
386                                 if (owner == null)
387                                         return -1;
388 #if NET_2_0
389                                 if (owner.VirtualMode)
390                                         return index;
391 #endif
392                                 else
393                                         return owner.Items.IndexOf (this);
394                         }
395                 }
396
397                 [Browsable (false)]
398                 public ListView ListView {
399                         get { return owner; }
400                 }
401
402 #if NET_2_0
403                 [Browsable (false)]
404                 [Localizable (true)]
405                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
406                 public string Name {
407                         get {
408                                 return name;
409                         }
410                         set {
411                                 name = value == null ? String.Empty : value;
412                         }
413                 }
414 #endif
415
416                 [Browsable (false)]
417                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
418                 public bool Selected {
419                         get { 
420                                 return selected; 
421                         }
422                         set {
423                                 if (selected == value)
424                                         return;
425
426                                 if (owner != null) {
427                                         if (value && !owner.MultiSelect)
428                                                 owner.SelectedItems.Clear ();
429                                         selected = value;
430                                         // force re-population of list
431                                         owner.SelectedIndices.Reset ();
432                                         Layout ();
433                                         owner.OnSelectedIndexChanged ();
434                                 } else {
435                                         selected = value;
436                                 }
437                                 Invalidate ();
438                         }
439                 }
440
441                 [DefaultValue (-1)]
442                 [Editor ("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design,
443                          typeof (System.Drawing.Design.UITypeEditor))]
444                 [Localizable (true)]
445 #if NET_2_0
446                 [RefreshProperties (RefreshProperties.Repaint)]
447                 // XXX [RelatedImageListAttribute ("ListView.StateImageList")]
448                 // XXX [TypeConverter (typeof (NoneExcludedImageIndexConverter))]
449 #else
450                 [TypeConverter (typeof (ImageIndexConverter))]
451 #endif
452                 public int StateImageIndex {
453                         get { return state_image_index; }
454                         set {
455                                 if (value < -1 || value > 14)
456                                         throw new ArgumentOutOfRangeException ("Invalid StateImageIndex. It must be in the range of [-1, 14].");
457
458                                 state_image_index = value;
459                         }
460                 }
461
462                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
463 #if NET_2_0
464                 [Editor ("System.Windows.Forms.Design.ListViewSubItemCollectionEditor, " + Consts.AssemblySystem_Design,
465                          typeof (System.Drawing.Design.UITypeEditor))]
466 #endif
467                 public ListViewSubItemCollection SubItems {
468                         get { return sub_items; }
469                 }
470
471                 [Bindable (true)]
472                 [DefaultValue (null)]
473                 [Localizable (false)]
474                 [TypeConverter (typeof (StringConverter))]
475                 public object Tag {
476                         get { return tag; }
477                         set { tag = value; }
478                 }
479
480                 [Localizable (true)]
481                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
482                 public string Text {
483                         get {
484                                 if (this.sub_items.Count > 0)
485                                         return this.sub_items [0].Text;
486                                 else
487                                         return string.Empty;
488                         }
489                         set { 
490                                 if (sub_items [0].Text == value)
491                                         return;
492
493                                 sub_items [0].Text = value; 
494
495                                 if (owner != null)
496                                         Layout ();
497                                 Invalidate ();
498                         }
499                 }
500
501                 [DefaultValue (true)]
502                 public bool UseItemStyleForSubItems {
503                         get { return use_item_style; }
504                         set { use_item_style = value; }
505                 }
506
507 #if NET_2_0
508                 [LocalizableAttribute(true)]
509                 [DefaultValue (null)]
510                 public ListViewGroup Group {
511                         get { return this.group; }
512                         set
513                         {
514                                 if (this.group != value)
515                                 {
516                                         if (value != null)
517                                         {
518                                                 value.Items.Add(this);
519
520                                                 if (this.group != null)
521                                                         this.group.Items.Remove(this);
522
523                                                 this.group = value;
524                                         }
525                                         else
526                                         {
527                                                 if(this.group != null)
528                                                 this.group.Items.Remove(this);
529                                         }
530                                 }
531                         }
532                 }
533 #endif
534
535                 #endregion      // Public Instance Properties
536
537                 #region Public Instance Methods
538                 public void BeginEdit ()
539                 {
540                         if (owner != null && owner.LabelEdit) {
541                                 owner.item_control.BeginEdit (this);
542                         }
543                         // FIXME: TODO
544                         // if (owner != null && owner.LabelEdit 
545                         //    && owner.Activation == ItemActivation.Standard)
546                         // allow editing
547                         // else
548                         // throw new InvalidOperationException ();
549                 }
550
551                 public virtual object Clone ()
552                 {
553                         ListViewItem clone = new ListViewItem ();
554                         clone.image_index = this.image_index;
555                         clone.is_checked = this.is_checked;
556                         clone.is_focused = this.is_focused;
557                         clone.selected = this.selected;
558                         clone.font = this.font;
559                         clone.state_image_index = this.state_image_index;
560                         clone.sub_items = new ListViewSubItemCollection (this);
561                         
562                         foreach (ListViewSubItem subItem in this.sub_items)
563                                 clone.sub_items.Add (subItem.Text, subItem.ForeColor,
564                                                      subItem.BackColor, subItem.Font);
565                         clone.tag = this.tag;
566                         clone.use_item_style = this.use_item_style;
567                         clone.owner = null;
568 #if NET_2_0
569                         clone.name = name;
570 #endif
571
572                         return clone;
573                 }
574
575                 public virtual void EnsureVisible ()
576                 {
577                         if (this.owner != null) {
578                                 owner.EnsureVisible (owner.Items.IndexOf (this));
579                         }
580                 }
581
582                 public Rectangle GetBounds (ItemBoundsPortion portion)
583                 {
584                         if (owner == null)
585                                 return Rectangle.Empty;
586                                 
587                         Rectangle rect;
588
589                         switch (portion) {
590                         case ItemBoundsPortion.Icon:
591                                 rect = icon_rect;
592                                 break;
593
594                         case ItemBoundsPortion.Label:
595                                 rect = label_rect;
596                                 break;
597
598                         case ItemBoundsPortion.ItemOnly:
599                                 rect = item_rect;
600                                 break;
601
602                         case ItemBoundsPortion.Entire:
603                                 rect = bounds;
604                                 break;
605
606                         default:
607                                 throw new ArgumentException ("Invalid value for portion.");
608                         }
609
610                         Point item_loc = owner.GetItemLocation (Index);
611                         rect.X += item_loc.X;
612                         rect.Y += item_loc.Y;
613                         return rect;
614                 }
615
616                 void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context)
617                 {
618                         // FIXME: TODO
619                 }
620
621                 public virtual void Remove ()
622                 {
623                         if (owner == null)
624                                 return;
625
626                         owner.item_control.CancelEdit (this);
627                         owner.Items.Remove (this);
628                         owner = null;
629                 }
630
631                 public override string ToString ()
632                 {
633                         return string.Format ("ListViewItem: {0}", this.Text);
634                 }
635                 #endregion      // Public Instance Methods
636
637                 #region Protected Methods
638                 protected virtual void Deserialize (SerializationInfo info, StreamingContext context)
639                 {
640                         // FIXME: TODO
641                 }
642
643                 protected virtual void Serialize (SerializationInfo info, StreamingContext context)
644                 {
645                         // FIXME: TODO
646                 }
647                 #endregion      // Protected Methods
648
649                 #region Private Internal Methods
650                 internal Rectangle CheckRectReal {
651                         get {
652                                 Rectangle rect = checkbox_rect;
653                                 Point item_loc = owner.GetItemLocation (Index);
654                                 rect.X += item_loc.X;
655                                 rect.Y += item_loc.Y;
656                                 return rect;
657                         }
658                 }
659                 
660                 internal ListView Owner {
661                         set {
662                                 if (owner == value)
663                                         return;
664
665                                 owner = value;
666                         }
667                 }
668
669 #if NET_2_0
670                 internal void SetIndex (int index)
671                 {
672                         this.index = index;
673                 }
674 #endif
675
676                 private void Invalidate ()
677                 {
678                         if (owner == null || owner.item_control == null)
679                                 return;
680
681                         owner.item_control.Invalidate (Bounds);
682                 }
683
684                 internal void Layout ()
685                 {
686                         int item_ht;
687                         Rectangle total;
688                         Size text_size = owner.text_size;
689                         
690                         checkbox_rect = Rectangle.Empty;
691                         if (owner.CheckBoxes)
692                                 checkbox_rect.Size = owner.CheckBoxSize;
693
694                         switch (owner.View) {
695                         case View.Details:
696                                 // LAMESPEC: MSDN says, "In all views except the details
697                                 // view of the ListView, this value specifies the same
698                                 // bounding rectangle as the Entire value." Actually, it
699                                 // returns same bounding rectangles for Item and Entire
700                                 // values in the case of Details view.
701
702                                 icon_rect = label_rect = Rectangle.Empty;
703                                 icon_rect.X = checkbox_rect.Width + 2;
704                                 item_ht = owner.ItemSize.Height;
705
706                                 if (owner.SmallImageList != null)
707                                         icon_rect.Width = owner.SmallImageList.ImageSize.Width;
708
709                                 label_rect.Height = icon_rect.Height = item_ht;
710                                 checkbox_rect.Y = item_ht - checkbox_rect.Height;
711
712                                 label_rect.X = icon_rect.Right + 1;
713
714                                 if (owner.Columns.Count > 0)
715                                         label_rect.Width = owner.Columns [0].Wd - label_rect.X;
716                                 else
717                                         label_rect.Width = text_size.Width;
718
719                                 item_rect = total = Rectangle.Union
720                                         (Rectangle.Union (checkbox_rect, icon_rect), label_rect);
721                                 bounds.Size = total.Size;
722
723                                 // Take into account the rest of columns. First column
724                                 // is already taken into account above.
725                                 for (int i = 1; i < owner.Columns.Count; i++) {
726                                         item_rect.Width += owner.Columns [i].Wd;
727                                         bounds.Width += owner.Columns [i].Wd;
728                                 }
729                                 break;
730
731                         case View.LargeIcon:
732                                 label_rect = icon_rect = Rectangle.Empty;
733
734                                 SizeF sz = owner.DeviceContext.MeasureString (Text, Font);
735                                 if ((int) sz.Width > text_size.Width) {
736                                         if (Focused) {
737                                                 int text_width = text_size.Width;
738                                                 StringFormat format = new StringFormat ();
739                                                 format.Alignment = StringAlignment.Center;
740                                                 sz = owner.DeviceContext.MeasureString (Text, Font, text_width, format);
741                                                 text_size.Height = (int) sz.Height;
742                                         } else
743                                                 text_size.Height = 2 * (int) sz.Height;
744                                 }
745
746                                 if (owner.LargeImageList != null) {
747                                         icon_rect.Width = owner.LargeImageList.ImageSize.Width;
748                                         icon_rect.Height = owner.LargeImageList.ImageSize.Height;
749                                 }
750
751                                 if (checkbox_rect.Height > icon_rect.Height)
752                                         icon_rect.Y = checkbox_rect.Height - icon_rect.Height;
753                                 else
754                                         checkbox_rect.Y = icon_rect.Height - checkbox_rect.Height;
755
756                                 if (text_size.Width <= icon_rect.Width) {
757                                         icon_rect.X = checkbox_rect.Width + 1;
758                                         label_rect.X = icon_rect.X + (icon_rect.Width - text_size.Width) / 2;
759                                         label_rect.Y = icon_rect.Bottom + 2;
760                                         label_rect.Size = text_size;
761                                 } else {
762                                         int centerX = text_size.Width / 2;
763                                         icon_rect.X = checkbox_rect.Width + 1 + centerX - icon_rect.Width / 2;
764                                         label_rect.X = checkbox_rect.Width + 1;
765                                         label_rect.Y = icon_rect.Bottom + 2;
766                                         label_rect.Size = text_size;
767                                 }
768
769                                 item_rect = Rectangle.Union (icon_rect, label_rect);
770                                 total = Rectangle.Union (item_rect, checkbox_rect);
771                                 bounds.Size = total.Size;
772                                 break;
773
774                         case View.List:
775                         case View.SmallIcon:
776                                 label_rect = icon_rect = Rectangle.Empty;
777                                 icon_rect.X = checkbox_rect.Width + 1;
778                                 item_ht = Math.Max (owner.CheckBoxSize.Height, text_size.Height);
779
780                                 if (owner.SmallImageList != null) {
781                                         item_ht = Math.Max (item_ht, owner.SmallImageList.ImageSize.Height);
782                                         icon_rect.Width = owner.SmallImageList.ImageSize.Width;
783                                         icon_rect.Height = owner.SmallImageList.ImageSize.Height;
784                                 }
785
786                                 checkbox_rect.Y = item_ht - checkbox_rect.Height;
787                                 label_rect.X = icon_rect.Right + 1;
788                                 label_rect.Width = text_size.Width;
789                                 label_rect.Height = icon_rect.Height = item_ht;
790
791                                 item_rect = Rectangle.Union (icon_rect, label_rect);
792                                 total = Rectangle.Union (item_rect, checkbox_rect);
793                                 bounds.Size = total.Size;
794                                 break;
795 #if NET_2_0
796                         case View.Tile:
797                                 label_rect = icon_rect = Rectangle.Empty;
798
799                                 if (owner.LargeImageList != null) {
800                                         icon_rect.Width = owner.LargeImageList.ImageSize.Width;
801                                         icon_rect.Height = owner.LargeImageList.ImageSize.Height;
802                                 }
803
804                                 int separation = 2;
805                                 SizeF tsize = owner.DeviceContext.MeasureString (Text, Font);
806
807                                 // Set initial values for subitem's layout
808                                 int total_height = (int)Math.Ceiling (tsize.Height);
809                                 int max_subitem_width = (int)Math.Ceiling (tsize.Width);
810                                 SubItems [0].bounds.Height = total_height;
811                         
812                                 int count = Math.Min (owner.Columns.Count, SubItems.Count);
813                                 for (int i = 1; i < count; i++) { // Ignore first column and first subitem
814                                         ListViewSubItem sub_item = SubItems [i];
815                                         if (sub_item.Text == null || sub_item.Text.Length == 0)
816                                                 continue;
817
818                                         tsize = owner.DeviceContext.MeasureString (sub_item.Text, sub_item.Font);
819                                 
820                                         int width = (int)Math.Ceiling (tsize.Width);
821                                 
822                                         if (width > max_subitem_width)
823                                                 max_subitem_width = width;
824                                 
825                                         int height = (int)Math.Ceiling (tsize.Height);
826                                         total_height += height + separation;
827                                 
828                                         sub_item.bounds.Height = height;
829                         
830                                 }
831
832                                 label_rect.X = icon_rect.Right + 4;
833                                 label_rect.Y = owner.TileSize.Height / 2 - total_height / 2;
834                                 label_rect.Width = max_subitem_width;
835                                 label_rect.Height = total_height;
836                         
837                                 // Second pass for assigning bounds. This time take first subitem into account.
838                                 int current_y = label_rect.Y;
839                                 for (int j = 0; j < count; j++) {
840                                         ListViewSubItem sub_item = SubItems [j];
841                                         if (sub_item.Text == null || sub_item.Text.Length == 0)
842                                                 continue;
843
844                                         sub_item.SetBounds (label_rect.X, current_y, max_subitem_width, sub_item.bounds.Height);
845                                         current_y += sub_item.Bounds.Height + separation;
846                                 }
847                                 
848                                 item_rect = Rectangle.Union (icon_rect, label_rect);
849                                 bounds.Size = item_rect.Size;
850                                 break;
851 #endif
852                         }
853                         
854                 }
855                 #endregion      // Private Internal Methods
856
857                 #region Subclasses
858
859                 [DefaultProperty ("Text")]
860                 [DesignTimeVisible (false)]
861                 [Serializable]
862                 [ToolboxItem (false)]
863                 [TypeConverter (typeof(ListViewSubItemConverter))]
864                 public class ListViewSubItem
865                 {
866                         private Color back_color;
867                         private Font font;
868                         private Color fore_color;
869                         internal ListViewItem owner;
870                         private string text = string.Empty;
871 #if NET_2_0
872                         private string name = String.Empty;
873                         private object tag;
874                         internal Rectangle bounds;
875 #endif
876                         
877                         #region Public Constructors
878                         public ListViewSubItem ()
879                         {
880                         }
881
882                         public ListViewSubItem (ListViewItem owner, string text)
883                                 : this (owner, text, ThemeEngine.Current.ColorWindowText,
884                                         ThemeEngine.Current.ColorWindow, null)
885                         {
886                         }
887
888                         public ListViewSubItem (ListViewItem owner, string text, Color foreColor,
889                                                 Color backColor, Font font)
890                         {
891                                 this.owner = owner;
892                                 Text = text;
893                                 this.fore_color = foreColor;
894                                 this.back_color = backColor;
895                                 this.font = font;
896                         }
897                         #endregion // Public Constructors
898
899                         #region Public Instance Properties
900                         public Color BackColor {
901                                 get { return back_color; }
902                                 set { 
903                                         back_color = value; 
904                                         Invalidate ();
905                                     }
906                         }
907
908 #if NET_2_0
909                         public Rectangle Bounds {
910                                 get {
911                                         Rectangle retval = bounds;
912                                         if (owner != null) {
913                                                 retval.X += owner.Bounds.X;
914                                                 retval.Y += owner.Bounds.Y;
915                                         }
916
917                                         return retval;
918                                 }
919                         }
920 #endif
921
922                         [Localizable (true)]
923                         public Font Font {
924                                 get {
925                                         if (font != null)
926                                                 return font;
927                                         else if (owner != null)
928                                                 return owner.Font;
929                                         return ThemeEngine.Current.DefaultFont;
930                                 }
931                                 set { 
932                                         if (font == value)
933                                                 return;
934                                         font = value; 
935                                         Invalidate ();
936                                     }
937                         }
938
939                         public Color ForeColor {
940                                 get { return fore_color; }
941                                 set { 
942                                         fore_color = value; 
943                                         Invalidate ();
944                                     }
945                         }
946
947 #if NET_2_0
948                         [Localizable (true)]
949                         public string Name {
950                                 get {
951                                         return name;
952                                 }
953                                 set {
954                                         name = value == null ? String.Empty : value;
955                                 }
956                         }
957
958                         [TypeConverter (typeof (StringConverter))]
959                         [BindableAttribute (true)]
960                         [DefaultValue (null)]
961                         [Localizable (false)]
962                         public object Tag {
963                                 get {
964                                         return tag;
965                                 }
966                                 set {
967                                         tag = value;
968                                 }
969                         }
970 #endif
971
972                         [Localizable (true)]
973                         public string Text {
974                                 get { return text; }
975                                 set { 
976                                         if(text == value)
977                                                 return;
978
979                                         if(value == null)
980                                                 text = string.Empty;
981                                         else
982                                                 text = value; 
983
984                                         Invalidate ();
985                                     }
986                         }
987                         #endregion // Public Instance Properties
988
989                         #region Public Methods
990                         public void ResetStyle ()
991                         {
992                                 font = ThemeEngine.Current.DefaultFont;
993                                 back_color = ThemeEngine.Current.DefaultControlBackColor;
994                                 fore_color = ThemeEngine.Current.DefaultControlForeColor;
995                                 Invalidate ();
996                         }
997
998                         public override string ToString ()
999                         {
1000                                 return string.Format ("ListViewSubItem {{0}}", text);
1001                         }
1002                         #endregion // Public Methods
1003
1004                         
1005                         #region Private Methods
1006                         private void Invalidate ()
1007                         {
1008                                 if (owner == null || owner.owner == null)
1009                                         return;
1010
1011                                 owner.owner.Invalidate ();
1012                         }
1013
1014 #if NET_2_0
1015                         internal int Height {
1016                                 get {
1017                                         return bounds.Height;
1018                                 }
1019                         }
1020
1021                         internal void SetBounds (int x, int y, int width, int height)
1022                         {
1023                                 bounds = new Rectangle (x, y, width, height);
1024                         }
1025 #endif
1026                         #endregion // Private Methods
1027                 }
1028
1029                 public class ListViewSubItemCollection : IList, ICollection, IEnumerable
1030                 {
1031                         private ArrayList list;
1032                         internal ListViewItem owner;
1033
1034                         #region Public Constructors
1035                         public ListViewSubItemCollection (ListViewItem owner)
1036                         {
1037                                 this.owner = owner;
1038                                 this.list = new ArrayList ();
1039                         }
1040                         #endregion // Public Constructors
1041
1042                         #region Public Properties
1043                         [Browsable (false)]
1044                         public int Count {
1045                                 get { return list.Count; }
1046                         }
1047
1048                         public bool IsReadOnly {
1049                                 get { return false; }
1050                         }
1051
1052                         public ListViewSubItem this [int index] {
1053                                 get { return (ListViewSubItem) list [index]; }
1054                                 set { 
1055                                         value.owner = this.owner;
1056                                         list [index] = value;
1057                                 }
1058                         }
1059
1060 #if NET_2_0
1061                         public virtual ListViewSubItem this [string key] {
1062                                 get {
1063                                         int idx = IndexOfKey (key);
1064                                         if (idx == -1)
1065                                                 return null;
1066
1067                                         return (ListViewSubItem) list [idx];
1068                                 }
1069                         }
1070 #endif
1071
1072                         bool ICollection.IsSynchronized {
1073                                 get { return list.IsSynchronized; }
1074                         }
1075
1076                         object ICollection.SyncRoot {
1077                                 get { return list.SyncRoot; }
1078                         }
1079
1080                         bool IList.IsFixedSize {
1081                                 get { return list.IsFixedSize; }
1082                         }
1083
1084                         object IList.this [int index] {
1085                                 get { return this [index]; }
1086                                 set {
1087                                         if (! (value is ListViewSubItem))
1088                                                 throw new ArgumentException ("Not of type ListViewSubItem", "value");
1089                                         this [index] = (ListViewSubItem) value;
1090                                 }
1091                         }
1092                         #endregion // Public Properties
1093
1094                         #region Public Methods
1095                         public ListViewSubItem Add (ListViewSubItem item)
1096                         {
1097                                 item.owner = this.owner;
1098                                 list.Add (item);
1099                                 return item;
1100                         }
1101
1102                         public ListViewSubItem Add (string text)
1103                         {
1104                                 ListViewSubItem item = new ListViewSubItem (this.owner, text);
1105                                 list.Add (item);
1106                                 return item;
1107                         }
1108
1109                         public ListViewSubItem Add (string text, Color foreColor,
1110                                                     Color backColor, Font font)
1111                         {
1112                                 ListViewSubItem item = new ListViewSubItem (this.owner, text,
1113                                                                             foreColor, backColor, font);
1114                                 list.Add (item);
1115                                 return item;
1116                         }
1117
1118                         public void AddRange (ListViewSubItem [] items)
1119                         {
1120                                 if (items == null)
1121                                         throw new ArgumentNullException ("items");
1122
1123                                 foreach (ListViewSubItem item in items) {
1124                                         if (item == null)
1125                                                 continue;
1126                                         this.Add (item);
1127                                 }
1128                         }
1129
1130                         public void AddRange (string [] items)
1131                         {
1132                                 if (items == null)
1133                                         throw new ArgumentNullException ("items");
1134
1135                                 foreach (string item in items) {
1136                                         if (item == null)
1137                                                 continue;
1138                                         this.Add (item);
1139                                 }
1140                         }
1141
1142                         public void AddRange (string [] items, Color foreColor,
1143                                               Color backColor, Font font)
1144                         {
1145                                 if (items == null)
1146                                         throw new ArgumentNullException ("items");
1147
1148                                 foreach (string item in items) {
1149                                         if (item == null)
1150                                                 continue;
1151                                         this.Add (item, foreColor, backColor, font);
1152                                 }
1153                         }
1154
1155                         public void Clear ()
1156                         {
1157                                 list.Clear ();
1158                         }
1159
1160                         public bool Contains (ListViewSubItem item)
1161                         {
1162                                 return list.Contains (item);
1163                         }
1164
1165 #if NET_2_0
1166                         public virtual bool ContainsKey (string key)
1167                         {
1168                                 return IndexOfKey (key) != -1;
1169                         }
1170 #endif
1171
1172                         public IEnumerator GetEnumerator ()
1173                         {
1174                                 return list.GetEnumerator ();
1175                         }
1176
1177                         void ICollection.CopyTo (Array dest, int index)
1178                         {
1179                                 list.CopyTo (dest, index);
1180                         }
1181
1182                         int IList.Add (object item)
1183                         {
1184                                 if (! (item is ListViewSubItem)) {
1185                                         throw new ArgumentException ("Not of type ListViewSubItem", "item");
1186                                 }
1187
1188                                 ListViewSubItem sub_item = (ListViewSubItem) item;
1189                                 sub_item.owner = this.owner;
1190                                 return list.Add (sub_item);
1191                         }
1192
1193                         bool IList.Contains (object subItem)
1194                         {
1195                                 if (! (subItem is ListViewSubItem)) {
1196                                         throw new ArgumentException ("Not of type ListViewSubItem", "subItem");
1197                                 }
1198
1199                                 return this.Contains ((ListViewSubItem) subItem);
1200                         }
1201
1202                         int IList.IndexOf (object subItem)
1203                         {
1204                                 if (! (subItem is ListViewSubItem)) {
1205                                         throw new ArgumentException ("Not of type ListViewSubItem", "subItem");
1206                                 }
1207
1208                                 return this.IndexOf ((ListViewSubItem) subItem);
1209                         }
1210
1211                         void IList.Insert (int index, object item)
1212                         {
1213                                 if (! (item is ListViewSubItem)) {
1214                                         throw new ArgumentException ("Not of type ListViewSubItem", "item");
1215                                 }
1216
1217                                 this.Insert (index, (ListViewSubItem) item);
1218                         }
1219
1220                         void IList.Remove (object item)
1221                         {
1222                                 if (! (item is ListViewSubItem)) {
1223                                         throw new ArgumentException ("Not of type ListViewSubItem", "item");
1224                                 }
1225
1226                                 this.Remove ((ListViewSubItem) item);
1227                         }
1228
1229                         public int IndexOf (ListViewSubItem subItem)
1230                         {
1231                                 return list.IndexOf (subItem);
1232                         }
1233
1234 #if NET_2_0
1235                         public virtual int IndexOfKey (string key)
1236                         {
1237                                 if (key == null || key.Length == 0)
1238                                         return -1;
1239
1240                                 for (int i = 0; i < list.Count; i++) {
1241                                         ListViewSubItem l = (ListViewSubItem) list [i];
1242                                         if (String.Compare (l.Name, key, true) == 0)
1243                                                 return i;
1244                                 }
1245
1246                                 return -1;
1247                         }
1248 #endif
1249
1250                         public void Insert (int index, ListViewSubItem item)
1251                         {
1252                                 item.owner = this.owner;
1253                                 list.Insert (index, item);
1254                         }
1255
1256                         public void Remove (ListViewSubItem item)
1257                         {
1258                                 list.Remove (item);
1259                         }
1260
1261 #if NET_2_0
1262                         public virtual void RemoveByKey (string key)
1263                         {
1264                                 int idx = IndexOfKey (key);
1265                                 if (idx != -1)
1266                                         RemoveAt (idx);
1267                         }
1268 #endif
1269
1270                         public void RemoveAt (int index)
1271                         {
1272                                 list.RemoveAt (index);
1273                         }
1274                         #endregion // Public Methods
1275                 }
1276                 #endregion // Subclasses
1277         }
1278 }