* ListViewItem.cs: When retrieving the focused state, the index check
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / ListViewItem.cs
index 25aa794370db43aa90fb859279eb2964ef1d29b1..4d576905a528d0715bb0450409b8d0edba46fa96 100644 (file)
 // Author:
 //      Ravindra (rkumar@novell.com)
 //      Mike Kestner <mkestner@novell.com>
-
-
-
-// NOT COMPLETE
-
+//      Daniel Nauck (dna(at)mono-project(dot)de)
 
 using System.Collections;
 using System.ComponentModel;
@@ -45,12 +41,17 @@ namespace System.Windows.Forms
                #region Instance Variables
                private int image_index = -1;
                private bool is_checked = false;
-               private bool is_focused = false;
                private int state_image_index = -1;
                private ListViewSubItemCollection sub_items;
                private object tag;
                private bool use_item_style = true;
-
+#if NET_2_0
+               private ListViewGroup group = null;
+               private string name = String.Empty;
+               private string image_key = String.Empty;
+               string tooltip_text = String.Empty;
+               int index;                      // cached index for VirtualMode
+#endif
                Rectangle bounds;
                Rectangle checkbox_rect;        // calculated by CalcListViewItem method
                Rectangle icon_rect;
@@ -58,6 +59,9 @@ namespace System.Windows.Forms
                Rectangle label_rect;
                ListView owner;
                Font font;
+#if NET_2_0
+               Font hot_font;                  // cached font for hot tracking
+#endif
                bool selected;
 
                internal int row;
@@ -66,10 +70,8 @@ namespace System.Windows.Forms
                #endregion Instance Variables
 
                #region Public Constructors
-               public ListViewItem ()
+               public ListViewItem () : this (string.Empty)
                {
-                       this.sub_items = new ListViewSubItemCollection (this);
-                       this.sub_items.Add ("");                        
                }
 
                public ListViewItem (string text) : this (text, -1)
@@ -83,7 +85,8 @@ namespace System.Windows.Forms
                public ListViewItem (ListViewItem.ListViewSubItem [] subItems, int imageIndex)
                {
                        this.sub_items = new ListViewSubItemCollection (this);
-                       this.sub_items.AddRange (subItems);
+                       for (int i = 0; i < subItems.Length; i++)
+                               sub_items.Add (subItems [i]);
                        this.image_index = imageIndex;
                }
 
@@ -97,20 +100,113 @@ namespace System.Windows.Forms
                public ListViewItem (string [] items, int imageIndex)
                {
                        this.sub_items = new ListViewSubItemCollection (this);
-                       this.sub_items.AddRange (items);
+                       if (items != null) {
+                               for (int i = 0; i < items.Length; i++)
+                                       sub_items.Add (new ListViewSubItem (this, items [i]));
+                       }
                        this.image_index = imageIndex;
                }
 
                public ListViewItem (string [] items, int imageIndex, Color foreColor, 
-                                    Color backColor, Font font)
+                                    Color backColor, Font font) : this (items, imageIndex)
+               {
+                       ForeColor = foreColor;
+                       BackColor = backColor;
+                       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.sub_items = new ListViewSubItemCollection (this);
-                       this.sub_items.AddRange (items);
-                       this.image_index = imageIndex;
+                       for (int i = 0; i < subItems.Length; i++)
+                               this.sub_items.Add (subItems [i]);
+                       this.ImageKey = imageKey;
+               }
+
+               public ListViewItem(string[] items, string imageKey, Color foreColor,
+                                       Color backColor, Font font) : this(items, imageKey)
+               {
                        ForeColor = foreColor;
                        BackColor = backColor;
                        this.font = font;
                }
+
+               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
@@ -125,8 +221,7 @@ namespace System.Windows.Forms
                                
                                return ThemeEngine.Current.ColorWindow;
                        }
-
-                       set { sub_items[0].BackColor = value; }
+                       set { SubItems [0].BackColor = value; }
                }
 
                [Browsable (false)]
@@ -144,37 +239,61 @@ namespace System.Windows.Forms
                                if (is_checked == value)
                                        return;
                                
