fpspreadsheet: Redo internal structure of merged cells (use MergeBase cell instead of neighbor links).

Suppress TsWorksheetGrid painting of inner grid lines of merged cells.
Fix inserting columns and rows running through merged cells. 
Silence some warnings. 
Fix ods reading merged cells incorrectly.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3569 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2014-09-15 20:54:39 +00:00
parent b7abdabd0b
commit e07e322170
5 changed files with 289 additions and 208 deletions

View File

@ -4,7 +4,7 @@ object MainFrm: TMainFrm
Top = 258
Width = 884
Caption = 'spready'
ClientHeight = 619
ClientHeight = 614
ClientWidth = 884
Menu = MainMenu
OnActivate = FormActivate
@ -14,7 +14,7 @@ object MainFrm: TMainFrm
object Panel1: TPanel
Left = 0
Height = 78
Top = 541
Top = 536
Width = 884
Align = alBottom
BevelOuter = bvNone
@ -23,7 +23,7 @@ object MainFrm: TMainFrm
TabOrder = 6
object EdFrozenCols: TSpinEdit
Left = 429
Height = 23
Height = 28
Top = 8
Width = 52
OnChange = EdFrozenColsChange
@ -31,7 +31,7 @@ object MainFrm: TMainFrm
end
object EdFrozenRows: TSpinEdit
Left = 429
Height = 23
Height = 28
Top = 39
Width = 52
OnChange = EdFrozenRowsChange
@ -39,37 +39,37 @@ object MainFrm: TMainFrm
end
object Label1: TLabel
Left = 344
Height = 15
Height = 20
Top = 13
Width = 62
Width = 77
Caption = 'Frozen cols:'
FocusControl = EdFrozenCols
ParentColor = False
end
object Label2: TLabel
Left = 344
Height = 15
Height = 20
Top = 40
Width = 66
Width = 82
Caption = 'Frozen rows:'
FocusControl = EdFrozenRows
ParentColor = False
end
object CbReadFormulas: TCheckBox
Left = 8
Height = 19
Height = 24
Top = 8
Width = 96
Width = 120
Caption = 'Read formulas'
OnChange = CbReadFormulasChange
TabOrder = 0
end
object CbHeaderStyle: TComboBox
Left = 200
Height = 23
Height = 28
Top = 8
Width = 116
ItemHeight = 15
ItemHeight = 20
ItemIndex = 2
Items.Strings = (
'Lazarus'
@ -83,18 +83,18 @@ object MainFrm: TMainFrm
end
object CbAutoCalcFormulas: TCheckBox
Left = 8
Height = 19
Height = 24
Top = 32
Width = 128
Width = 158
Caption = 'Calculate on change'
OnChange = CbAutoCalcFormulasChange
TabOrder = 1
end
object CbTextOverflow: TCheckBox
Left = 8
Height = 19
Height = 24
Top = 56
Width = 91
Width = 114
Caption = 'Text overflow'
Checked = True
OnChange = CbTextOverflowChange
@ -189,19 +189,19 @@ object MainFrm: TMainFrm
end
object FontComboBox: TComboBox
Left = 52
Height = 23
Height = 28
Top = 2
Width = 127
ItemHeight = 15
ItemHeight = 20
OnSelect = FontComboBoxSelect
TabOrder = 0
end
object FontSizeComboBox: TComboBox
Left = 179
Height = 23
Height = 28
Top = 2
Width = 48
ItemHeight = 15
ItemHeight = 20
Items.Strings = (
'8'
'9'
@ -375,7 +375,7 @@ object MainFrm: TMainFrm
end
object InspectorSplitter: TSplitter
Left = 648
Height = 462
Height = 457
Top = 79
Width = 5
Align = alRight
@ -383,7 +383,7 @@ object MainFrm: TMainFrm
end
object InspectorPageControl: TPageControl
Left = 653
Height = 462
Height = 457
Top = 79
Width = 231
ActivePage = PgCellValue
@ -393,11 +393,11 @@ object MainFrm: TMainFrm
OnChange = InspectorPageControlChange
object PgCellValue: TTabSheet
Caption = 'Cell value'
ClientHeight = 434
ClientHeight = 424
ClientWidth = 223
object CellInspector: TValueListEditor
Left = 0
Height = 434
Height = 424
Top = 0
Width = 223
Align = alClient
@ -438,7 +438,7 @@ object MainFrm: TMainFrm
end
object TabControl: TTabControl
Left = 0
Height = 462
Height = 457
Top = 79
Width = 648
OnChange = TabControlChange
@ -446,7 +446,7 @@ object MainFrm: TMainFrm
TabOrder = 3
object WorksheetGrid: TsWorksheetGrid
Left = 2
Height = 457
Height = 452
Top = 3
Width = 644
FrozenCols = 0
@ -456,6 +456,7 @@ object MainFrm: TMainFrm
AutoAdvance = aaDown
BorderStyle = bsNone
ColCount = 27
ExtendedSelect = False
MouseWheelOption = mwGrid
Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect, goRowSizing, goColSizing, goThumbTracking, goSmoothScroll, goFixedColSizing]
RowCount = 101
@ -463,7 +464,7 @@ object MainFrm: TMainFrm
TitleStyle = tsNative
OnSelection = WorksheetGridSelection
ColWidths = (
42
56
64
64
64

View File

@ -546,6 +546,7 @@ begin
WorksheetGrid.MergeCells
else
WorksheetGrid.UnmergeCells;
WorksheetGridSelection(nil, WorksheetGrid.Col, WorksheetGrid.Row);
end;
procedure TMainFrm.AcNewExecute(Sender: TObject);
@ -1041,11 +1042,11 @@ begin
if (ACell=nil) or not (uffNumberFormat in ACell^.UsedFormattingFields)
then Strings.Add('NumberFormatStr=')
else Strings.Add('NumberFormatStr=' + ACell^.NumberFormatStr);
if (ACell=nil) or (ACell^.MergedNeighbors = []) then
Strings.Add('Merged neighbors=')
if not WorksheetGrid.Worksheet.IsMerged(ACell) then
Strings.Add('Merged range=')
else begin
WorksheetGrid.Worksheet.FindMergedRange(ACell, r1, c1, r2, c2);
Strings.Add('Merged neighbors=' + GetCellRangeString(r1, c1, r2, c2));
Strings.Add('Merged range=' + GetCellRangeString(r1, c1, r2, c2));
end;
end;
@ -1167,7 +1168,7 @@ begin
AcWordwrap.Checked := wrapped;
end;
procedure TMainFrm.WorksheetGridSelection(Sender: TObject; aCol, aRow: Integer);
procedure TMainFrm.WorksheetGridSelection(Sender: TObject; ACol, ARow: Integer);
var
r, c: Cardinal;
cell: PCell;
@ -1209,7 +1210,7 @@ begin
EdFormula.Text := '';
EdCellAddress.Text := GetCellString(r, c, [rfRelRow, rfRelCol]);
AcMergeCells.Checked := (cell <> nil) and (cell^.MergedNeighbors <> []);
AcMergeCells.Checked := WorksheetGrid.Worksheet.IsMerged(cell);
UpdateHorAlignmentActions;
UpdateVertAlignmentActions;

View File

@ -1841,50 +1841,60 @@ begin
// These nodes occur due to indentation spaces which are not skipped
// automatically any more due to PreserveWhiteSpace option applied
// to ReadXMLFile
{
if nodeName <> 'table:table-cell' then begin //= '#text' then begin
cellNode := cellNode.NextSibling;
Continue;
end;
}
if nodeName = 'table:table-cell' then begin
// select this cell value's type
paramValueType := GetAttrValue(CellNode, 'office:value-type');
paramFormula := GetAttrValue(CellNode, 'table:formula');
tableStyleName := GetAttrValue(CellNode, 'table:style-name');
// select this cell value's type
paramValueType := GetAttrValue(CellNode, 'office:value-type');
paramFormula := GetAttrValue(CellNode, 'table:formula');
tableStyleName := GetAttrValue(CellNode, 'table:style-name');
if paramValueType = 'string' then
ReadLabel(row, col, cellNode)
else
if (paramValueType = 'float') or (paramValueType = 'percentage') or
(paramValueType = 'currency')
then
ReadNumber(row, col, cellNode)
else if (paramValueType = 'date') or (paramValueType = 'time') then
ReadDateTime(row, col, cellNode)
else if (paramValueType = '') and (tableStyleName <> '') then
ReadBlank(row, col, cellNode);
if paramValueType = 'string' then
ReadLabel(row, col, cellNode)
if ParamFormula <> '' then
ReadFormula(row, col, cellNode);
paramColsSpanned := GetAttrValue(cellNode, 'table:number-columns-spanned');
if paramColsSpanned <> '' then
colsSpanned := StrToInt(paramColsSpanned) - 1
else
colsSpanned := 0;
paramRowsSpanned := GetAttrValue(cellNode, 'table:number-rows-spanned');
if paramRowsSpanned <> '' then
rowsSpanned := StrToInt(paramRowsSpanned) - 1
else
rowsSpanned := 0;
if (colsSpanned <> 0) or (rowsSpanned <> 0) then
FWorksheet.MergeCells(row, col, row+rowsSpanned, col+colsSpanned);
paramColsRepeated := GetAttrValue(cellNode, 'table:number-columns-repeated');
if paramColsRepeated = '' then paramColsRepeated := '1';
end
else
if (paramValueType = 'float') or (paramValueType = 'percentage') or
(paramValueType = 'currency')
then
ReadNumber(row, col, cellNode)
else if (paramValueType = 'date') or (paramValueType = 'time') then
ReadDateTime(row, col, cellNode)
else if (paramValueType = '') and (tableStyleName <> '') then
ReadBlank(row, col, cellNode);
if nodeName = 'table:covered-table-cell' then
begin
paramColsRepeated := GetAttrValue(cellNode, 'table:number-columns-repeated');
if paramColsRepeated = '' then paramColsRepeated := '1';
end else
paramColsRepeated := '0';
if ParamFormula <> '' then
ReadFormula(row, col, cellNode);
paramColsSpanned := GetAttrValue(cellNode, 'table:number-columns-spanned');
if paramColsSpanned <> '' then
colsSpanned := StrToInt(paramColsSpanned) - 1
else
colsSpanned := 0;
paramRowsSpanned := GetAttrValue(cellNode, 'table:number-rows-spanned');
if paramRowsSpanned <> '' then
rowsSpanned := StrToInt(paramRowsSpanned) - 1
else
rowsSpanned := 0;
if (colsSpanned <> 0) or (rowsSpanned <> 0) then
FWorksheet.MergeCells(row, col, row+rowsSpanned, col+colsSpanned);
paramColsRepeated := GetAttrValue(cellNode, 'table:number-columns-repeated');
if paramColsRepeated = '' then paramColsRepeated := '1';
col := col + StrToInt(paramColsRepeated);
cellNode := cellNode.NextSibling;
end; //while Assigned(cellNode)
@ -3056,7 +3066,8 @@ begin
cell := ASheet.FindCell(r, c);
// Belongs to merged block?
if (cell <> nil) and not FWorksheet.IsMergeBase(cell) and (cell^.MergedNeighbors <> []) then
// if (cell <> nil) and not FWorksheet.IsMergeBase(cell) and (cell^.MergedNeighbors <> []) then
if (cell <> nil) and not FWorksheet.IsMergeBase(cell) and (cell^.MergeBase <> nil) then
begin
AppendToStream(AStream,
'<table:covered-table-cell />');

View File

@ -435,7 +435,8 @@ type
BoolValue: Boolean;
ErrorValue: TsErrorValue;
SharedFormulaBase: PCell; // Cell containing the shared formula
MergedNeighbors: TsCellBorders;
MergeBase: PCell; // Upper left cell if a merged range
//MergedNeighbors: TsCellBorders;
{ Formatting fields }
{ When adding/deleting formatting fields don't forget to update CopyFormat! }
UsedFormattingFields: TsUsedFormattingFields;
@ -583,6 +584,7 @@ type
function FindMergedRange(ACell: PCell; out ARow1, ACol1, ARow2, ACol2: Cardinal): Boolean;
procedure GetMergedCellRanges(out AList: TsCellRangeArray);
function IsMergeBase(ACell: PCell): Boolean;
function IsMerged(ACell: PCell): Boolean;
{ Writing of values }
function WriteBlank(ARow, ACol: Cardinal): PCell; overload;
@ -2918,69 +2920,13 @@ begin
if (ARow1 = ARow2) and (ACol1 = ACol2) then
exit;
// Case 2: single row
if (ARow1 = ARow2) and (ACol1 <> ACol2) then begin
cell := GetCell(ARow1, ACol1);
cell^.MergedNeighbors := [cbEast];
cell := GetCell(ARow2, ACol2);
cell^.MergedNeighbors := [cbWest];
for c := ACol1+1 to ACol2-1 do begin
cell := GetCell(ARow1, c);
cell^.MergedNeighbors := [cbEast, cbWest];
base := GetCell(ARow1, ACol1);
for r := ARow1 to ARow2 do
for c := ACol1 to ACol2 do
begin
cell := GetCell(r, c);
cell^.MergeBase := base;
end;
end else
// Case 3: single column
if (ARow1 <> ARow2) and (ACol1 = ACol2) then begin
cell := GetCell(ARow1, ACol1);
cell^.MergedNeighbors := [cbSouth];
cell := GetCell(ARow2, ACol2);
cell^.MergedNeighbors := [cbNorth];
for r := ARow1+1 to ARow2-1 do begin
cell := GetCell(r, ACol1);
cell^.MergedNeighbors := [cbNorth, cbSouth];
end;
end else
// case 4: general case
begin
// left/top corner
cell := GetCell(ARow1, ACol1);
cell^.MergedNeighbors := [cbEast, cbSouth];
// right/top corner
cell := GetCell(ARow1, ACol2);
cell^.MergedNeighbors := [cbWest, cbSouth];
// left/bottom corner
cell := GetCell(ARow2, ACol1);
cell^.MergedNeighbors := [cbEast, cbNorth];
// right/bottom corner
cell := GetCell(ARow2, ACol2);
cell^.MergedNeighbors := [cbWest, cbNorth];
// top row
for c := ACol1+1 to ACol2-1 do begin
cell := GetCell(ARow1, c);
cell^.MergedNeighbors := [cbSouth, cbEast, cbWest];
end;
// bottom row
for c := ACol1+1 to ACol2-1 do begin
cell := GetCell(ARow2, c);
cell^.MergedNeighbors := [cbNorth, cbEast, cbWest];
end;
// left column
for r := ARow1+1 to ARow2-1 do begin
cell := GetCell(r, ACol1);
cell^.MergedNeighbors := [cbEast, cbNorth, cbSouth];
end;
// right column
for r := ARow1+1 to ARow2-1 do begin
cell := GetCell(r, ACol2);
cell^.MergedNeighbors := [cbWest, cbNorth, cbSouth];
end;
// inner
for r := ARow1+1 to ARow2-1 do
for c := ACol1+1 to ACol2-1 do begin
cell := GetCell(r, c);
cell^.MergedNeighbors := [cbEast, cbWest, cbNorth, cbSouth];
end;
end;
ChangedCell(ARow1, ACol1);
end;
@ -3008,9 +2954,9 @@ end;
}
procedure TsWorksheet.UnmergeCells(ARow, ACol: Cardinal);
var
cell: PCell;
r, c: Cardinal;
r1, c1, r2, c2: Cardinal;
cell: PCell;
begin
cell := FindCell(ARow, ACol);
if not FindMergedRange(cell, r1, c1, r2, c2) then
@ -3020,7 +2966,8 @@ begin
begin
cell := FindCell(r, c);
if cell <> nil then
cell^.MergedNeighbors := [];
cell^.MergeBase := nil;
// cell^.MergedNeighbors := [];
end;
ChangedCell(ARow, ACol);
end;
@ -3054,6 +3001,13 @@ end;
nil.
}
function TsWorksheet.FindMergeBase(ACell: PCell): PCell;
begin
if ACell = nil then
Result := nil
else
Result := ACell^.MergeBase;
end;
(*
var
r, c: Cardinal;
begin
@ -3072,7 +3026,7 @@ begin
Result := FindCell(r, c);
end;
end;
*)
{@@
Determines the merged cell block to which a given cell belongs
@ -3090,15 +3044,38 @@ function TsWorksheet.FindMergedRange(ACell: PCell;
var
r, c: Cardinal;
cell: PCell;
base: PCell;
begin
cell := FindMergeBase(ACell);
if cell = nil then begin
base := FindMergeBase(ACell);
if base = nil then begin
Result := false;
exit;
end;
ARow1 := cell^.Row;
ACol1 := cell^.Col;
// Assuming that the merged block is rectangular, we start at merge base...
ARow1 := base^.Row;
ARow2 := ARow1;
ACol1 := base^.Col;
ACol2 := ACol1;
// ... and go along first COLUMN to find the end of the merged block, ...
for c := ACol1+1 to GetLastColIndex do
begin
cell := FindCell(ARow1, c);
if (cell = nil) or (cell^.MergeBase <> base) then
break
else
ACol2 := c;
end;
// ... and go along first ROW to find the end of the merged block
for r := ARow1 + 1 to GetLastRowIndex do
begin
cell := FindCell(r, ACol1);
if (cell = nil) or (cell^.MergeBase <> base) then
break
else
ARow2 := r;
end;
{
while (cell <> nil) and (cbSouth in cell^.MergedNeighbors) do begin
inc(ARow2);
cell := FindCell(ARow2, ACol1);
@ -3116,6 +3093,7 @@ begin
Result := false;
exit;
end;
}
Result := true;
end;
@ -3145,9 +3123,9 @@ begin
SetLength(AList, n+1);
AList[n] := rng;
inc(n);
c := rng.Col2; // jump to next cell not belonging to this block
c := rng.Col2; // jump to last cell of block
end;
inc(c);
inc(c); // go to next cell
end;
end;
end;
@ -3161,11 +3139,24 @@ end;
}
function TsWorksheet.IsMergeBase(ACell: PCell): Boolean;
begin
Result := (ACell <> nil) and (ACell = ACell^.MergeBase);
{
Result := (ACell <> nil) and (
(ACell^.MergedNeighbors = [cbEast]) or // single row
(ACell^.MergedNeighbors = [cbSouth]) or // single column
(ACell^.MergedNeighbors = [cbEast, cbSouth]) // 2d
);
}
end;
{@@ Returns TRUE if the specified cell belongs to a merged block
@param ACell Pointer to the cell of interest
@return TRUE if the cell belongs to a merged block, FALSE if not.
}
function TsWorksheet.IsMerged(ACell: PCell): Boolean;
begin
Result := (ACell <> nil) and (ACell^.MergeBase <> nil);
end;
{@@
@ -5033,36 +5024,50 @@ var
begin
col := PtrInt(arg);
cell := PCell(data);
if cell = nil then // This should not happen. Just to make sure...
exit;
// Update column index of moved cells
if cell^.Col >= col then
if (cell^.Col >= col) then
// Update column index of moved cell
inc(cell^.Col);
// Update formulas
// (1) create an rpn formula
formula := BuildRPNFormula(cell);
// (2) update cell addresses affected by the insertion of a column
for i:=0 to Length(formula)-1 do begin
fe := Formula[i]; // "fe" means "formula element"
case fe.ElementKind of
fekCell, fekCellRef:
if fe.Col >= col then inc(fe.Col);
fekCellRange:
begin
if fe.Col >= col then inc(fe.Col);
if fe.Col2 >= col then inc(fe.Col2);
if HasFormula(cell) then
begin
{
if cell^.SharedFormulaBase <> cell then
begin
newCell := GetCell(cell^.Row, col);
newCell^.SharedFormulaBase := cell^.SharedFormulaBasse;
end else
}
begin
// (1) create an rpn formula
formula := BuildRPNFormula(cell);
// (2) update cell addresses affected by the insertion of a column
for i:=0 to Length(formula)-1 do
begin
fe := Formula[i]; // "fe" means "formula element"
case fe.ElementKind of
fekCell, fekCellRef:
if fe.Col >= col then inc(fe.Col);
fekCellRange:
begin
if fe.Col >= col then inc(fe.Col);
if fe.Col2 >= col then inc(fe.Col2);
end;
end;
end;
// (3) convert rpn formula back to string formula
cell^.FormulaValue := ConvertRPNFormulaToStringFormula(formula);
end;
end;
// (3) convert rpn formula back to string formula
cell^.FormulaValue := ConvertRPNFormulaToStringFormula(formula);
end;
{@@
Inserts a column BEFORE the index specified. Cells with greater column indexes are
moved one column up. Cell references in rpn formulas are considered as well.
However, lacking a parser for string formulas, references in string formulas
are not changed which may lead to incorrect operation!
moved one column to the right. Merged cell blocks and cell references in formulas
are considered as well.
@param ACol Index of the column before which a new column is inserted.
}
@ -5071,6 +5076,9 @@ var
cellnode: TAVLTreeNode;
col: PCol;
i: Integer;
r, c: Cardinal;
r1, c1, r2, c2: Cardinal;
cell, nextcell, gapcell: PCell;
begin
// Update column index of cell records
cellnode := FCells.FindLowest;
@ -5079,6 +5087,26 @@ begin
cellnode := FCells.FindSuccessor(cellnode);
end;
// Fix merged cells: If the inserted column runs through a block of merged
// cells the block is cut into two pieces. Here we fill the gap with dummy
// cells and set their MergeBase correctly.
for r := 0 to GetLastRowIndex do
for c := 0 to GetLastColIndex do
begin
cell := FindCell(r, c);
if IsMergeBase(cell) then begin
FindMergedRange(cell, r1, c1, r2, c2);
if ACol = c2 + 1 then begin
nextcell := FindCell(r, ACol + 1);
if Assigned(nextcell) and (nextcell^.MergeBase = cell) then
begin
gapcell := GetCell(r, ACol);
gapcell^.MergeBase := cell;
end;
end;
end;
end;
// Update column index of column records
for i:=0 to FCols.Count-1 do begin
col := PCol(FCols.Items[i]);
@ -5106,31 +5134,33 @@ begin
if cell^.Row >= row then
inc(cell^.Row);
// Update rpn formulas
// (1) create an rpn formula
formula := BuildRPNFormula(cell);
// (2) update cell addresses affected by the insertion of a column
for i:=0 to Length(formula)-1 do begin
fe := formula[i]; // "fe" means "formula element"
case fe.ElementKind of
fekCell, fekCellRef:
if fe.Row >= row then inc(fe.Row);
fekCellRange:
begin
// Update formulas
if HasFormula(cell) then
begin
// (1) create an rpn formula
formula := BuildRPNFormula(cell);
// (2) update cell addresses affected by the insertion of a column
for i:=0 to Length(formula)-1 do begin
fe := formula[i]; // "fe" means "formula element"
case fe.ElementKind of
fekCell, fekCellRef:
if fe.Row >= row then inc(fe.Row);
if fe.Row2 >= row then inc(fe.Row2);
end;
fekCellRange:
begin
if fe.Row >= row then inc(fe.Row);
if fe.Row2 >= row then inc(fe.Row2);
end;
end;
end;
// (3) convert rpn formula back to string formula
cell^.FormulaValue := ConvertRPNFormulaToStringFormula(formula);
end;
// (3) convert rpn formula back to string formula
cell^.FormulaValue := ConvertRPNFormulaToStringFormula(formula);
end;
{@@
Inserts a row BEFORE the row specified. Cells with greater row indexes are
moved one row up. Cell references in rpn formulas are considered as well.
However, lacking a parser for string formulas, references in string formulas
are not changed which may lead to incorrect operation!
moved one row down. Merged cell blocks and cell references in formulas are
considered as well.
@param ARow Index of the row before which a new row is inserted.
}
@ -5139,6 +5169,8 @@ var
row: PRow;
cellnode: TAVLTreeNode;
i: Integer;
r, c, r1, c1, r2, c2: Cardinal;
cell, nextcell, gapcell: PCell;
begin
// Update row index of cell records
cellnode := FCells.FindLowest;
@ -5147,6 +5179,26 @@ begin
cellnode := FCells.FindSuccessor(cellnode);
end;
// Fix merged cells: If the inserted row runs through a block of merged
// cells the block is cut into two pieces. Here we fill the gap with dummy
// cells and set their MergeBase correctly.
for r := 0 to GetLastRowIndex do
for c := 0 to GetLastColIndex do
begin
cell := FindCell(r, c);
if IsMergeBase(cell) then begin
FindMergedRange(cell, r1, c1, r2, c2);
if ARow = r2 + 1 then begin
nextcell := FindCell(ARow + 1, c);
if Assigned(nextcell) and (nextcell^.MergeBase = cell) then
begin
gapcell := GetCell(ARow, c);
gapcell^.MergeBase := cell;
end;
end;
end;
end;
// Update row index of row records
for i:=0 to FRows.Count-1 do begin
row := PRow(FRows.Items[i]);

View File

@ -1489,7 +1489,8 @@ begin
then
Continue;
// Overflow possible from non-merged, non-right-aligned, horizontal label cells
if (cell^.MergedNeighbors = []) and (cell^.ContentType = cctUTF8String) and
// if (cell^.MergedNeighbors = []) and (cell^.ContentType = cctUTF8String) and
if (cell^.MergeBase = nil) and (cell^.ContentType = cctUTF8String) and
not (uffTextRotation in cell^.UsedFormattingFields) and
(uffHorAlign in cell^.UsedFormattingFields) and (cell^.HorAlignment <> haRight)
then
@ -1514,7 +1515,8 @@ begin
then
continue;
// Overflow possible from non-merged, horizontal, non-left-aligned label cells
if (cell^.MergedNeighbors = []) and (cell^.ContentType = cctUTF8String) and
// if (cell^.MergedNeighbors = []) and (cell^.ContentType = cctUTF8String) and
if (cell^.MergeBase = nil) and (cell^.ContentType = cctUTF8String) and
not (uffTextRotation in cell^.UsedFormattingFields) and
(uffHorAlign in cell^.UsedFormattingFields) and (cell^.HorAlignment <> haLeft)
then
@ -1535,7 +1537,9 @@ begin
if Assigned(FWorksheet) and (gr >= FixedRows) and (gc >= FixedCols) then
begin
cell := FWorksheet.FindCell(GetWorksheetRow(gr), GetWorksheetCol(gc));
if (cell = nil) or (cell^.MergedNeighbors = []) then begin
//if (cell = nil) or (cell^.MergedNeighbors = []) then begin
if (cell = nil) or (cell^.Mergebase = nil) then
begin
// single cell
FDrawingCell := cell;
if FTextOverflow then
@ -2265,7 +2269,9 @@ begin
lCell := FWorksheet.FindCell(ARow-FHeaderCount, ACol-FHeaderCount);
if lCell <> nil then begin
if lCell^.MergedNeighbors <> [] then begin
//if lCell^.MergedNeighbors <> [] then begin
if (lCell^.Mergebase <> nil) then
begin
FWorksheet.FindMergedRange(lCell, r1, c1, r2, c2);
if r1 <> r2 then
// If the merged range encloses several rows we skip automatic row height
@ -2323,7 +2329,7 @@ end;
@param ACol Grid column index of the cell
@param ARow Grid row index of the cell
@return Text to be displayed in the cell.
}
}
function TsCustomWorksheetGrid.GetCellText(ACol, ARow: Integer): String;
var
lCell: PCell;
@ -2362,7 +2368,6 @@ begin
end;
end;
end;
// else Result := 'NIL';
end;
end;
@ -2374,7 +2379,7 @@ end;
@param ACol Grid column index of the cell being edited
@param ARow Grid row index of the grid cell being edited
@return Text to be passed to the cell editor.
}
}
function TsCustomWorksheetGrid.GetEditText(aCol, aRow: Integer): string;
begin
Result := GetCellText(aCol, aRow);
@ -2383,7 +2388,9 @@ end;
{ Determines the style of the border between a cell and its neighbor given by
ADeltaCol and ADeltaRow (one of them must be 0, the other one can only be +/-1).
ACol and ARow are in grid units. }
ACol and ARow are in grid units.
Result is FALSE if there is no border line.
}
function TsCustomWorksheetGrid.GetBorderStyle(ACol, ARow, ADeltaCol, ADeltaRow: Integer;
out ABorderStyle: TsCellBorderStyle): Boolean;
var
@ -2408,37 +2415,46 @@ begin
border := cbSouth;
neighborBorder := cbNorth;
end else
raise Exception.Create('TsCustomWorksheetGrid: incorrect col/row for GetBorderStyle.');
raise Exception.Create('[TsCustomWorksheetGrid] Incorrect col/row for GetBorderStyle.');
r := GetWorksheetRow(ARow);
c := GetWorksheetCol(ACol);
cell := FWorksheet.FindCell(r, c);
if (r+ADeltaRow < 0) or (c + ADeltaCol < 0) then
if (ARow - FHeaderCount + ADeltaRow < 0) or (ACol - FHeaderCount + ADeltaCol < 0) then
neighborcell := nil
else
neighborcell := FWorksheet.FindCell(r+ADeltaRow, c+ADeltaCol);
neighborcell := FWorksheet.FindCell(ARow - FHeaderCount + ADeltaRow, ACol - FHeaderCount + ADeltaCol);
// Only cell has border, but neighbor has not
if HasBorder(cell, border) and not HasBorder(neighborCell, neighborBorder) then
{ if ((cell <> nil) and (border in cell^.Border)) and
((neighborcell = nil) or (neighborborder in neighborcell^.Border))
then }
ABorderStyle := cell^.BorderStyles[border]
begin
if FWorksheet.IsMerged(cell) and FWorksheet.IsMerged(neighborcell) and
(cell^.MergeBase = neighborcell^.Mergebase)
then
result := false
else
ABorderStyle := cell^.BorderStyles[border]
end
else
// Only neighbor has border, cell has not
if not HasBorder(cell, border) and HasBorder(neighborCell, neighborBorder) then
{
if ((cell = nil) or not (border in cell^.Border)) and
(neighborcell <> nil) and (neighborborder in neighborcell^.Border)
then
}
ABorderStyle := neighborcell^.BorderStyles[neighborborder]
begin
if FWorksheet.IsMerged(cell) and FWorksheet.IsMerged(neighborcell) and
(cell^.MergeBase = neighborcell^.Mergebase)
then
result := false
else
ABorderStyle := neighborcell^.BorderStyles[neighborborder]
end
else
// Both cells have shared border -> use top or left border
if HasBorder(cell, border) and HasBorder(neighborCell, neighborBorder) then begin
{
if (cell <> nil) and (border in cell^.Border) and
(neighborcell <> nil) and (neighborborder in neighborcell^.Border)
then begin
}
if HasBorder(cell, border) and HasBorder(neighborCell, neighborBorder) then
begin
if FWorksheet.IsMerged(cell) and FWorksheet.IsMerged(neighborcell) and
(cell^.MergeBase = neighborcell^.Mergebase)
then
result := false
else
if (border in [cbNorth, cbWest]) then
ABorderStyle := neighborcell^.BorderStyles[neighborborder]
else
@ -2457,7 +2473,7 @@ end;
}
function TsCustomWorksheetGrid.GetGridCol(ASheetCol: Cardinal): Integer;
begin
Result := ASheetCol + FHeaderCount
Result := Integer(ASheetCol) + FHeaderCount
end;
{@@
@ -2470,7 +2486,7 @@ end;
}
function TsCustomWorksheetGrid.GetGridRow(ASheetRow: Cardinal): Integer;
begin
Result := ASheetRow + FHeaderCount;
Result := Integer(ASheetRow) + FHeaderCount;
end;
function TsCustomWorksheetGrid.GetHorAlignment(ACol, ARow: Integer): TsHorAlignment;
@ -2700,7 +2716,7 @@ begin
if AGridCol < FHeaderCount then
exit;
if FWorksheet.GetLastColIndex+1 + FHeaderCount >= FInitColCount then
if FWorksheet.GetLastColIndex + 1 + FHeaderCount >= FInitColCount then
ColCount := ColCount + 1;
c := AGridCol - FHeaderCount;
FWorksheet.InsertCol(c);
@ -2833,7 +2849,7 @@ begin
P := ARect.TopLeft;
case AJustification of
0: ts.Alignment := taLeftJustify;
1: if (FDrawingCell <> nil) and (FDrawingCell^.MergedNeighbors = []) then
1: if (FDrawingCell <> nil) and (FDrawingCell^.MergeBase = nil) then //(FDrawingCell^.MergedNeighbors = []) then
begin
// Special treatment for overflowing cells: they must be centered
// at their original column, not in the total enclosing rectangle.