//######################################################################################### //★★★★★★★ 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.Drawing.Design; using XPTable.Events; using XPTable.Models.Design; namespace XPTable.Models { /// /// SRepresents a row of Cells displayed in a Table /// [DesignTimeVisible(true), TypeConverter(typeof(RowConverter))] public class Row : IDisposable { #region EventHandlers /// /// Occurs when a Cell is added to the Row /// public event RowEventHandler CellAdded; /// /// Occurs when a Cell is removed from the Row /// public event RowEventHandler CellRemoved; /// /// Occurs when the value of a Row's property changes /// public event RowEventHandler PropertyChanged; #endregion #region Class Data // Row state flags private static readonly int STATE_EDITABLE = 1; private static readonly int STATE_ENABLED = 2; /// /// The collection of Cells's contained in the Row /// private CellCollection cells; /// /// An object that contains data about the Row /// private object tag; /// /// The TableModel that the Row belongs to /// private TableModel tableModel; /// /// The index of the Row /// private int index; /// /// the current state of the Row /// private byte state; /// /// The Row's RowStyle /// private RowStyle rowStyle; /// /// The number of Cells in the Row that are selected /// private int selectedCellCount; /// /// Specifies whether the Row has been disposed /// private bool disposed = false; #endregion #region Constructor /// /// Initializes a new instance of the Row class with default settings /// public Row() { this.Init(); } /// /// Initializes a new instance of the Row class with an array of strings /// representing Cells /// /// An array of strings that represent the Cells of /// the Row public Row(string[] items) { if (items == null) { throw new ArgumentNullException("items", "string[] cannot be null"); } this.Init(); if (items.Length > 0) { Cell[] cells = new Cell[items.Length]; for (int i=0; i /// Initializes a new instance of the Row class with an array of Cell objects /// /// An array of Cell objects that represent the Cells of the Row public Row(Cell[] cells) { if (cells == null) { throw new ArgumentNullException("cells", "Cell[] cannot be null"); } this.Init(); if (cells.Length > 0) { this.Cells.AddRange(cells); } } /// /// Initializes a new instance of the Row class with an array of strings /// representing Cells and the foreground color, background color, and font /// of the Row /// /// An array of strings that represent the Cells of the Row /// The foreground Color of the Row /// The background Color of the Row /// The Font used to draw the text in the Row's Cells public Row(string[] items, Color foreColor, Color backColor, Font font) { if (items == null) { throw new ArgumentNullException("items", "string[] cannot be null"); } this.Init(); this.ForeColor = foreColor; this.BackColor = backColor; this.Font = font; if (items.Length > 0) { Cell[] cells = new Cell[items.Length]; for (int i=0; i /// Initializes a new instance of the Row class with an array of Cell objects and /// the foreground color, background color, and font of the Row /// /// An array of Cell objects that represent the Cells of the Row /// The foreground Color of the Row /// The background Color of the Row /// The Font used to draw the text in the Row's Cells public Row(Cell[] cells, Color foreColor, Color backColor, Font font) { if (cells == null) { throw new ArgumentNullException("cells", "Cell[] cannot be null"); } this.Init(); this.ForeColor = foreColor; this.BackColor = backColor; this.Font = font; if (cells.Length > 0) { this.Cells.AddRange(cells); } } /// /// Initialise default values /// private void Init() { this.cells = null; this.tag = null; this.tableModel = null; this.index = -1; this.rowStyle = null; this.selectedCellCount = 0; this.state = (byte) (STATE_EDITABLE | STATE_ENABLED); } #endregion #region Methods /// /// Releases all resources used by the Row /// public void Dispose() { if (!this.disposed) { this.tag = null; if (this.tableModel != null) { this.tableModel.Rows.Remove(this); } this.tableModel = null; this.index = -1; if (this.cells != null) { Cell cell; for (int i=0; i /// 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 /// /// A CellCollection representing the collection of /// Cells contained within the Row /// [Category("Behavior"), Description("Cell Collection"), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), Editor(typeof(CellCollectionEditor), typeof(UITypeEditor))] public CellCollection Cells { get { if (this.cells == null) { this.cells = new CellCollection(this); } return this.cells; } } /// /// Gets or sets the object that contains data about the Row /// [Category("Appearance"), DefaultValue(null), Description("User defined data associated with the row"), TypeConverter(typeof(StringConverter))] public object Tag { get { return this.tag; } set { this.tag = value; } } /// /// Gets or sets the RowStyle used by the Row /// [Browsable(false), DefaultValue(null)] public RowStyle RowStyle { get { return this.rowStyle; } set { if (this.rowStyle != value) { this.rowStyle = value; this.OnPropertyChanged(new RowEventArgs(this, RowEventType.StyleChanged)); } } } /// /// Gets or sets the background color for the Row /// [Browsable(true), Category("Appearance"), Description("The background color used to display text and graphics in the row")] public Color BackColor { get { if (this.RowStyle == null) { return Color.Transparent; } return this.RowStyle.BackColor; } set { if (this.RowStyle == null) { this.RowStyle = new RowStyle(); } if (this.RowStyle.BackColor != value) { this.RowStyle.BackColor = value; this.OnPropertyChanged(new RowEventArgs(this, RowEventType.BackColorChanged)); } } } /// /// Specifies whether the BackColor property should be serialized at /// design time /// /// true if the BackColor property should be serialized, /// false otherwise private bool ShouldSerializeBackColor() { return (this.rowStyle != null && this.rowStyle.BackColor != Color.Empty); } /// /// Gets or sets the foreground Color for the Row /// [Browsable(true), Category("Appearance"), Description("The foreground color used to display text and graphics in the row")] public Color ForeColor { get { if (this.RowStyle == null) { if (this.TableModel != null && this.TableModel.Table != null) { return this.TableModel.Table.ForeColor; } return Color.Black; } else { if (this.RowStyle.ForeColor == Color.Empty || this.RowStyle.ForeColor == Color.Transparent) { if (this.TableModel != null && this.TableModel.Table != null) { return this.TableModel.Table.ForeColor; } } return this.RowStyle.ForeColor; } } set { if (this.RowStyle == null) { this.RowStyle = new RowStyle(); } if (this.RowStyle.ForeColor != value) { this.RowStyle.ForeColor = value; this.OnPropertyChanged(new RowEventArgs(this, RowEventType.ForeColorChanged)); } } } /// /// Specifies whether the ForeColor property should be serialized at /// design time /// /// true if the ForeColor property should be serialized, /// false otherwise private bool ShouldSerializeForeColor() { return (this.rowStyle != null && this.rowStyle.ForeColor != Color.Empty); } /// /// Gets or sets the vertical alignment of the objects displayed in the Row /// [Browsable(true), Category("Appearance"), DefaultValue(RowAlignment.Center), Description("The vertical alignment of the objects displayed in the row")] public RowAlignment Alignment { get { if (this.RowStyle == null) { return RowAlignment.Center; } return this.RowStyle.Alignment; } set { if (!Enum.IsDefined(typeof(RowAlignment), value)) { throw new InvalidEnumArgumentException("value", (int) value, typeof(RowAlignment)); } if (this.RowStyle == null) { this.RowStyle = new RowStyle(); } if (this.RowStyle.Alignment != value) { this.RowStyle.Alignment = value; this.OnPropertyChanged(new RowEventArgs(this, RowEventType.AlignmentChanged)); } } } /// /// Gets or sets the Font used by the Row /// [Browsable(true), Category("Appearance"), Description("The font used to display text in the row")] public Font Font { get { if (this.RowStyle == null) { if (this.TableModel != null && this.TableModel.Table != null) { return this.TableModel.Table.Font; } return null; } else { if (this.RowStyle.Font == null) { if (this.TableModel != null && this.TableModel.Table != null) { return this.TableModel.Table.Font; } } return this.RowStyle.Font; } } set { if (this.RowStyle == null) { this.RowStyle = new RowStyle(); } if (this.RowStyle.Font != value) { this.RowStyle.Font = value; this.OnPropertyChanged(new RowEventArgs(this, RowEventType.FontChanged)); } } } /// /// Specifies whether the Font property should be serialized at /// design time /// /// true if the Font property should be serialized, /// false otherwise private bool ShouldSerializeFont() { return (this.rowStyle != null && this.rowStyle.Font != null); } /// /// Gets or sets a value indicating whether the Row's Cells are able /// to be edited /// [Browsable(true), Category("Appearance"), Description("Controls whether the row's cell contents are able to be changed by the user")] public bool Editable { get { if (!this.GetState(STATE_EDITABLE)) { return false; } return this.Enabled; } set { bool editable = this.Editable; this.SetState(STATE_EDITABLE, value); if (editable != value) { this.OnPropertyChanged(new RowEventArgs(this, RowEventType.EditableChanged)); } } } /// /// 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 Row's Cells can respond to /// user interaction /// [Browsable(true), Category("Appearance"), Description("Indicates whether the row's cells can respond to user interaction"), RefreshProperties(RefreshProperties.All)] public bool Enabled { get { if (!this.GetState(STATE_ENABLED)) { return false; } if (this.TableModel == null) { return true; } return this.TableModel.Enabled; } set { bool enabled = this.Enabled; this.SetState(STATE_ENABLED, value); if (enabled != value) { this.OnPropertyChanged(new RowEventArgs(this, RowEventType.EnabledChanged)); } } } /// /// 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 the TableModel the Row belongs to /// [Browsable(false)] public TableModel TableModel { get { return this.tableModel; } } /// /// Gets or sets the TableModel the Row belongs to /// internal TableModel InternalTableModel { get { return this.tableModel; } set { this.tableModel = value; } } /// /// Gets the index of the Row within its TableModel /// [Browsable(false)] public int Index { get { return this.index; } } /// /// Gets or sets the index of the Row within its TableModel /// internal int InternalIndex { get { return this.index; } set { this.index = value; } } /// /// Updates the Cell's Index property so that it matches the Cells /// position in the CellCollection /// /// The index to start updating from internal void UpdateCellIndicies(int start) { if (start == -1) { start = 0; } for (int i=start; i /// Gets whether the Row is able to raise events /// protected internal bool CanRaiseEvents { get { if (this.TableModel != null) { return this.TableModel.CanRaiseEvents; } return true; } } /// /// Gets the number of Cells that are selected within the Row /// [Browsable(false)] public int SelectedCellCount { get { return this.selectedCellCount; } } /// /// Gets or sets the number of Cells that are selected within the Row /// internal int InternalSelectedCellCount { get { return this.selectedCellCount; } set { this.selectedCellCount = value; } } /// /// Gets whether any Cells within the Row are selected /// [Browsable(false)] public bool AnyCellsSelected { get { return (this.selectedCellCount > 0); } } /// /// Returns whether the Cell at the specified index is selected /// /// The index of the Cell in the Row's Row.CellCollection /// True if the Cell at the specified index is selected, /// otherwise false public bool IsCellSelected(int index) { if (this.Cells.Count == 0) { return false; } if (index < 0 || index >= this.Cells.Count) { return false; } return this.Cells[index].Selected; } /// /// Removes the selected state from all the Cells within the Row /// internal void ClearSelection() { this.selectedCellCount = 0; for (int i=0; i /// Returns an array of Cells that contains all the selected Cells /// within the Row /// [Browsable(false)] public Cell[] SelectedItems { get { if (this.SelectedCellCount == 0 || this.Cells.Count == 0) { return new Cell[0]; } Cell[] items = new Cell[this.SelectedCellCount]; int count = 0; for (int i=0; i /// Returns an array that contains the indexes of all the selected Cells /// within the Row /// [Browsable(false)] public int[] SelectedIndicies { get { if (this.Cells.Count == 0) { return new int[0]; } int[] indicies = new int[this.SelectedCellCount]; int count = 0; for (int i=0; i /// Raises the PropertyChanged event /// /// A RowEventArgs that contains the event data protected virtual void OnPropertyChanged(RowEventArgs e) { e.SetRowIndex(this.Index); if (this.CanRaiseEvents) { if (this.TableModel != null) { this.TableModel.OnRowPropertyChanged(e); } if (PropertyChanged != null) { PropertyChanged(this, e); } } } /// /// Raises the CellAdded event /// /// A RowEventArgs that contains the event data protected internal virtual void OnCellAdded(RowEventArgs e) { e.SetRowIndex(this.Index); e.Cell.InternalRow = this; e.Cell.InternalIndex = e.CellFromIndex; e.Cell.SetSelected(false); this.UpdateCellIndicies(e.CellFromIndex); if (this.CanRaiseEvents) { if (this.TableModel != null) { this.TableModel.OnCellAdded(e); } if (CellAdded != null) { CellAdded(this, e); } } } /// /// Raises the CellRemoved event /// /// A RowEventArgs that contains the event data protected internal virtual void OnCellRemoved(RowEventArgs e) { e.SetRowIndex(this.Index); if (e.Cell != null) { if (e.Cell.Row == this) { e.Cell.InternalRow = null; e.Cell.InternalIndex = -1; if (e.Cell.Selected) { e.Cell.SetSelected(false); this.InternalSelectedCellCount--; if (this.SelectedCellCount == 0 && this.TableModel != null) { this.TableModel.Selections.RemoveRow(this); } } } } else { if (e.CellFromIndex == -1 && e.CellToIndex == -1) { if (this.SelectedCellCount != 0 && this.TableModel != null) { this.InternalSelectedCellCount = 0; this.TableModel.Selections.RemoveRow(this); } } } this.UpdateCellIndicies(e.CellFromIndex); if (this.CanRaiseEvents) { if (this.TableModel != null) { this.TableModel.OnCellRemoved(e); } if (CellRemoved != null) { CellRemoved(this, e); } } } /// /// Raises the CellPropertyChanged event /// /// A CellEventArgs that contains the event data internal void OnCellPropertyChanged(CellEventArgs e) { if (this.TableModel != null) { this.TableModel.OnCellPropertyChanged(e); } } #endregion } }