diff options
Diffstat (limited to 'source/ShiftUI/Widgets/ListViewItem.cs')
| -rw-r--r-- | source/ShiftUI/Widgets/ListViewItem.cs | 1638 |
1 files changed, 1638 insertions, 0 deletions
diff --git a/source/ShiftUI/Widgets/ListViewItem.cs b/source/ShiftUI/Widgets/ListViewItem.cs new file mode 100644 index 0000000..b9473e1 --- /dev/null +++ b/source/ShiftUI/Widgets/ListViewItem.cs @@ -0,0 +1,1638 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. (http://www.novell.com) +// +// Author: +// Ravindra ([email protected]) +// Mike Kestner <[email protected]> +// Daniel Nauck (dna(at)mono-project(dot)de) + +using System.Collections; +using System.ComponentModel; +using System.Drawing; +using System.Runtime.Serialization; +using System; + +namespace ShiftUI +{ + [DefaultProperty ("Text")] + [DesignTimeVisible (false)] + [Serializable] + [ToolboxItem (false)] + [TypeConverter (typeof (ListViewItemConverter))] + public class ListViewItem : ICloneable, ISerializable + { + #region Instance Variables + private int image_index = -1; + private bool is_checked = false; + private int state_image_index = -1; + private ListViewSubItemCollection sub_items; + private object tag; + private bool use_item_style = true; + int display_index = -1; // actual position in ListView + private ListViewGroup group = null; + private string name = String.Empty; + private string image_key = String.Empty; + string tooltip_text = String.Empty; + int indent_count; + Point position = new Point (-1, -1); // cached to mimic .Net behaviour + Rectangle bounds = Rectangle.Empty; + Rectangle checkbox_rect; // calculated by CalcListViewItem method + Rectangle icon_rect; + Rectangle item_rect; + Rectangle label_rect; + ListView owner; + Font font; + Font hot_font; // cached font for hot tracking + bool selected; + + internal int row; + internal int col; + + + #region UIA Framework: Methods, Properties and Events + + internal event EventHandler UIATextChanged; + + internal event LabelEditEventHandler UIASubItemTextChanged; + + internal void OnUIATextChanged () + { + if (UIATextChanged != null) + UIATextChanged (this, EventArgs.Empty); + } + + internal void OnUIASubItemTextChanged (LabelEditEventArgs args) + { + //If our index is 0 we also generate TextChanged for the ListViewItem + //because ListViewItem.Text is the same as ListViewItem.SubItems [0].Text + if (args.Item == 0) + OnUIATextChanged (); + + if (UIASubItemTextChanged != null) + UIASubItemTextChanged (this, args); + } + + #endregion // UIA Framework: Methods, Properties and Events + + + #endregion Instance Variables + + #region Public Constructors + public ListViewItem () : this (string.Empty) + { + } + + public ListViewItem (string text) : this (text, -1) + { + } + + public ListViewItem (string [] items) : this (items, -1) + { + } + + public ListViewItem (ListViewItem.ListViewSubItem [] subItems, int imageIndex) + { + this.sub_items = new ListViewSubItemCollection (this, null); + for (int i = 0; i < subItems.Length; i++) + sub_items.Add (subItems [i]); + this.image_index = imageIndex; + } + + public ListViewItem (string text, int imageIndex) + { + this.image_index = imageIndex; + this.sub_items = new ListViewSubItemCollection (this, text); + } + + public ListViewItem (string [] items, int imageIndex) + { + this.sub_items = new ListViewSubItemCollection (this, null); + if (items != null) { + for (int i = 0; i < items.Length; i++) + sub_items.Add (new ListViewSubItem (this, items [i])); + } + this.image_index = imageIndex; + } + + public ListViewItem (string [] items, int imageIndex, Color foreColor, + Color backColor, Font font) : this (items, imageIndex) + { + ForeColor = foreColor; + BackColor = backColor; + this.font = font; + } + + public ListViewItem(string[] items, string imageKey) : this(items) + { + this.ImageKey = imageKey; + } + + public ListViewItem(string text, string imageKey) : this(text) + { + this.ImageKey = imageKey; + } + + public ListViewItem(ListViewSubItem[] subItems, string imageKey) + { + this.sub_items = new ListViewSubItemCollection (this, null); + for (int i = 0; i < subItems.Length; i++) + this.sub_items.Add (subItems [i]); + this.ImageKey = imageKey; + } + + public ListViewItem(string[] items, string imageKey, Color foreColor, + Color backColor, Font font) : this(items, imageKey) + { + ForeColor = foreColor; + BackColor = backColor; + this.font = font; + } + + public ListViewItem(ListViewGroup group) : this() + { + Group = group; + } + + public ListViewItem(string text, ListViewGroup group) : this(text) + { + Group = group; + } + + public ListViewItem(string[] items, ListViewGroup group) : this(items) + { + Group = group; + } + + public ListViewItem(ListViewSubItem[] subItems, int imageIndex, ListViewGroup group) + : this(subItems, imageIndex) + { + Group = group; + } + + public ListViewItem(ListViewSubItem[] subItems, string imageKey, ListViewGroup group) + : this(subItems, imageKey) + { + Group = group; + } + + public ListViewItem(string text, int imageIndex, ListViewGroup group) + : this(text, imageIndex) + { + Group = group; + } + + public ListViewItem(string text, string imageKey, ListViewGroup group) + : this(text, imageKey) + { + Group = group; + } + + public ListViewItem(string[] items, int imageIndex, ListViewGroup group) + : this(items, imageIndex) + { + Group = group; + } + + public ListViewItem(string[] items, string imageKey, ListViewGroup group) + : this(items, imageKey) + { + Group = group; + } + + public ListViewItem(string[] items, int imageIndex, Color foreColor, Color backColor, + Font font, ListViewGroup group) + : this(items, imageIndex, foreColor, backColor, font) + { + Group = group; + } + + public ListViewItem(string[] items, string imageKey, Color foreColor, Color backColor, + Font font, ListViewGroup group) + : this(items, imageKey, foreColor, backColor, font) + { + Group = group; + } + #endregion // Public Constructors + + protected ListViewItem (SerializationInfo info, StreamingContext context) + { + Deserialize (info, context); + } + + #region Public Instance Properties + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public Color BackColor { + get { + if (sub_items.Count > 0) + return sub_items[0].BackColor; + + if (owner != null) + return owner.BackColor; + + return ThemeEngine.Current.ColorWindow; + } + set { SubItems [0].BackColor = value; } + } + + [Browsable (false)] + public Rectangle Bounds { + get { + return GetBounds (ItemBoundsPortion.Entire); + } + } + + [DefaultValue (false)] + [RefreshProperties (RefreshProperties.Repaint)] + public bool Checked { + get { return is_checked; } + set { + if (is_checked == value) + return; + + if (owner != null) { + CheckState current_value = is_checked ? CheckState.Checked : CheckState.Unchecked; + CheckState new_value = value ? CheckState.Checked : CheckState.Unchecked; + + ItemCheckEventArgs icea = new ItemCheckEventArgs (Index, + new_value, current_value); + owner.OnItemCheck (icea); + + if (new_value != current_value) { + // force re-population of list + owner.CheckedItems.Reset (); + is_checked = new_value == CheckState.Checked; + Invalidate (); + + ItemCheckedEventArgs args = new ItemCheckedEventArgs (this); + owner.OnItemChecked (args); + } + } else + is_checked = value; + } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public bool Focused { + get { + if (owner == null) + return false; + + // In virtual mode the checks are always done using indexes + if (owner.VirtualMode) + return Index == owner.focused_item_index; + + // Light check + return owner.FocusedItem == this; + + } + set { + if (owner == null) + return; + + if (Focused == value) + return; + + ListViewItem prev_focused_item = owner.FocusedItem; + if (prev_focused_item != null) + prev_focused_item.UpdateFocusedState (); + + owner.focused_item_index = value ? Index : -1; + if (value) + owner.OnUIAFocusedItemChanged (); + + UpdateFocusedState (); + } + } + + [Localizable (true)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public Font Font { + get { + if (font != null) + return font; + else if (owner != null) + return owner.Font; + + return ThemeEngine.Current.DefaultFont; + } + set { + if (font == value) + return; + + font = value; + hot_font = null; + + if (owner != null) + Layout (); + Invalidate (); + } + } + + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public Color ForeColor { + get { + if (sub_items.Count > 0) + return sub_items[0].ForeColor; + + if (owner != null) + return owner.ForeColor; + + return ThemeEngine.Current.ColorWindowText; + } + set { SubItems [0].ForeColor = value; } + } + + [DefaultValue (-1)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + //[Editor ("ShiftUI.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, + //typeof (System.Drawing.Design.UITypeEditor))] + [Localizable (true)] + [RefreshProperties (RefreshProperties.Repaint)] + [TypeConverter (typeof (NoneExcludedImageIndexConverter))] + public int ImageIndex { + get { return image_index; } + set { + if (value < -1) + throw new ArgumentException ("Invalid ImageIndex. It must be greater than or equal to -1."); + + image_index = value; + image_key = String.Empty; + + if (owner != null) + Layout (); + Invalidate (); + } + } + + [DefaultValue ("")] + [LocalizableAttribute (true)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + //[Editor ("ShiftUI.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, + //typeof (System.Drawing.Design.UITypeEditor))] + [RefreshProperties (RefreshProperties.Repaint)] + [TypeConverter (typeof (ImageKeyConverter))] + public string ImageKey { + get { + return image_key; + } + set { + image_key = value == null ? String.Empty : value; + image_index = -1; + + if (owner != null) + Layout (); + Invalidate (); + } + } + + [Browsable (false)] + public ImageList ImageList { + get { + if (owner == null) + return null; + else if (owner.View == View.LargeIcon) + return owner.large_image_list; + else + return owner.small_image_list; + } + } + + [DefaultValue (0)] + public int IndentCount { + get { + return indent_count; + } + set { + if (value < 0) + throw new ArgumentOutOfRangeException ("value"); + + if (value == indent_count) + return; + + indent_count = value; + Invalidate (); + } + } + + [Browsable (false)] + public int Index { + get { + if (owner == null) + return -1; + if (owner.VirtualMode) + return display_index; + + if (display_index == -1) + return owner.Items.IndexOf (this); + + return owner.GetItemIndex (display_index); + } + } + + [Browsable (false)] + public ListView ListView { + get { return owner; } + } + + [Browsable (false)] + [Localizable (true)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public string Name { + get { + return name; + } + set { + name = value == null ? String.Empty : value; + } + } + + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + [Browsable (false)] + public Point Position { + get { + if (owner != null && owner.VirtualMode) + return owner.GetItemLocation (display_index); + + if (owner != null && !owner.IsHandleCreated) + return new Point (-1, -1); + + return position; + } + set { + if (owner == null || owner.View == View.Details || owner.View == View.List) + return; + + if (owner.VirtualMode) + throw new InvalidOperationException (); + + owner.ChangeItemLocation (display_index, value); + } + } + + // When ListView uses VirtualMode, selection state info + // lives in the ListView, not in the item + // Also, in VirtualMode we can't Reset() the selection + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public bool Selected { + get { + if (owner != null && owner.VirtualMode) + return owner.SelectedIndices.Contains (Index); + + return selected; + } + set { + if (selected == value && owner != null && !owner.VirtualMode) + return; + + SetSelectedCore (value); + } + } + + // Expose this method as internal so we can force an update in the selection. + internal void SetSelectedCore (bool value) + { + if (owner != null) { + if (value && !owner.MultiSelect) + owner.SelectedIndices.Clear (); + if (owner.VirtualMode) { + if (value) + owner.SelectedIndices.InsertIndex (Index); + else + owner.SelectedIndices.RemoveIndex (Index); + } else { + selected = value; + owner.SelectedIndices.Reset (); // force re-population of list + } + + owner.OnItemSelectionChanged (new ListViewItemSelectionChangedEventArgs (this, Index, value)); + owner.OnSelectedIndexChanged (); + Invalidate (); + } else + selected = value; + } + + [DefaultValue (-1)] + //[Editor ("ShiftUI.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, + //typeof (System.Drawing.Design.UITypeEditor))] + [Localizable (true)] + [RefreshProperties (RefreshProperties.Repaint)] + [RelatedImageListAttribute ("ListView.StateImageList")] + [TypeConverter (typeof (NoneExcludedImageIndexConverter))] + public int StateImageIndex { + get { return state_image_index; } + set { + if (value < -1 || value > 14) + throw new ArgumentOutOfRangeException ("Invalid StateImageIndex. It must be in the range of [-1, 14]."); + + state_image_index = value; + } + } + + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + //[Editor ("ShiftUI.Design.ListViewSubItemCollectionEditor, " + Consts.AssemblySystem_Design, + //typeof (System.Drawing.Design.UITypeEditor))] + public ListViewSubItemCollection SubItems { + get { + if (sub_items.Count == 0) + this.sub_items.Add (string.Empty); + return sub_items; + } + } + + [Bindable (true)] + [DefaultValue (null)] + [Localizable (false)] + [TypeConverter (typeof (StringConverter))] + public object Tag { + get { return tag; } + set { tag = value; } + } + + [Localizable (true)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public string Text { + get { + if (this.sub_items.Count > 0) + return this.sub_items [0].Text; + else + return string.Empty; + } + set { + if (SubItems [0].Text == value) + return; + + sub_items [0].Text = value; + + if (owner != null) + Layout (); + Invalidate (); + + //UIA Framework: Generates Text changed + OnUIATextChanged (); + + } + } + + [DefaultValue (true)] + public bool UseItemStyleForSubItems { + get { return use_item_style; } + set { use_item_style = value; } + } + + [LocalizableAttribute(true)] + [DefaultValue (null)] + public ListViewGroup Group { + get { return this.group; } + set { + if (group != value) { + if (value == null) + group.Items.Remove (this); + else + value.Items.Add (this); + + group = value; + } + } + } + + [DefaultValue ("")] + public string ToolTipText { + get { + return tooltip_text; + } + set { + if (value == null) + value = String.Empty; + + tooltip_text = value; + } + } + + #endregion // Public Instance Properties + + #region Public Instance Methods + public void BeginEdit () + { + if (owner != null && owner.LabelEdit) { + owner.item_control.BeginEdit (this); + } + // FIXME: TODO + // if (owner != null && owner.LabelEdit + // && owner.Activation == ItemActivation.Standard) + // allow editing + // else + // throw new InvalidOperationException (); + } + + public virtual object Clone () + { + ListViewItem clone = new ListViewItem (); + clone.image_index = this.image_index; + clone.is_checked = this.is_checked; + clone.selected = this.selected; + clone.font = this.font; + clone.state_image_index = this.state_image_index; + clone.sub_items = new ListViewSubItemCollection (this, null); + + foreach (ListViewSubItem subItem in this.sub_items) + clone.sub_items.Add (subItem.Text, subItem.ForeColor, + subItem.BackColor, subItem.Font); + clone.tag = this.tag; + clone.use_item_style = this.use_item_style; + clone.owner = null; + clone.name = name; + clone.tooltip_text = tooltip_text; + + return clone; + } + + public virtual void EnsureVisible () + { + if (this.owner != null) { + owner.EnsureVisible (owner.Items.IndexOf (this)); + } + } + + public ListViewItem FindNearestItem (SearchDirectionHint searchDirection) + { + if (owner == null) + return null; + + Point loc = owner.GetItemLocation (display_index); + return owner.FindNearestItem (searchDirection, loc); + } + + public Rectangle GetBounds (ItemBoundsPortion portion) + { + if (owner == null) + return Rectangle.Empty; + + Rectangle rect; + + switch (portion) { + case ItemBoundsPortion.Icon: + rect = icon_rect; + break; + + case ItemBoundsPortion.Label: + rect = label_rect; + break; + + case ItemBoundsPortion.ItemOnly: + rect = item_rect; + break; + + case ItemBoundsPortion.Entire: + rect = bounds; + break; + + default: + throw new ArgumentException ("Invalid value for portion."); + } + + Point item_loc = owner.GetItemLocation (DisplayIndex); + rect.X += item_loc.X; + rect.Y += item_loc.Y; + return rect; + } + + void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context) + { + Serialize (info, context); + } + + public ListViewSubItem GetSubItemAt (int x, int y) + { + if (owner != null && owner.View != View.Details) + return null; + + foreach (ListViewSubItem sub_item in sub_items) + if (sub_item.Bounds.Contains (x, y)) + return sub_item; + + return null; + } + + public virtual void Remove () + { + if (owner == null) + return; + + owner.item_control.CancelEdit (this); + owner.Items.Remove (this); + owner = null; + } + + public override string ToString () + { + return string.Format ("ListViewItem: {0}", this.Text); + } + #endregion // Public Instance Methods + + #region Protected Methods + protected virtual void Deserialize (SerializationInfo info, StreamingContext context) + { + sub_items = new ListViewSubItemCollection (this, null); + int sub_items_count = 0; + + foreach (SerializationEntry entry in info) { + switch (entry.Name) { + case "Text": + sub_items.Add ((string)entry.Value); + break; + case "Font": + font = (Font)entry.Value; + break; + case "Checked": + is_checked = (bool)entry.Value; + break; + case "ImageIndex": + image_index = (int)entry.Value; + break; + case "StateImageIndex": + state_image_index = (int)entry.Value; + break; + case "UseItemStyleForSubItems": + use_item_style = (bool)entry.Value; + break; + case "SubItemCount": + sub_items_count = (int)entry.Value; + break; + case "Group": + group = (ListViewGroup)entry.Value; + break; + case "ImageKey": + if (image_index == -1) + image_key = (string)entry.Value; + break; + } + } + + Type subitem_type = typeof (ListViewSubItem); + if (sub_items_count > 0) { + sub_items.Clear (); // .net fixup + Text = info.GetString ("Text"); + for (int i = 0; i < sub_items_count - 1; i++) + sub_items.Add ((ListViewSubItem)info.GetValue ("SubItem" + (i + 1), subitem_type)); + } + + // After any sub item has been added. + ForeColor = (Color)info.GetValue ("ForeColor", typeof (Color)); + BackColor = (Color)info.GetValue ("BackColor", typeof (Color)); + } + + protected virtual void Serialize (SerializationInfo info, StreamingContext context) + { + info.AddValue ("Text", Text); + info.AddValue ("Font", Font); + info.AddValue ("ImageIndex", image_index); + info.AddValue ("Checked", is_checked); + info.AddValue ("StateImageIndex", state_image_index); + info.AddValue ("UseItemStyleForSubItems", use_item_style); + info.AddValue ("BackColor", BackColor); + info.AddValue ("ForeColor", ForeColor); + info.AddValue ("ImageKey", image_key); + if (group != null) + info.AddValue ("Group", group); + if (sub_items.Count > 1) { + info.AddValue ("SubItemCount", sub_items.Count); + for (int i = 1; i < sub_items.Count; i++) { + info.AddValue ("SubItem" + i, sub_items [i]); + } + } + } + #endregion // Protected Methods + + #region Private Internal Methods + internal Rectangle CheckRectReal { + get { + Rectangle rect = checkbox_rect; + Point item_loc = owner.GetItemLocation (DisplayIndex); + rect.X += item_loc.X; + rect.Y += item_loc.Y; + return rect; + } + } + + Rectangle text_bounds; + internal Rectangle TextBounds { + get { + // Call Layout() if it hasn't been called before. + if (owner.VirtualMode && bounds == new Rectangle (-1, -1, -1, -1)) + Layout (); + Rectangle result = text_bounds; + Point loc = owner.GetItemLocation (DisplayIndex); + result.X += loc.X; + result.Y += loc.Y; + return result; + } + } + + internal int DisplayIndex { + get { + // Special case for Details view + // and no columns (which means no Layout at all) + if (display_index == -1) + return owner.Items.IndexOf (this); + + return display_index; + } + set { + display_index = value; + } + } + + internal bool Hot { + get { + return Index == owner.HotItemIndex; + } + } + + internal Font HotFont { + get { + if (hot_font == null) + hot_font = new Font (Font, Font.Style | FontStyle.Underline); + + return hot_font; + } + } + + internal ListView Owner { + set { + if (owner == value) + return; + + owner = value; + } + } + + internal void SetGroup (ListViewGroup group) + { + this.group = group; + } + + internal void SetPosition (Point position) + { + this.position = position; + } + + // When focus changed, we need to invalidate area + // with previous layout and with the new one + void UpdateFocusedState () + { + if (owner != null) { + Invalidate (); + Layout (); + Invalidate (); + } + } + + internal void Invalidate () + { + if (owner == null || owner.item_control == null || owner.updating) + return; + + // Add some padding to bounds (focused extra space, selection) + Rectangle rect = Bounds; + rect.Inflate (1, 1); + owner.item_control.Invalidate (rect); + } + + internal void Layout () + { + if (owner == null) + return; + int item_ht; + Rectangle total; + Size text_size = owner.text_size; + + checkbox_rect = Rectangle.Empty; + if (owner.CheckBoxes) + checkbox_rect.Size = owner.CheckBoxSize; + switch (owner.View) { + case View.Details: + // LAMESPEC: MSDN says, "In all views except the details + // view of the ListView, this value specifies the same + // bounding rectangle as the Entire value." Actually, it + // returns same bounding rectangles for Item and Entire + // values in the case of Details view. + + int x_offset = 0; + if (owner.SmallImageList != null) + x_offset = indent_count * owner.SmallImageList.ImageSize.Width; + + // Handle reordered column + if (owner.Columns.Count > 0) + checkbox_rect.X = owner.Columns[0].Rect.X + x_offset; + + icon_rect = label_rect = Rectangle.Empty; + icon_rect.X = checkbox_rect.Right + 2; + item_ht = owner.ItemSize.Height; + + if (owner.SmallImageList != null) + icon_rect.Width = owner.SmallImageList.ImageSize.Width; + + label_rect.Height = icon_rect.Height = item_ht; + checkbox_rect.Y = item_ht - checkbox_rect.Height; + + label_rect.X = icon_rect.Width > 0 ? icon_rect.Right + 1 : icon_rect.Right; + + if (owner.Columns.Count > 0) + label_rect.Width = owner.Columns[0].Wd - label_rect.X + checkbox_rect.X; + else + label_rect.Width = text_size.Width; + + SizeF text_sz = TextRenderer.MeasureString (Text, Font); + text_bounds = label_rect; + text_bounds.Width = (int) text_sz.Width; + + item_rect = total = Rectangle.Union + (Rectangle.Union (checkbox_rect, icon_rect), label_rect); + bounds.Size = total.Size; + + item_rect.Width = 0; + bounds.Width = 0; + for (int i = 0; i < owner.Columns.Count; i++) { + item_rect.Width += owner.Columns [i].Wd; + bounds.Width += owner.Columns [i].Wd; + } + + // Bounds for sub items + int n = Math.Min (owner.Columns.Count, sub_items.Count); + for (int i = 0; i < n; i++) { + Rectangle col_rect = owner.Columns [i].Rect; + sub_items [i].SetBounds (col_rect.X, 0, col_rect.Width, item_ht); + } + break; + + case View.LargeIcon: + label_rect = icon_rect = Rectangle.Empty; + + SizeF sz = TextRenderer.MeasureString (Text, Font); + if ((int) sz.Width > text_size.Width) { + if (Focused && owner.InternalContainsFocus) { + int text_width = text_size.Width; + StringFormat format = new StringFormat (); + format.Alignment = StringAlignment.Center; + sz = TextRenderer.MeasureString (Text, Font, text_width, format); + text_size.Height = (int) sz.Height; + } else + text_size.Height = 2 * (int) sz.Height; + } + + if (owner.LargeImageList != null) { + icon_rect.Width = owner.LargeImageList.ImageSize.Width; + icon_rect.Height = owner.LargeImageList.ImageSize.Height; + } + + if (checkbox_rect.Height > icon_rect.Height) + icon_rect.Y = checkbox_rect.Height - icon_rect.Height; + else + checkbox_rect.Y = icon_rect.Height - checkbox_rect.Height; + + if (text_size.Width <= icon_rect.Width) { + icon_rect.X = checkbox_rect.Width + 1; + label_rect.X = icon_rect.X + (icon_rect.Width - text_size.Width) / 2; + label_rect.Y = icon_rect.Bottom + 2; + label_rect.Size = text_size; + } else { + int centerX = text_size.Width / 2; + icon_rect.X = checkbox_rect.Width + 1 + centerX - icon_rect.Width / 2; + label_rect.X = checkbox_rect.Width + 1; + label_rect.Y = icon_rect.Bottom + 2; + label_rect.Size = text_size; + } + + item_rect = Rectangle.Union (icon_rect, label_rect); + total = Rectangle.Union (item_rect, checkbox_rect); + bounds.Size = total.Size; + break; + + case View.List: + case View.SmallIcon: + label_rect = icon_rect = Rectangle.Empty; + icon_rect.X = checkbox_rect.Width + 1; + item_ht = Math.Max (owner.CheckBoxSize.Height, text_size.Height); + + if (owner.SmallImageList != null) { + item_ht = Math.Max (item_ht, owner.SmallImageList.ImageSize.Height); + icon_rect.Width = owner.SmallImageList.ImageSize.Width; + icon_rect.Height = owner.SmallImageList.ImageSize.Height; + } + + checkbox_rect.Y = item_ht - checkbox_rect.Height; + label_rect.X = icon_rect.Right + 1; + label_rect.Width = text_size.Width; + label_rect.Height = icon_rect.Height = item_ht; + + item_rect = Rectangle.Union (icon_rect, label_rect); + total = Rectangle.Union (item_rect, checkbox_rect); + bounds.Size = total.Size; + break; + case View.Tile: + if (!Application.VisualStylesEnabled) + goto case View.LargeIcon; + + label_rect = icon_rect = Rectangle.Empty; + + if (owner.LargeImageList != null) { + icon_rect.Width = owner.LargeImageList.ImageSize.Width; + icon_rect.Height = owner.LargeImageList.ImageSize.Height; + } + + int separation = 2; + SizeF tsize = TextRenderer.MeasureString (Text, Font); + int main_item_height = (int) Math.Ceiling (tsize.Height); + int main_item_width = (int) Math.Ceiling (tsize.Width); + sub_items [0].bounds.Height = main_item_height; + + // Set initial values for subitem's layout + int total_height = main_item_height; + int max_subitem_width = main_item_width; + + int count = Math.Min (owner.Columns.Count, sub_items.Count); + for (int i = 1; i < count; i++) { // Ignore first column and first subitem + ListViewSubItem sub_item = sub_items [i]; + if (sub_item.Text == null || sub_item.Text.Length == 0) + continue; + + tsize = TextRenderer.MeasureString (sub_item.Text, sub_item.Font); + + int width = (int)Math.Ceiling (tsize.Width); + if (width > max_subitem_width) + max_subitem_width = width; + + int height = (int)Math.Ceiling (tsize.Height); + total_height += height + separation; + + sub_item.bounds.Height = height; + } + + max_subitem_width = Math.Min (max_subitem_width, owner.TileSize.Width - (icon_rect.Width + 4)); + label_rect.X = icon_rect.Right + 4; + label_rect.Y = owner.TileSize.Height / 2 - total_height / 2; + label_rect.Width = max_subitem_width; + label_rect.Height = total_height; + + // Main item - always set bounds for it + sub_items [0].SetBounds (label_rect.X, label_rect.Y, max_subitem_width, sub_items [0].bounds.Height); + + // Second pass to assign bounds for every sub item + int current_y = sub_items [0].bounds.Bottom + separation; + for (int j = 1; j < count; j++) { + ListViewSubItem sub_item = sub_items [j]; + if (sub_item.Text == null || sub_item.Text.Length == 0) + continue; + + sub_item.SetBounds (label_rect.X, current_y, max_subitem_width, sub_item.bounds.Height); + current_y += sub_item.Bounds.Height + separation; + } + + item_rect = Rectangle.Union (icon_rect, label_rect); + bounds.Size = item_rect.Size; + break; + } + + } + #endregion // Private Internal Methods + + #region Subclasses + + [DefaultProperty ("Text")] + [DesignTimeVisible (false)] + [Serializable] + [ToolboxItem (false)] + [TypeConverter (typeof(ListViewSubItemConverter))] + public class ListViewSubItem + { + [NonSerialized] + internal ListViewItem owner; + private string text = string.Empty; + private string name; + private object userData; + private SubItemStyle style; + [NonSerialized] + internal Rectangle bounds; + + + #region UIA Framework: Methods, Properties and Events + + [field:NonSerialized] + internal event EventHandler UIATextChanged; + + private void OnUIATextChanged () + { + if (UIATextChanged != null) + UIATextChanged (this, EventArgs.Empty); + } + + #endregion // UIA Framework: Methods, Properties and Events + + + #region Public Constructors + public ListViewSubItem () + : this (null, string.Empty, Color.Empty, + Color.Empty, null) + { + } + + public ListViewSubItem (ListViewItem owner, string text) + : this (owner, text, Color.Empty, + Color.Empty, null) + { + } + + public ListViewSubItem (ListViewItem owner, string text, Color foreColor, + Color backColor, Font font) + { + this.owner = owner; + Text = text; + this.style = new SubItemStyle (foreColor, + backColor, font); + } + #endregion // Public Constructors + + #region Public Instance Properties + public Color BackColor { + get { + if (style.backColor != Color.Empty) + return style.backColor; + if (this.owner != null && this.owner.ListView != null) + return this.owner.ListView.BackColor; + return ThemeEngine.Current.ColorWindow; + } + set { + style.backColor = value; + Invalidate (); + } + } + + [Browsable (false)] + public Rectangle Bounds { + get { + Rectangle retval = bounds; + if (owner != null) { + retval.X += owner.Bounds.X; + retval.Y += owner.Bounds.Y; + } + + return retval; + } + } + + [Localizable (true)] + public Font Font { + get { + if (style.font != null) + return style.font; + else if (owner != null) + return owner.Font; + return ThemeEngine.Current.DefaultFont; + } + set { + if (style.font == value) + return; + style.font = value; + Invalidate (); + } + } + + public Color ForeColor { + get { + if (style.foreColor != Color.Empty) + return style.foreColor; + if (this.owner != null && this.owner.ListView != null) + return this.owner.ListView.ForeColor; + return ThemeEngine.Current.ColorWindowText; + } + set { + style.foreColor = value; + Invalidate (); + } + } + + [Localizable (true)] + public string Name { + get { + if (name == null) + return string.Empty; + return name; + } + set { + name = value; + } + } + + [TypeConverter (typeof (StringConverter))] + [BindableAttribute (true)] + [DefaultValue (null)] + [Localizable (false)] + public object Tag { + get { + return userData; + } + set { + userData = value; + } + } + + [Localizable (true)] + public string Text { + get { return text; } + set { + if(text == value) + return; + + if(value == null) + text = string.Empty; + else + text = value; + + Invalidate (); + + // UIA Framework: Generates SubItem TextChanged + OnUIATextChanged (); + } + } + #endregion // Public Instance Properties + + #region Public Methods + public void ResetStyle () + { + style.Reset (); + Invalidate (); + } + + public override string ToString () + { + return string.Format ("ListViewSubItem {{0}}", text); + } + #endregion // Public Methods + + #region Private Methods + private void Invalidate () + { + if (owner == null || owner.owner == null) + return; + + owner.Invalidate (); + } + + [OnDeserialized] + void OnDeserialized (StreamingContext context) + { + name = null; + userData = null; + } + + internal int Height { + get { + return bounds.Height; + } + } + + internal void SetBounds (int x, int y, int width, int height) + { + bounds = new Rectangle (x, y, width, height); + } + + #endregion // Private Methods + + [Serializable] + class SubItemStyle + { + public SubItemStyle () + { + } + + public SubItemStyle (Color foreColor, Color backColor, Font font) + { + this.foreColor = foreColor; + this.backColor = backColor; + this.font = font; + } + + public void Reset () + { + foreColor = Color.Empty; + backColor = Color.Empty; + font = null; + } + + public Color backColor; + public Color foreColor; + public Font font; + } + } + + public class ListViewSubItemCollection : IList, ICollection, IEnumerable + { + private ArrayList list; + internal ListViewItem owner; + + #region Public Constructors + public ListViewSubItemCollection (ListViewItem owner) : this (owner, owner.Text) + { + } + #endregion // Public Constructors + + internal ListViewSubItemCollection (ListViewItem owner, string text) + { + this.owner = owner; + this.list = new ArrayList (); + if (text != null) + Add (text); + } + #region Public Properties + [Browsable (false)] + public int Count { + get { return list.Count; } + } + + public bool IsReadOnly { + get { return false; } + } + + public ListViewSubItem this [int index] { + get { return (ListViewSubItem) list [index]; } + set { + value.owner = owner; + list [index] = value; + owner.Layout (); + owner.Invalidate (); + } + } + + public virtual ListViewSubItem this [string key] { + get { + int idx = IndexOfKey (key); + if (idx == -1) + return null; + + return (ListViewSubItem) list [idx]; + } + } + + bool ICollection.IsSynchronized { + get { return list.IsSynchronized; } + } + + object ICollection.SyncRoot { + get { return list.SyncRoot; } + } + + bool IList.IsFixedSize { + get { return list.IsFixedSize; } + } + + object IList.this [int index] { + get { return this [index]; } + set { + if (! (value is ListViewSubItem)) + throw new ArgumentException ("Not of type ListViewSubItem", "value"); + this [index] = (ListViewSubItem) value; + } + } + #endregion // Public Properties + + #region Public Methods + public ListViewSubItem Add (ListViewSubItem item) + { + AddSubItem (item); + owner.Layout (); + owner.Invalidate (); + return item; + } + + public ListViewSubItem Add (string text) + { + ListViewSubItem item = new ListViewSubItem (owner, text); + return Add (item); + } + + public ListViewSubItem Add (string text, Color foreColor, + Color backColor, Font font) + { + ListViewSubItem item = new ListViewSubItem (owner, text, + foreColor, backColor, font); + return Add (item); + } + + public void AddRange (ListViewSubItem [] items) + { + if (items == null) + throw new ArgumentNullException ("items"); + + foreach (ListViewSubItem item in items) { + if (item == null) + continue; + AddSubItem (item); + } + owner.Layout (); + owner.Invalidate (); + } + + public void AddRange (string [] items) + { + if (items == null) + throw new ArgumentNullException ("items"); + + foreach (string item in items) { + if (item == null) + continue; + AddSubItem (new ListViewSubItem (owner, item)); + } + owner.Layout (); + owner.Invalidate (); + } + + public void AddRange (string [] items, Color foreColor, + Color backColor, Font font) + { + if (items == null) + throw new ArgumentNullException ("items"); + + foreach (string item in items) { + if (item == null) + continue; + + AddSubItem (new ListViewSubItem (owner, item, foreColor, backColor, font)); + } + owner.Layout (); + owner.Invalidate (); + } + + void AddSubItem (ListViewSubItem subItem) + { + subItem.owner = owner; + list.Add (subItem); + + //UIA Framework + subItem.UIATextChanged += OnUIASubItemTextChanged; + } + + public void Clear () + { + list.Clear (); + } + + public bool Contains (ListViewSubItem subItem) + { + return list.Contains (subItem); + } + + public virtual bool ContainsKey (string key) + { + return IndexOfKey (key) != -1; + } + + public IEnumerator GetEnumerator () + { + return list.GetEnumerator (); + } + + void ICollection.CopyTo (Array dest, int index) + { + list.CopyTo (dest, index); + } + + int IList.Add (object item) + { + if (! (item is ListViewSubItem)) { + throw new ArgumentException ("Not of type ListViewSubItem", "item"); + } + + ListViewSubItem sub_item = (ListViewSubItem) item; + sub_item.owner = this.owner; + //UIA Framework + sub_item.UIATextChanged += OnUIASubItemTextChanged; + return list.Add (sub_item); + } + + bool IList.Contains (object subItem) + { + if (! (subItem is ListViewSubItem)) { + throw new ArgumentException ("Not of type ListViewSubItem", "subItem"); + } + + return this.Contains ((ListViewSubItem) subItem); + } + + int IList.IndexOf (object subItem) + { + if (! (subItem is ListViewSubItem)) { + throw new ArgumentException ("Not of type ListViewSubItem", "subItem"); + } + + return this.IndexOf ((ListViewSubItem) subItem); + } + + void IList.Insert (int index, object item) + { + if (! (item is ListViewSubItem)) { + throw new ArgumentException ("Not of type ListViewSubItem", "item"); + } + + this.Insert (index, (ListViewSubItem) item); + } + + void IList.Remove (object item) + { + if (! (item is ListViewSubItem)) { + throw new ArgumentException ("Not of type ListViewSubItem", "item"); + } + + this.Remove ((ListViewSubItem) item); + } + + public int IndexOf (ListViewSubItem subItem) + { + return list.IndexOf (subItem); + } + + public virtual int IndexOfKey (string key) + { + if (key == null || key.Length == 0) + return -1; + + for (int i = 0; i < list.Count; i++) { + ListViewSubItem l = (ListViewSubItem) list [i]; + if (String.Compare (l.Name, key, true) == 0) + return i; + } + + return -1; + } + + public void Insert (int index, ListViewSubItem item) + { + item.owner = this.owner; + list.Insert (index, item); + owner.Layout (); + owner.Invalidate (); + + //UIA Framework + item.UIATextChanged += OnUIASubItemTextChanged; + } + + public void Remove (ListViewSubItem item) + { + list.Remove (item); + owner.Layout (); + owner.Invalidate (); + + //UIA Framework + item.UIATextChanged -= OnUIASubItemTextChanged; + } + + public virtual void RemoveByKey (string key) + { + int idx = IndexOfKey (key); + if (idx != -1) + RemoveAt (idx); + } + + public void RemoveAt (int index) + { + //UIA Framework + if (index >= 0 && index < list.Count) + ((ListViewSubItem) list [index]).UIATextChanged -= OnUIASubItemTextChanged; + + list.RemoveAt (index); + + } + #endregion // Public Methods + #region UIA Event Handler + + private void OnUIASubItemTextChanged (object sender, EventArgs args) + { + owner.OnUIASubItemTextChanged (new LabelEditEventArgs (list.IndexOf (sender))); + } + + #endregion + + + } + #endregion // Subclasses + } +} |