-                               is_checked = value;
-
                                if (owner != null) {
-                                       if (is_checked) {
-                                               if (owner.CheckedItems.Contains (this) == false) {
-                                                       owner.CheckedItems.list.Add (this);
-                                               }
-                                       }
-                                       else {
-                                               owner.CheckedItems.list.Remove (this);
+                                       CheckState current_value = is_checked ? CheckState.Checked : CheckState.Unchecked;
+                                       CheckState new_value = value ? CheckState.Checked : CheckState.Unchecked;
+
+                                       ItemCheckEventArgs icea = new ItemCheckEventArgs (Index,
+                                                       new_value, current_value);
+                                       owner.OnItemCheck (icea);
+
+                                       if (new_value != current_value) {
+                                               // force re-population of list
+                                               owner.CheckedItems.Reset ();
+                                               is_checked = new_value == CheckState.Checked;
+                                               Invalidate ();
+
+#if NET_2_0
+                                               ItemCheckedEventArgs args = new ItemCheckedEventArgs (this);
+                                               owner.OnItemChecked (args);
+#endif
                                        }
-                                       
-                                       Layout ();
-                               }                       
-                               Invalidate ();
+                               } else
+                                       is_checked = value;
                        }
                }
 
                [Browsable (false)]
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                public bool Focused {
-                       get { return is_focused; }
+                       get { 
+                               if (owner == null)
+                                       return false;
+
+#if NET_2_0
+                               // In virtual mode the checks are always done using indexes
+                               if (owner.VirtualMode)
+                                       return Index == owner.focused_item_index;
+#endif
+
+                               // Light check
+                               return owner.FocusedItem == this;
+
+                       }
                        set {   
-                               if (is_focused == value)
+                               if (owner == null)
                                        return;
 
-                               is_focused = value; 
+                               if (Focused == value)
+                                       return;
 
-                               if (owner != null)
-                                       Layout ();
-                               Invalidate ();
+                               ListViewItem prev_focused_item = owner.FocusedItem;
+                               if (prev_focused_item != null)
+                                       prev_focused_item.UpdateFocusedState ();
+                                       
+                               owner.focused_item_index = value ? Index : -1;
+
+                               UpdateFocusedState ();
                        }
                }
 
@@ -194,6 +313,9 @@ namespace System.Windows.Forms
                                        return;
 
                                font = value; 
+#if NET_2_0
+                               hot_font = null;
+#endif
 
                                if (owner != null)
                                        Layout ();
@@ -212,7 +334,7 @@ namespace System.Windows.Forms
 
                                return ThemeEngine.Current.ColorWindowText;
                        }
-                       set { sub_items[0].ForeColor = value; }
+                       set { SubItems [0].ForeColor = value; }
                }
 
                [DefaultValue (-1)]
@@ -220,7 +342,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 {
@@ -228,6 +355,9 @@ 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)
                                        Layout ();
@@ -235,6 +365,29 @@ namespace System.Windows.Forms
                        }
                }
 
+#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)]
+               [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 {
@@ -252,6 +405,10 @@ namespace System.Windows.Forms
                        get {
                                if (owner == null)
                                        return -1;
+#if NET_2_0
+                               if (owner.VirtualMode)
+                                       return index;
+#endif
                                else
                                        return owner.Items.IndexOf (this);
                        }
@@ -262,19 +419,62 @@ 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
+
+               // When ListView uses VirtualMode, selection state info
+               // lives in the ListView, not in the item
                [Browsable (false)]
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                public bool Selected {
-                       get { return selected; }
+                       get { 
+#if NET_2_0
+                               if (owner != null && owner.VirtualMode)
+                                       return owner.SelectedIndices.Contains (Index);
+#endif
+
+                               return selected; 
+                       }
                        set {
+#if NET_2_0
+                               if (selected == value && owner != null && !owner.VirtualMode)
+#else
                                if (selected == value)
+#endif
                                        return;
 
-                               selected = value;
-
                                if (owner != null) {
-                                       owner.UpdateSelection (this);
-                                       Layout ();
+                                       if (value && !owner.MultiSelect)
+                                               owner.SelectedIndices.Clear ();
+#if NET_2_0
+                                       if (owner.VirtualMode)
+                                               if (value)
+                                                       owner.SelectedIndices.InsertIndex (Index);
+                                               else
+                                                       owner.SelectedIndices.RemoveIndex (Index);
+                                       else
+#endif
+                                               selected = value;
+                                               
+                                       // force re-population of list
+                                       owner.SelectedIndices.Reset ();
+#if NET_2_0
+                                       owner.OnItemSelectionChanged (new ListViewItemSelectionChangedEventArgs (this, Index, value));
+#endif
+                                       owner.OnSelectedIndexChanged ();
+                               } else {
+                                       selected = value;
                                }
                                Invalidate ();
                        }
@@ -284,7 +484,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)]
+               [RelatedImageListAttribute ("ListView.StateImageList")]
+               [TypeConverter (typeof (NoneExcludedImageIndexConverter))]
+#else
                [TypeConverter (typeof (ImageIndexConverter))]
+#endif
                public int StateImageIndex {
                        get { return state_image_index; }
                        set {
@@ -296,8 +502,16 @@ 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; }
+                       get {
+                               if (sub_items.Count == 0)
+                                       this.sub_items.Add (string.Empty);
+                               return sub_items;
+                       }
                }
 
                [Bindable (true)]
@@ -316,10 +530,10 @@ 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)
+                               if (SubItems [0].Text == value)
                                        return;
 
                                sub_items [0].Text = value; 
