//######################################################################################### //★★★★★★★ http://www.cnpopsoft.com [华普软件] ★★★★★★★ //★★★★★★★ 华普软件 - VB & C#.NET 专业论文与源码荟萃! ★★★★★★★ //######################################################################################### /* * Copyright ?2005, Mathew Hall * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. */ using System; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; using XPTable.Editors; using XPTable.Events; using XPTable.Renderers; namespace XPTable.Models { /// /// Summary description for Column. /// [DesignTimeVisible(false), ToolboxItem(false)] public abstract class Column : Component { #region Event Handlers /// /// Occurs when one of the Column's properties changes /// public event ColumnEventHandler PropertyChanged; #endregion #region Class Data // Column state flags private readonly static int STATE_EDITABLE = 1; private readonly static int STATE_ENABLED = 2; private readonly static int STATE_VISIBLE = 4; private readonly static int STATE_SELECTABLE = 8; private readonly static int STATE_SORTABLE = 16; /// /// The amount of space on each side of the Column that can /// be used as a resizing handle /// public static readonly int ResizePadding = 8; /// /// The default width of a Column /// public static readonly int DefaultWidth = 75; /// /// The maximum width of a Column /// public static readonly int MaximumWidth = 1024; /// /// The minimum width of a Column /// public static readonly int MinimumWidth = ResizePadding * 2; /// /// Contains the current state of the the Column /// public byte state; /// /// The text displayed in the Column's header /// private string text; /// /// A string that specifies how a Column's Cell contents are formatted /// private string format; /// /// The alignment of the text displayed in the Column's Cells /// private ColumnAlignment alignment; /// /// The width of the Column /// private int width; /// /// The Image displayed on the Column's header /// private Image image; /// /// Specifies whether the Image displayed on the Column's header should /// be draw on the right hand side of the Column /// private bool imageOnRight; /// /// The current state of the Column /// private ColumnState columnState; /// /// The text displayed when a ToolTip is shown for the Column's header /// private string tooltipText; /// /// The ColumnModel that the Column belongs to /// private ColumnModel columnModel; /// /// The x-coordinate of the column's left edge in pixels /// private int x; /// /// The current SortOrder of the Column /// private SortOrder sortOrder; /// /// The CellRenderer used to draw the Column's Cells /// private ICellRenderer renderer; /// /// The CellEditor used to edit the Column's Cells /// private ICellEditor editor; /// /// The Type of the IComparer used to compare the Column's Cells /// private Type comparer; #endregion #region Constructor /// /// Creates a new Column with default values /// public Column() : base() { this.Init(); } /// /// Creates a new Column with the specified header text /// /// The text displayed in the column's header public Column(string text) : base() { this.Init(); this.text = text; } /// /// Creates a new Column with the specified header text and width /// /// The text displayed in the column's header /// The column's width public Column(string text, int width) : base() { this.Init(); this.text = text; this.width = width; } /// /// Creates a new Column with the specified header text, width and visibility /// /// The text displayed in the column's header /// The column's width /// Specifies whether the column is visible public Column(string text, int width, bool visible) : base() { this.Init(); this.text = text; this.width = width; this.Visible = visible; } /// /// Creates a new Column with the specified header text and image /// /// The text displayed in the column's header /// The image displayed on the column's header public Column(string text, Image image) : base() { this.Init(); this.text = text; this.image = image; } /// /// Creates a new Column with the specified header text, image and width /// /// The text displayed in the column's header /// The image displayed on the column's header /// The column's width public Column(string text, Image image, int width) : base() { this.Init(); this.text = text; this.image = image; this.width = width; } /// /// Creates a new Column with the specified header text, image, width and visibility /// /// The text displayed in the column's header /// The image displayed on the column's header /// The column's width /// Specifies whether the column is visible public Column(string text, Image image, int width, bool visible) : base() { this.Init(); this.text = text; this.image = image; this.width = width; this.Visible = visible; } /// /// Initialise default values /// private void Init() { this.text = null; this.width = Column.DefaultWidth; this.columnState = ColumnState.Normal; this.alignment = ColumnAlignment.Left; this.image = null; this.imageOnRight = false; this.columnModel = null; this.x = 0; this.tooltipText = null; this.format = ""; this.sortOrder = SortOrder.None; this.renderer = null; this.editor = null; this.comparer = null; this.state = (byte) (STATE_ENABLED | STATE_EDITABLE | STATE_VISIBLE | STATE_SELECTABLE | STATE_SORTABLE); } #endregion #region Methods /// /// Gets a string that specifies the name of the Column's default CellRenderer /// /// A string that specifies the name of the Column's default /// CellRenderer public abstract string GetDefaultRendererName(); /// /// Gets the Column's default CellRenderer /// /// The Column's default CellRenderer public abstract ICellRenderer CreateDefaultRenderer(); /// /// Gets a string that specifies the name of the Column's default CellEditor /// /// A string that specifies the name of the Column's default /// CellEditor public abstract string GetDefaultEditorName(); /// /// Gets the Column's default CellEditor /// /// The Column's default CellEditor public abstract ICellEditor CreateDefaultEditor(); /// /// Returns the state represented by the specified state flag /// /// A flag that represents the state to return /// The state represented by the specified state flag internal bool GetState(int flag) { return ((this.state & flag) != 0); } /// /// Sets the state represented by the specified state flag to the specified value /// /// A flag that represents the state to be set /// The new value of the state internal void SetState(int flag, bool value) { this.state = (byte) (value ? (this.state | flag) : (this.state & ~flag)); } #endregion #region Properties /// /// Gets or sets the text displayed on the Column header /// [Category("Appearance"), DefaultValue(null), Description("The text displayed in the column's header.")] public string Text { get { return this.text; } set { if (value == null) { value = ""; } if (!value.Equals(this.text)) { string oldText = this.text; this.text = value; this.OnPropertyChanged(new ColumnEventArgs(this, ColumnEventType.TextChanged, oldText)); } } } /// /// Gets or sets the string that specifies how a Column's Cell contents /// are formatted /// [Category("Appearance"), DefaultValue(""), Description("A string that specifies how a column's cell contents are formatted.")] public string Format { get { return this.format; } set { if (value == null) { value = ""; } if (!value.Equals(this.format)) { string oldFormat = this.format; this.format = value; this.OnPropertyChanged(new ColumnEventArgs(this, ColumnEventType.FormatChanged, oldFormat)); } } } /// /// Gets or sets the horizontal alignment of the Column's Cell contents /// [Category("Appearance"), DefaultValue(ColumnAlignment.Left), Description("The horizontal alignment of the column's cell contents.")] public virtual ColumnAlignment Alignment { get { return this.alignment; } set { if (!Enum.IsDefined(typeof(ColumnAlignment), value)) { throw new InvalidEnumArgumentException("value", (int) value, typeof(ColumnAlignment)); } if (this.alignment != value) { ColumnAlignment oldAlignment = this.alignment; this.alignment = value; this.OnPropertyChanged(new ColumnEventArgs(this, ColumnEventType.AlignmentChanged, oldAlignment)); } } } /// /// Gets or sets the width of the Column /// [Category("Appearance"), Description("The width of the column.")] public int Width { get { return this.width; } set { if (this.width != value) { int oldWidth = this.Width; // Set the width, and check min & max this.width = Math.Min(Math.Max(value, MinimumWidth), MaximumWidth); this.OnPropertyChanged(new ColumnEventArgs(this, ColumnEventType.WidthChanged, oldWidth)); } } } /// /// Specifies whether the Width property should be serialized at /// design time /// /// true if the Width property should be serialized, /// false otherwise private bool ShouldSerializeWidth() { return this.Width != Column.DefaultWidth; } /// /// Gets or sets the Image displayed in the Column's header /// [Category("Appearance"), DefaultValue(null), Description("Ihe image displayed in the column's header")] public Image Image { get { return this.image; } set { if (this.image != value) { Image oldImage = this.Image; this.image = value; this.OnPropertyChanged(new ColumnEventArgs(this, ColumnEventType.ImageChanged, oldImage)); } } } /// /// Gets or sets whether the Image displayed on the Column's header should /// be draw on the right hand side of the Column /// [Category("Appearance"), DefaultValue(false), Description("Specifies whether the image displayed on the column's header should be drawn on the right hand side of the column")] public bool ImageOnRight { get { return this.imageOnRight; } set { if (this.imageOnRight != value) { this.imageOnRight = value; this.OnPropertyChanged(new ColumnEventArgs(this, ColumnEventType.ImageChanged, null)); } } } /// /// Gets the state of the Column /// [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public ColumnState ColumnState { get { return this.columnState; } } /// /// Gets or sets the state of the Column /// internal ColumnState InternalColumnState { get { return this.ColumnState; } set { if (!Enum.IsDefined(typeof(ColumnState), value)) { throw new InvalidEnumArgumentException("value", (int) value, typeof(ColumnState)); } if (this.columnState != value) { ColumnState oldState = this.columnState; this.columnState = value; this.OnPropertyChanged(new ColumnEventArgs(this, ColumnEventType.StateChanged, oldState)); } } } /// /// Gets or sets the whether the Column is displayed /// [Category("Appearance"), DefaultValue(true), Description("Determines whether the column is visible or hidden.")] public bool Visible { get { return this.GetState(STATE_VISIBLE); } set { bool visible = this.Visible; this.SetState(STATE_VISIBLE, value); if (visible != value) { this.OnPropertyChanged(new ColumnEventArgs(this, ColumnEventType.VisibleChanged, visible)); } } } /// /// Gets or sets whether the Column is able to be sorted /// [Category("Appearance"), DefaultValue(true), Description("Determines whether the column is able to be sorted.")] public virtual bool Sortable { get { return this.GetState(STATE_SORTABLE); } set { bool sortable = this.Sortable; this.SetState(STATE_SORTABLE, value); if (sortable != value) { this.OnPropertyChanged(new ColumnEventArgs(this, ColumnEventType.SortableChanged, sortable)); } } } /// /// Gets or sets the user specified ICellRenderer that is used to draw the /// Column's Cells /// [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public ICellRenderer Renderer { get { return this.renderer; } set { if (this.renderer != value) { this.renderer = value; this.OnPropertyChanged(new ColumnEventArgs(this, ColumnEventType.RendererChanged, null)); } } } /// /// Gets or sets the user specified ICellEditor that is used to edit the /// Column's Cells /// [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public ICellEditor Editor { get { return this.editor; } set { if (this.editor != value) { this.editor = value; this.OnPropertyChanged(new ColumnEventArgs(this, ColumnEventType.EditorChanged, null)); } } } /// /// Gets or sets the user specified Comparer type that is used to edit the /// Column's Cells /// [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public Type Comparer { get { return this.comparer; } set { if (this.comparer != value) { this.comparer = value; this.OnPropertyChanged(new ColumnEventArgs(this, ColumnEventType.ComparerChanged, null)); } } } /// /// Gets the Type of the default Comparer used to compare the Column's Cells when /// the Column is sorting /// [Browsable(false)] public abstract Type DefaultComparerType { get; } /// /// Gets the current SortOrder of the Column /// [Browsable(false)] public SortOrder SortOrder { get { return this.sortOrder; } } /// /// Gets or sets the current SortOrder of the Column /// internal SortOrder InternalSortOrder { get { return this.SortOrder; } set { if (!Enum.IsDefined(typeof(SortOrder), value)) { throw new InvalidEnumArgumentException("value", (int) value, typeof(SortOrder)); } if (this.sortOrder != value) { SortOrder oldOrder = this.sortOrder; this.sortOrder = value; this.OnPropertyChanged(new ColumnEventArgs(this, ColumnEventType.SortOrderChanged, oldOrder)); } } } /// /// Gets or sets a value indicating whether the Column's Cells contents /// are able to be edited /// [Category("Appearance"), Description("Controls whether the column's cell contents are able to be changed by the user")] public virtual bool Editable { get { if (!this.GetState(STATE_EDITABLE)) { return false; } return this.Visible && this.Enabled; } set { bool editable = this.GetState(STATE_EDITABLE); this.SetState(STATE_EDITABLE, value); if (editable != value) { this.OnPropertyChanged(new ColumnEventArgs(this, ColumnEventType.EditableChanged, editable)); } } } /// /// Specifies whether the Editable property should be serialized at /// design time /// /// true if the Editable property should be serialized, /// false otherwise private bool ShouldSerializeEditable() { return !this.GetState(STATE_EDITABLE); } /// /// Gets or sets a value indicating whether the Column's Cells can respond to /// user interaction /// [Category("Appearance"), Description("Indicates whether the column's cells can respond to user interaction")] public bool Enabled { get { if (!this.GetState(STATE_ENABLED)) { return false; } if (this.ColumnModel == null) { return true; } return this.ColumnModel.Enabled; } set { bool enabled = this.GetState(STATE_ENABLED); this.SetState(STATE_ENABLED, value); if (enabled != value) { this.OnPropertyChanged(new ColumnEventArgs(this, ColumnEventType.EnabledChanged, enabled)); } } } /// /// Specifies whether the Enabled property should be serialized at /// design time /// /// true if the Enabled property should be serialized, /// false otherwise private bool ShouldSerializeEnabled() { return !this.GetState(STATE_ENABLED); } /// /// Gets or sets a value indicating whether the Column's Cells can be selected /// [Category("Appearance"), DefaultValue(true), Description("Indicates whether the column's cells can be selected")] public virtual bool Selectable { get { return this.GetState(STATE_SELECTABLE); } set { bool selectable = this.Selectable; this.SetState(STATE_SELECTABLE, value); if (selectable != value) { this.OnPropertyChanged(new ColumnEventArgs(this, ColumnEventType.SelectableChanged, selectable)); } } } /// /// Gets or sets the ToolTip text associated with the Column /// [Category("Appearance"), DefaultValue(null), Description("The ToolTip text associated with the Column")] public string ToolTipText { get { return this.tooltipText; } set { if (value == null) { value = ""; } if (!value.Equals(this.tooltipText)) { string oldTip = this.tooltipText; this.tooltipText = value; this.OnPropertyChanged(new ColumnEventArgs(this, ColumnEventType.ToolTipTextChanged, oldTip)); } } } /// /// Gets the x-coordinate of the column's left edge in pixels /// internal int X { get { return this.x; } set { this.x = value; } } /// /// Gets the x-coordinate of the column's left edge in pixels /// [Browsable(false)] public int Left { get { return this.X; } } /// /// Gets the x-coordinate of the column's right edge in pixels /// [Browsable(false)] public int Right { get { return this.Left + this.Width; } } /// /// Gets or sets the ColumnModel the Column belongs to /// protected internal ColumnModel ColumnModel { get { return this.columnModel; } set { this.columnModel = value; } } /// /// Gets the ColumnModel the Column belongs to. This member is not /// intended to be used directly from your code /// [Browsable(false)] public ColumnModel Parent { get { return this.ColumnModel; } } /// /// Gets whether the Column is able to raise events /// protected bool CanRaiseEvents { get { // check if the ColumnModel that the Colum belongs to is able to // raise events (if it can't, the Colum shouldn't raise events either) if (this.ColumnModel != null) { return this.ColumnModel.CanRaiseEvents; } return true; } } #endregion #region Events /// /// Raises the PropertyChanged event /// /// A ColumnEventArgs that contains the event data protected virtual void OnPropertyChanged(ColumnEventArgs e) { if (this.ColumnModel != null) { e.SetIndex(this.ColumnModel.Columns.IndexOf(this)); } if (this.CanRaiseEvents) { if (this.ColumnModel != null) { this.ColumnModel.OnColumnPropertyChanged(e); } if (PropertyChanged != null) { PropertyChanged(this, e); } } } #endregion } }