1042 lines
30 KiB
C#

using System.Collections.Generic;
using System.Drawing;
namespace DevComponents.DotNetBar.SuperGrid
{
internal class MergeScan
{
#region Private variables
private GridContainer _GridContainer;
private GridPanel _GridPanel;
private List<CellRange> _ScanItems;
private List<DisplayRange> _LastDrs;
#endregion
#region Public properties
#region ScanItems
///<summary>
/// ScanItems
///</summary>
public List<CellRange> ScanItems
{
get { return (GetScanItems()); }
}
#endregion
#endregion
///<summary>
/// MergeScan
///</summary>
///<param name="gridContainer"></param>
public MergeScan(GridContainer gridContainer)
{
_GridContainer = gridContainer;
_GridPanel = _GridContainer.GridPanel;
}
#region GetScanItems
internal List<CellRange> GetScanItems()
{
if (_GridContainer != null && _GridPanel != null)
{
int rowCount = GetRowCount();
if (rowCount > 0)
{
SuperGridControl sg = _GridPanel.SuperGrid;
if (sg.NeedMergeLayout == true)
_GridContainer.NeedMergeLayout = true;
if (_GridContainer.NeedMergeLayout == true ||
_GridContainer.DisplayedMergeLayoutCount != sg.DisplayedMergeLayoutCount)
{
_ScanItems = GetDisplayedScanItems();
_GridContainer.NeedMergeLayout = false;
_GridContainer.DisplayedMergeLayoutCount = sg.DisplayedMergeLayoutCount;
sg.PostInternalMouseMove();
sg.DeactivateNonModalEditor();
}
return (_ScanItems);
}
}
return (null);
}
#region GetRowCount
private int GetRowCount()
{
if (_GridPanel.VirtualMode == true)
return (_GridPanel.VirtualRowCount);
return (_GridContainer.Rows.Count);
}
#endregion
#region GetDisplayedScanItems
private List<CellRange> GetDisplayedScanItems()
{
List<DisplayRange> drs = GetDisplayRanges();
if (drs != null)
{
_GridPanel.SuperGrid.DoGetDisplayRangesEvent(_GridContainer, ref drs);
if (drs != null && drs.Count > 0)
return (GetCellRanges(drs));
}
return (null);
}
#region GetDisplayRanges
private List<DisplayRange> GetDisplayRanges()
{
GridPanel panel = _GridContainer as GridPanel;
int frCount = 0;
int fcCount = 0;
if (panel != null)
{
frCount = panel.FrozenRowCount;
GridColumn lastColumn = panel.Columns.GetLastVisibleFrozenColumn();
if (lastColumn != null)
fcCount = panel.Columns.GetDisplayIndex(lastColumn) + 1;
}
DisplayRange dr = new DisplayRange();
if (GetRowRange(dr) > 1 | GetColumnRange(dr) > 1)
{
List<DisplayRange> drs;
if (frCount == 0 && fcCount == 0)
{
drs = new List<DisplayRange>();
drs.Add(dr);
}
else if (frCount != 0 && fcCount != 0)
{
drs = new List<DisplayRange>(4);
drs.Add(GetNewRange(dr, 0, frCount, 0, fcCount));
drs.Add(GetNewRange(dr, 0, frCount, fcCount, dr.ColumnCount));
drs.Add(GetNewRange(dr, frCount, dr.RowCount, 0, fcCount));
drs.Add(GetNewRange(dr, frCount, dr.RowEnd, fcCount, dr.ColumnCount));
}
else
{
drs = new List<DisplayRange>(2);
if (frCount != 0)
{
int n = (dr.RowStart < frCount ? frCount : dr.RowStart);
drs.Add(GetNewRange(dr, 0, frCount, dr.ColumnStart, dr.ColumnCount));
drs.Add(GetNewRange(dr, n, dr.RowCount, dr.ColumnStart, dr.ColumnCount));
}
else
{
int n = (dr.ColumnStart < fcCount ? fcCount : dr.ColumnStart);
drs.Add(GetNewRange(dr, dr.RowStart, dr.RowCount, 0, fcCount));
drs.Add(GetNewRange(dr, dr.RowStart, dr.RowCount, n, dr.ColumnCount));
}
}
return (drs);
}
return (null);
}
#region GetRowRange
private int GetRowRange(DisplayRange dr)
{
int rowCount = GetRowCount();
if (rowCount < 50)
{
dr.RowStart = 0;
dr.RowEnd = rowCount;
}
else
{
Rectangle t = _GridContainer.SuperGrid.ViewRect;
dr.RowEnd = _GridContainer.FirstOnScreenRowIndex;
dr.RowStart = GetPreviousRowIndex(dr.RowEnd);
bool fpass = false;
for (int i = dr.RowStart; i < rowCount; i++)
{
GridContainer item = GetRow(i);
if (item != null && item.Visible == true)
{
Rectangle r = item.BoundsRelative;
if (item.IsVFrozen == false)
r.Y -= _GridContainer.VScrollOffset;
if (r.Y > t.Bottom)
{
if (fpass == true)
break;
fpass = true;
}
}
dr.RowEnd = i;
}
dr.RowEnd = GetNextRowIndex(dr.RowEnd) + 1;
}
return (dr.RowCount);
}
#region GetPreviousRowIndex
private int GetPreviousRowIndex(int index)
{
if ((uint)index < GetRowCount())
{
for (int i = index - 1; i >= 0; i--)
{
GridContainer row = GetRow(i);
if (row != null && row.Visible == true)
return (i);
}
}
return (index);
}
#endregion
#region GetNextRowIndex
private int GetNextRowIndex(int index)
{
int rowCount = GetRowCount();
if ((uint)index < rowCount)
{
for (int i = index + 1; i < rowCount; i++)
{
GridContainer row = GetRow(i);
if (row != null && row.Visible == true)
return (i);
}
}
return (index);
}
#endregion
#endregion
#region GetColumnRange
private int GetColumnRange(DisplayRange dr)
{
GridColumnCollection columns = _GridPanel.Columns;
int colCount = columns.Count;
dr.ColumnStart = 0;
dr.ColumnCount = colCount;
if (colCount > 10)
{
int[] map = columns.DisplayIndexMap;
for (int i = 0; i < map.Length; i++)
{
int index = map[i];
GridColumn column = columns[index];
if (column.Visible == true)
{
if (column.IsOnScreen == true && column.IsHFrozen == false)
break;
dr.ColumnStart = i;
}
}
dr.ColumnEnd = dr.ColumnStart;
for (int i = dr.ColumnStart + 1; i < map.Length; i++)
{
int index = map[i];
GridColumn column = columns[index];
if (column.Visible == true)
{
dr.ColumnEnd = i;
if (column.IsOnScreen == false)
break;
}
}
dr.ColumnEnd++;
}
return (dr.ColumnCount);
}
#endregion
#region GetNewRange
private DisplayRange GetNewRange(DisplayRange dr,
int rowStart, int rowCount, int columnStart, int columnCount)
{
DisplayRange ndr = new DisplayRange();
ndr.RowStart = rowStart;
ndr.RowCount = rowCount;
if (ndr.RowEnd > dr.RowEnd)
ndr.RowEnd = dr.RowEnd;
ndr.ColumnStart = columnStart;
ndr.ColumnCount = columnCount;
if (ndr.ColumnEnd > dr.ColumnEnd)
ndr.ColumnEnd = dr.ColumnEnd;
return (ndr);
}
#endregion
#endregion
#region GetCellRanges
private List<CellRange> GetCellRanges(List<DisplayRange> drs)
{
List<CellRange> cellRanges = null;
if (_GridPanel.SuperGrid.EditorActive == true || LastScanIsValid(drs) == true)
{
cellRanges = _ScanItems;
}
else
{
foreach (DisplayRange dr in drs)
{
List<CellRange> crs = UpdateMergeRange(dr);
if (crs != null)
{
if (cellRanges != null)
cellRanges.InsertRange(0, crs);
else
cellRanges = crs;
}
}
_LastDrs = drs;
}
if (cellRanges != null)
{
_GridContainer.SuperGrid.BoundsUpdateCount++;
foreach (CellRange cr in cellRanges)
cr.BackBounds = GetDisplayBounds(cr);
_GridContainer.GridPanel.UpdateSelectionCount();
}
return (cellRanges);
}
#region LastScanIsValid
private bool LastScanIsValid(List<DisplayRange> drs)
{
if (_GridContainer.NeedMergeLayout == false)
{
if (_LastDrs != null)
{
if (drs.Count == _LastDrs.Count)
{
for (int i = 0; i < drs.Count; i++)
{
if (drs[i].IsRangeEqualTo(_LastDrs[i]) == false)
return (false);
}
return (true);
}
}
}
return (false);
}
#endregion
#region UpdateMergeRange
private List<CellRange> UpdateMergeRange(DisplayRange dr)
{
UpdateMergeFlags(dr);
UpdateMergeCount(dr);
List<CellRange> cellRanges = null;
if (_GridContainer.SuperGrid.DoGetCellRangesEvent(_GridContainer, dr, ref cellRanges) == false)
cellRanges = GetCellMergeRanges(dr);
if (cellRanges != null)
PostProcessCellRanges(cellRanges);
_GridContainer.SuperGrid.DoUpdateCellDisplayRangesEvent(_GridContainer, dr, ref cellRanges);
return (cellRanges);
}
#endregion
#region UpdateMergeFlags
private void UpdateMergeFlags(DisplayRange dr)
{
GridRow lastRow = null;
for (int i = dr.RowStart; i < dr.RowEnd; i++)
{
GridContainer item = GetRow(i);
if (item != null && item.Visible == true)
{
GridRow row = item as GridRow;
if (row != null)
{
SetHMergeFlags(row, dr);
SetVMergeFlags(row, lastRow, dr);
}
lastRow = row;
}
}
}
#region SetHMergeFlags
private void SetHMergeFlags(GridRow row, DisplayRange dr)
{
GridPanel panel = _GridContainer.GridPanel;
GridColumnCollection columns = panel.Columns;
int[] map = columns.DisplayIndexMap;
GridCell lastCell = null;
for (int i = dr.ColumnStart; i < dr.ColumnEnd; i++)
{
int index = map[i];
GridColumn column = columns[index];
if (column.Visible == true)
{
GridCell cell = row[index];
if (cell != null)
{
if (lastCell != null)
{
if (_GridContainer.SuperGrid.NeedMergeLayout == true ||
cell.MergeUpdateCount != _GridContainer.MergeUpdateCount ||
lastCell.MergeUpdateCount != _GridContainer.MergeUpdateCount)
{
bool merged = false;
if (CanHMergeCells(panel, column, lastCell.GridColumn))
merged = CanMergeValues(cell, lastCell);
cell.MergedLeft = merged;
lastCell.MergedRight = merged;
}
}
else
{
cell.MergedLeft = false;
}
}
lastCell = cell;
}
}
}
#region CanHMergeCells
private bool CanHMergeCells(
GridPanel panel, GridColumn column1, GridColumn column2)
{
return (IsHCellMerge(panel, column1.CellMergeMode, CellMergeMode.HorizontalLeft) &&
IsHCellMerge(panel, column2.CellMergeMode, CellMergeMode.HorizontalRight));
}
#region IsHCellMerge
private bool IsHCellMerge(GridPanel panel, CellMergeMode cMode, CellMergeMode tMode)
{
if (cMode == CellMergeMode.NotSet)
cMode = panel.CellMergeMode;
return ((cMode & tMode) == tMode);
}
#endregion
#endregion
#region CanVMergeCells
private bool CanVMergeCells(GridPanel panel, GridColumn column)
{
return (IsVCellMerge(panel, column.CellMergeMode));
}
#region IsVCellMerge
private bool IsVCellMerge(GridPanel panel, CellMergeMode mode)
{
if (mode == CellMergeMode.NotSet)
mode = panel.CellMergeMode;
return ((mode & CellMergeMode.Vertical) == CellMergeMode.Vertical);
}
#endregion
#endregion
#endregion
#region SetVMergeFlags
private void SetVMergeFlags(GridRow row, GridRow lastRow, DisplayRange dr)
{
GridPanel panel = _GridContainer.GridPanel;
GridColumnCollection columns = panel.Columns;
int[] map = columns.DisplayIndexMap;
for (int i = dr.ColumnStart; i < dr.ColumnEnd; i++)
{
int index = map[i];
GridColumn column = columns[index];
if (column.Visible == true)
{
GridCell cell = row[index];
if (cell != null)
{
if (lastRow != null)
{
GridCell lastCell = lastRow[index];
if (lastRow.Rows.Count <= 0 || lastRow.Expanded == false)
{
if (lastCell != null)
{
if (_GridContainer.SuperGrid.NeedMergeLayout == true ||
cell.MergeUpdateCount != _GridContainer.MergeUpdateCount ||
cell.MergeUpdateCount != row.MergeUpdateCount ||
lastCell.MergeUpdateCount != _GridContainer.MergeUpdateCount ||
lastCell.MergeUpdateCount != lastRow.MergeUpdateCount)
{
bool merged = false;
if (CanVMergeCells(panel, column) == true)
merged = CanMergeValues(cell, lastCell);
cell.MergedTop = merged;
lastCell.MergedBottom = merged;
}
}
else
{
cell.MergedTop = false;
}
}
else
{
if (lastCell != null)
lastCell.MergedBottom = false;
cell.MergedTop = false;
}
}
}
}
}
}
#endregion
#region CanMergeValues
private bool CanMergeValues(GridCell cell1, GridCell cell2)
{
if (cell1.IsValueNull || cell2.IsValueNull)
{
if (cell1.Value == cell2.Value)
return (cell1.AllowNullMerge & cell2.AllowNullMerge);
return (false);
}
string s1 = cell1.FormattedValue;
string s2 = cell2.FormattedValue;
return (s1.Equals(s2));
}
#endregion
#endregion
#region UpdateMergeCount
private void UpdateMergeCount(DisplayRange dr)
{
GridPanel panel = _GridContainer.GridPanel;
GridColumnCollection columns = panel.Columns;
int[] map = columns.DisplayIndexMap;
for (int i = dr.RowStart; i < dr.RowEnd; i++)
{
GridContainer item = GetRow(i);
if (item != null && item.Visible == true)
{
GridRow row = item as GridRow;
if (row != null)
{
row.MergeUpdateCount = _GridContainer.MergeUpdateCount;
for (int j = dr.ColumnStart; j < dr.ColumnEnd; j++)
{
int index = map[j];
GridCell cell = row[index];
if (cell != null)
cell.MergeUpdateCount = _GridContainer.MergeUpdateCount;
}
}
}
}
}
#endregion
#region GetCellMergeRanges
private List<CellRange> GetCellMergeRanges(DisplayRange dr)
{
switch (_GridPanel.CellMergeOrder)
{
case CellMergeOrder.HorizontalThenVertical:
return (MergeHCells(dr));
default:
return (MergeVCells(dr));
}
}
#region MergeVCells
private List<CellRange> MergeVCells(DisplayRange dr)
{
List<CellRange> cellRanges = new List<CellRange>();
GridColumnCollection columns = _GridContainer.GridPanel.Columns;
int[] map = columns.DisplayIndexMap;
for (int i = dr.ColumnStart; i < dr.ColumnEnd; i++)
{
int index = map[i];
GridColumn column = columns[index];
if (column.Visible == true)
{
CellRange cr = null;
for (int j = dr.RowStart; j < dr.RowEnd; j++)
{
GridRow row = GetRow(j);
if (row != null && row.Visible == true && row.IsTempInsertRow == false)
{
GridCell cell = row.GetCell(index);
if (cell != null)
{
if (cell.MergedTop == true)
{
if (cr == null)
cr = new CellRange(j, i);
else
cr.RowEnd = j + 1;
}
else
{
OutputVCellRange(cellRanges, cr, map);
cr = new CellRange(j, i);
}
}
}
}
OutputVCellRange(cellRanges, cr, map);
}
}
return (cellRanges);
}
#region OutputVCellRange
private void OutputVCellRange(
List<CellRange> cellRanges, CellRange cr, int[] map)
{
if (cr != null)
{
for (int i = 0; i < cellRanges.Count; i++)
{
CellRange crn = cellRanges[i];
if (crn.ColumnEnd == cr.ColumnStart)
{
if (crn.RowStart == cr.RowStart && crn.RowEnd == cr.RowEnd)
{
GridRow row = GetRow(cr.RowStart);
if (row != null)
{
if (row[map[crn.ColumnEnd - 1]].MergedRight == true)
{
crn.ColumnEnd = cr.ColumnEnd;
cr = null;
}
else
{
if (crn.RowStart == crn.RowEnd && crn.ColumnStart == crn.ColumnEnd)
cellRanges.RemoveAt(i);
}
}
break;
}
}
}
if (cr != null)
cellRanges.Add(cr);
}
}
#endregion
#endregion
#region MergeHCells
private List<CellRange> MergeHCells(DisplayRange dr)
{
List<CellRange> cellRanges = new List<CellRange>();
GridColumnCollection columns = _GridPanel.Columns;
int[] map = columns.DisplayIndexMap;
for (int j = dr.RowStart; j < dr.RowEnd; j++)
{
GridRow row = GetRow(j);
if (row != null && row.Visible == true && row.IsTempInsertRow == false)
{
CellRange cr = null;
for (int i = dr.ColumnStart; i < dr.ColumnEnd; i++)
{
int index = map[i];
GridColumn column = columns[index];
if (column.Visible == true)
{
GridCell cell = row[index];
if (cell != null)
{
if (cell.MergedLeft == true)
{
if (cr == null)
cr = new CellRange(j, i);
else
cr.ColumnEnd = i + 1;
}
else
{
OutputHCellRange(cellRanges, cr, map);
cr = new CellRange(j, i);
}
}
}
}
OutputHCellRange(cellRanges, cr, map);
}
}
return (cellRanges);
}
#region OutputHCellRange
private void OutputHCellRange(
List<CellRange> cellRanges, CellRange cr, int[] map)
{
if (cr != null)
{
for (int i = 0; i < cellRanges.Count; i++)
{
CellRange crn = cellRanges[i];
if (crn.RowEnd == cr.RowStart)
{
if (crn.ColumnStart == cr.ColumnStart && crn.ColumnEnd == cr.ColumnEnd)
{
GridRow row = GetRow(crn.RowEnd - 1);
if (row != null)
{
if (row[map[crn.ColumnEnd - 1]].MergedBottom == true)
{
crn.RowEnd = cr.RowEnd;
cr = null;
}
else
{
if (crn.RowStart == crn.RowEnd && crn.ColumnStart == crn.ColumnEnd)
cellRanges.RemoveAt(i);
}
}
break;
}
}
}
if (cr != null)
cellRanges.Add(cr);
}
}
#endregion
#endregion
#endregion
#region PostProcessCellRanges
private void PostProcessCellRanges(List<CellRange> cellRanges)
{
if (cellRanges != null)
{
for (int i = cellRanges.Count - 1; i >= 0; i--)
{
CellRange cr = cellRanges[i];
if (cr.ColumnCount <= 1 && cr.RowCount <= 1)
{
cellRanges.RemoveAt(i);
}
else
{
if (cr.FormattedValue == null)
{
GridCell cell = GetRow(cr.RowStart)[_GridPanel.Columns.DisplayIndexMap[cr.ColumnStart]];
if (cell != null)
{
string s = cell.FormattedValue;
cell.SuperGrid.DoGetCellRangeFormattedValueEvent((GridContainer)cell.GridRow.Parent, cr, ref s);
cr.FormattedValue = s;
}
else
{
cr.FormattedValue = "";
}
}
}
}
}
}
#endregion
#region GetDisplayBounds
private Rectangle GetDisplayBounds(CellRange cr)
{
Rectangle r = Rectangle.Empty;
if (cr != null)
{
GridPanel panel = _GridContainer.GridPanel;
int[] map = panel.Columns.DisplayIndexMap;
int rowHeight = 200;
for (int ri = cr.RowStart; ri < cr.RowEnd; ri++)
{
GridRow row = GetRow(ri);
if (row.Visible == true)
{
for (int ci = cr.ColumnStart; ci < cr.ColumnEnd; ci++)
{
int index = map[ci];
GridCell cell = row.GetCell(index);
if (cell != null)
{
r = (r.IsEmpty == true)
? cell.BackBounds
: Rectangle.Union(r, cell.BackBounds);
}
}
if (rowHeight > row.FixedRowHeight)
rowHeight = row.FixedRowHeight;
}
}
if (r.IsEmpty == false)
r = AdjustMergeRect(panel, map, r, cr, rowHeight);
}
return (r);
}
#region AdjustMergeRect
private Rectangle AdjustMergeRect(GridPanel panel,
int[] map, Rectangle r, CellRange cr, int rowHeight)
{
Rectangle r2 = r;
Rectangle t = _GridContainer.SViewRect;
if (r.IntersectsWith(t))
r.Intersect(t);
if (r.Width > 0 && r.Height > 0)
{
if (r2.Y < t.Y)
{
if (r.Height < rowHeight)
{
r.Y = r.Bottom - rowHeight;
r.Height = rowHeight;
}
}
else if (r2.Bottom > t.Bottom)
{
if (r.Height < rowHeight)
r.Height = rowHeight;
}
GridColumn cols = panel.Columns[map[cr.ColumnStart]];
GridColumn cole = panel.Columns[map[cr.ColumnEnd - 1]];
if (r2.X < t.X && cole.Bounds.X < t.X)
{
if (r.Width < cole.BoundsRelative.Width)
{
r.X = r2.Right - cole.BoundsRelative.Width;
r.Width = cole.BoundsRelative.Width;
}
}
else if (r2.Right > t.Right && cols.Bounds.Right > r.Right)
{
if (r.Width < cols.BoundsRelative.Width)
{
r.X = r2.X;
r.Width = cols.BoundsRelative.Width;
}
}
}
return (r);
}
#endregion
#endregion
#endregion
#region GetRow
private GridRow GetRow(int index)
{
return (_GridPanel.VirtualMode == true)
? _GridPanel.VirtualRows[index]
: _GridContainer.Rows[index] as GridRow;
}
#endregion
#endregion
#endregion
}
}