2007-01-10 Jonathan Pobst <jpobst@novell.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / ListViewItem.cs
index dc223d13aefddc71546cc32b2c022f638db44c36..f16cd3bb813e0f584c85ff3a43a4a22887bc6e26 100644 (file)
 //
 // Author:
 //      Ravindra (rkumar@novell.com)
-//
-// Todo:
-//     - Drawing of focus rectangle
-
+//      Mike Kestner <mkestner@novell.com>
+//      Daniel Nauck (dna(at)mono-project(dot)de)
 
 
-// NOT COMPLETE
-
 
 using System.Collections;
 using System.ComponentModel;
@@ -52,16 +48,22 @@ namespace System.Windows.Forms
                private ListViewSubItemCollection sub_items;
                private object tag;
                private bool use_item_style = true;
-
-               // internal variables
-               internal Rectangle checkbox_rect;       // calculated by CalcListViewItem method
-               internal Rectangle entire_rect;
-               internal Rectangle icon_rect;
-               internal Rectangle item_rect;
-               internal Rectangle label_rect;
-               internal Point location = Point.Empty;  // set by the ListView control
-               internal ListView owner;
-               internal bool selected;
+#if NET_2_0
+               private ListViewGroup group = null;
+               private string name = String.Empty;
+               private string image_key = String.Empty;
+#endif
+               Rectangle bounds;
+               Rectangle checkbox_rect;        // calculated by CalcListViewItem method
+               Rectangle icon_rect;
+               Rectangle item_rect;
+               Rectangle label_rect;
+               ListView owner;
+               Font font;
+               bool selected;
+
+               internal int row;
+               internal int col;
 
                #endregion Instance Variables
 
@@ -69,7 +71,7 @@ namespace System.Windows.Forms
                public ListViewItem ()
                {
                        this.sub_items = new ListViewSubItemCollection (this);
-                       this.sub_items.Add ("");                        
+                       this.sub_items.Add ("");
                }
 
                public ListViewItem (string text) : this (text, -1)
@@ -109,8 +111,102 @@ namespace System.Windows.Forms
                        this.image_index = imageIndex;
                        ForeColor = foreColor;
                        BackColor = backColor;
-                       Font = font;
+                       this.font = font;
+               }
+
+#if NET_2_0
+               public ListViewItem(string[] items, string imageKey) : this(items)
+               {
+                       this.ImageKey = imageKey;
+               }
+
+               public ListViewItem(string text, string imageKey) : this(text)
+               {
+                       this.ImageKey = imageKey;
+               }
+
+               public ListViewItem(ListViewSubItem[] subItems, string imageKey) : this()
+               {
+                       this.sub_items.AddRange(subItems);
+                       this.ImageKey = imageKey;
+               }
+
+               public ListViewItem(string[] items, string imageKey, Color foreColor,
+                                       Color backColor, Font font) : this()
+               {
+                       this.sub_items = new ListViewSubItemCollection(this);
+                       this.sub_items.AddRange(items);
+                       ForeColor = foreColor;
+                       BackColor = backColor;
+                       this.font = font;
+                       this.ImageKey = imageKey;
+               }
+
+               public ListViewItem(ListViewGroup group) : this()
+               {
+                       this.group = group;
+               }
+
+               public ListViewItem(string text, ListViewGroup group) : this(text)
+               {
+                       this.group = group;
+               }
+
+               public ListViewItem(string[] items, ListViewGroup group) : this(items)
+               {
+                       this.group = group;
+               }
+
+               public ListViewItem(ListViewSubItem[] subItems, int imageIndex, ListViewGroup group)
+                       : this(subItems, imageIndex)
+               {
+                       this.group = group;
                }
