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 _ScanItems; private List _LastDrs; #endregion #region Public properties #region ScanItems /// /// ScanItems /// public List ScanItems { get { return (GetScanItems()); } } #endregion #endregion /// /// MergeScan /// /// public MergeScan(GridContainer gridContainer) { _GridContainer = gridContainer; _GridPanel = _GridContainer.GridPanel; } #region GetScanItems internal List 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 GetDisplayedScanItems() { List 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 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 drs; if (frCount == 0 && fcCount == 0) { drs = new List(); drs.Add(dr); } else if (frCount != 0 && fcCount != 0) { drs = new List(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(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 GetCellRanges(List drs) { List cellRanges = null; if (_GridPanel.SuperGrid.EditorActive == true || LastScanIsValid(drs) == true) { cellRanges = _ScanItems; } else { foreach (DisplayRange dr in drs) { List 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 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 UpdateMergeRange(DisplayRange dr) { UpdateMergeFlags(dr); UpdateMergeCount(dr); List 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 GetCellMergeRanges(DisplayRange dr) { switch (_GridPanel.CellMergeOrder) { case CellMergeOrder.HorizontalThenVertical: return (MergeHCells(dr)); default: return (MergeVCells(dr)); } } #region MergeVCells private List MergeVCells(DisplayRange dr) { List cellRanges = new List(); 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 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 MergeHCells(DisplayRange dr) { List cellRanges = new List(); 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 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 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 } }