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