+
+               public ListViewItem(ListViewSubItem[] subItems, string imageKey, ListViewGroup group)
+                       : this(subItems, imageKey)
+               {
+                       this.group = group;
+               }
+
+               public ListViewItem(string text, int imageIndex, ListViewGroup group)
+                       : this(text, imageIndex)
+               {
+                       this.group = group;
+               }
+
+               public ListViewItem(string text, string imageKey, ListViewGroup group)
+                       : this(text, imageKey)
+               {
+                       this.group = group;
+               }
+
+               public ListViewItem(string[] items, int imageIndex, ListViewGroup group)
+                       : this(items, imageIndex)
+               {
+                       this.group = group;
+               }
+
+               public ListViewItem(string[] items, string imageKey, ListViewGroup group)
+                       : this(items, imageKey)
+               {
+                       this.group = group;
+               }
+
+               public ListViewItem(string[] items, int imageIndex, Color foreColor, Color backColor,
+                               Font font, ListViewGroup group)
+                       : this(items, imageIndex, foreColor, backColor, font)
+               {
+                       this.group = group;
+               }
+
+               public ListViewItem(string[] items, string imageKey, Color foreColor, Color backColor,
+                               Font font, ListViewGroup group)
+                       : this(items, imageKey, foreColor, backColor, font)
+               {
+                       this.group = group;
+               }
+#endif
                #endregion      // Public Constructors
 
                #region Public Instance Properties
@@ -144,21 +240,14 @@ namespace System.Windows.Forms
                                if (is_checked == value)
                                        return;
                                
+                               is_checked = value;
+
                                if (owner != null) {
-                                       is_checked = value;
-                                       if (is_checked) {
-                                               if (owner.CheckedItems.Contains (this) == false) {
-                                                       owner.CheckedItems.list.Add (this);
-                                                       owner.CheckedIndices.list.Add (this.Index);
-                                               }
-                                       }
-                                       else {
-                                               owner.CheckedItems.list.Remove (this);
-                                               owner.CheckedIndices.list.Remove (this.Index);
-                                       }
-                                       
-                                       owner.Invalidate (Bounds);
+                                       // force re-population of list
+                                       owner.CheckedItems.Reset ();
+                                       Layout ();
                                }                       
+                               Invalidate ();
                        }
                }
 
@@ -172,8 +261,10 @@ namespace System.Windows.Forms
 
                                is_focused = value; 
 
+                               Invalidate ();
                                if (owner != null)
-                                       owner.Invalidate (Bounds);
+                                       Layout ();
+                               Invalidate ();
                        }
                }
 
@@ -181,22 +272,22 @@ namespace System.Windows.Forms
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                public Font Font {
                        get {
-                               if (sub_items.Count > 0)
-                                       return sub_items[0].Font;
-
-                               if (owner != null)
+                               if (font != null)
+                                       return font;
+                               else if (owner != null)
                                        return owner.Font;
 
                                return ThemeEngine.Current.DefaultFont;
                        }
                        set {   
-                               if (sub_items[0].Font == value)
+                               if (font == value)
                                        return;
 
-                               sub_items[0].Font = value; 
+                               font = value; 
 
                                if (owner != null)
-                                       owner.Invalidate (Bounds);
+                                       Layout ();
+                               Invalidate ();
                        }
                }
 
@@ -219,7 +310,12 @@ namespace System.Windows.Forms
                [Editor ("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design,
                         typeof (System.Drawing.Design.UITypeEditor))]
                [Localizable (true)]
+#if NET_2_0
+               [RefreshProperties (RefreshProperties.Repaint)]
+               // [TypeConverter (typeof (NoneExcludedImageIndexConverter))]
+#else
                [TypeConverter (typeof (ImageIndexConverter))]
+#endif
                public int ImageIndex {
                        get { return image_index; }
                        set {
@@ -227,12 +323,39 @@ namespace System.Windows.Forms
                                        throw new ArgumentException ("Invalid ImageIndex. It must be greater than or equal to -1.");
                                
                                image_index = value;
+#if NET_2_0
+                               image_key = String.Empty;
+#endif
 
                                if (owner != null)
-                                       owner.Invalidate (Bounds);      
+                                       Layout ();
+                               Invalidate ();
                        }
                }
 
