534 lines
13 KiB
C#
534 lines
13 KiB
C#
using System;
|
|
using System.Drawing;
|
|
|
|
namespace DevComponents.DotNetBar.SuperGrid
|
|
{
|
|
/// <summary>
|
|
/// Defines the collection of Virtual Rows
|
|
/// </summary>
|
|
public class GridVirtualRows
|
|
{
|
|
#region Private Variables
|
|
|
|
private GridContainer _Container;
|
|
|
|
private const int MaxRows = 50;
|
|
private const int MaxBuckets = 100;
|
|
|
|
private int _BucketHead;
|
|
private VPageBucket _LastAccessedBucket;
|
|
private VPageBucket[] _PageBuckets;
|
|
|
|
#endregion
|
|
|
|
///<summary>
|
|
/// GridVirtualRowList
|
|
///</summary>
|
|
///<param name="container"></param>
|
|
public GridVirtualRows(GridContainer container)
|
|
{
|
|
_Container = container;
|
|
|
|
_PageBuckets = new VPageBucket[MaxBuckets];
|
|
_PageBuckets[0] = new VPageBucket(_Container, 0);
|
|
}
|
|
|
|
#region Public properties
|
|
|
|
#region MaxRowIndex
|
|
|
|
///<summary>
|
|
/// MaxRowIndex
|
|
///</summary>
|
|
///<exception cref="Exception"></exception>
|
|
public int MaxRowIndex
|
|
{
|
|
get { return (GetMaxRowIndex()); }
|
|
set { TruncateRowIndex(value); }
|
|
}
|
|
|
|
#region TruncateRowIndex
|
|
|
|
private void TruncateRowIndex(int index)
|
|
{
|
|
_LastAccessedBucket = null;
|
|
|
|
for (int i = 0; i < MaxBuckets; i++)
|
|
{
|
|
int n = (_BucketHead + i) % MaxBuckets;
|
|
|
|
if (_PageBuckets[n] != null)
|
|
{
|
|
if (_PageBuckets[n].StartIndex >= index)
|
|
_PageBuckets[n] = null;
|
|
|
|
else if (_PageBuckets[n].EndIndex > index)
|
|
{
|
|
for (int j = 0; j < MaxRows; j++)
|
|
{
|
|
if (_PageBuckets[n].StartIndex + j > index)
|
|
_PageBuckets[n].Rows[j] = null;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetMaxRowIndex
|
|
|
|
private int GetMaxRowIndex()
|
|
{
|
|
int maxIndex = 0;
|
|
|
|
for (int i = 0; i < MaxBuckets; i++)
|
|
{
|
|
int n = (_BucketHead + i) % MaxBuckets;
|
|
|
|
VPageBucket bucket = _PageBuckets[n];
|
|
|
|
if (bucket != null)
|
|
{
|
|
int index = bucket.StartIndex;
|
|
|
|
if (index >= maxIndex)
|
|
{
|
|
foreach (GridRow row in bucket.Rows)
|
|
{
|
|
if (row != null)
|
|
{
|
|
if (row.GridIndex > maxIndex)
|
|
maxIndex = row.GridIndex;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return (maxIndex);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region Row Indexer
|
|
|
|
///<summary>
|
|
/// Row indexer
|
|
///</summary>
|
|
///<param name="index"></param>
|
|
public GridRow this[int index]
|
|
{
|
|
get { return (GetRow(index)); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region FindBucket
|
|
|
|
private VPageBucket FindBucket(int index)
|
|
{
|
|
if (_LastAccessedBucket != null)
|
|
{
|
|
if (_LastAccessedBucket.Contains(index))
|
|
return (_LastAccessedBucket);
|
|
}
|
|
|
|
for (int i = 0; i < MaxBuckets; i++)
|
|
{
|
|
int n = (_BucketHead + i) % MaxBuckets;
|
|
|
|
if (_PageBuckets[n] != null)
|
|
{
|
|
if (_PageBuckets[n].Contains(index))
|
|
return (_PageBuckets[n]);
|
|
}
|
|
}
|
|
|
|
return (null);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region FreeRow
|
|
|
|
///<summary>
|
|
/// FreeRow
|
|
///</summary>
|
|
///<param name="index"></param>
|
|
///<returns></returns>
|
|
///<exception cref="Exception"></exception>
|
|
public void FreeRow(int index)
|
|
{
|
|
VPageBucket bucket = FindBucket(index);
|
|
|
|
if (bucket != null)
|
|
{
|
|
GridRow[] rows = bucket.Rows;
|
|
GridRow row = rows[index - bucket.StartIndex];
|
|
|
|
if (row != null)
|
|
{
|
|
row.Dispose();
|
|
rows[index - bucket.StartIndex] = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IsCachedRow
|
|
|
|
///<summary>
|
|
/// Gets whether the row is currently cached
|
|
///</summary>
|
|
public bool IsCachedRow(int index)
|
|
{
|
|
if (_LastAccessedBucket != null)
|
|
{
|
|
if (_LastAccessedBucket.Contains(index) == true)
|
|
return (_LastAccessedBucket.IsCached(index));
|
|
}
|
|
|
|
for (int i = 0; i < MaxBuckets; i++)
|
|
{
|
|
int n = (_BucketHead + i) % MaxBuckets;
|
|
|
|
if (_PageBuckets[n] != null)
|
|
{
|
|
if (_PageBuckets[n].Contains(index) == true)
|
|
return (_PageBuckets[n].IsCached(index));
|
|
}
|
|
}
|
|
|
|
return (false);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetRow
|
|
|
|
private GridRow GetRow(int index)
|
|
{
|
|
if (_LastAccessedBucket != null)
|
|
{
|
|
if (_LastAccessedBucket.Contains(index))
|
|
return (_LastAccessedBucket[index]);
|
|
}
|
|
|
|
for (int i = 0; i < MaxBuckets; i++)
|
|
{
|
|
int n = (_BucketHead + i) % MaxBuckets;
|
|
|
|
if (_PageBuckets[n] == null)
|
|
return (NewBucketRow(n, index));
|
|
|
|
if (_PageBuckets[n].Contains(index))
|
|
{
|
|
_LastAccessedBucket = _PageBuckets[n];
|
|
|
|
return (_LastAccessedBucket[index]);
|
|
}
|
|
}
|
|
|
|
int bucket = _BucketHead;
|
|
|
|
GridPanel panel = _Container.GridPanel;
|
|
|
|
if (panel != null)
|
|
{
|
|
for (int i = 0; i < MaxBuckets; i++)
|
|
{
|
|
bucket = (_BucketHead + i) % MaxBuckets;
|
|
|
|
if (panel.FrozenRowCount > 0)
|
|
{
|
|
if (_PageBuckets[bucket].Contains(0))
|
|
continue;
|
|
}
|
|
|
|
if (panel.ActiveRow != null)
|
|
{
|
|
if (_PageBuckets[bucket].Contains(panel.ActiveRow.Index))
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
_BucketHead = (bucket + 1) % MaxBuckets;
|
|
|
|
return (NewBucketRow(bucket, index));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region NewBucketRow
|
|
|
|
private GridRow NewBucketRow(int n, int index)
|
|
{
|
|
int startIndex = (index / MaxRows) * MaxRows;
|
|
|
|
if (_PageBuckets[n] != null)
|
|
_PageBuckets[n].Reset(_Container, startIndex);
|
|
else
|
|
_PageBuckets[n] = new VPageBucket(_Container, startIndex);
|
|
|
|
_LastAccessedBucket = _PageBuckets[n];
|
|
|
|
return (_LastAccessedBucket[index]);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Clear
|
|
|
|
///<summary>
|
|
/// Clear
|
|
///</summary>
|
|
public void Clear()
|
|
{
|
|
for (int i = 0; i < MaxBuckets; i++)
|
|
{
|
|
if (_PageBuckets[i] != null)
|
|
_PageBuckets[i].Reset(null, 0);
|
|
|
|
_PageBuckets[i] = null;
|
|
}
|
|
|
|
_BucketHead = 0;
|
|
_LastAccessedBucket = null;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region VPageBucket
|
|
|
|
private class VPageBucket
|
|
{
|
|
#region Static data
|
|
|
|
static private GridLayoutInfo _layoutInfo = new GridLayoutInfo(null, Rectangle.Empty);
|
|
static private GridLayoutStateInfo _stateInfo = new GridLayoutStateInfo(null, 0);
|
|
|
|
#endregion
|
|
|
|
#region Private variables
|
|
|
|
private GridContainer _Container;
|
|
private int _StartIndex;
|
|
private int _EndIndex;
|
|
|
|
private GridRow[] _Rows;
|
|
|
|
#endregion
|
|
|
|
public VPageBucket(GridContainer container, int startIndex)
|
|
{
|
|
_Container = container;
|
|
_StartIndex = startIndex;
|
|
_EndIndex = startIndex + MaxRows - 1;
|
|
|
|
_Rows = new GridRow[MaxRows];
|
|
}
|
|
|
|
#region Public properties
|
|
|
|
#region EndIndex
|
|
|
|
public int EndIndex
|
|
{
|
|
get { return (_EndIndex); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Row Indexer
|
|
|
|
///<summary>
|
|
/// Row indexer
|
|
///</summary>
|
|
///<param name="index"></param>
|
|
public GridRow this[int index]
|
|
{
|
|
get { return (GetRow(index)); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Rows
|
|
|
|
public GridRow[] Rows
|
|
{
|
|
get { return (_Rows); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region StartIndex
|
|
|
|
public int StartIndex
|
|
{
|
|
get { return (_StartIndex); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region Contains
|
|
|
|
public bool Contains(int index)
|
|
{
|
|
return (index >= _StartIndex && index <= _EndIndex);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IsCached
|
|
|
|
public bool IsCached(int index)
|
|
{
|
|
if (Contains(index) == true)
|
|
return (_Rows[index - _StartIndex] != null);
|
|
|
|
return (false);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetRow
|
|
|
|
private GridRow GetRow(int index)
|
|
{
|
|
int n = index - _StartIndex;
|
|
|
|
if (_Rows[n] == null)
|
|
_Rows[n] = AllocNewGridRow(index);
|
|
|
|
GridRow row = _Rows[n];
|
|
|
|
if (row.ArrangeLayoutCount != row.SuperGrid.ArrangeLayoutCount)
|
|
ArrangeRow(row.GridPanel, row);
|
|
|
|
return (row);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Reset
|
|
|
|
public void Reset(GridContainer container, int startIndex)
|
|
{
|
|
for (int i = 0; i < MaxRows; i++)
|
|
{
|
|
GridRow row = _Rows[i];
|
|
|
|
if (row != null)
|
|
{
|
|
row.Dispose();
|
|
|
|
_Rows[i] = null;
|
|
}
|
|
}
|
|
|
|
_Container = container;
|
|
_StartIndex = startIndex;
|
|
_EndIndex = startIndex + MaxRows - 1;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region AllocNewGridRow
|
|
|
|
private GridRow AllocNewGridRow(int index)
|
|
{
|
|
GridPanel panel = _Container.GridPanel;
|
|
|
|
if (panel != null)
|
|
{
|
|
GridRow row = new GridRow();
|
|
|
|
row.Parent = _Container;
|
|
|
|
row.GridIndex = index;
|
|
row.Index = index;
|
|
row.RowIndex = index;
|
|
row.FullIndex = index;
|
|
|
|
row.MergeUpdateCount = _Container.MergeUpdateCount;
|
|
row.MergeUpdateCount--;
|
|
|
|
row.Loading = true;
|
|
|
|
try
|
|
{
|
|
GridColumnCollection columns = panel.Columns;
|
|
|
|
if (columns.Count > 0)
|
|
{
|
|
for (int i = 0; i < columns.Count; i++)
|
|
{
|
|
GridColumn col = panel.Columns[i];
|
|
|
|
GridCell cell = new GridCell(col.DefaultNewRowCellValue);
|
|
|
|
cell.Parent = row;
|
|
cell.ColumnIndex = i;
|
|
|
|
row.Cells.Add(cell);
|
|
}
|
|
}
|
|
|
|
ArrangeRow(panel, row);
|
|
|
|
if (columns.Count > 0)
|
|
{
|
|
_Container.SuperGrid.DoLoadVirtualRowEvent(panel, row);
|
|
_Container.SuperGrid.DoVirtualRowLoadedEvent(panel, row);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
row.Loading = false;
|
|
}
|
|
|
|
return (row);
|
|
}
|
|
|
|
return (null);
|
|
}
|
|
|
|
#region ArrangeRow
|
|
|
|
private void ArrangeRow(GridPanel panel, GridRow row)
|
|
{
|
|
Rectangle r = panel.BoundsRelative;
|
|
|
|
int vrh = Dpi.Height(panel.VirtualRowHeight);
|
|
|
|
r.Y += (panel.FixedRowHeight - (panel.FrozenRowCount * vrh));
|
|
r.Y += (row.Index * vrh);
|
|
|
|
r.Size = new Size(panel.ColumnHeader.Size.Width, vrh);
|
|
|
|
_layoutInfo.ClientBounds = r;
|
|
_stateInfo.GridPanel = panel;
|
|
|
|
row.FixedRowHeight = r.Size.Height;
|
|
row.Arrange(_layoutInfo, _stateInfo, r);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|