@@ -335,11 +549,46 @@ 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 (group != value) {
+                                       if (value == null)
+                                               group.Items.Remove (this);
+                                       else
+                                               value.Items.Add (this);
+                               
+                                       group = value;
+                               }
+                       }
+               }
+
+               [DefaultValue ("")]
+               public string ToolTipText {
+                       get {
+                               return tooltip_text;
+                       }
+                       set {
+                               if (value == null)
+                                       value = String.Empty;
+
+                               tooltip_text = value;
+                       }
+               }
+#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)
@@ -353,7 +602,6 @@ namespace System.Windows.Forms
                        ListViewItem clone = new ListViewItem ();
                        clone.image_index = this.image_index;
                        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;
@@ -365,6 +613,10 @@ 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;
+                       clone.tooltip_text = tooltip_text;
+#endif
 
                        return clone;
                }
@@ -383,6 +635,12 @@ namespace System.Windows.Forms
                                
                        Rectangle rect;
 
+#if NET_2_0
+                       // Can't cache bounds in Virtual mode,
+                       // since we can get different item instances at each invocation
+                       if (owner.VirtualMode)
+                               Layout ();
+#endif
                        switch (portion) {
                        case ItemBoundsPortion.Icon:
                                rect = icon_rect;
@@ -398,16 +656,15 @@ namespace System.Windows.Forms
 
                        case ItemBoundsPortion.Entire:
                                rect = bounds;
-                               rect.X -= owner.h_marker;
-                               rect.Y -= owner.v_marker;
-                               return rect;                            
+                               break;
 
                        default:
                                throw new ArgumentException ("Invalid value for portion.");
                        }
 
-                       rect.X += bounds.X - owner.h_marker;
-                       rect.Y += bounds.Y - owner.v_marker;
+                       Point item_loc = owner.GetItemLocation (Index);
+                       rect.X += item_loc.X;
+                       rect.Y += item_loc.Y;
                        return rect;
                }
 
@@ -416,10 +673,27 @@ namespace System.Windows.Forms
                        // FIXME: TODO
                }
 
+#if NET_2_0
+               public ListViewSubItem GetSubItemAt (int x, int y)
+               {
+                       if (owner != null && owner.View != View.Details)
+                               return null;
+
+                       foreach (ListViewSubItem sub_item in sub_items)
+                               if (sub_item.Bounds.Contains (x, y))
+                                       return sub_item;
+
+                       return null;
+               }
+#endif
+
                public virtual void Remove ()
                {
-                       if (owner != null)
-                               owner.Items.Remove (this);
+                       if (owner == null)
+                               return;
+
+                       owner.item_control.CancelEdit (this);
+                       owner.Items.Remove (this);
                        owner = null;
                }
 
@@ -445,39 +719,40 @@ namespace System.Windows.Forms
                internal Rectangle CheckRectReal {
                        get {
                                Rectangle rect = checkbox_rect;
-                               rect.X += bounds.X - owner.h_marker;
-                               rect.Y += bounds.Y - owner.v_marker;
+                               Point item_loc = owner.GetItemLocation (Index);
+                               rect.X += item_loc.X;
+                               rect.Y += item_loc.Y;
                                return rect;
                        }
                }
                