+#if NET_2_0
+               [DefaultValue ("")]
+               [LocalizableAttribute (true)]
+               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+               [Editor ("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design,
+                        typeof (System.Drawing.Design.UITypeEditor))]
+               [RefreshProperties (RefreshProperties.Repaint)]
+               // XXX [TypeConverter (typeof (ImageKeyConverter))
+               public string ImageKey {
+                       get {
+                               return image_key;
+                       }
+                       set {
+                               image_key = value == null ? String.Empty : value;
+                               image_index = -1;
+
+                               if (owner != null)
+                                       Layout ();
+                               Invalidate ();
+                       }
+               }
+#endif
+
                [Browsable (false)]
                public ImageList ImageList {
                        get {
@@ -260,32 +383,40 @@ namespace System.Windows.Forms
                        get { return owner; }
                }
 
+#if NET_2_0
+               [Browsable (false)]
+               [Localizable (true)]
+               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+               public string Name {
+                       get {
+                               return name;
+                       }
+                       set {
+                               name = value == null ? String.Empty : value;
+                       }
+               }
+#endif
+
                [Browsable (false)]
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                public bool Selected {
                        get { return selected; }
                        set {
+                               if (selected == value)
+                                       return;
+
                                if (owner != null) {
-                                       if (owner.CanMultiselect == false &&
-                                           owner.SelectedItems.Count > 0) {
+                                       if (value && !owner.MultiSelect)
                                                owner.SelectedItems.Clear ();
-                                               owner.SelectedIndices.list.Clear ();
-                                       }
-
                                        selected = value;
-                                       if (selected) {
-                                               if (owner.SelectedItems.Contains (this) == false) {
-                                                       owner.SelectedItems.list.Add (this);
-                                                       owner.SelectedIndices.list.Add (this.Index);
-                                               }
-                                       }
-                                       else {
-                                               owner.SelectedItems.list.Remove (this);
-                                               owner.SelectedIndices.list.Remove (this.Index);
-                                       }       
-                                       
-                                       owner.Invalidate (Bounds);
+                                       // force re-population of list
+                                       owner.SelectedItems.Reset ();
+                                       Layout ();
+                                       owner.OnSelectedIndexChanged ();
+                               } else {
+                                       selected = value;
                                }
+                               Invalidate ();
                        }
                }
 
@@ -293,7 +424,13 @@ namespace System.Windows.Forms
                [Editor ("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design,
                         typeof (System.Drawing.Design.UITypeEditor))]
                [Localizable (true)]
+#if NET_2_0
+               [RefreshProperties (RefreshProperties.Repaint)]
+               // XXX [RelatedImageListAttribute ("ListView.StateImageList")]
+               // XXX [TypeConverter (typeof (NoneExcludedImageIndexConverter))]
+#else
                [TypeConverter (typeof (ImageIndexConverter))]
+#endif
                public int StateImageIndex {
                        get { return state_image_index; }
                        set {
@@ -305,6 +442,10 @@ namespace System.Windows.Forms
                }
 
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+#if NET_2_0
+               [Editor ("System.Windows.Forms.Design.ListViewSubItemCollectionEditor, " + Consts.AssemblySystem_Design,
+                        typeof (System.Drawing.Design.UITypeEditor))]
+#endif
                public ListViewSubItemCollection SubItems {
                        get { return sub_items; }
                }
@@ -325,9 +466,18 @@ namespace System.Windows.Forms
                                if (this.sub_items.Count > 0)
                                        return this.sub_items [0].Text;
                                else
-                                       return "";
+                                       return string.Empty;
+                       }
+                       set { 
+                               if (sub_items [0].Text == value)
+                                       return;
+
+                               sub_items [0].Text = value; 
+
+                               if (owner != null)
+                                       Layout ();
+                               Invalidate ();
                        }
-                       set { this.sub_items [0].Text = value; }
                }
 
                [DefaultValue (true)]
@@ -335,11 +485,43 @@ namespace System.Windows.Forms
                        get { return use_item_style; }
                        set { use_item_style = value; }
                }
+
+#if NET_2_0
+               [LocalizableAttribute(true)]
+               [DefaultValue (null)]
+               public ListViewGroup Group {
+                       get { return this.group; }
+                       set
+                       {
+                               if (this.group != value)
+                               {
+                                       if (value != null)
+                                       {
+                                               value.Items.Add(this);
+
+                                               if (this.group != null)
+                                                       this.group.Items.Remove(this);
+
+                                               this.group = value;
+                                       }
+                                       else
+                                       {
+                                               if(this.group != null)
+                                               this.group.Items.Remove(this);
+                                       }
+                               }
+                       }
+               }
+#endif
+
                #endregion      // Public Instance Properties
 
                #region Public Instance Methods
                public void BeginEdit ()
                {
+                       if (owner != null && owner.LabelEdit) {
+                               owner.item_control.BeginEdit (this);
+                       }
                        // FIXME: TODO
                        // if (owner != null && owner.LabelEdit 
                        //    && owner.Activation == ItemActivation.Standard)
@@ -355,6 +537,7 @@ namespace System.Windows.Forms
                        clone.is_checked = this.is_checked;
                        clone.is_focused = this.is_focused;
                        clone.selected = this.selected;
+                       clone.font = this.font;
                        clone.state_image_index = this.state_image_index;
                        clone.sub_items = new ListViewSubItemCollection (this);
                        
@@ -364,6 +547,9 @@ namespace System.Windows.Forms
                        clone.tag = this.tag;
                        clone.use_item_style = this.use_item_style;
                        clone.owner = null;
+#if NET_2_0
+                       clone.name = name;
+#endif
 
                        return clone;
                }
