859 lines
21 KiB
C#

using System;
using System.Drawing;
using DevComponents.DotNetBar.SuperGrid.Style;
namespace DevComponents.DotNetBar.SuperGrid
{
///<summary>
/// Defines a merged cell range, comprised
/// of a starting and ending row,column index pair.
///</summary>
public class CellRange : DisplayRange
{
#region Private variables
private Cs _States;
private CellRangeData _CellRangeData;
private object _Tag;
private string _ToolTip;
private ushort _StyleUpdateCount;
#endregion
#region Constructors
///<summary>
/// Defines a merged cell range, comprised
/// of a starting and ending row,column index pair.
///</summary>
public CellRange()
{
AllowSuspend = true;
AllowSelection = true;
}
///<summary>
/// Defines a merged cell range, comprised
/// of a starting and ending row,column index pair.
///</summary>
///<param name="rowIndex">Initial start and end row index</param>
///<param name="columnIndex">Initial start and end column index</param>
public CellRange(int rowIndex, int columnIndex)
: this()
{
RowStart = rowIndex;
ColumnStart = columnIndex;
RowCount = 1;
ColumnCount = 1;
}
///<summary>
/// Defines a merged cell range, comprised
/// of a starting and ending row,column index pair.
///</summary>
///<param name="startRowIndex">Starting row index</param>
///<param name="startColumnIndex">Starting column index</param>
///<param name="rowCount">Row count</param>
///<param name="columnCount">Column count</param>
public CellRange(int startRowIndex, int startColumnIndex, int rowCount, int columnCount)
: this()
{
RowStart = startRowIndex;
ColumnStart = startColumnIndex;
RowCount = rowCount;
ColumnCount = columnCount;
}
#endregion
#region Public properties
#region AllowSelection
///<summary>
/// Gets or sets whether the range can be selected
///</summary>
public bool AllowSelection
{
get { return (TestState(Cs.AllowSelection)); }
set { SetState(Cs.AllowSelection, value); }
}
#endregion
#region AllowSuspend
///<summary>
/// Gets or sets whether the merged cell range can be temporarily
/// suspended when either the user double clicks the displayed range
/// or the application initiates a cell.SuspendMerge().
///</summary>
public bool AllowSuspend
{
get { return (TestState(Cs.AllowSuspend)); }
set { SetState(Cs.AllowSuspend, value); }
}
#endregion
#region AlwaysDisplayFormattedValue
///<summary>
/// Gets or sets whether the 'FormattedValue' value will be
/// displayed for all cell types when merged, or only for Modal Cells.
///</summary>
public bool AlwaysDisplayFormattedValue
{
get { return (TestState(Cs.AlwaysDisplayFormattedValue)); }
set { SetState(Cs.AlwaysDisplayFormattedValue, value); }
}
#endregion
#region BackBounds
///<summary>
/// Gets the range display bounds
///</summary>
public Rectangle BackBounds
{
get { return (RangeData.BackBounds); }
internal set { RangeData.BackBounds = value; }
}
#endregion
#region CellStyles
/// <summary>
/// Gets or sets the visual styles assigned to the cell
/// </summary>
public CellVisualStyles CellStyles
{
get
{
if (RangeData.CellStyles == null)
RangeData.CellStyles = new CellVisualStyles();
return (RangeData.CellStyles);
}
set { RangeData.CellStyles = value; }
}
#endregion
#region FormattedValue
///<summary>
/// Gets or sets the formatted value for the range display. This value will
/// be displayed by default for all Modal Cells - all other cells will
/// have their default cell rendering displayed when merged
/// (unless 'AlwaysDisplayFormattedValue' is set to true).
///</summary>
public string FormattedValue
{
get { return (RangeData.FormattedValue); }
set { RangeData.FormattedValue = value; }
}
#endregion
#region Tag
///<summary>
/// Gets or sets user-defined data associated with the object
///</summary>
public object Tag
{
get { return (_Tag); }
set { _Tag = value; }
}
#endregion
#region ToolTip
///<summary>
/// Gets or sets the ToolTip text for the cell range.
///</summary>
public string ToolTip
{
get { return (_ToolTip); }
set { _ToolTip = value; }
}
#endregion
#endregion
#region Internal properties
#region Modified
internal bool Modified
{
get { return (TestState(Cs.Modified)); }
set { SetState(Cs.Modified, value); }
}
#endregion
#region RenderCount
internal int RenderCount
{
get { return (RangeData.RenderCount); }
set { RangeData.RenderCount = value; }
}
#endregion
#region SelectionUpdateCount
internal int SelectionUpdateCount
{
get { return (RangeData.SelectionUpdateCount); }
set { RangeData.SelectionUpdateCount = value; }
}
#endregion
#region Suspended
internal bool Suspended
{
get { return (TestState(Cs.Suspended)); }
set { SetState(Cs.Suspended, value); }
}
#endregion
#endregion
#region Private properties
#region EffectiveStyles
/// <summary>
/// Gets or sets the 'effective' visual styles assigned to the range
/// </summary>
private CellVisualStyles EffectiveStyles
{
get { return (RangeData.EffectiveStyles); }
set { RangeData.EffectiveStyles = value; }
}
#endregion
#region RangeData
private CellRangeData RangeData
{
get
{
if (_CellRangeData == null)
_CellRangeData = new CellRangeData();
return (_CellRangeData);
}
}
#endregion
#endregion
#region TestState
private bool TestState(Cs state)
{
return ((_States & state) == state);
}
#endregion
#region SetState
private void SetState(Cs state, bool value)
{
if (value == true)
_States |= state;
else
_States &= ~state;
}
#endregion
#region GetEffectiveStyle
internal CellVisualStyle GetEffectiveStyle(GridContainer cont, StyleState cellState)
{
switch (cellState)
{
case StyleState.MouseOver:
return (GetStyle(cont, StyleType.MouseOver));
case StyleState.Selected:
return (GetStyle(cont, StyleType.Selected));
case StyleState.Selected | StyleState.MouseOver:
return (GetStyle(cont, StyleType.SelectedMouseOver));
case StyleState.ReadOnly:
return (GetStyle(cont, StyleType.ReadOnly));
case StyleState.ReadOnly | StyleState.MouseOver:
return (GetStyle(cont, StyleType.ReadOnlyMouseOver));
case StyleState.ReadOnly | StyleState.Selected:
return (GetStyle(cont, StyleType.ReadOnlySelected));
case StyleState.ReadOnly | StyleState.MouseOver | StyleState.Selected:
return (GetStyle(cont, StyleType.ReadOnlySelectedMouseOver));
default:
return (GetStyle(cont, StyleType.Default));
}
}
#region GetStyle
private CellVisualStyle GetStyle(GridContainer cont, StyleType e)
{
GridPanel panel = cont.GridPanel;
ValidateStyle(panel);
CellVisualStyles cvs = EffectiveStyles ?? new CellVisualStyles();
if (cvs.IsValid(e) == false)
{
CellVisualStyle style = new CellVisualStyle();
StyleType[] css = style.GetApplyStyleTypes(e);
if (css != null)
{
int cindex = panel.Columns.DisplayIndexMap[ColumnStart];
GridRow row = null;
GridColumn column = panel.Columns.ColumnAtDisplayIndex(ColumnStart);
if (RowCount == 1)
{
GridCell cell = cont.GetCell(RowStart, cindex);
if (cell != null)
row = cell.GridRow;
}
foreach (StyleType cs in css)
{
if (column != null)
column.ApplyCellStyle(style, cs);
if (row != null)
row.ApplyCellStyle(style, cs);
panel.ApplyMergedCellStyle(style, cs);
if (RangeData.CellStyles != null)
style.ApplyStyle(RangeData.CellStyles[cs]);
}
}
panel.SuperGrid.DoGetMergedCellStyleEvent(panel, this, e, ref style);
if (style.Background == null || style.Background.IsEmpty == true)
style.Background = new Background(Color.White);
if (style.Font == null)
style.Font = SystemFonts.DefaultFont;
cvs[e] = style;
}
EffectiveStyles = cvs;
return (EffectiveStyles[e]);
}
#endregion
#region ValidateStyle
private void ValidateStyle(GridPanel panel)
{
if (_StyleUpdateCount != panel.SuperGrid.StyleUpdateCount)
ClearEffectiveStyles();
_StyleUpdateCount = panel.SuperGrid.StyleUpdateCount;
}
#endregion
#region InvalidateStyle
///<summary>
///Invalidates the cached Style
///definition for all defined StyleTypes
///</summary>
public void InvalidateStyle()
{
ClearEffectiveStyles();
}
///<summary>
///Invalidate the cached Style
///definition for the given StyleType
///</summary>
///<param name="type"></param>
public void InvalidateStyle(StyleType type)
{
if (EffectiveStyles != null)
EffectiveStyles[type] = null;
}
#endregion
#region ClearEffectiveStyles
internal void ClearEffectiveStyles()
{
if (EffectiveStyles != null)
{
EffectiveStyles.Dispose();
EffectiveStyles = null;
}
}
#endregion
#endregion
#region IsSelected
internal bool IsSelected(GridPanel panel, GridContainer cont)
{
if (AllowSelection == true)
{
if (panel.AllowSelection == true)
{
if (RangeData.SelectionUpdateCount != panel.SelectionUpdateCount)
{
RangeData.SelectionUpdateCount = panel.SelectionUpdateCount;
SetState(Cs.Selected, IsMergeSelected(panel, cont));
}
return (TestState(Cs.Selected));
}
}
return (false);
}
#region IsMergeSelected
private bool IsMergeSelected(GridPanel panel, GridContainer cont)
{
int rowCount = GetRowCount(panel, cont);
if (RowIsSelected(panel, cont, rowCount))
return (true);
if (ColumnIsSelected(panel))
return (true);
return (CellIsSelected(panel, cont, rowCount));
}
#region RowIsSelected
private bool RowIsSelected(GridPanel panel, GridContainer cont, int rowCount)
{
for (int i = RowStart; i < RowEnd; i++)
{
if (i < rowCount)
{
GridContainer row = GetRow(panel, cont, i);
if (row != null)
{
if (row.IsSelected == true)
return (true);
}
}
}
return (false);
}
#endregion
#region ColumnIsSelected
private bool ColumnIsSelected(GridPanel panel)
{
int[] map = panel.Columns.DisplayIndexMap;
for (int i = ColumnStart; i < ColumnEnd; i++)
{
if (i < panel.Columns.Count)
{
if (panel.Columns[map[i]].IsSelected == true)
return (true);
}
}
return (false);
}
#endregion
#region CellIsSelected
private bool CellIsSelected(GridPanel panel, GridContainer cont, int rowCount)
{
int[] map = panel.Columns.DisplayIndexMap;
for (int i = RowStart; i < RowEnd; i++)
{
if (i < rowCount)
{
GridRow row = GetRow(panel, cont, i) as GridRow;
if (row != null)
{
for (int j = ColumnStart; j < ColumnEnd; j++)
{
if (j < panel.Columns.Count)
{
GridCell cell = row.GetCell(map[j]);
if (cell != null)
{
if (panel.IsItemSelectedEx(cell) == true)
return (true);
}
}
}
}
}
}
return (false);
}
#endregion
#region GetRowCount
private int GetRowCount(GridPanel panel, GridContainer cont)
{
if (panel.VirtualMode == true)
return (panel.VirtualRowCount);
return (cont.Rows.Count);
}
#endregion
#region GetRow
private GridContainer GetRow(GridPanel panel, GridContainer cont, int index)
{
return (panel.VirtualMode == true)
? panel.VirtualRows[index]
: cont.Rows[index] as GridContainer;
}
#endregion
#endregion
#endregion
#region CellStates
[Flags]
private enum Cs
{
AllowSelection = (1 << 0),
AllowSuspend = (1 << 1),
AlwaysDisplayFormattedValue = (1 << 2),
Modified = (1 << 3),
Selected = (1 << 4),
Suspended = (1 << 5),
}
#endregion
#region CellRangeData
private class CellRangeData
{
#region Private data
private int _RenderCount;
private int _SelectionUpdateCount;
private Rectangle _BackBounds;
private string _FormattedValue;
private CellVisualStyles _CellStyles;
private CellVisualStyles _EffectiveStyles;
#endregion
#region public properties
#region BackBounds
public Rectangle BackBounds
{
get { return (_BackBounds); }
set { _BackBounds = value; }
}
#endregion
#region CellStyles
public CellVisualStyles CellStyles
{
get { return (_CellStyles); }
set { _CellStyles = value; }
}
#endregion
#region EffectiveStyles
public CellVisualStyles EffectiveStyles
{
get { return (_EffectiveStyles); }
set { _EffectiveStyles = value; }
}
#endregion
#region FormattedValue
public string FormattedValue
{
get { return (_FormattedValue); }
set { _FormattedValue = value; }
}
#endregion
#region RenderCount
public int RenderCount
{
get { return (_RenderCount); }
set { _RenderCount = value; }
}
#endregion
#region SelectionUpdateCount
public int SelectionUpdateCount
{
get { return (_SelectionUpdateCount); }
set { _SelectionUpdateCount = value; }
}
#endregion
#endregion
}
#endregion
}
#region DisplayRange
///<summary>
///Row/Column display index range
///</summary>
public class DisplayRange
{
#region Private variables
private int _RowStart;
private int _RowCount;
private int _ColumnStart;
private int _ColumnCount;
#endregion
#region Public properties
#region ColumnCount
///<summary>
///Number of columns
///</summary>
public int ColumnCount
{
get { return (_ColumnCount); }
set
{
if (value < 0)
throw new ArgumentException(@"ColumnCount cannot be negative", "value");
_ColumnCount = value;
}
}
#endregion
#region ColumnEnd
///<summary>
///Ending column display index (exclusive)
///</summary>
public int ColumnEnd
{
get { return (_ColumnStart + _ColumnCount); }
set
{
int count = value - _ColumnStart;
if (count < 0)
throw new ArgumentException(@"ColumnEnd cannot be less than ColumnStart", "value");
ColumnCount = count;
}
}
#endregion
#region ColumnStart
///<summary>
///Starting column display index
///</summary>
public int ColumnStart
{
get { return (_ColumnStart); }
set { _ColumnStart = value; }
}
#endregion
#region Contains
internal bool Contains(int rowIndex, int columnIndex)
{
return ((rowIndex >= _RowStart && rowIndex < RowEnd) &&
(columnIndex >= _ColumnStart && columnIndex < ColumnEnd));
}
#endregion
#region RowCount
///<summary>
///Number of rows
///</summary>
public int RowCount
{
get { return (_RowCount); }
set
{
if (value < 0)
throw new ArgumentException(@"RowCount cannot be negative", "value");
_RowCount = value;
}
}
#endregion
#region RowEnd
///<summary>
///Ending row index (exclusive)
///</summary>
public int RowEnd
{
get { return (_RowStart + _RowCount); }
set
{
int count = value - _RowStart;
if (count < 0)
throw new ArgumentException(@"RowEnd cannot be less than RowStart", "value");
RowCount = count;
}
}
#endregion
#region RowStart
///<summary>
///Starting row index
///</summary>
public int RowStart
{
get { return (_RowStart); }
set { _RowStart = value; }
}
#endregion
#endregion
#region IsRangeEqualTo
///<summary>
///Returns whether the display range is
///logically equal to the given item's display range.
///</summary>
///<param name="dr"></param>
///<returns></returns>
public bool IsRangeEqualTo(DisplayRange dr)
{
if (dr != null)
{
return (dr.RowStart == _RowStart && dr.ColumnStart == _ColumnStart &&
dr.RowCount == _RowCount && dr.ColumnCount == _ColumnCount);
}
return (false);
}
#endregion
#region ToString
/// <summary>
/// ToString
/// </summary>
/// <returns></returns>
public override string ToString()
{
return ("RowStart = " + RowStart + ", RowEnd = " + RowEnd +
" ColStart = " + ColumnStart + " ColEnd = " + ColumnEnd);
}
#endregion
}
#endregion
}