-               Rectangle CheckRect {
-                       get { return this.checkbox_rect; }
-               }
-
-               Rectangle IconRect {
-                       get { return this.icon_rect; }
+               Rectangle text_bounds;
+               internal Rectangle TextBounds {
+                       get {
+                               Rectangle result = text_bounds;
+                               Point loc = owner.GetItemLocation (Index);
+                               result.X += loc.X;
+                               result.Y += loc.Y;
+                               return result;
+                       }
                }
 
-               Rectangle LabelRect {
-                       get { return this.label_rect; }
+#if NET_2_0
+               internal bool Hot {
+                       get {
+                               return Index == owner.HotItemIndex;
+                       }
                }
 
-               internal Point Location {
-                       set {
-                               if (bounds.X == value.X && bounds.Y == value.Y)
-                                       return;
+               internal Font HotFont {
+                       get {
+                               if (hot_font == null)
+                                       hot_font = new Font (Font, Font.Style | FontStyle.Underline);
 
-                               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);
-                               }
+                               return hot_font;
                        }
                }
+#endif
 
                internal ListView Owner {
                        set {
@@ -485,15 +760,35 @@ namespace System.Windows.Forms
                                        return;
 
                                owner = value;
-                               if (owner != null)
-                                       Layout ();
+                       }
+               }
+
+#if NET_2_0
+               internal void SetIndex (int index)
+               {
+                       this.index = index;
+               }
+
+               internal void SetGroup (ListViewGroup group)
+               {
+                       this.group = group;
+               }
+#endif
+
+               // When focus changed, we need to invalidate area
+               // with previous layout and with the new one
+               void UpdateFocusedState ()
+               {
+                       if (owner != null) {
+                               Invalidate ();
+                               Layout ();
                                Invalidate ();
                        }
                }
 
-               private void Invalidate ()
+               internal void Invalidate ()
                {
-                       if (owner == null || owner.item_control == null)
+                       if (owner == null || owner.item_control == null || owner.updating)
                                return;
 
                        owner.item_control.Invalidate (Bounds);
@@ -501,6 +796,8 @@ namespace System.Windows.Forms
 
                internal void Layout ()
                {
+                       if (owner == null)
+                               return;
                        int item_ht;
                        Rectangle total;
                        Size text_size = owner.text_size;
@@ -508,7 +805,6 @@ namespace System.Windows.Forms
                        checkbox_rect = Rectangle.Empty;
                        if (owner.CheckBoxes)
                                checkbox_rect.Size = owner.CheckBoxSize;
-
                        switch (owner.View) {
                        case View.Details:
                                // LAMESPEC: MSDN says, "In all views except the details
@@ -517,14 +813,16 @@ namespace System.Windows.Forms
                                // returns same bounding rectangles for Item and Entire
                                // values in the case of Details view.
 
+                               // Handle reordered column
+                               if (owner.Columns.Count > 0)
+                                       checkbox_rect.X = owner.Columns[0].Rect.X;
+
                                icon_rect = label_rect = Rectangle.Empty;
-                               icon_rect.X = checkbox_rect.Width + 2;
-                               item_ht = Math.Max (owner.CheckBoxSize.Height, text_size.Height);
+                               icon_rect.X = checkbox_rect.Right + 2;
+                               item_ht = owner.ItemSize.Height;
 
-                               if (owner.SmallImageList != null) {
-                                       item_ht = Math.Max (item_ht, owner.SmallImageList.ImageSize.Height);
+                               if (owner.SmallImageList != null)
                                        icon_rect.Width = owner.SmallImageList.ImageSize.Width;
-                               }
 
                                label_rect.Height = icon_rect.Height = item_ht;
                                checkbox_rect.Y = item_ht - checkbox_rect.Height;
@@ -532,25 +830,48 @@ namespace System.Windows.Forms
                                label_rect.X = icon_rect.Right + 1;
 
                                if (owner.Columns.Count > 0)
-                                       label_rect.Width = Math.Max (text_size.Width, owner.Columns[0].Wd);
+                                       label_rect.Width = owner.Columns[0].Wd - label_rect.X + checkbox_rect.X;
                                else
                                        label_rect.Width = text_size.Width;
 
+                               SizeF text_sz = TextRenderer.MeasureString (Text, Font);
+                               text_bounds = label_rect;
+                               text_bounds.Width = (int) text_sz.Width;
+
                                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 = 0;
+                               bounds.Width = 0;
+                               for (int i = 0; i < owner.Columns.Count; i++) {
                                        item_rect.Width += owner.Columns [i].Wd;
                                        bounds.Width += owner.Columns [i].Wd;
                                }
+
+                               // Bounds for sub items
+                               int n = Math.Min (owner.Columns.Count, sub_items.Count);
+                               for (int i = 0; i < n; i++) {
+                                       Rectangle col_rect = owner.Columns [i].Rect;
+                                       sub_items [i].SetBounds (col_rect.X, 0, col_rect.Width, item_ht);
+                               }
                                break;
 
                        case View.LargeIcon:
                                label_rect = icon_rect = Rectangle.Empty;
 
+                               SizeF sz = TextRenderer.MeasureString (Text, Font);
+                               if ((int) sz.Width > text_size.Width) {
+                                       if (Focused && owner.InternalContainsFocus) {
+                                               int text_width = text_size.Width;
+                                               StringFormat format = new StringFormat ();
+                                               format.Alignment = StringAlignment.Center;
+                                               sz = TextRenderer.MeasureString (Text, Font, text_width, format);
+                                               text_size.Height = (int) sz.Height;
+                                       } else
+                                               text_size.Height = 2 * (int) sz.Height;
+                               }
+
                                if (owner.LargeImageList != null) {
                                        icon_rect.Width = owner.LargeImageList.ImageSize.Width;
                                        icon_rect.Height = owner.LargeImageList.ImageSize.Height;
@@ -561,7 +882,6 @@ namespace System.Windows.Forms
                                else
                                        checkbox_rect.Y = icon_rect.Height - checkbox_rect.Height;
 
-
                                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;
@@ -601,6 +921,63 @@ namespace System.Windows.Forms
                                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 = TextRenderer.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 = TextRenderer.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);
+                               bounds.Size = item_rect.Size;
+                               break;
+#endif
                        }
                        
                }
@@ -619,7 +996,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;
+#endif
+                       internal Rectangle bounds;
                        
                        #region Public Constructors
                        public ListViewSubItem ()
@@ -627,8 +1009,8 @@ namespace System.Windows.Forms
                        }
 
                        public ListViewSubItem (ListViewItem owner, string text)
-                               : this (owner, text, ThemeEngine.Current.ColorWindowText,
-                                       ThemeEngine.Current.ColorWindow, null)
+                               : this (owner, text, Color.Empty,
+                                       Color.Empty, null)
                        {
                        }
 
@@ -636,7 +1018,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;
@@ -645,11 +1027,36 @@ namespace System.Windows.Forms
 
                        #region Public Instance Properties
                        public Color BackColor {
-                               get { return back_color; }
+                               get {
+                                       if (this.back_color != Color.Empty)
+                                               return this.back_color;
+                                       if (this.owner != null && this.owner.ListView != null)
+                                               return this.owner.ListView.BackColor;
+                                       return ThemeEngine.Current.ColorWindow;
+                               }
                                set { 
                                        back_color = value; 
                                        Invalidate ();
-                                   }
+                               }
+                       }
+
+#if NET_2_0
+                       [Browsable (false)]
+                       public 
+#else
+                               
+                       internal
+#endif
+                       Rectangle Bounds {
+                               get {
+                                       Rectangle retval = bounds;
+                                       if (owner != null) {
+                                               retval.X += owner.Bounds.X;
+                                               retval.Y += owner.Bounds.Y;
+                                       }
+
+                                       return retval;
+                               }
                        }
 
                        [Localizable (true)]
@@ -670,18 +1077,56 @@ namespace System.Windows.Forms
                        }
 
                        public Color ForeColor {
-                               get { return fore_color; }
+                               get {
+                                       if (this.fore_color != Color.Empty)
+                                               return this.fore_color;
+                                       if (this.owner != null && this.owner.ListView != null)
+                                               return this.owner.ListView.ForeColor;
+                                       return ThemeEngine.Current.ColorWindowText;
+                               }
                                set { 
                                        fore_color = value; 
                                        Invalidate ();
-                                   }
+                               }
                        }
 