@@ -380,42 +566,34 @@ namespace System.Windows.Forms
                        if (owner == null)
                                return Rectangle.Empty;
                                
-                       /*  Original Ravi's design calculated all items in a virtual space
-                           We convert them real screen positions
-                       */
+                       Rectangle rect;
+
                        switch (portion) {
+                       case ItemBoundsPortion.Icon:
+                               rect = icon_rect;
+                               break;
 
-                       case ItemBoundsPortion.Icon: {
-                               Rectangle rect = icon_rect;
-                               rect.X -= owner.h_marker;
-                               rect.Y -= owner.v_marker;
-                               return rect;
-                       }
+                       case ItemBoundsPortion.Label:
+                               rect = label_rect;
+                               break;
 
-                       case ItemBoundsPortion.Label: {
-                               Rectangle rect = label_rect;
-                               rect.X -= owner.h_marker;
-                               rect.Y -= owner.v_marker;
-                               return rect;
-                       }
+                       case ItemBoundsPortion.ItemOnly:
+                               rect = item_rect;
+                               break;
 
-                       case ItemBoundsPortion.ItemOnly: {
-                               Rectangle rect = item_rect;
+                       case ItemBoundsPortion.Entire:
+                               rect = bounds;
                                rect.X -= owner.h_marker;
                                rect.Y -= owner.v_marker;
                                return rect;
-                       }
-
-                       case ItemBoundsPortion.Entire: {
-                               Rectangle rect = entire_rect;
-                               rect.X -= owner.h_marker;
-                               rect.Y -= owner.v_marker;
-                               return rect;                            
-                       }
 
                        default:
                                throw new ArgumentException ("Invalid value for portion.");
                        }
+
+                       rect.X += bounds.X - owner.h_marker;
+                       rect.Y += bounds.Y - owner.v_marker;
+                       return rect;
                }
 
                void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context)
@@ -452,42 +630,59 @@ namespace System.Windows.Forms
                internal Rectangle CheckRectReal {
                        get {
                                Rectangle rect = checkbox_rect;
-                               rect.X -= owner.h_marker;
-                               rect.Y -= owner.v_marker;
+                               rect.X += bounds.X - owner.h_marker;
+                               rect.Y += bounds.Y - owner.v_marker;
                                return rect;
                        }
                }
                
