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