+#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 ();
                                    }
                        }
@@ -709,7 +1154,18 @@ namespace System.Windows.Forms
                                if (owner == null || owner.owner == null)
                                        return;
 
-                               owner.owner.Invalidate ();
+                               owner.Invalidate ();
+                       }
+
+                       internal int Height {
+                               get {
+                                       return bounds.Height;
+                               }
+                       }
+
+                       internal void SetBounds (int x, int y, int width, int height)
+                       {
+                               bounds = new Rectangle (x, y, width, height);
                        }
                        #endregion // Private Methods
                }
@@ -740,10 +1196,24 @@ namespace System.Windows.Forms
                        public ListViewSubItem this [int index] {
                                get { return (ListViewSubItem) list [index]; }
                                set { 
-                                       value.owner = this.owner;
+                                       value.owner = owner;
                                        list [index] = value;
+                                       owner.Layout ();
+                                       owner.Invalidate ();
+                               }
+                       }
+
+#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; }
@@ -770,47 +1240,74 @@ namespace System.Windows.Forms
                        #region Public Methods
                        public ListViewSubItem Add (ListViewSubItem item)
                        {
-                               item.owner = this.owner;
-                               list.Add (item);
+                               AddSubItem (item);
+                               owner.Layout ();
+                               owner.Invalidate ();
                                return item;
                        }
 
                        public ListViewSubItem Add (string text)
                        {
-                               ListViewSubItem item = new ListViewSubItem (this.owner, text);
-                               list.Add (item);
-                               return item;
+                               ListViewSubItem item = new ListViewSubItem (owner, text);
+                               return Add (item);
                        }
 
                        public ListViewSubItem Add (string text, Color foreColor,
                                                    Color backColor, Font font)
                        {
-                               ListViewSubItem item = new ListViewSubItem (this.owner, text,
+                               ListViewSubItem item = new ListViewSubItem (owner, text,
                                                                            foreColor, backColor, font);
-                               list.Add (item);
-                               return item;
+                               return Add (item);
                        }
 
                        public void AddRange (ListViewSubItem [] items)
                        {
-                               list.Clear ();
-                               foreach (ListViewSubItem item in items)
-                                       this.Add (item);
+                               if (items == null)
+                                       throw new ArgumentNullException ("items");
+
+                               foreach (ListViewSubItem item in items) {
+                                       if (item == null)
+                                               continue;
+                                       AddSubItem (item);
+                               }
+                               owner.Layout ();
+                               owner.Invalidate ();
                        }
 
                        public void AddRange (string [] items)
                        {
-                               list.Clear ();
-                               foreach (string item in items)
-                                       this.Add (item);
+                               if (items == null)
+                                       throw new ArgumentNullException ("items");
+
+                               foreach (string item in items) {
+                                       if (item == null)
+                                               continue;
+                                       AddSubItem (new ListViewSubItem (owner, item));
+                               }
+                               owner.Layout ();
+                               owner.Invalidate ();
                        }
 
                        public void AddRange (string [] items, Color foreColor,
                                              Color backColor, Font font)
                        {
-                               list.Clear ();
-                               foreach (string item in items)
-                                       this.Add (item, foreColor, backColor, font);
+                               if (items == null)
+                                       throw new ArgumentNullException ("items");
+
+                               foreach (string item in items) {
+                                       if (item == null)
+                                               continue;
+
+                                       AddSubItem (new ListViewSubItem (owner, item, foreColor, backColor, font));
+                               }
+                               owner.Layout ();
+                               owner.Invalidate ();
+                       }
+
+                       void AddSubItem (ListViewSubItem subItem)
+                       {
+                               subItem.owner = owner;
+                               list.Add (subItem);
                        }
 
                        public void Clear ()
@@ -823,6 +1320,13 @@ namespace System.Windows.Forms
                                return list.Contains (item);
                        }
 
+#if NET_2_0
+                       public virtual bool ContainsKey (string key)
+                       {
+                               return IndexOfKey (key) != -1;
+                       }
+#endif
+
                        public IEnumerator GetEnumerator ()
                        {
                                return list.GetEnumerator ();
@@ -885,16 +1389,45 @@ 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;
                                list.Insert (index, item);
+                               owner.Layout ();
+                               owner.Invalidate ();
                        }
 
                        public void Remove (ListViewSubItem item)
                        {
                                list.Remove (item);
+                               owner.Layout ();
+                               owner.Invalidate ();
+                       }
+
+#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)
                        {