-               internal Rectangle CheckRect {
-                       get { return this.checkbox_rect; }
-               }
+               internal Point Location {
+                       set {
+                               if (bounds.X == value.X && bounds.Y == value.Y)
+                                       return;
 
-               internal Rectangle EntireRect {
-                       get { return this.entire_rect; }
+                               Rectangle prev = Bounds;
+                               bounds.X = value.X;
+                               bounds.Y = value.Y;
+                               if (owner != null) {
+                                       if (prev != Rectangle.Empty)
+                                               owner.item_control.Invalidate (prev);
+                                       owner.item_control.Invalidate (Bounds);
+                               }
+                       }
                }
 
-               internal Rectangle IconRect {
-                       get { return this.icon_rect; }
+               internal ListView Owner {
+                       set {
+                               if (owner == value)
+                                       return;
+
+                               owner = value;
+                               if (owner != null)
+                                       Layout ();
+                               Invalidate ();
+                       }
                }
 
-               internal Rectangle LabelRect {
-                       get { return this.label_rect; }
+               private void Invalidate ()
+               {
+                       if (owner == null || owner.item_control == null)
+                               return;
+
+                       owner.item_control.Invalidate (Bounds);
                }
 
-               internal void CalcListViewItem ()
+               internal void Layout ()
                {
                        int item_ht;
+                       Rectangle total;
                        Size text_size = owner.text_size;
                        
+                       checkbox_rect = Rectangle.Empty;
                        if (owner.CheckBoxes)
                                checkbox_rect.Size = owner.CheckBoxSize;
-                       else
-                               checkbox_rect = Rectangle.Empty;
-
-                       checkbox_rect.Location = this.location;
 
                        switch (owner.View) {
-
                        case View.Details:
                                // LAMESPEC: MSDN says, "In all views except the details
                                // view of the ListView, this value specifies the same
@@ -495,105 +690,158 @@ namespace System.Windows.Forms
                                // returns same bounding rectangles for Item and Entire
                                // values in the case of Details view.
 
-                               icon_rect.X = checkbox_rect.X + checkbox_rect.Width + 2;
-                               icon_rect.Y = checkbox_rect.Y;
-
-                               item_ht = Math.Max (owner.CheckBoxSize.Height + 1,
-                                                   text_size.Height);
+                               icon_rect = label_rect = Rectangle.Empty;
+                               icon_rect.X = checkbox_rect.Width + 2;
+                               item_ht = Math.Max (owner.CheckBoxSize.Height, text_size.Height);
 
                                if (owner.SmallImageList != null) {
-                                       item_ht = Math.Max (item_ht,
-                                                           owner.SmallImageList.ImageSize.Height + 1);
+                                       item_ht = Math.Max (item_ht, owner.SmallImageList.ImageSize.Height);
                                        icon_rect.Width = owner.SmallImageList.ImageSize.Width;
                                }
-                               else
-                                       icon_rect.Width = 0;
 
-                               label_rect.Height = checkbox_rect.Height = icon_rect.Height = item_ht;
+                               label_rect.Height = icon_rect.Height = item_ht;
+                               checkbox_rect.Y = item_ht - checkbox_rect.Height;
 
-                               label_rect.X = icon_rect.X + icon_rect.Width;
-                               label_rect.Y = icon_rect.Y;
+                               label_rect.X = icon_rect.Right + 1;
 
                                if (owner.Columns.Count > 0)
                                        label_rect.Width = Math.Max (text_size.Width, owner.Columns[0].Wd);
                                else
                                        label_rect.Width = text_size.Width;
 
-                               item_rect = entire_rect = Rectangle.Union
+                               item_rect = total = Rectangle.Union
                                        (Rectangle.Union (checkbox_rect, icon_rect), label_rect);
+                               bounds.Size = total.Size;
 
                                // Take into account the rest of columns. First column
                                // is already taken into account above.
                                for (int i = 1; i < owner.Columns.Count; i++) {
                                        item_rect.Width += owner.Columns [i].Wd;
-                                       entire_rect.Width += owner.Columns [i].Wd;
+                                       bounds.Width += owner.Columns [i].Wd;
                                }
                                break;
 
                        case View.LargeIcon:
-                               if (owner.LargeImageList != null) {
-                                       icon_rect.Width = owner.LargeImageList.ImageSize.Width + 16;
-                                       icon_rect.Height = owner.LargeImageList.ImageSize.Height + 4;
+                               label_rect = icon_rect = Rectangle.Empty;
+
+                               SizeF sz = owner.DeviceContext.MeasureString (Text, Font);
+                               if ((int) sz.Width > text_size.Width) {
+                                       if (Focused) {
+                                               int text_width = text_size.Width;
+                                               StringFormat format = new StringFormat ();
+                                               format.Alignment = StringAlignment.Center;
+                                               sz = owner.DeviceContext.MeasureString (Text, Font, text_width, format);
+                                               text_size.Height = (int) sz.Height;
+                                       } else
+                                               text_size.Height = 2 * (int) sz.Height;
                                }
-                               else {
-                                       icon_rect.Width = 16;
-                                       icon_rect.Height = 4;
-                               }
-
-                               if (text_size.Width <= (checkbox_rect.Width + icon_rect.Width)) {
-                                       icon_rect.X = checkbox_rect.X + checkbox_rect.Width;
-                                       icon_rect.Y = checkbox_rect.Y;
 
-                                       label_rect.X = icon_rect.X + (icon_rect.Width 
-                                                                     - text_size.Width) / 2;
-                                       label_rect.Y = Math.Max (checkbox_rect.Bottom,
-                                                                icon_rect.Bottom) + 2;
-                                       label_rect.Size = text_size;
+                               if (owner.LargeImageList != null) {
+                                       icon_rect.Width = owner.LargeImageList.ImageSize.Width;
+                                       icon_rect.Height = owner.LargeImageList.ImageSize.Height;
                                }
-                               else {
-                                       label_rect.X = this.location.X;
 
-                                       int centerX = label_rect.X + text_size.Width / 2;
-                                       icon_rect.X = centerX - icon_rect.Width / 2;
-                                       checkbox_rect.X = (icon_rect.X - checkbox_rect.Width);
-
-                                       icon_rect.Y = checkbox_rect.Y;
+                               if (checkbox_rect.Height > icon_rect.Height)
+                                       icon_rect.Y = checkbox_rect.Height - icon_rect.Height;
+                               else
+                                       checkbox_rect.Y = icon_rect.Height - checkbox_rect.Height;
 
-                                       label_rect.Y = Math.Max (checkbox_rect.Bottom,
-                                                                icon_rect.Bottom) + 2;
+                               if (text_size.Width <= icon_rect.Width) {
+                                       icon_rect.X = checkbox_rect.Width + 1;
+                                       label_rect.X = icon_rect.X + (icon_rect.Width - text_size.Width) / 2;
+                                       label_rect.Y = icon_rect.Bottom + 2;
+                                       label_rect.Size = text_size;
+                               } else {
+                                       int centerX = text_size.Width / 2;
+                                       icon_rect.X = checkbox_rect.Width + 1 + centerX - icon_rect.Width / 2;
+                                       label_rect.X = checkbox_rect.Width + 1;
+                                       label_rect.Y = icon_rect.Bottom + 2;
                                        label_rect.Size = text_size;
                                }
 
                                item_rect = Rectangle.Union (icon_rect, label_rect);
-                               entire_rect = Rectangle.Union (item_rect, checkbox_rect);
+                               total = Rectangle.Union (item_rect, checkbox_rect);
+                               bounds.Size = total.Size;
                                break;
 
                        case View.List:
-                                       goto case View.SmallIcon;
-
                        case View.SmallIcon:
-                               icon_rect.X = checkbox_rect.X + checkbox_rect.Width;
-                               icon_rect.Y = checkbox_rect.Y;
-
+                               label_rect = icon_rect = Rectangle.Empty;
+                               icon_rect.X = checkbox_rect.Width + 1;
                                item_ht = Math.Max (owner.CheckBoxSize.Height, text_size.Height);
 
                                if (owner.SmallImageList != null) {
-                                       item_ht = Math.Max (item_ht,
-                                                           owner.SmallImageList.ImageSize.Height + 1);
+                                       item_ht = Math.Max (item_ht, owner.SmallImageList.ImageSize.Height);
                                        icon_rect.Width = owner.SmallImageList.ImageSize.Width;
+                                       icon_rect.Height = owner.SmallImageList.ImageSize.Height;
                                }
-                               else
-                                       icon_rect.Width = 0;
-
-                               label_rect.Height = checkbox_rect.Height = icon_rect.Height = item_ht;
 
-                               label_rect.X = icon_rect.X + icon_rect.Width;
-                               label_rect.Y = icon_rect.Y;
+                               checkbox_rect.Y = item_ht - checkbox_rect.Height;
+                               label_rect.X = icon_rect.Right + 1;
                                label_rect.Width = text_size.Width;
+                               label_rect.Height = icon_rect.Height = item_ht;
+
+                               item_rect = Rectangle.Union (icon_rect, label_rect);
+                               total = Rectangle.Union (item_rect, checkbox_rect);
+                               bounds.Size = total.Size;
+                               break;
+#if NET_2_0
+                       case View.Tile:
+                               label_rect = icon_rect = Rectangle.Empty;
+
+                               if (owner.LargeImageList != null) {
+                                       icon_rect.Width = owner.LargeImageList.ImageSize.Width;
+                                       icon_rect.Height = owner.LargeImageList.ImageSize.Height;
+                               }
+
+                               int separation = 2;
+                               SizeF tsize = owner.DeviceContext.MeasureString (Text, Font);
+
+                               // Set initial values for subitem's layout
+                               int total_height = (int)Math.Ceiling (tsize.Height);
+                               int max_subitem_width = (int)Math.Ceiling (tsize.Width);
+                               SubItems [0].bounds.Height = total_height;
+                       
+                               int count = Math.Min (owner.Columns.Count, SubItems.Count);
+                               for (int i = 1; i < count; i++) { // Ignore first column and first subitem
+                                       ListViewSubItem sub_item = SubItems [i];
+                                       if (sub_item.Text == null || sub_item.Text.Length == 0)
+                                               continue;
+
+                                       tsize = owner.DeviceContext.MeasureString (sub_item.Text, sub_item.Font);
+                               
+                                       int width = (int)Math.Ceiling (tsize.Width);
+                               
+                                       if (width > max_subitem_width)
+                                               max_subitem_width = width;
+                               
+                                       int height = (int)Math.Ceiling (tsize.Height);
+                                       total_height += height + separation;
+                               
+                                       sub_item.bounds.Height = height;
+                       
+                               }
 
+                               label_rect.X = icon_rect.Right + 4;
+                               label_rect.Y = owner.TileSize.Height / 2 - total_height / 2;
+                               label_rect.Width = max_subitem_width;
+                               label_rect.Height = total_height;
+                       
+                               // Second pass for assigning bounds. This time take first subitem into account.
+                               int current_y = label_rect.Y;
+                               for (int j = 0; j < count; j++) {
+                                       ListViewSubItem sub_item = SubItems [j];
+                                       if (sub_item.Text == null || sub_item.Text.Length == 0)
+                                               continue;
+
+                                       sub_item.SetBounds (label_rect.X, current_y, max_subitem_width, sub_item.bounds.Height);
+                                       current_y += sub_item.Bounds.Height + separation;
+                               }
+                               
                                item_rect = Rectangle.Union (icon_rect, label_rect);
-                               entire_rect = Rectangle.Union (item_rect, checkbox_rect);
+                               bounds.Size = item_rect.Size;
                                break;
+#endif
                        }
                        
                }
@@ -612,7 +860,12 @@ namespace System.Windows.Forms
                        private Font font;
                        private Color fore_color;
                        internal ListViewItem owner;
-                       private string text;
+                       private string text = string.Empty;
+#if NET_2_0
+                       private string name = String.Empty;
+                       private object tag;
+                       internal Rectangle bounds;
+#endif
                        
                        #region Public Constructors
                        public ListViewSubItem ()
@@ -621,8 +874,7 @@ namespace System.Windows.Forms
 
                        public ListViewSubItem (ListViewItem owner, string text)
                                : this (owner, text, ThemeEngine.Current.ColorWindowText,
-                                       ThemeEngine.Current.ColorWindow,
-                                       ThemeEngine.Current.DefaultFont)
+                                       ThemeEngine.Current.ColorWindow, null)
                        {
                        }
 
@@ -630,7 +882,7 @@ namespace System.Windows.Forms
                                                Color backColor, Font font)
                        {
                                this.owner = owner;
-                               this.text = text;
+                               Text = text;
                                this.fore_color = foreColor;
                                this.back_color = backColor;
                                this.font = font;
@@ -646,6 +898,20 @@ namespace System.Windows.Forms
                                    }
                        }
 
+#if NET_2_0
+                       public Rectangle Bounds {
+                               get {
+                                       Rectangle retval = bounds;
+                                       if (owner != null) {
+                                               retval.X += owner.Bounds.X;
+                                               retval.Y += owner.Bounds.Y;
+                                       }
+
+                                       return retval;
+                               }
+                       }
+#endif
+
                        [Localizable (true)]
                        public Font Font {
                                get {
@@ -653,9 +919,11 @@ namespace System.Windows.Forms
                                                return font;
                                        else if (owner != null)
                                                return owner.Font;
-                                       return font;
+                                       return ThemeEngine.Current.DefaultFont;
                                }
                                set { 
+                                       if (font == value)
+                                               return;
                                        font = value; 
                                        Invalidate ();
                                    }
@@ -669,11 +937,43 @@ namespace System.Windows.Forms
                                    }
                        }
 
+#if NET_2_0
+                       [Localizable (true)]
+                       public string Name {
+                               get {
+                                       return name;
+                               }
+                               set {
+                                       name = value == null ? String.Empty : value;
+                               }
+                       }
+
+                       [TypeConverter (typeof (StringConverter))]
+                       [BindableAttribute (true)]
+                       [DefaultValue (null)]
+                       [Localizable (false)]
+                       public object Tag {
+                               get {
+                                       return tag;
+                               }
+                               set {
+                                       tag = value;
+                               }
+                       }
+#endif
+
                        [Localizable (true)]
                        public string Text {
                                get { return text; }
                                set { 
-                                       text = value; 
+                                       if(text == value)
+                                               return;
+
+                                       if(value == null)
+                                               text = string.Empty;
+                                       else
+                                               text = value; 
+
                                        Invalidate ();
                                    }
                        }
@@ -703,6 +1003,13 @@ namespace System.Windows.Forms
 
                                owner.owner.Invalidate ();
                        }
+
+#if NET_2_0
+                       internal void SetBounds (int x, int y, int width, int height)
+                       {
+                               bounds = new Rectangle (x, y, width, height);
+                       }
+#endif
                        #endregion // Private Methods
                }
 
