Fix grid multicell integrity after inserting/deleting rows/columns
Deal with possible size changes of a multicell (both main and inside cells) when inserting or deleting rows or columns and, in the case of deletion only, the disappearing of a multicell's main cell. Closes #4238.
This commit is contained in:
@@ -820,13 +820,82 @@ void UpdateCellAttrRowsOrCols(wxGridCellWithAttrArray& attrs, int editPos,
|
|||||||
size_t count = attrs.GetCount();
|
size_t count = attrs.GetCount();
|
||||||
for ( size_t n = 0; n < count; n++ )
|
for ( size_t n = 0; n < count; n++ )
|
||||||
{
|
{
|
||||||
|
wxGridCellAttr* cellAttr = attrs[n].attr;
|
||||||
|
int cellRows, cellCols;
|
||||||
|
cellAttr->GetSize(&cellRows, &cellCols);
|
||||||
|
|
||||||
wxGridCellCoords& coords = attrs[n].coords;
|
wxGridCellCoords& coords = attrs[n].coords;
|
||||||
const wxCoord cellRow = coords.GetRow(),
|
const wxCoord cellRow = coords.GetRow(),
|
||||||
cellCol = coords.GetCol(),
|
cellCol = coords.GetCol(),
|
||||||
cellPos = (isEditingRows ? cellRow : cellCol);
|
cellPos = (isEditingRows ? cellRow : cellCol);
|
||||||
|
|
||||||
if ( cellPos < editPos )
|
if ( cellPos < editPos )
|
||||||
|
{
|
||||||
|
// This cell's coords aren't influenced by the editing, however
|
||||||
|
// do adjust a multicell's main size, if needed.
|
||||||
|
if ( GetCellSpan(cellRows, cellCols) == wxGrid::CellSpan_Main )
|
||||||
|
{
|
||||||
|
int mainSize = isEditingRows ? cellRows : cellCols;
|
||||||
|
if ( cellPos + mainSize > editPos )
|
||||||
|
{
|
||||||
|
// Multicell is within affected range:
|
||||||
|
// Adjust its size.
|
||||||
|
|
||||||
|
if ( editCount >= 0 )
|
||||||
|
{
|
||||||
|
mainSize += editCount;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Reduce multicell size by number of deletions, but
|
||||||
|
// never more than the multicell's size minus one:
|
||||||
|
// cellPos (the main cell) is always less than editPos
|
||||||
|
// at this point, then with the below code a multicell
|
||||||
|
// with size 7 is at most reduced by:
|
||||||
|
// cellPos + 7 - (cellPos + 1) = 7 - 1 = 6.
|
||||||
|
mainSize -= wxMin(-editCount,
|
||||||
|
cellPos + mainSize - editPos);
|
||||||
|
/*
|
||||||
|
The above was derived from:
|
||||||
|
first_del = edit
|
||||||
|
last_del = min(edit - count - 1, cell + size - 1)
|
||||||
|
size -= (last_del + 1 - first_del)
|
||||||
|
|
||||||
|
eliminating the 1's:
|
||||||
|
|
||||||
|
first_del = edit
|
||||||
|
last_del = min(edit - count, cell + size)
|
||||||
|
size -= (last_del - first_del)
|
||||||
|
|
||||||
|
reducing each by edit:
|
||||||
|
|
||||||
|
first_del = 0
|
||||||
|
last_del_plus_1 = min(0 - count, cell + size - edit)
|
||||||
|
size -= (last_del_plus_1 - 0)
|
||||||
|
|
||||||
|
after eliminating the 0's and substitution, leaving:
|
||||||
|
|
||||||
|
size -= min(-count, cell + size - edit)
|
||||||
|
|
||||||
|
E.g. with a multicell of size 7 and at 2 positions
|
||||||
|
after the main cell 100 positions are deleted then
|
||||||
|
the size will not (/can't) be reduced by 100 cells
|
||||||
|
but by:
|
||||||
|
|
||||||
|
cellPos + 7 - editPos = # editPos = cellPos + 2
|
||||||
|
cellPos + 7 - (cellPos + 2) = # eliminate cellPos
|
||||||
|
7 - 2 =
|
||||||
|
5 cells, making the final size 7 - 5 = 2.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
cellAttr->SetSize(isEditingRows ? mainSize : cellRows,
|
||||||
|
isEditingRows ? cellCols : mainSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if ( editCount < 0 && cellPos < editPos - editCount )
|
if ( editCount < 0 && cellPos < editPos - editCount )
|
||||||
{
|
{
|
||||||
@@ -839,9 +908,68 @@ void UpdateCellAttrRowsOrCols(wxGridCellWithAttrArray& attrs, int editPos,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( GetCellSpan(cellRows, cellCols) != wxGrid::CellSpan_Inside )
|
||||||
|
{
|
||||||
// Rows/cols inserted or deleted (and this cell still exists):
|
// Rows/cols inserted or deleted (and this cell still exists):
|
||||||
// Adjust cell coords.
|
// Adjust cell coords.
|
||||||
coords.Set(cellRow + editRowCount, cellCol + editColCount);
|
coords.Set(cellRow + editRowCount, cellCol + editColCount);
|
||||||
|
|
||||||
|
// Nothing more to do: cell is not an inside cell of a multicell.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle inside cell's existence, coords, and size.
|
||||||
|
|
||||||
|
const int mainPos = cellPos + (isEditingRows ? cellRows : cellCols);
|
||||||
|
|
||||||
|
if ( editCount < 0
|
||||||
|
&& mainPos >= editPos && mainPos < editPos - editCount )
|
||||||
|
{
|
||||||
|
// On a position that still exists after deletion but main cell
|
||||||
|
// of multicell is within deletion range so the multicell is gone:
|
||||||
|
// Remove the attribute.
|
||||||
|
attrs.RemoveAt(n);
|
||||||
|
n--;
|
||||||
|
count--;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rows/cols inserted or deleted (and this inside cell still exists):
|
||||||
|
// Adjust (inside) cell coords.
|
||||||
|
coords.Set(cellRow + editRowCount, cellCol + editColCount);
|
||||||
|
|
||||||
|
if ( mainPos >= editPos )
|
||||||
|
{
|
||||||
|
// Nothing more to do: the multicell that this inside cell is part
|
||||||
|
// of is moving its main cell as well so offsets to the main cell
|
||||||
|
// don't change and there are no edits changing the multicell size.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( editCount > 0 && cellPos == editPos )
|
||||||
|
{
|
||||||
|
// At an (old) position that is newly inserted: this is the only
|
||||||
|
// opportunity to add required inside cells that point to
|
||||||
|
// the main cell. E.g. with a 2x1 multicell that increases in size
|
||||||
|
// there's only one inside cell that will be visited while there
|
||||||
|
// can be multiple insertions.
|
||||||
|
for ( int i = 0; i < editCount; ++i )
|
||||||
|
{
|
||||||
|
const int adjustRows = i * isEditingRows,
|
||||||
|
adjustCols = i * !isEditingRows;
|
||||||
|
|
||||||
|
wxGridCellAttr* attr = new wxGridCellAttr;
|
||||||
|
attr->SetSize(cellRows - adjustRows, cellCols - adjustCols);
|
||||||
|
|
||||||
|
attrs.Add(new wxGridCellWithAttr(cellRow + adjustRows,
|
||||||
|
cellCol + adjustCols,
|
||||||
|
attr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let this inside cell's size point to the main cell of the multicell.
|
||||||
|
cellAttr->SetSize(cellRows - editRowCount, cellCols - editColCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user