fpspreadsheet: Add method TsWorksheet.MoveCell (forum https://forum.lazarus.freepascal.org/index.php/topic,59137).

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@8260 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz 2022-04-22 20:12:08 +00:00
parent b4ac1e075d
commit 02bd21629c
2 changed files with 86 additions and 12 deletions

View File

@ -197,6 +197,8 @@ type
function FindFormula(ARow, ACol: Cardinal): PsFormula; overload;
procedure FixReferences(AIndex: Cardinal; IsRow, IsDeleting: Boolean;
InSheet: TsBasicWorksheet);
procedure FixReferenceToMovedCell(ACell: PCell; AToRow, AToCol: Cardinal;
ASheet: TsBasicWorksheet);
// enumerators
function GetEnumerator: TsFormulaEnumerator;
end;
@ -474,6 +476,26 @@ begin
end;
end;
procedure FixFormulaToMovedCell(AExprNode: TsExprNode; AData1, AData2: Pointer;
var MustRebuildFormulas: Boolean);
var
oldCell, newCell: PCell;
begin
oldCell := PCell(AData1);
newCell := PCell(AData2);
if AExprNode is TsCellExprNode then
begin
if (oldCell^.Worksheet = TsCellExprNode(AExprNode).GetSheet) and
(oldCell^.Row = TsCellExprNode(AExprNode).Row) and
(oldCell^.Col = TsCellExprNode(AExprNode).Col) then
begin
TsCellExprNode(AExprNode).Row := newCell^.Row;
TsCellExprNode(AExprNode).Col := newCell^.Col;
MustRebuildFormulas := true;
end;
end;
end;
{==============================================================================}
{ TsRowColEnumerator }
@ -1571,6 +1593,24 @@ begin
formula^.Text := formula^.Parser.Expression[fdExcelA1];
end;
{ A cell in the specified sheet has been moved from its old location at AFromRow/
AFromCol to a new location at AToRow/AToCol. If the cell is referenced by
a formula the formula must be adjusted such it points to the new location.
However, this occurs only when the reference is a single cell, not a cell range.}
procedure TsFormulas.FixReferenceToMovedCell(
ACell: PCell; AToRow, AToCol: Cardinal; ASheet: TsBasicWorksheet);
var
formula: PsFormula;
newCell: TCell;
begin
newCell := ACell^;
newCell.Row := AToRow;
newCell.Col := AToCol;
for formula in self do
if formula^.Parser.IterateNodes(@FixFormulaToMovedCell, ACell, @newCell) then
formula^.Text := formula^.Parser.Expression[fdExcelA1];
end;
// Formula enumerators (use in "for ... in" syntax)
function TsFormulas.GetEnumerator: TsFormulaEnumerator;
begin

View File

@ -458,6 +458,8 @@ type
function GetCell(AddressStr: String): PCell; overload;
function GetCellCount: Cardinal;
procedure MoveCell(ACell: PCell; AToRow, AToCol: Cardinal);
function FindNextCellInCol(ARow, ACol: Cardinal): PCell;
function FindNextCellInRow(ARow, ACol: Cardinal): PCell;
function FindPrevCellInCol(ARow, ACol: Cardinal): PCell;
@ -2257,6 +2259,50 @@ begin
Result := FCells.Count;
end;
{@@ ----------------------------------------------------------------------------
Moves a cell to a different location.
All additional data (comments, format, hyperlinks, formulas) are moved to the
new location. If the old location was referenced by a formula then the formula
is adjusted so that it points to the new location, however, only if the
formula references a single cell, not a cell range.
@param ACell Cell to be moved
@param AToRow Row index of the new location
@param AToCol Column index of the new location
-------------------------------------------------------------------------------}
procedure TsWorksheet.MoveCell(ACell: PCell; AToRow, AToCol: Cardinal);
var
fromRow, fromCol: Cardinal;
sheet: TsWorksheet;
i: Integer;
begin
if ACell = nil then
exit;
// Store old location
fromRow := ACell^.Row;
fromCol := ACell^.Col;
// Copy cell to new location
CopyCell(fromRow, fromCol, AToRow, AToCol);
// Fix formula references to this cell
for i := 0 to FWorkbook.GetWorksheetcount-1 do begin
sheet := FWorkbook.GetWorksheetByIndex(i);
sheet.Formulas.FixReferenceToMovedCell(ACell, AToRow, AToCol, self);
end;
// Delete cell at old location
DeleteCell(ACell);
// Notify visual controls of changes
ChangedCell(AToRow, AToCol);
// Notify visual controls of possibly changed row heights.
ChangedFont(AToRow, AToCol);
end;
{@@ ----------------------------------------------------------------------------
Determines the number of decimals displayed for the number in the cell
@ -5585,12 +5631,7 @@ var
i: Integer;
rng: PsCellRange;
sheet: TsWorksheet;
wasAutoCalculating: Boolean;
begin
// Turn off auto-calculation of formulas
wasAutoCalculating := (boAutoCalc in Workbook.Options);
//Workbook.Options := Workbook.Options - [boAutoCalc];
// Update row indexes of cell comments
FComments.InsertRowOrCol(AIndex, IsRow);
@ -5685,13 +5726,6 @@ begin
ChangedCell(0, AIndex);
end;
// Calculate formulas
if wasAutoCalculating then
begin
//Workbook.Options := Workbook.Options + [boAutoCalc];
//CalcFormulas;
end;
end;
{@@ ----------------------------------------------------------------------------