@@ -721,11 +1028,11 @@ namespace System.Windows.Forms
 
                        #region Public Properties
                        [Browsable (false)]
-                       public virtual int Count {
+                       public int Count {
                                get { return list.Count; }
                        }
 
-                       public virtual bool IsReadOnly {
+                       public bool IsReadOnly {
                                get { return false; }
                        }
 
@@ -737,6 +1044,18 @@ namespace System.Windows.Forms
                                }
                        }
 
+#if NET_2_0
+                       public virtual ListViewSubItem this [string key] {
+                               get {
+                                       int idx = IndexOfKey (key);
+                                       if (idx == -1)
+                                               return null;
+
+                                       return (ListViewSubItem) list [idx];
+                               }
+                       }
+#endif
+
                        bool ICollection.IsSynchronized {
                                get { return list.IsSynchronized; }
                        }
@@ -785,27 +1104,42 @@ namespace System.Windows.Forms
 
                        public void AddRange (ListViewSubItem [] items)
                        {
-                               this.Clear ();
-                               foreach (ListViewSubItem item in items)
+                               if (items == null)
+                                       throw new ArgumentNullException ("items");
+
+                               foreach (ListViewSubItem item in items) {
+                                       if (item == null)
+                                               continue;
                                        this.Add (item);
+                               }
                        }
 
                        public void AddRange (string [] items)
                        {
-                               this.Clear ();
-                               foreach (string item in items)
+                               if (items == null)
+                                       throw new ArgumentNullException ("items");
+
+                               foreach (string item in items) {
+                                       if (item == null)
+                                               continue;
                                        this.Add (item);
+                               }
                        }
 
                        public void AddRange (string [] items, Color foreColor,
                                              Color backColor, Font font)
                        {
-                               this.Clear ();
-                               foreach (string item in items)
+                               if (items == null)
+                                       throw new ArgumentNullException ("items");
+
+                               foreach (string item in items) {
+                                       if (item == null)
+                                               continue;
                                        this.Add (item, foreColor, backColor, font);
+                               }
                        }
 
