From 2252e04cecc89e87faf3657a764d55570f05086d Mon Sep 17 00:00:00 2001 From: wp_xxyyzz Date: Thu, 19 Mar 2015 11:40:07 +0000 Subject: [PATCH] fpspreadsheet: Improve copying of multiple cells in the WorksheetGrid. Fix worksheet not deleting formula if a blank cell is written. git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@4054 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- components/fpspreadsheet/fpspreadsheet.pas | 6 +- .../fpspreadsheet/fpspreadsheetctrls.pas | 89 +++++++++++++++---- 2 files changed, 76 insertions(+), 19 deletions(-) diff --git a/components/fpspreadsheet/fpspreadsheet.pas b/components/fpspreadsheet/fpspreadsheet.pas index 3a9476638..c143ea80f 100755 --- a/components/fpspreadsheet/fpspreadsheet.pas +++ b/components/fpspreadsheet/fpspreadsheet.pas @@ -1887,7 +1887,6 @@ begin RemoveAndFreeCell(ACell^.Row, ACell^.Col); end; - {@@ ---------------------------------------------------------------------------- Internal call-back procedure for looping through all cells when deleting a specified column. Deletion happens in DeleteCol BEFORE this callback! @@ -3713,7 +3712,7 @@ end; On formats that don't support unicode, the text will be converted to ISO Latin 1. - @param ACell Poiner to the cell + @param ACell Pointer to the cell @param AText The text to be written encoded in utf-8 -------------------------------------------------------------------------------} procedure TsWorksheet.WriteUTF8Text(ACell: PCell; AText: ansistring); @@ -3938,6 +3937,7 @@ end; procedure TsWorksheet.WriteBlank(ACell: PCell); begin if ACell <> nil then begin + ACell^.FormulaValue := ''; if HasHyperlink(ACell) then WriteUTF8Text(ACell, '') // '' will be replaced by the hyperlink target. else @@ -4001,7 +4001,7 @@ end; string, the worksheet tries to guess whether it is a number, a date/time or a text and calls the corresponding writing method. - @param ACell Poiner to the cell + @param ACell Pointer to the cell @param AValue Value to be written into the cell given as a string. Depending on the structure of the string, however, the value is written as a number, a date/time or a text. diff --git a/components/fpspreadsheet/fpspreadsheetctrls.pas b/components/fpspreadsheet/fpspreadsheetctrls.pas index 9f7621361..01d834cf9 100644 --- a/components/fpspreadsheet/fpspreadsheetctrls.pas +++ b/components/fpspreadsheet/fpspreadsheetctrls.pas @@ -467,6 +467,7 @@ end; type TsCellList = class(TList) private + FMultipleRanges: Boolean; function GetCell(AIndex: Integer): PCell; procedure SetCell(AIndex: Integer; ACell: PCell); public @@ -478,6 +479,7 @@ type procedure Delete(AIndex: Integer); function IndexOf(ACell: PCell): Integer; property CellByIndex[AIndex: Integer]: PCell read GetCell write SetCell; + property MultipleRanges: Boolean read FMultipleRanges write FMultipleRanges; end; var @@ -1086,6 +1088,7 @@ end; procedure TsWorkbookSource.ClearCellClipboard; begin CellClipboard.Clear; + CellClipboard.MultipleRanges := false; end; {@@ ---------------------------------------------------------------------------- @@ -1115,6 +1118,8 @@ begin else CellClipboard.AddCell(cell); end; + + CellClipboard.MultipleRanges := (Length(sel) > 1); end; {@@ ---------------------------------------------------------------------------- @@ -1137,9 +1142,12 @@ end; -------------------------------------------------------------------------------} procedure TsWorkbookSource.PasteCellsFromClipboard(AItem: TsCopyOperation); var - r, c, dr, dc: LongInt; - i: Integer; + r, c, dr, dc, destRow, destCol: LongInt; + i, j: Integer; cell: PCell; + baserng, rng: TsCellRange; + nc, nr: Integer; + baseRow, baseCol: Cardinal; begin if CellClipboard.Count = 0 then exit; @@ -1160,24 +1168,73 @@ begin end; cell := CellClipboard.CellByIndex[0]; - dr := FWorksheet.ActiveCellRow - cell^.Row; - dc := FWorksheet.ActiveCellCol - cell^.Col; + baseRow := cell^.Row; + baseCol := cell^.Col; - for i:=0 to CellClipboard.Count-1 do + if CellClipboard.MultipleRanges then begin - cell := CellClipboard.CellByIndex[i]; - case AItem of - coCopyCell: - FWorksheet.CopyCell(cell^.Row, cell^.Col, LongInt(cell^.Row) + dr, LongInt(cell^.Col) + dc); - coCopyValue: - FWorksheet.CopyValue(cell, LongInt(cell^.Row) + dr, LongInt(cell^.Col) + dc); - coCopyFormat: - FWorksheet.CopyFormat(cell, LongInt(cell^.Row) + dr, LongInt(cell^.Col) + dc); - coCopyFormula: - FWorksheet.CopyFormula(cell, LongInt(cell^.Row) + dr, LongInt(cell^.Col) + dc); + dr := FWorksheet.ActiveCellRow - baseRow; + dc := FWorksheet.ActiveCellCol - baseCol; + for i:=0 to CellClipboard.Count-1 do + begin + cell := CellClipboard.CellByIndex[i]; + case AItem of + coCopyCell: + FWorksheet.CopyCell(cell^.Row, cell^.Col, LongInt(cell^.Row) + dr, LongInt(cell^.Col) + dc); + coCopyValue: + FWorksheet.CopyValue(cell, LongInt(cell^.Row) + dr, LongInt(cell^.Col) + dc); + coCopyFormat: + FWorksheet.CopyFormat(cell, LongInt(cell^.Row) + dr, LongInt(cell^.Col) + dc); + coCopyFormula: + FWorksheet.CopyFormula(cell, LongInt(cell^.Row) + dr, LongInt(cell^.Col) + dc); + end; + end; + end else + begin + // Determine cell range enclosed by cells in clipboard + baserng.Row1 := MaxInt; + baserng.Col1 := MaxInt; + baserng.Row2 := 0; + baserng.Col2 := 0; + for i :=0 to CellClipboard.Count-1 do + begin + cell := CellClipboard.CellByIndex[i]; + baserng.Row1 := Min(baserng.Row1, cell^.Row); + baserng.Row2 := Max(baserng.Row2, cell^.Row); + baserng.Col1 := Min(baserng.Col1, cell^.Col); + baserng.Col2 := Max(baserng.Col2, cell^.Col); + end; + + // Each selected range of the worksheet gets tiled copies of the range of + // the cells in clipboard + for j:=0 to FWorksheet.GetSelectionCount-1 do + begin + rng := FWorksheet.GetSelection[j]; + r := rng.Row1; + while (r <= rng.Row2) do begin + c := rng.Col1; + while (c <= rng.Col2) do begin + for i:=0 to CellClipboard.Count-1 do begin + cell := CellClipboard.CellByIndex[i]; + destRow := r + LongInt(cell^.Row) - baserng.Row1; + destCol := c + LongInt(cell^.Col) - baserng.Col1; + case AItem of + coCopyCell: + FWorksheet.CopyCell(cell^.Row, cell^.Col, destRow, destCol); + coCopyValue: + FWorksheet.CopyValue(cell, destRow, destCol); + coCopyFormat: + FWorksheet.CopyFormat(cell, destRow, destCol); + coCopyFormula: + FWorksheet.CopyFormula(cell, destRow, destCol); + end; + end; + inc(c, baserng.Col2 - baserng.Col1 + 1); + end; + inc(r, baserng.Row2 - baserng.Row1 + 1); + end; end; end; - finally EnableControls; end;