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