-                       public virtual void Clear ()
+                       public void Clear ()
                        {
                                list.Clear ();
                        }
@@ -815,7 +1149,14 @@ namespace System.Windows.Forms
                                return list.Contains (item);
                        }
 
-                       public virtual IEnumerator GetEnumerator ()
+#if NET_2_0
+                       public virtual bool ContainsKey (string key)
+                       {
+                               return IndexOfKey (key) != -1;
+                       }
+#endif
+
+                       public IEnumerator GetEnumerator ()
                        {
                                return list.GetEnumerator ();
                        }
@@ -877,6 +1218,22 @@ namespace System.Windows.Forms
                                return list.IndexOf (subItem);
                        }
 
+#if NET_2_0
+                       public virtual int IndexOfKey (string key)
+                       {
+                               if (key == null || key.Length == 0)
+                                       return -1;
+
+                               for (int i = 0; i < list.Count; i++) {
+                                       ListViewSubItem l = (ListViewSubItem) list [i];
+                                       if (String.Compare (l.Name, key, true) == 0)
+                                               return i;
+                               }
+
+                               return -1;
+                       }
+#endif
+
                        public void Insert (int index, ListViewSubItem item)
                        {
                                item.owner = this.owner;
@@ -888,7 +1245,16 @@ namespace System.Windows.Forms
                                list.Remove (item);
                        }
 
-                       public virtual void RemoveAt (int index)
+#if NET_2_0
+                       public virtual void RemoveByKey (string key)
+                       {
+                               int idx = IndexOfKey (key);
+                               if (idx != -1)
+                                       RemoveAt (idx);
+                       }
+#endif
+
+                       public void RemoveAt (int index)
                        {
                                list.RemoveAt (index);
                        }