aboutsummaryrefslogtreecommitdiff
path: root/source/ShiftUI/Widgets/ListViewItem.cs
diff options
context:
space:
mode:
authorMichaelTheShifter <[email protected]>2016-07-20 09:40:36 -0400
committerMichaelTheShifter <[email protected]>2016-07-20 09:40:36 -0400
commitd40fed5ce2bc806a91245adb18039634eac13ed0 (patch)
treef1d7168aee6db109ac2c738ad18c9db667a6ba69 /source/ShiftUI/Widgets/ListViewItem.cs
parentf1856e8ed30ed882229fd3fa2a4038122a5fb441 (diff)
downloadshiftos-c--d40fed5ce2bc806a91245adb18039634eac13ed0.tar.gz
shiftos-c--d40fed5ce2bc806a91245adb18039634eac13ed0.tar.bz2
shiftos-c--d40fed5ce2bc806a91245adb18039634eac13ed0.zip
Move ShiftUI source code to ShiftOS
This'll be a lot easier to work on.
Diffstat (limited to 'source/ShiftUI/Widgets/ListViewItem.cs')
-rw-r--r--source/ShiftUI/Widgets/ListViewItem.cs1638
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
+ }
+}