From 9365a1dff21962bf6af064ea88c5afaa9972af27 Mon Sep 17 00:00:00 2001 From: wp_xxyyzz Date: Fri, 6 Mar 2015 12:12:45 +0000 Subject: [PATCH] fpspreadsheet: Reduce support for shared formulas (too many problems...), only reading from xls and xlsx files supported. git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3998 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- .../examples/other/demo_write_formula.pas | 10 - components/fpspreadsheet/fpsclasses.pas | 8 +- components/fpspreadsheet/fpscsv.pas | 15 +- components/fpspreadsheet/fpsexprparser.pas | 72 +- components/fpspreadsheet/fpsopendocument.pas | 2 + components/fpspreadsheet/fpspreadsheet.pas | 481 +------- .../fpspreadsheet/fpspreadsheetctrls.pas | 2 + components/fpspreadsheet/fpstypes.pas | 4 +- .../fpspreadsheet/tests/formulatests.pas | 18 +- .../fpspreadsheet/tests/insertdeletetests.pas | 1093 ++--------------- components/fpspreadsheet/xlsbiff2.pas | 19 +- components/fpspreadsheet/xlsbiff8.pas | 33 +- components/fpspreadsheet/xlscommon.pas | 70 +- components/fpspreadsheet/xlsxooxml.pas | 83 +- 14 files changed, 260 insertions(+), 1650 deletions(-) diff --git a/components/fpspreadsheet/examples/other/demo_write_formula.pas b/components/fpspreadsheet/examples/other/demo_write_formula.pas index 05f6e7e08..582efc788 100644 --- a/components/fpspreadsheet/examples/other/demo_write_formula.pas +++ b/components/fpspreadsheet/examples/other/demo_write_formula.pas @@ -63,16 +63,6 @@ begin RPNNumber(5.0, RPNFunc(fekAdd, nil))))); - (* - // Write a shared formula "=E1+100" to the cell range F1:F5 - // Please note that shared formulas are not written by sfOOXML and sfOpenDocument formats. - MyCell := MyWorksheet.WriteRPNFormula(0, 5, CreateRPNFormula( - RPNCellOffset(0, -1, [rfRelRow, rfRelCol], - RPNNumber(100, - RPNFunc(fekAdd, - nil))))); - MyWorksheet.UseSharedFormula('F1:F5', MyCell); - *) end; procedure WriteSecondWorksheet(); diff --git a/components/fpspreadsheet/fpsclasses.pas b/components/fpspreadsheet/fpsclasses.pas index 2269d2b8d..737c79046 100644 --- a/components/fpspreadsheet/fpsclasses.pas +++ b/components/fpspreadsheet/fpsclasses.pas @@ -5,7 +5,7 @@ unit fpsclasses; interface uses - Classes, SysUtils, AVL_Tree, avglvltree, + Classes, SysUtils, AVL_Tree, //avglvltree, fpstypes; type @@ -175,7 +175,8 @@ type implementation uses - Math, fpsUtils; + {%H-}Math, + fpsUtils; { Helper function for sorting } @@ -233,9 +234,6 @@ begin end; function TsRowColEnumerator.MoveNext: Boolean; -var - r1,c1,r2,c2: Cardinal; - item: TsRowCol; begin if FCurrentNode <> nil then begin if FReverse then diff --git a/components/fpspreadsheet/fpscsv.pas b/components/fpspreadsheet/fpscsv.pas index 345b1d521..14b59eb28 100644 --- a/components/fpspreadsheet/fpscsv.pas +++ b/components/fpspreadsheet/fpscsv.pas @@ -602,8 +602,8 @@ end; procedure TsCSVWriter.WriteSheet(AStream: TStream; AWorksheet: TsWorksheet); var - r, c: Cardinal; - LastRow, LastCol: Cardinal; + r: Cardinal; + LastRow: Cardinal; cell: PCell; begin FWorksheet := AWorksheet; @@ -616,23 +616,12 @@ begin FCSVBuilder.SetOutput(AStream); LastRow := FWorksheet.GetLastOccupiedRowIndex; - LastCol := FWorksheet.GetLastOccupiedColIndex; for r := 0 to LastRow do begin for cell in FWorksheet.Cells.GetRowEnumerator(r) do WriteCellToStream(AStream, cell); FCSVBuilder.AppendRow; end; - { - for c := 0 to LastCol do - begin - Cell := FWorksheet.FindCell(r, c); - if Cell <> nil then - WriteCellCallback(Cell, AStream); - if c = LastCol then - FCSVBuilder.AppendRow; - end; - } finally FreeAndNil(FCSVBuilder); end; diff --git a/components/fpspreadsheet/fpsexprparser.pas b/components/fpspreadsheet/fpsexprparser.pas index 60f33bdf5..321805208 100644 --- a/components/fpspreadsheet/fpsexprparser.pas +++ b/components/fpspreadsheet/fpsexprparser.pas @@ -682,7 +682,9 @@ type FDirty: Boolean; FWorksheet: TsWorksheet; FDialect: TsFormulaDialect; - FActiveCell: PCell; + FSourceCell: PCell; + FDestCell: PCell; +// FActiveCell: PCell; procedure CheckEOF; procedure CheckNodes(var ALeft, ARight: TsExprNode); function ConvertNode(Todo: TsExprNode; ToType: TsResultType): TsExprNode; @@ -730,10 +732,11 @@ type destructor Destroy; override; function IdentifierByName(AName: ShortString): TsExprIdentifierDef; virtual; procedure Clear; + function CopyMode: Boolean; function Evaluate: TsExpressionResult; procedure EvaluateExpression(out Result: TsExpressionResult); + procedure PrepareCopyMode(ASourceCell, ADestCell: PCell); function ResultType: TsResultType; - function SharedFormulaMode: Boolean; property AsFloat: TsExprFloat read GetAsFloat; property AsInteger: Int64 read GetAsInteger; @@ -747,7 +750,7 @@ type property RPNFormula: TsRPNFormula read GetRPNFormula write SetRPNFormula; property Identifiers: TsExprIdentifierDefs read FIdentifiers write SetIdentifiers; property BuiltIns: TsBuiltInExprCategories read FBuiltIns write SetBuiltIns; - property ActiveCell: PCell read FActiveCell write FActiveCell; +// property ActiveCell: PCell read FActiveCell write FActiveCell; property Worksheet: TsWorksheet read FWorksheet; property Dialect: TsFormulaDialect read FDialect write FDialect; end; @@ -1299,6 +1302,22 @@ begin end; end; +{ Prepares copy mode: The formula is contained in ASourceCell and will be + modified such as seen from ADestCell. } +procedure TsExpressionParser.PrepareCopyMode(ASourceCell, ADestCell: PCell); +begin + FSourceCell := ASourceCell; + FDestCell := ADestCell; +end; + +{ Signals that the parser is in "CopyMode", i.e. there is are source and + destination cells. All relative references in the formula of the source cell + habe to be adapted as seen from the destination cell. } +function TsExpressionParser.CopyMode: Boolean; +begin + Result := (FDestCell <> nil) and (FSourceCell <> nil); +end; + procedure TsExpressionParser.CreateHashList; var ID: TsExprIdentifierDef; @@ -1975,14 +1994,14 @@ begin CreateNodeFromRPN(FExprNode, index); if Assigned(FExprNode) then FExprNode.Check; end; - +(* { Signals that the parser is in SharedFormulaMode, i.e. there is an active cell to which all relative addresses have to be adapted. } function TsExpressionParser.SharedFormulaMode: Boolean; begin Result := (ActiveCell <> nil) and (ActiveCell^.SharedFormulaBase <> nil); end; - + *) function TsExpressionParser.TokenType: TsTokenType; begin Result := FScanner.TokenType; @@ -3811,37 +3830,27 @@ begin end; { Calculates the row address of the node's cell for various cases: - (1) SharedFormula mode: - The "ActiveCell" of the parser is the cell for which the formula is - calculated. If the formula contains a relative address in the cell node - the function calculates the row address of the cell represented by the - node as seen from the active cell. + (1) Copy mode: + The "DestCell" of the parser is the cell for which the formula is + calculated. The "SourceCell" contains the formula. If the formula contains + a relative address in the cell node the function calculates the row + address of the cell represented by the node as seen from the DestCell. If the formula contains an absolute address the function returns the row - address of the SharedFormulaBase of the ActiveCell. + address of the SourceCell. (2) Normal mode: Returns the "true" row address of the cell assigned to the formula node. } function TsCellExprNode.GetCol: Cardinal; begin - if FParser.SharedFormulaMode then - begin - // A shared formula is stored in the SharedFormulaBase cell of the ActiveCell - // Since the cell data stored in the node are those used by the formula in - // the SharedFormula, the current node is relative to the SharedFormulaBase - if rfRelCol in FFlags then - Result := FCol - FParser.ActiveCell^.SharedFormulaBase^.Col + FParser.ActiveCell^.Col - else - Result := FCol; //FParser.ActiveCell^.SharedFormulaBase^.Col; - end - else - // Normal mode - Result := FCol; + Result := FCol; + if FParser.CopyMode and (rfRelCol in FFlags) then + Result := FCol - FParser.FSourceCell^.Col + FParser.FDestCell^.Col; end; procedure TsCellExprNode.GetNodeValue(out Result: TsExpressionResult); var cell: PCell; begin - if Parser.SharedFormulaMode then + if Parser.CopyMode then cell := FWorksheet.FindCell(GetRow, GetCol) else cell := FCell; @@ -3863,15 +3872,9 @@ end; { See GetCol } function TsCellExprNode.GetRow: Cardinal; begin - if Parser.SharedFormulaMode then - begin - if rfRelRow in FFlags then - Result := FRow - FParser.ActiveCell^.SharedFormulaBase^.Row + FParser.ActiveCell^.Row - else - Result := FRow; //FParser.ActiveCell^.SharedFormulaBase^.Row; - end - else - Result := FRow; + Result := FRow; + if Parser.CopyMode and (rfRelRow in FFlags) then + Result := FRow - FParser.FSourceCell^.Row + FParser.FDestCell^.Row; end; function TsCellExprNode.NodeType: TsResultType; @@ -3998,7 +4001,6 @@ end; function ArgToInt(Arg: TsExpressionResult): Integer; var cell: PCell; - s: String; begin Result := 0; case Arg.ResultType of diff --git a/components/fpspreadsheet/fpsopendocument.pas b/components/fpspreadsheet/fpsopendocument.pas index c1618550c..5366031e7 100755 --- a/components/fpspreadsheet/fpsopendocument.pas +++ b/components/fpspreadsheet/fpsopendocument.pas @@ -4058,11 +4058,13 @@ begin parser := TsSpreadsheetParser.Create(FWorksheet); try parser.Dialect := fdOpenDocument; + { if ACell^.SharedFormulaBase <> nil then begin parser.ActiveCell := ACell; parser.Expression := ACell^.SharedFormulaBase^.FormulaValue; end else + } parser.Expression := ACell^.FormulaValue; formula := Parser.LocalizedExpression[FPointSeparatorSettings]; finally diff --git a/components/fpspreadsheet/fpspreadsheet.pas b/components/fpspreadsheet/fpspreadsheet.pas index 56167f0ab..5848fb578 100755 --- a/components/fpspreadsheet/fpspreadsheet.pas +++ b/components/fpspreadsheet/fpspreadsheet.pas @@ -234,11 +234,6 @@ type procedure WriteRPNFormula(ACell: PCell; AFormula: TsRPNFormula); overload; - procedure WriteSharedFormula(ARow1, ACol1, ARow2, ACol2: Cardinal; - const AFormula: String); overload; - procedure WriteSharedFormula(ACellRange: String; - const AFormula: String); overload; - function WriteUTF8Text(ARow, ACol: Cardinal; AText: ansistring): PCell; overload; procedure WriteUTF8Text(ACell: PCell; AText: ansistring); overload; @@ -330,15 +325,10 @@ type procedure WriteWordwrap(ACell: PCell; AValue: boolean); overload; { Formulas } - function BuildRPNFormula(ACell: PCell): TsRPNFormula; + function BuildRPNFormula(ACell: PCell; ADestCell: PCell = nil): TsRPNFormula; procedure CalcFormula(ACell: PCell); procedure CalcFormulas; function ConvertRPNFormulaToStringFormula(const AFormula: TsRPNFormula): String; - function FindSharedFormulaBase(ACell: PCell): PCell; - function FindSharedFormulaRange(ACell: PCell; out ARow1, ACol1, ARow2, ACol2: Cardinal): Boolean; - procedure FixSharedFormulas; - procedure SplitSharedFormula(ACell: PCell); - function UseSharedFormula(ARow, ACol: Cardinal; ASharedFormulaBase: PCell): PCell; function GetCalcState(ACell: PCell): TsCalcState; procedure SetCalcState(ACell: PCell; AValue: TsCalcState); @@ -586,7 +576,6 @@ type FFontList: TFPList; { Internal methods } - procedure FixSharedFormulas; procedure GetLastRowColIndex(out ALastRow, ALastCol: Cardinal); procedure PrepareBeforeReading; procedure PrepareBeforeSaving; @@ -979,15 +968,13 @@ begin end; {@@ ---------------------------------------------------------------------------- - Returns TRUE if the cell contains a formula (direct or shared, does not matter). + Returns TRUE if the cell contains a formula. @param ACell Pointer to the cell checked -------------------------------------------------------------------------------} function HasFormula(ACell: PCell): Boolean; begin - Result := Assigned(ACell) and ( - (ACell^.SharedFormulaBase <> nil) or (Length(ACell^.FormulaValue) > 0) - ); + Result := Assigned(ACell) and (Length(ACell^.FormulaValue) > 0); end; function CompareCells(Item1, Item2: Pointer): Integer; @@ -1108,11 +1095,14 @@ end; Helper function which constructs an rpn formula from the cell's string formula. This is needed, for example, when writing a formula to xls biff file format. - If the cell belongs to a shared formula the formula is taken from the - shared formula base cell, cell references are adapted accordingly to the - location of the cell. + The formula is stored in ACell. + If ADestCell is not nil then the relative references are adjusted as seen + from ADestCell. This means that this function returns the formula that + would be created if ACell is copied to the location of ADestCell. + Needed for copying formulas and for splitting shared formulas. -------------------------------------------------------------------------------} -function TsWorksheet.BuildRPNFormula(ACell: PCell): TsRPNFormula; +function TsWorksheet.BuildRPNFormula(ACell: PCell; + ADestCell: PCell = nil): TsRPNFormula; var parser: TsSpreadsheetParser; begin @@ -1122,11 +1112,9 @@ begin end; parser := TsSpreadsheetParser.Create(self); try - if (ACell^.SharedFormulaBase <> nil) then begin - parser.ActiveCell := ACell; - parser.Expression := ACell^.SharedFormulaBase^.FormulaValue; - end else - parser.Expression := ACell^.FormulaValue; + if ADestCell <> nil then + parser.PrepareCopyMode(ACell, ADestCell); + parser.Expression := ACell^.FormulaValue; Result := parser.RPNFormula; finally parser.Free; @@ -1145,27 +1133,16 @@ procedure TsWorksheet.CalcFormula(ACell: PCell); var parser: TsSpreadsheetParser; res: TsExpressionResult; - formula: String; - cell: PCell; p: Integer; link, txt: String; + cell: PCell; begin ACell^.Flags := ACell^.Flags + [cfCalculating] - [cfCalculated]; parser := TsSpreadsheetParser.Create(self); try - if ACell^.SharedFormulaBase = nil then - begin - formula := ACell^.FormulaValue; - parser.ActiveCell := nil; - end else - begin - formula := ACell^.SharedFormulaBase^.FormulaValue; - parser.ActiveCell := ACell; - end; - try - parser.Expression := formula; + parser.Expression := ACell^.FormulaValue; res := parser.Evaluate; except on E:ECalcEngine do @@ -1248,9 +1225,7 @@ begin node := FCells.FindLowest; while Assigned(node) do begin cell := PCell(node.Data); - if (cell^.ContentType <> cctError) and - (HasFormula(cell) or HasFormula(cell^.SharedFormulaBase)) - then + if (cell^.ContentType <> cctError) and HasFormula(cell) then CalcFormula(cell); node := FCells.FindSuccessor(node); end; @@ -1496,7 +1471,6 @@ end; function TsWorksheet.ValidHyperlink(AValue: String; out AErrMsg: String): Boolean; var uri: TUri; - mark: String; sheet: TsWorksheet; r, c: Cardinal; begin @@ -1664,7 +1638,7 @@ begin if IsMergeBase(AFromCell) then begin FindMergedRange(AFromCell, row1, col1, row2, col2); - MergeCells(toRow, toCol, toRow + row2 - row1, toCol + col2 - col1); + MergeCells(toRow, toCol, toRow + LongInt(row2) - LongInt(row1), toCol + LongInt(col2) - LongInt(col1)); end; // Copy comment @@ -1743,7 +1717,6 @@ end; procedure TsWorksheet.CopyFormula(AFromCell, AToCell: PCell); var rpnFormula: TsRPNFormula; - lCell: TCell; begin if (AFromCell = nil) or (AToCell = nil) then exit; @@ -1753,11 +1726,7 @@ begin else begin // Here we convert the formula to an rpn formula as seen from source... - // (The mechanism needs the ActiveCell of the parser which is only - // valid if the cell contains a shared formula) - lCell := AToCell^; - lCell.SharedFormulaBase := AFromCell; - rpnFormula := BuildRPNFormula(@lCell); + rpnFormula := BuildRPNFormula(AFromCell, AToCell); // ... and here we reconstruct the string formula as seen from destination cell. AToCell^.FormulaValue := ConvertRPNFormulaToStringFormula(rpnFormula); end; @@ -1811,7 +1780,7 @@ end; {@@ ---------------------------------------------------------------------------- Deletes a specified cell. If the cell belongs to a merged block its content - and formatting is erased. Otherwise the cell is destroyed, its memory is + and formatting is erased. Otherwise the cell is destroyed and its memory is released. -------------------------------------------------------------------------------} procedure TsWorksheet.DeleteCell(ACell: PCell); @@ -1831,12 +1800,6 @@ begin exit; end; - // Is base of shared formula block? Recreate individual formulas - if ACell^.SharedFormulaBase = ACell then - SplitSharedFormula(ACell); - - // Belongs to shared formula block? --> nothing to do - // Destroy the cell, and remove it from the tree RemoveAndFreeCell(ACell^.Row, ACell^.Col); end; @@ -2619,7 +2582,6 @@ end; {@@ ---------------------------------------------------------------------------- If a cell contains a formula (string formula or RPN formula) the formula is returned as a string in Excel syntax. - If the cell belongs to a shared formula the adapted shared formula is returned. @param ACell Pointer to the cell considered @param ALocalized If true, the formula is returned with decimal and list @@ -2636,40 +2598,19 @@ begin if ACell = nil then exit; if HasFormula(ACell) then begin - // case (1): Formula is localized and has to be converted to default syntax if ALocalized then begin + // case (1): Formula is localized and has to be converted to default syntax // !!!! Is this comment correct? parser := TsSpreadsheetParser.Create(self); try - if ACell^.SharedFormulaBase <> nil then begin - // case (1a): shared formula - parser.ActiveCell := ACell; - parser.Expression := ACell^.SharedFormulaBase^.FormulaValue; - end else begin - // case (1b): normal formula - parser.ActiveCell := nil; - parser.Expression := ACell^.FormulaValue; - end; + parser.Expression := ACell^.FormulaValue; Result := parser.LocalizedExpression[Workbook.FormatSettings]; finally parser.Free; end; end else - // case (2): Formula is in default syntax - if ACell^.SharedFormulaBase <> nil then - begin - // case (2a): shared formula - parser := TsSpreadsheetParser.Create(self); - try - parser.ActiveCell := ACell; - parser.Expression := ACell^.SharedFormulaBase^.FormulaValue; - Result := parser.Expression; - finally - parser.Free; - end; - end else - // case (2b): normal formula + // case (2): Formula is already in default syntax Result := ACell^.FormulaValue; end; end; @@ -3121,7 +3062,6 @@ end; procedure TsWorksheet.UnmergeCells(ARow, ACol: Cardinal); var rng: PsCellRange; - r, c: Cardinal; cell: PCell; begin rng := FMergedCells.FindRangeWithCell(ARow, ACol); @@ -3155,23 +3095,6 @@ begin UnmergeCells(rng.Row1, rng.Col1); end; -{@@ ---------------------------------------------------------------------------- - Finds the upper left cell of a shared formula block to which the specified - cell belongs. This is the "shared formula base". - - @param ACell Cell under investigation - @return A pointer to the cell in the upper left corner of the shared formula - block to which ACell belongs. If ACell is not part of a shared formula - block then the function returns NIL. --------------------------------------------------------------------------------} -function TsWorksheet.FindSharedFormulaBase(ACell: PCell): PCell; -begin - if ACell = nil then - Result := nil - else - Result := ACell^.SharedFormulaBase; -end; - {@@ ---------------------------------------------------------------------------- Determines the merged cell block to which a particular cell belongs @@ -3244,90 +3167,6 @@ begin end; -{ Shared formulas } - -{@@ ---------------------------------------------------------------------------- - Determines the cell block sharing the same formula which is used by a given cell - - Note: the block may not be contiguous. The function returns the outer edges - of the range. - - @param ACell Pointer to the cell being investigated - @param ARow1 (output) Top row index of the shared formula block - @param ACol1 (outout) Left column index of the shared formula block - @param ARow2 (output) Bottom row index of the shared formula block - @param ACol2 (output) Right column index of the shared formula block - - @return True if the cell belongs to a shared formula block, False if not or - if the cell does not exist at all. --------------------------------------------------------------------------------} -function TsWorksheet.FindSharedFormulaRange(ACell: PCell; - out ARow1, ACol1, ARow2, ACol2: Cardinal): Boolean; -var - r, c: Cardinal; - cell: PCell; - base: PCell; - lastCol, lastRow: Cardinal; -begin - base := FindSharedFormulaBase(ACell); - if base = nil then begin - Result := false; - exit; - end; - // Assuming that the shared formula block is rectangular, we start at the base... - ARow1 := base^.Row; - ARow2 := ARow1; - ACol1 := base^.Col; - ACol2 := ACol1; - lastCol := GetLastOccupiedColIndex; - lastRow := GetLastOccupiedRowIndex; - // ... and go along first COLUMN to find the end of the shared formula block, ... - for c := ACol1+1 to lastCol do - begin - cell := FindCell(ARow1, c); - if (cell <> nil) and (cell^.SharedFormulaBase = base) then - ACol2 := c; - end; - // ... and go along first ROW to find the end of the shared formula block - for r := ARow1 + 1 to lastRow do - begin - cell := FindCell(r, ACol1); - if (cell <> nil) and (cell^.SharedFormulaBase = base) then - ARow2 := r; - end; - - Result := true; -end; - -{@@ ---------------------------------------------------------------------------- - A shared formula must contain at least two cells. If there is only a single - cell then the shared formula is converted to a regular one. - Is called before writing to stream. --------------------------------------------------------------------------------} -procedure TsWorksheet.FixSharedFormulas; -var - r,c, r1,c1, r2,c2: Cardinal; - cell: PCell; -// firstRow, firstCol, lastRow, lastCol: Cardinal; -begin - for cell in Cells do - if FindSharedFormulaRange(cell, r1, c1, r2, c2) and (r1 = r2) and (c1 = c2) then - cell^.SharedFormulaBase := nil; - { - firstRow := GetFirstRowIndex; - firstCol := GetFirstColIndex; - lastRow := GetLastOccupiedRowIndex; - lastCol := GetLastOccupiedColIndex; - for r := firstRow to lastRow do - for c := firstCol to lastCol do - begin - cell := FindCell(r, c); - if FindSharedFormulaRange(cell, r1, c1, r2, c2) and (r1 = r2) and (c1 = c2) then - cell^.SharedFormulaBase := nil; - end; - } -end; - {@@ ---------------------------------------------------------------------------- Removes the comment from a cell and releases the memory occupied by the node. -------------------------------------------------------------------------------} @@ -3745,72 +3584,6 @@ begin FLastRowIndex := GetLastRowIndex(true); end; -{@@ ---------------------------------------------------------------------------- - Splits a shared formula range to which the specified cell belongs into - individual cells. Each cell gets the same formula as it had in the block. - This is required because insertion and deletion of columns/rows make shared - formulas very complicated. --------------------------------------------------------------------------------} -procedure TsWorksheet.SplitSharedFormula(ACell: PCell); -var - r, c: Cardinal; - baseRow, baseCol: Cardinal; - lastRow, lastCol: Cardinal; - cell: PCell; - rpnFormula: TsRPNFormula; -begin - if (ACell = nil) or (ACell^.SharedFormulaBase = nil) then - exit; - lastRow := GetLastOccupiedRowIndex; - lastCol := GetLastOccupiedColIndex; - baseRow := ACell^.SharedFormulaBase^.Row; - baseCol := ACell^.SharedFormulaBase^.Col; - for r := baseRow to lastRow do - for c := baseCol to lastCol do - begin - cell := FindCell(r, c); - if (cell = nil) or (cell^.SharedFormulaBase = nil) then - continue; - if (cell^.SharedFormulaBase^.Row = baseRow) and - (cell^.SharedFormulaBase^.Col = baseCol) then - begin - // This method converts the shared formula to an rpn formula as seen from cell... - rpnFormula := BuildRPNFormula(cell); - // ... and this reconstructs the string formula, again as seen from cell. - cell^.FormulaValue := ConvertRPNFormulaToStringFormula(rpnFormula); - // Remove the SharedFormulaBase information --> cell is isolated. - cell^.SharedFormulaBase := nil; - end; - end; -end; - -{@@ ---------------------------------------------------------------------------- - Defines a cell range sharing the "same" formula. Note that relative cell - references are updated for each cell in the range. - - @param ARow Row of the cell - @param ACol Column index of the cell - @param ASharedFormulaBase Cell containing the shared formula - - Note: An exception is raised if the cell already contains a formula (and is - different from the ASharedFormulaBase cell). --------------------------------------------------------------------------------} -function TsWorksheet.UseSharedFormula(ARow, ACol: Cardinal; - ASharedFormulaBase: PCell): PCell; -begin - if ASharedFormulaBase = nil then begin - Result := nil; - exit; - end; - Result := GetCell(ARow, ACol); - Result.SharedFormulaBase := ASharedFormulaBase; - if (Result^.FormulaValue <> '') and - ((ASharedFormulaBase.Row <> ARow) and (ASharedFormulaBase.Col <> ACol)) - then - raise Exception.CreateFmt('[TsWorksheet.UseSharedFormula] Cell %s uses a shared formula, but contains an own formula.', - [GetCellString(ARow, ACol)]); -end; - {@@ ---------------------------------------------------------------------------- Writes UTF-8 encoded text to a cell. @@ -3855,7 +3628,6 @@ begin begin if (Workbook.GetCellFormat(ACell^.FormatIndex).UsedFormattingFields = []) and (ACell^.Flags * [cfHyperlink, cfHasComment, cfMerged] = []) and - (ACell^.SharedFormulaBase = nil) and (ACell^.FormulaValue = '') then begin @@ -4052,8 +3824,6 @@ end; along a range of cells including empty cells. -------------------------------------------------------------------------------} procedure TsWorksheet.WriteBlank(ACell: PCell); -var - hyperlink: TsHyperlink; begin if ACell <> nil then begin if HasHyperlink(ACell) then @@ -4818,57 +4588,6 @@ begin ChangedCell(ACell^.Row, ACell^.Col); end; -{@@ ---------------------------------------------------------------------------- - Writes a formula to a cell and shares it with other cells. - - @param ARow1, ACol1 Row and column index of the top left corner of - the range sharing the formula. The cell in this - cell stores the formula. - @param ARow2, ACol2 Row and column of the bottom right corner of the - range sharing the formula. - @param AFormula Formula in Excel notation --------------------------------------------------------------------------------} -procedure TsWorksheet.WriteSharedFormula(ARow1, ACol1, ARow2, ACol2: Cardinal; - const AFormula: String); -var - cell: PCell; - r, c: Cardinal; -begin - if (ARow1 > ARow2) or (ACol1 > ACol2) then - raise Exception.Create('[TsWorksheet.WriteSharedFormula] Rows/cols not ordered correctly: ARow1 <= ARow2, ACol1 <= ACol2.'); - - if (ARow1 = ARow2) and (ACol1 = ACol2) then - raise Exception.Create('[TsWorksheet.WriteSharedFormula] A shared formula range must contain at least two cells.'); - - // The cell at the top/left corner of the cell range is the "SharedFormulaBase". - // It is the only cell which stores the formula. - cell := WriteFormula(ARow1, ACol1, AFormula); - for r := ARow1 to ARow2 do - for c := ACol1 to ACol2 do - UseSharedFormula(r, c, cell); -end; - -{@@ ---------------------------------------------------------------------------- - Writes a formula to a cell and shares it with other cells. - - @param ACellRangeStr Range of cells which will use the shared formula. - The range is given as a string in Excel notation, - such as A1:B5, or A1 - @param AFormula Formula (in Excel notation) to be shared. The cell - addresses are relative to the top/left cell of the - range. --------------------------------------------------------------------------------} -procedure TsWorksheet.WriteSharedFormula(ACellRange: String; - const AFormula: String); -var - r1,r2, c1,c2: Cardinal; -begin - if ParseCellRangeString(ACellRange, r1, c1, r2, c2) then - WriteSharedFormula(r1, c1, r2, c2, AFormula) - else - raise Exception.Create('[TsWorksheet.WriteSharedFormula] No valid cell range string.'); -end; - {@@ ---------------------------------------------------------------------------- Adds font specification to the formatting of a cell. Looks in the workbook's FontList and creates an new entry if the font is not used so far. Returns the @@ -5699,20 +5418,12 @@ end; function TsWorksheet.CalcAutoRowHeight(ARow: Cardinal): Single; var cell: PCell; - col: Integer; h0: Single; begin Result := 0; h0 := Workbook.GetDefaultFontSize; for cell in Cells.GetRowEnumerator(ARow) do Result := Max(Result, ReadCellFont(cell).Size / h0); - { - for col := GetFirstColIndex to GetLastColIndex do begin - cell := FindCell(ARow, col); - if cell <> nil then - Result := Max(Result, ReadCellFont(cell).Size / h0); - end; - } end; {@@ ---------------------------------------------------------------------------- @@ -5901,43 +5612,13 @@ procedure TsWorksheet.DeleteCol(ACol: Cardinal); var col: PCol; i: Integer; - r, rr, cc: Cardinal; - cell, basecell, nextcell: PCell; - firstRow, lastCol, lastRow: Cardinal; + r: Cardinal; + cell: PCell; + firstRow, lastRow: Cardinal; begin - lastCol := GetLastColIndex; lastRow := GetLastOccupiedRowIndex; firstRow := GetFirstRowIndex; - // Loop along the column to be deleted and fix shared formulas - for r := firstRow to lastRow do - begin - cell := FindCell(r, ACol); - - // Fix shared formulas: if the deleted column contains the shared formula base - // of a shared formula block then the shared formula has to be moved to the - // next column - if (cell <> nil) and (cell^.SharedFormulaBase = cell) then begin - basecell := cell; - nextcell := FindCell(r, ACol+1); // cell in next column and same row - // Next cell in col at the right does not share this formula --> done with this formula - if (nextcell = nil) or (nextcell^.SharedFormulaBase <> cell) then - continue; - // Write adapted formula to the cell below. - WriteFormula(nextcell, basecell^.Formulavalue); //ReadFormulaAsString(nextcell)); - // Have all cells sharing the formula use the new formula base - for rr := r to lastRow do - for cc := ACol+1 to lastCol do - begin - cell := FindCell(rr, cc); - if (cell <> nil) and (cell^.SharedFormulaBase = basecell) then - cell^.SharedFormulaBase := nextcell - else - break; - end; - end; - end; - // Fix merged cells FMergedCells.DeleteRowOrCol(ACol, false); @@ -5981,41 +5662,12 @@ procedure TsWorksheet.DeleteRow(ARow: Cardinal); var row: PRow; i: Integer; - c, rr, cc: Cardinal; - firstCol, lastCol, lastRow: Cardinal; - cell, nextcell, basecell: PCell; + c: Cardinal; + firstCol, lastCol: Cardinal; + cell: PCell; begin firstCol := GetFirstColIndex; lastCol := GetLastOccupiedColIndex; - lastRow := GetLastOccupiedRowIndex; - - // Loop along the row to be deleted and fix shared formulas - for c := firstCol to lastCol do - begin - cell := FindCell(ARow, c); - // Fix shared formulas: if the deleted row contains the shared formula base - // of a shared formula block then the shared formula has to be moved to the - // next row - if (cell <> nil) and (cell^.SharedFormulaBase = cell) then begin - basecell := cell; - nextcell := FindCell(ARow+1, c); // cell in next row at same column - // Next cell in row below does not share this formula --> done with this formula - if (nextcell = nil) or (nextcell^.SharedFormulaBase <> cell) then - continue; - // Write adapted formula to the cell below. - WriteFormula(nextcell, basecell^.FormulaValue); //ReadFormulaAsString(nextcell)); - // Have all cells sharing the formula use the new formula base - for rr := ARow+1 to lastRow do - for cc := c to lastCol do - begin - cell := FindCell(rr, cc); - if (cell <> nil) and (cell^.SharedFormulaBase = basecell) then - cell^.SharedFormulaBase := nextcell - else - break; - end; - end; - end; // Fix merged cells FMergedCells.DeleteRowOrCol(ARow, true); @@ -6027,7 +5679,7 @@ begin FHyperlinks.DeleteRowOrCol(ARow, true); // Delete cells - for c := lastCol downto 0 do + for c := lastCol downto firstCol do RemoveAndFreeCell(ARow, c); // Update row index of cell records @@ -6061,15 +5713,9 @@ procedure TsWorksheet.InsertCol(ACol: Cardinal); var col: PCol; i: Integer; - r: Cardinal; cell: PCell; rng: PsCellRange; begin - // Handling of shared formula references is too complicated for me... - // Split them into isolated cell formulas - for cell in FCells do - SplitSharedFormula(cell); - // Update column index of comments FComments.InsertRowOrCol(ACol, false); @@ -6091,24 +5737,15 @@ begin // Fix merged cells for rng in FMergedCells do -// rng := PsCellRange(FMergedCells.GetFirst); -// while rng <> nil do begin // The new column is at the LEFT of the merged block // --> Shift entire range to the right by 1 column if (ACol < rng^.Col1) then begin - // The former first column is no longer marged --> un-tag its cells + // The former first column is no longer merged --> un-tag its cells for cell in Cells.GetColEnumerator(rng^.Col1, rng^.Row1, rng^.Row2) do Exclude(cell^.Flags, cfMerged); - { - for r := rng^.Row1 to rng^.Row2 do - begin - cell := FindCell(r, rng^.Col1); - if cell <> nil then - Exclude(cell^.Flags, cfMerged); - end; - } + // Shift merged block to the right // Don't call "MergeCells" here - this would add a new merged block // because of the new merge base! --> infinite loop! @@ -6117,21 +5754,11 @@ begin // The right column needs to be tagged for cell in Cells.GetColEnumerator(rng^.Col2, rng^.Row1, rng^.Row2) do Include(cell^.Flags, cfMerged); - { - for r := rng^.Row1 to rng^.Row2 do - begin - cell := FindCell(R, rng^.Col2); - if cell <> nil then - Include(cell^.Flags, cfMerged); - end; - } end else // The new column goes through this cell block --> Shift only the right // column of the range to the right by 1 if (ACol >= rng^.Col1) and (ACol <= rng^.Col2) then MergeCells(rng^.Row1, rng^.Col1, rng^.Row2, rng^.Col2+1); - // Continue with next merged block -// rng := PsCellRange(FMergedCells.GetNext); end; ChangedCell(0, ACol); @@ -6187,15 +5814,9 @@ procedure TsWorksheet.InsertRow(ARow: Cardinal); var row: PRow; i: Integer; - c: Cardinal; cell: PCell; rng: PsCellRange; begin - // Handling of shared formula references is too complicated for me... - // Splits them into isolated cell formulas - for cell in FCells do - SplitSharedFormula(cell); - // Update row index of cell comments FComments.InsertRowOrCol(ARow, true); @@ -6217,8 +5838,6 @@ begin // Fix merged cells for rng in FMergedCells do -// rng := PsCellRange(FMergedCells.GetFirst); -// while rng <> nil do begin // The new row is ABOVE the merged block --> Shift entire range down by 1 row if (ARow < rng^.Row1) then @@ -6226,14 +5845,7 @@ begin // The formerly first row is no longer merged --> un-tag its cells for cell in Cells.GetRowEnumerator(rng^.Row1, rng^.Col1, rng^.Col2) do Exclude(cell^.Flags, cfMerged); - { - for c := rng^.Col1 to rng^.Col2 do - begin - cell := FindCell(rng^.Row1, c); - if cell <> nil then - Exclude(cell^.Flags, cfMerged); - end; - } + // Shift merged block down // (Don't call "MergeCells" here - this would add a new merged block // because of the new merge base! --> infinite loop!) @@ -6242,21 +5854,11 @@ begin // The last row needs to be tagged for cell in Cells.GetRowEnumerator(rng^.Row2, rng^.Col1, rng^.Col2) do Include(cell^.Flags, cfMerged); - { - for c := rng^.Col1 to rng^.Col2 do - begin - cell := FindCell(rng^.Row2, c); - if cell <> nil then - Include(cell^.Flags, cfMerged); - end; - } end else // The new row goes through this cell block --> Shift only the bottom row // of the range down by 1 if (ARow >= rng^.Row1) and (ARow <= rng^.Row2) then MergeCells(rng^.Row1, rng^.Col1, rng^.Row2+1, rng^.Col2); - // Continue with next block -// rng := PsCellRange(FMergedCells.GetNext); end; ChangedCell(ARow, 0); @@ -6472,9 +6074,6 @@ begin // Updates fist/last column/row index UpdateCaches; - // Shared formulas must contain at least two cells - FixSharedFormulas; - // Calculated formulas (if requested) if (boCalcBeforeSaving in FOptions) then for sheet in FWorksheets do @@ -6717,22 +6316,6 @@ begin raise Exception.Create(rsUnsupportedWriteFormat); end; -{@@ ---------------------------------------------------------------------------- - Shared formulas must contain at least two cells. If it's a single cell, then - the cell formula is converted to a standard one. --------------------------------------------------------------------------------} -procedure TsWorkbook.FixSharedFormulas; -var - sheet: TsWorksheet; - i: Integer; -begin - for i := 0 to GetWorksheetCount-1 do - begin - sheet := GetWorksheetByIndex(i); - sheet.FixSharedFormulas - end; -end; - {@@ ---------------------------------------------------------------------------- Determines the maximum index of used columns and rows in all sheets of this workbook. Respects VirtualMode. diff --git a/components/fpspreadsheet/fpspreadsheetctrls.pas b/components/fpspreadsheet/fpspreadsheetctrls.pas index d8bc85bd8..40f196efa 100644 --- a/components/fpspreadsheet/fpspreadsheetctrls.pas +++ b/components/fpspreadsheet/fpspreadsheetctrls.pas @@ -2692,12 +2692,14 @@ begin if ACell^.ContentType = cctError then AStrings.Add(Format('ErrorValue=%s', [GetEnumName(TypeInfo(TsErrorValue), ord(ACell^.ErrorValue))])); AStrings.Add(Format('FormulaValue=%s', [Worksheet.ReadFormulaAsString(ACell, true)])); + { if ACell^.SharedFormulaBase = nil then AStrings.Add('SharedFormulaBase=') else AStrings.Add(Format('SharedFormulaBase=%s', [GetCellString( ACell^.SharedFormulaBase^.Row, ACell^.SharedFormulaBase^.Col) ])); + } if (cfHyperlink in ACell^.Flags) then begin hyperlink := Worksheet.FindHyperlink(ACell); diff --git a/components/fpspreadsheet/fpstypes.pas b/components/fpspreadsheet/fpstypes.pas index 93b51181d..330e255fc 100644 --- a/components/fpspreadsheet/fpstypes.pas +++ b/components/fpspreadsheet/fpstypes.pas @@ -548,13 +548,11 @@ type { Location of the cell } Row: Cardinal; // zero-based Col: Cardinal; // zero-based - Worksheet: Pointer; // Must be cast to TsWorksheet when used + Worksheet: Pointer; // Must be cast to TsWorksheet when used (avoids circular unit reference) { Status flags } Flags: TsCellFlags; { Index of format record in the workbook's FCellFormatList } FormatIndex: Integer; - { Special information } - SharedFormulaBase: PCell; // Cell containing the shared formula { Cell content } UTF8StringValue: String; // Strings cannot be part of a variant record FormulaValue: String; diff --git a/components/fpspreadsheet/tests/formulatests.pas b/components/fpspreadsheet/tests/formulatests.pas index 9fa5715a5..bb4e03ddb 100644 --- a/components/fpspreadsheet/tests/formulatests.pas +++ b/components/fpspreadsheet/tests/formulatests.pas @@ -33,13 +33,17 @@ type // Test reconstruction of formula strings procedure Test_Write_Read_FormulaStrings(AFormat: TsSpreadsheetFormat; UseRPNFormula: Boolean); + { // Test reconstruction of shared formula strings procedure Test_Write_Read_SharedFormulaStrings(AFormat: TsSpreadsheetFormat); // Test calculation of formulas + } procedure Test_Write_Read_CalcFormulas(AFormat: TsSpreadsheetformat; UseRPNFormula: Boolean); + { // Test calculation of shared formulas procedure Test_Write_Read_CalcSharedFormulas(AFormat: TsSpreadsheetformat); + } published // Writes out formulas & reads them back. @@ -54,6 +58,7 @@ type { ODS Tests } procedure Test_Write_Read_FormulaStrings_ODS; + (* // Writes out shared formulas & reads them back. { BIFF2 Tests } procedure Test_Write_Read_SharedFormulaStrings_BIFF2; @@ -64,7 +69,7 @@ type { OOXML Tests } procedure Test_Write_Read_SharedFormulaStrings_OOXML; { ODS Tests } - procedure Test_Write_Read_SharedFormulaStrings_ODS; + procedure Test_Write_Read_SharedFormulaStrings_ODS; *) // Writes out and calculates rpn formulas, read back { BIFF2 Tests } @@ -89,7 +94,7 @@ type procedure Test_Write_Read_CalcStringFormula_OOXML; { ODS Tests } procedure Test_Write_Read_CalcStringFormula_ODS; - + (* // Writes out and calculates shared formulas, read back { BIFF2 Tests } procedure Test_Write_Read_CalcSharedFormula_BIFF2; @@ -100,7 +105,7 @@ type { OOXML Tests } procedure Test_Write_Read_CalcSharedFormula_OOXML; { ODS Tests } - procedure Test_Write_Read_CalcSharedFormula_ODS; + procedure Test_Write_Read_CalcSharedFormula_ODS; *) end; @@ -227,7 +232,7 @@ end; { Test writing and reading (i.e. reconstruction) of shared formula strings } - + (* procedure TSpreadWriteReadFormulaTests.Test_Write_Read_SharedFormulaStrings( AFormat: TsSpreadsheetFormat); const @@ -352,7 +357,7 @@ procedure TSpreadWriteReadFormulaTests.Test_Write_Read_SharedFormulaStrings_ODS; begin Test_Write_Read_SharedFormulaStrings(sfOpenDocument); end; - + *) { Test calculation of formulas } procedure TSpreadWriteReadFormulaTests.Test_Write_Read_CalcFormulas( @@ -550,6 +555,7 @@ end; //------------------------------------------------------------------------------ // Calculation of shared formulas //------------------------------------------------------------------------------ +(* procedure TSpreadWriteReadFormulaTests.Test_Write_Read_CalcSharedFormulas( AFormat: TsSpreadsheetFormat); const @@ -707,7 +713,7 @@ procedure TSpreadWriteReadFormulaTests.Test_Write_Read_CalcSharedFormula_ODS; begin Test_Write_Read_CalcSharedFormulas(sfOpenDocument); end; - + *) initialization // Register so these tests are included in a full run diff --git a/components/fpspreadsheet/tests/insertdeletetests.pas b/components/fpspreadsheet/tests/insertdeletetests.pas index d73c379fd..0ce17954b 100644 --- a/components/fpspreadsheet/tests/insertdeletetests.pas +++ b/components/fpspreadsheet/tests/insertdeletetests.pas @@ -38,7 +38,7 @@ type end; var - InsDelTestData: array[0..52] of TInsDelTestDataItem; + InsDelTestData: array[0..34] of TInsDelTestDataItem; procedure InitTestData; @@ -89,48 +89,24 @@ type procedure TestWriteRead_InsDelColRow_20_BIFF8; // after formula cell procedure TestWriteRead_InsDelColRow_21_BIFF8; // cell in formula - // Writes out cell layout with shared formula - procedure TestWriteRead_InsDelColRow_22_BIFF8; // no insert/delete; just test shared formula - // ... and inserts columns - procedure TestWriteRead_InsDelColRow_23_BIFF8; // column before shared formula cells - procedure TestWriteRead_InsDelColRow_24_BIFF8; // column after shared formula cells - procedure TestWriteRead_InsDelColRow_25_BIFF8; // column through cells addressed by shared formula - procedure TestWriteRead_InsDelColRow_26_BIFF8; // column through shared formula block - procedure TestWriteRead_InsDelColRow_27_BIFF8; // column behind shared formula block - // ... and inserts rows - procedure TestWriteRead_InsDelColRow_28_BIFF8; // row before shared formula - procedure TestWriteRead_InsDelColRow_29_BIFF8; // row after shared formula cells - procedure TestWriteRead_InsDelColRow_30_BIFF8; // row through shared formula block - procedure TestWriteRead_InsDelColRow_31_BIFF8; // row below shared formula block - // ... and deletes columns - procedure TestWriteRead_InsDelColRow_32_BIFF8; // column before shared formula cells - procedure TestWriteRead_InsDelColRow_33_BIFF8; // column after shared formula cells - procedure TestWriteRead_InsDelColRow_34_BIFF8; // column in shared formula block, no formula cell - procedure TestWriteRead_InsDelColRow_35_BIFF8; // column used in shared formula - // ... and deletes rows - procedure TestWriteRead_InsDelColRow_36_BIFF8; // row above shared formula cells - procedure TestWriteRead_InsDelColRow_37_BIFF8; // row below shared formula cells - procedure TestWriteRead_InsDelColRow_38_BIFF8; // row through shared formula block - procedure TestWriteRead_InsDelColRow_39_BIFF8; // row with cell used in shared formula - // Writes out cell layout with merged cells - procedure TestWriteRead_InsDelColRow_40_BIFF8; // no insert/delete; just test merged block + procedure TestWriteRead_InsDelColRow_22_BIFF8; // no insert/delete; just test merged block // ... and inserts columns - procedure TestWriteRead_InsDelColRow_41_BIFF8; // column before merged block - procedure TestWriteRead_InsDelColRow_42_BIFF8; // column through merged block - procedure TestWriteRead_InsDelColRow_43_BIFF8; // column after merged block + procedure TestWriteRead_InsDelColRow_23_BIFF8; // column before merged block + procedure TestWriteRead_InsDelColRow_24_BIFF8; // column through merged block + procedure TestWriteRead_InsDelColRow_25_BIFF8; // column after merged block // ... and inserts rows - procedure TestWriteRead_InsDelColRow_44_BIFF8; // row before merged block - procedure TestWriteRead_InsDelColRow_45_BIFF8; // row through merged block - procedure TestWriteRead_InsDelColRow_46_BIFF8; // row after merged block + procedure TestWriteRead_InsDelColRow_26_BIFF8; // row before merged block + procedure TestWriteRead_InsDelColRow_27_BIFF8; // row through merged block + procedure TestWriteRead_InsDelColRow_28_BIFF8; // row after merged block // ... and deletes columns procedure TestWriteRead_DelColBeforeMerge_BIFF8; // column before merged block procedure TestWriteRead_DelColInMerge_BIFF8; // column through merged block procedure TestWriteRead_DelColAfterMerge_BIFF8; // column after merged block // ... and deletes rows - procedure TestWriteRead_InsDelColRow_50_BIFF8; // row before merged block - procedure TestWriteRead_InsDelColRow_51_BIFF8; // row through merged block - procedure TestWriteRead_InsDelColRow_52_BIFF8; // row after merged block + procedure TestWriteRead_InsDelColRow_32_BIFF8; // row before merged block + procedure TestWriteRead_InsDelColRow_33_BIFF8; // row through merged block + procedure TestWriteRead_InsDelColRow_34_BIFF8; // row after merged block // *** OOXML tests *** @@ -166,48 +142,24 @@ type procedure TestWriteRead_InsDelColRow_20_OOXML; // after formula cell procedure TestWriteRead_InsDelColRow_21_OOXML; // cell in formula - // Writes out cell layout with shared formula - procedure TestWriteRead_InsDelColRow_22_OOXML; // no insert/delete; just test shared formula - // ... and inserts columns - procedure TestWriteRead_InsDelColRow_23_OOXML; // column before shared formula cells - procedure TestWriteRead_InsDelColRow_24_OOXML; // column after shared formula cells - procedure TestWriteRead_InsDelColRow_25_OOXML; // column through cells addressed by shared formula - procedure TestWriteRead_InsDelColRow_26_OOXML; // column through shared formula block - procedure TestWriteRead_InsDelColRow_27_OOXML; // column behind shared formula block - // ... and inserts rows - procedure TestWriteRead_InsDelColRow_28_OOXML; // row before shared formula - procedure TestWriteRead_InsDelColRow_29_OOXML; // row after shared formula cells - procedure TestWriteRead_InsDelColRow_30_OOXML; // row through shared formula block - procedure TestWriteRead_InsDelColRow_31_OOXML; // row below shared formula block - // ... and deletes columns - procedure TestWriteRead_InsDelColRow_32_OOXML; // column before shared formula cells - procedure TestWriteRead_InsDelColRow_33_OOXML; // column after shared formula cells - procedure TestWriteRead_InsDelColRow_34_OOXML; // column in shared formula block, no formula cell - procedure TestWriteRead_InsDelColRow_35_OOXML; // column used in shared formula - // ... and deletes rows - procedure TestWriteRead_InsDelColRow_36_OOXML; // row above shared formula cells - procedure TestWriteRead_InsDelColRow_37_OOXML; // row below shared formula cells - procedure TestWriteRead_InsDelColRow_38_OOXML; // row through shared formula block - procedure TestWriteRead_InsDelColRow_39_OOXML; // row with cell used in shared formula - // Writes out cell layout with merged cells - procedure TestWriteRead_InsDelColRow_40_OOXML; // no insert/delete; just test merged block + procedure TestWriteRead_InsDelColRow_22_OOXML; // no insert/delete; just test merged block // ... and inserts columns - procedure TestWriteRead_InsDelColRow_41_OOXML; // column before merged block - procedure TestWriteRead_InsDelColRow_42_OOXML; // column through merged block - procedure TestWriteRead_InsDelColRow_43_OOXML; // column after merged block + procedure TestWriteRead_InsDelColRow_23_OOXML; // column before merged block + procedure TestWriteRead_InsDelColRow_24_OOXML; // column through merged block + procedure TestWriteRead_InsDelColRow_25_OOXML; // column after merged block // ... and inserts rows - procedure TestWriteRead_InsDelColRow_44_OOXML; // row before merged block - procedure TestWriteRead_InsDelColRow_45_OOXML; // row through merged block - procedure TestWriteRead_InsDelColRow_46_OOXML; // row after merged block + procedure TestWriteRead_InsDelColRow_26_OOXML; // row before merged block + procedure TestWriteRead_InsDelColRow_27_OOXML; // row through merged block + procedure TestWriteRead_InsDelColRow_28_OOXML; // row after merged block // ... and deletes columns procedure TestWriteRead_DelColBeforeMerge_OOXML; // column before merged block procedure TestWriteRead_DelColInMerge_OOXML; // column through merged block procedure TestWriteRead_DelColAfterMerge_OOXML; // column after merged block // ... and deletes rows - procedure TestWriteRead_InsDelColRow_50_OOXML; // row before merged block - procedure TestWriteRead_InsDelColRow_51_OOXML; // row through merged block - procedure TestWriteRead_InsDelColRow_52_OOXML; // row after merged block + procedure TestWriteRead_InsDelColRow_32_OOXML; // row before merged block + procedure TestWriteRead_InsDelColRow_33_OOXML; // row through merged block + procedure TestWriteRead_InsDelColRow_34_OOXML; // row after merged block // *** OpenDocument tests *** @@ -243,48 +195,24 @@ type procedure TestWriteRead_InsDelColRow_20_ODS; // after formula cell procedure TestWriteRead_InsDelColRow_21_ODS; // cell in formula - // Writes out cell layout with shared formula - procedure TestWriteRead_InsDelColRow_22_ODS; // no insert/delete; just test shared formula - // ... and inserts columns - procedure TestWriteRead_InsDelColRow_23_ODS; // column before shared formula cells - procedure TestWriteRead_InsDelColRow_24_ODS; // column after shared formula cells - procedure TestWriteRead_InsDelColRow_25_ODS; // column through cells addressed by shared formula - procedure TestWriteRead_InsDelColRow_26_ODS; // column through shared formula block - procedure TestWriteRead_InsDelColRow_27_ODS; // column behind shared formula block - // ... and inserts rows - procedure TestWriteRead_InsDelColRow_28_ODS; // row before shared formula - procedure TestWriteRead_InsDelColRow_29_ODS; // row after shared formula cells - procedure TestWriteRead_InsDelColRow_30_ODS; // row through shared formula block - procedure TestWriteRead_InsDelColRow_31_ODS; // row below shared formula block - // ... and deletes columns - procedure TestWriteRead_InsDelColRow_32_ODS; // column before shared formula cells - procedure TestWriteRead_InsDelColRow_33_ODS; // column after shared formula cells - procedure TestWriteRead_InsDelColRow_34_ODS; // column in shared formula block, no formula cell - procedure TestWriteRead_InsDelColRow_35_ODS; // column used in shared formula - // ... and deletes rows - procedure TestWriteRead_InsDelColRow_36_ODS; // row above shared formula cells - procedure TestWriteRead_InsDelColRow_37_ODS; // row below shared formula cells - procedure TestWriteRead_InsDelColRow_38_ODS; // row through shared formula block - procedure TestWriteRead_InsDelColRow_39_ODS; // row with cell used in shared formula - // Writes out cell layout with merged cells - procedure TestWriteRead_InsDelColRow_40_ODS; // no insert/delete; just test merged block + procedure TestWriteRead_InsDelColRow_22_ODS; // no insert/delete; just test merged block // ... and inserts columns - procedure TestWriteRead_InsDelColRow_41_ODS; // column before merged block - procedure TestWriteRead_InsDelColRow_42_ODS; // column through merged block - procedure TestWriteRead_InsDelColRow_43_ODS; // column after merged block + procedure TestWriteRead_InsDelColRow_23_ODS; // column before merged block + procedure TestWriteRead_InsDelColRow_24_ODS; // column through merged block + procedure TestWriteRead_InsDelColRow_25_ODS; // column after merged block // ... and inserts rows - procedure TestWriteRead_InsDelColRow_44_ODS; // row before merged block - procedure TestWriteRead_InsDelColRow_45_ODS; // row through merged block - procedure TestWriteRead_InsDelColRow_46_ODS; // row after merged block + procedure TestWriteRead_InsDelColRow_26_ODS; // row before merged block + procedure TestWriteRead_InsDelColRow_27_ODS; // row through merged block + procedure TestWriteRead_InsDelColRow_28_ODS; // row after merged block // ... and deletes columns procedure TestWriteRead_DelColBeforeMerge_ODS; // column before merged block procedure TestWriteRead_DelColInMerge_ODS; // column through merged block procedure TestWriteRead_DelColAfterMerge_ODS; // column after merged block // ... and deletes rows - procedure TestWriteRead_InsDelColRow_50_ODS; // row before merged block - procedure TestWriteRead_InsDelColRow_51_ODS; // row through merged block - procedure TestWriteRead_InsDelColRow_52_ODS; // row after merged block + procedure TestWriteRead_InsDelColRow_32_ODS; // row before merged block + procedure TestWriteRead_InsDelColRow_33_ODS; // row through merged block + procedure TestWriteRead_InsDelColRow_34_ODS; // row after merged block end; implementation @@ -699,519 +627,13 @@ begin '67890123'; end; - { ---------------------------------------------------------------------------} - { Layouts with shared formula } - { ---------------------------------------------------------------------------} - - // No insert/delete, just to test the shared formula - with InsDelTestData[22] do begin - Layout := '12345678|'+ - '23456789|'+ - '345S 890|'+ // "S" = shared formula (2 cols x 3 rows) - '456 901|'+ - '567 012|'+ - '67890123'; - Formula := 'A3-$B$2'; - SharedFormulaColCount := 2; - SharedFormulaRowCount := 3; - SharedFormulaBaseCol_After := 3; - SharedFormulaBaseRow_After := 2; - SharedFormulaColCount_After := 2; - SharedFormulaRowCount_After := 3; - SollFormula := 'A3-$B$2,B3-$B$2;'+ - 'A4-$B$2,B4-$B$2;'+ - 'A5-$B$2,B5-$B$2'; - // comma-separated --> cells along row; semicolon separates rows - SollLayout := '12345678|'+ - '23456789|'+ - '34501890|'+ - '45612901|'+ - '56723012|'+ - '67890123'; - end; - - // Insert column before any cell referred to by the shared formula (col = 0) - with InsDelTestData[23] do begin - Layout := '12345678|'+ - '23456789|'+ - '345S 890|'+ // "S" = shared formula (2 cols x 3 rows) - '456 901|'+ - '567 012|'+ - '67890123'; - InsertCol := 0; - Formula := 'A3-$B$2'; - SharedFormulaColCount := 2; - SharedFormulaRowCount := 3; - SharedFormulaBaseCol_After := 4; // Position of shared formula after insert op - SharedFormulaBaseRow_After := 2; - SharedFormulaColCount_After := 2; // Size of shared formula block after insert op - SharedFormulaRowCount_After := 3; - SollFormula := 'B3-$C$2,C3-$C$2;'+ // all column indexes increase by 1 due to added col in front - 'B4-$C$2,C4-$C$2;'+ - 'B5-$C$2,C5-$C$2'; - // comma-separated --> cells along row; semicolon separates rows - SollLayout := ' 12345678|'+ - ' 23456789|'+ - ' 34501890|'+ - ' 45612901|'+ - ' 56723012|'+ - ' 67890123'; - end; - - // Insert column after last cell addressed by the shared formula - with InsDelTestData[24] do begin - Layout := '12345678|'+ - '23456789|'+ - '345S 890|'+ // "S" = shared formula (2 cols x 3 rows) - '456 901|'+ - '567 012|'+ - '67890123'; - InsertCol := 7; - Formula := 'A3-$B$2'; - SharedFormulaColCount := 2; - SharedFormulaRowCount := 3; - SharedFormulaBaseCol_After := 3; - SharedFormulaBaseRow_After := 2; - SharedFormulaColCount_After := 2; - SharedFormulaRowCount_After := 3; - SollFormula := 'A3-$B$2,B3-$B$2;'+ // formulas unchanged by insert - 'A4-$B$2,B4-$B$2;'+ - 'A5-$B$2,B5-$B$2'; - // comma-separated --> cells along row; semicolon separates rows - SollLayout := '1234567 8|'+ - '2345678 9|'+ - '3450189 0|'+ - '4561290 1|'+ - '5672301 2|'+ - '6789012 3'; - end; - - // Insert column between cells referred to by the shared formula (col = 1) - with InsDelTestData[25] do begin - Layout := '12345678|'+ - '23456789|'+ - '345S 890|'+ // "S" = shared formula (2 cols x 3 rows) - '456 901|'+ - '567 012|'+ - '67890123'; - InsertCol := 1; - Formula := 'A3-$B$2'; - SharedFormulaColCount := 2; - SharedFormulaRowCount := 3; - SharedFormulaBaseCol_After := 4; - SharedFormulaBaseRow_After := 2; - SharedFormulaColCount_After := 2; - SharedFormulaRowCount_After := 3; - SollFormula := 'A3-$C$2,C3-$C$2;'+ - 'A4-$C$2,C4-$C$2;'+ - 'A5-$C$2,C5-$C$2'; - SollLayout := '1 2345678|'+ - '2 3456789|'+ - '3 4501890|'+ - '4 5612901|'+ - '5 6723012|'+ - '6 7890123'; - end; - - // Insert column to run through formula block (col = 4) - with InsDelTestData[26] do begin - Layout := '12345678|'+ - '23456789|'+ - '345S 890|'+ // "S" = shared formula (2 cols x 3 rows) - '456 901|'+ - '567 012|'+ - '67890123'; - InsertCol := 4; - Formula := 'A3-$B$2'; - SharedFormulaColCount := 2; - SharedFormulaRowCount := 3; - SharedFormulaBaseCol_After := 3; - SharedFormulaBaseRow_After := 2; - SharedFormulaColCount_After := 3; - SharedFormulaRowCount_After := 3; - SollFormula := 'A3-$B$2,'',B3-$B$2;'+ - 'A4-$B$2,'',B4-$B$2;'+ - 'A5-$B$2,'',B5-$B$2'; - SollLayout := '1234 5678|'+ - '2345 6789|'+ - '3450 1890|'+ - '4561 2901|'+ - '5672 3012|'+ - '6789 0123'; - end; - - // Insert column behind shared formula block (col = 7) - with InsDelTestData[27] do begin - Layout := '12345678|'+ - '23456789|'+ - '345S 890|'+ // "S" = shared formula (2 cols x 3 rows) - '456 901|'+ - '567 012|'+ - '67890123'; - InsertCol := 7; - Formula := 'A3-$B$2'; - SharedFormulaColCount := 2; - SharedFormulaRowCount := 3; - SharedFormulaBaseCol_After := 3; - SharedFormulaBaseRow_After := 2; - SharedFormulaColCount_After := 2; - SharedFormulaRowCount_After := 3; - SollFormula := 'A3-$B$2,B3-$B$2;'+ - 'A4-$B$2,B4-$B$2;'+ - 'A5-$B$2,B5-$B$2'; - SollLayout := '1234567 8|'+ - '2345678 9|'+ - '3450189 0|'+ - '4561290 1|'+ - '5672301 2|'+ - '6789012 3'; - end; - - // Insert row before any cell referred to by the shared formula (row = 0) - with InsDelTestData[28] do begin - Layout := '12345678|'+ - '23456789|'+ - '345S 890|'+ // "S" = shared formula (2 cols x 3 rows) - '456 901|'+ - '567 012|'+ - '67890123'; - InsertRow := 0; - Formula := 'A3-$B$2'; - SharedFormulaColCount := 2; - SharedFormulaRowCount := 3; - SharedFormulaBaseCol_After := 3; // Position of shared formula after insert op - SharedFormulaBaseRow_After := 3; - SharedFormulaColCount_After := 2; // Size of shared formula block after insert op - SharedFormulaRowCount_After := 3; - SollFormula := 'A4-$B$3,B4-$B$3;'+ // all row indexes increase by 1 due to added row in front - 'A5-$B$3,B5-$B$3;'+ - 'A6-$B$3,B6-$B$3'; - // comma-separated --> cells along row; semicolon separates rows - SollLayout := ' |'+ - '12345678|'+ - '23456789|'+ - '34501890|'+ - '45612901|'+ - '56723012|'+ - '67890123'; - end; - - // Insert row through cells referred to by the shared formula (row = 2) - with InsDelTestData[29] do begin - Layout := '12345678|'+ - '23456789|'+ - '345S 890|'+ // "S" = shared formula (2 cols x 3 rows) - '456 901|'+ - '567 012|'+ - '67890123'; - InsertRow := 2; - Formula := 'A3-$B$2'; - SharedFormulaColCount := 2; - SharedFormulaRowCount := 3; - SharedFormulaBaseCol_After := 3; // Position of shared formula after insert op - SharedFormulaBaseRow_After := 3; - SharedFormulaColCount_After := 2; // Size of shared formula block after insert op - SharedFormulaRowCount_After := 3; - SollFormula := 'A4-$B$2,B4-$B$2;'+ // row 3 --> 4 - 'A5-$B$2,B5-$B$2;'+ - 'A6-$B$2,B6-$B$2'; - // comma-separated --> cells along row; semicolon separates rows - SollLayout := '12345678|'+ - '23456789|'+ - ' |'+ - '34501890|'+ - '45612901|'+ - '56723012|'+ - '67890123'; - end; - - // Insert row through shared formula block (row = 3) - with InsDelTestData[30] do begin - Layout := '12345678|'+ - '23456789|'+ - '345S 890|'+ // "S" = shared formula (2 cols x 3 rows) - '456 901|'+ - '567 012|'+ - '67890123'; - InsertRow := 3; - Formula := 'A3-$B$2'; - SharedFormulaColCount := 2; - SharedFormulaRowCount := 3; - SharedFormulaBaseCol_After := 3; // Position of shared formula after insert op - SharedFormulaBaseRow_After := 2; - SharedFormulaColCount_After := 2; // Size of shared formula block after insert op - SharedFormulaRowCount_After := 4; - SollFormula := 'A3-$B$2,B3-$B$2;'+ - ' , ;'+ - 'A5-$B$2,B5-$B$2;'+ - 'A6-$B$2,B6-$B$2'; - // comma-separated --> cells along row; semicolon separates rows - SollLayout := '12345678|'+ - '23456789|'+ - '34501890|'+ - ' |'+ - '45612901|'+ - '56723012|'+ - '67890123'; - end; - - // Insert row below shared formula block (row = 5) - with InsDelTestData[31] do begin - Layout := '12345678|'+ - '23456789|'+ - '345S 890|'+ // "S" = shared formula (2 cols x 3 rows) - '456 901|'+ - '567 012|'+ - '67890123'; - InsertRow := 5; - Formula := 'A3-$B$2'; - SharedFormulaColCount := 2; - SharedFormulaRowCount := 3; - SharedFormulaBaseCol_After := 3; // Position of shared formula after insert op - SharedFormulaBaseRow_After := 2; - SharedFormulaColCount_After := 2; // Size of shared formula block after insert op - SharedFormulaRowCount_After := 3; - SollFormula := 'A3-$B$2,B3-$B$2;'+ - 'A4-$B$2,B4-$B$2;'+ - 'A5-$B$2,B5-$B$2'; - // comma-separated --> cells along row; semicolon separates rows - SollLayout := '12345678|'+ - '23456789|'+ - '34501890|'+ - '45612901|'+ - '56723012|'+ - ' |'+ - '67890123'; - end; - - // Delete column 0 (this is before any cell of the shared formula) - with InsDelTestData[32] do begin - Layout := '12345678|'+ - '23456789|'+ - '345S 890|'+ // "S" = shared formula (2 cols x 3 rows) - '456 901|'+ - '567 012|'+ - '67890123'; - DeleteCol := 0; - Formula := 'B3-$C$2'; - SharedFormulaColCount := 2; - SharedFormulaRowCount := 3; - SharedFormulaBaseCol_After := 2; // Position of shared formula after delete op - SharedFormulaBaseRow_After := 2; - SharedFormulaColCount_After := 2; // Size of shared formula block after insert op - SharedFormulaRowCount_After := 3; - SollFormula := 'A3-$B$2,B3-$B$2;'+ // all column indexes decrease by 1 due to deleted col in front - 'A4-$B$2,B4-$B$2;'+ - 'A5-$B$2,B5-$B$2'; - // comma-separated --> cells along row; semicolon separates rows - SollLayout := '2345678|'+ - '3456789|'+ - '4501890|'+ - '5612901|'+ - '6723012|'+ - '7890123'; - end; - - // Delete last column (this is behind any cell of the shared formula) - with InsDelTestData[33] do begin - Layout := '12345678|'+ - '23456789|'+ - '345S 890|'+ // "S" = shared formula (2 cols x 3 rows) - '456 901|'+ - '567 012|'+ - '67890123'; - DeleteCol := 7; - Formula := 'B3-$C$2'; - SharedFormulaColCount := 2; - SharedFormulaRowCount := 3; - SharedFormulaBaseCol_After := 3; // Position of shared formula after delete op - SharedFormulaBaseRow_After := 2; - SharedFormulaColCount_After := 2; // Size of shared formula block after insert op - SharedFormulaRowCount_After := 3; - SollFormula := 'B3-$C$2,C3-$C$2;'+ // all column indexes unchanged due to delete behind - 'B4-$C$2,C4-$C$2;'+ - 'B5-$C$2,C5-$C$2'; - // comma-separated --> cells along row; semicolon separates rows - SollLayout := '1234567|'+ - '2345678|'+ - '3450189|'+ - '4561290|'+ - '5672301|'+ - '6789012'; - end; - - // Delete in shared formula block, but no formula cell affected - with InsDelTestData[34] do begin - Layout := '12345678|'+ - '23456789|'+ - '345S 890|'+ // "S" = shared formula (2 cols x 3 rows) - '456 901|'+ - '567 012|'+ - '67890123'; - DeleteCol := 4; - Formula := 'B3-$C$2'; - SharedFormulaColCount := 2; - SharedFormulaRowCount := 3; - SharedFormulaBaseCol_After := 3; // Position of shared formula after delete op - SharedFormulaBaseRow_After := 2; - SharedFormulaColCount_After := 1; // Size of shared formula block after insert op - SharedFormulaRowCount_After := 3; - SollFormula := 'B3-$C$2;'+ - 'B4-$C$2;'+ - 'B5-$C$2'; - // comma-separated --> cells along row; semicolon separates rows - SollLayout := '1234678|'+ - '2345789|'+ - '3450890|'+ - '4561901|'+ - '5672012|'+ - '6789123'; - end; - - // Delete column used in shared formula base - with InsDelTestData[35] do begin - Layout := '12345678|'+ - '23456789|'+ - '345S 890|'+ // "S" = shared formula (2 cols x 3 rows) - '456 901|'+ - '567 012|'+ - '67890123'; - DeleteCol := 1; - Formula := 'B3-$C$2'; - SharedFormulaColCount := 2; - SharedFormulaRowCount := 3; - SharedFormulaBaseCol_After := 2; // Position of shared formula after delete op - SharedFormulaBaseRow_After := 2; - SharedFormulaColCount_After := 2; // Size of shared formula block after insert op - SharedFormulaRowCount_After := 3; - SollFormula := '#REF!-$B$2,#REF!-$B$2;'+ - '#REF!-$B$2,#REF!-$B$2;'+ - '#REF!-$B$2,#REF!-$B$2'; - // comma-separated --> cells along row; semicolon separates rows - SollLayout := '1345678|'+ - '2456789|'+ - '35EE890|'+ - '46EE901|'+ - '57EE012|'+ - '6890123'; - end; - - // Delete row 0 (this is before any cell of the shared formula) - with InsDelTestData[36] do begin - Layout := '12345678|'+ - '23456789|'+ - '345S 890|'+ // "S" = shared formula (2 cols x 3 rows) - '456 901|'+ - '567 012|'+ - '67890123'; - DeleteRow := 0; - Formula := 'B3-$C$2'; - SharedFormulaColCount := 2; - SharedFormulaRowCount := 3; - SharedFormulaBaseCol_After := 3; // Position of shared formula after delete op - SharedFormulaBaseRow_After := 1; - SharedFormulaColCount_After := 2; // Size of shared formula block after insert op - SharedFormulaRowCount_After := 3; - SollFormula := 'B2-$C$1,C2-$C$1;'+ // all row indexes decrease by 1 due to deleted row in front - 'B3-$C$1,C3-$C$1;'+ - 'B4-$C$1,C4-$C$1'; - // comma-separated --> cells along row; semicolon separates rows - SollLayout := '23456789|'+ - '34501890|'+ - '45612901|'+ - '56723012|'+ - '67890123'; - end; - - // Delete lsst row (this is below any cell of the shared formula) - with InsDelTestData[37] do begin - Layout := '12345678|'+ - '23456789|'+ - '345S 890|'+ // "S" = shared formula (2 cols x 3 rows) - '456 901|'+ - '567 012|'+ - '67890123'; - DeleteRow := 5; - Formula := 'B3-$C$2'; - SharedFormulaColCount := 2; - SharedFormulaRowCount := 3; - SharedFormulaBaseCol_After := 3; // Position of shared formula after delete op - SharedFormulaBaseRow_After := 2; - SharedFormulaColCount_After := 2; // Size of shared formula block after insert op - SharedFormulaRowCount_After := 3; - SollFormula := 'B3-$C$2,C3-$C$2;'+ // all row indexes unchanged - 'B4-$C$2,C4-$C$2;'+ - 'B5-$C$2,C5-$C$2'; - // comma-separated --> cells along row; semicolon separates rows - SollLayout := '12345678|'+ - '23456789|'+ - '34501890|'+ - '45612901|'+ - '56723012|'; - end; - - // Delete row through shared formula block - with InsDelTestData[38] do begin - Layout := '12345678|'+ - '23456789|'+ - '345S 890|'+ // "S" = shared formula (2 cols x 3 rows) - '456 901|'+ - '567 012|'+ - '67890123'; - DeleteRow := 3; - Formula := 'B3-$C$2'; - SharedFormulaColCount := 2; - SharedFormulaRowCount := 3; - SharedFormulaBaseCol_After := 3; // Position of shared formula after delete op - SharedFormulaBaseRow_After := 2; - SharedFormulaColCount_After := 2; // Size of shared formula block after insert op - SharedFormulaRowCount_After := 2; - SollFormula := 'B3-$C$2,C3-$C$2;'+ - 'B4-$C$2,C4-$C$2;'+ - 'B5-$C$2,C5-$C$2'; - // comma-separated --> cells along row; semicolon separates rows - SollLayout := '12345678|'+ - '23456789|'+ - '34501890|'+ - // '45612901|'+ - '56723012|'+ - '67890123';; - end; - - // Delete row through shared formula block - with InsDelTestData[39] do begin - Layout := '12345678|'+ - '23456789|'+ - '345S 890|'+ // "S" = shared formula (2 cols x 3 rows) - '456 901|'+ - '567 012|'+ - '67890123'; - DeleteRow := 1; - Formula := 'B3-$C$2'; - SharedFormulaColCount := 2; - SharedFormulaRowCount := 3; - SharedFormulaBaseCol_After := 3; // Position of shared formula after delete op - SharedFormulaBaseRow_After := 1; - SharedFormulaColCount_After := 2; // Size of shared formula block after insert op - SharedFormulaRowCount_After := 3; - SollFormula := 'B2-#REF!,C2-#REF!;'+ // Confirmed by Excel - 'B3-#REF!,C3-#REF!;'+ - 'B4-#REF!,C4-#REF!'; - // comma-separated --> cells along row; semicolon separates rows - SollLayout := '12345678|'+ // Confirmed by Excel - // '23456789|'+ - '345EE890|'+ - '456EE901|'+ - '567EE012|'+ - '67890123';; - end; { ---------------------------------------------------------------------------} { Layouts with merged cells } { ---------------------------------------------------------------------------} // No insert/delete, just to test the merged block - with InsDelTestData[40] do begin + with InsDelTestData[22] do begin Layout := '12345678|'+ '23456789|'+ '345M 890|'+ // "M" = merged block (2 cols x 3 rows) @@ -1231,7 +653,7 @@ begin end; // Insert column before merged block - with InsDelTestData[41] do begin + with InsDelTestData[23] do begin Layout := '12345678|'+ '23456789|'+ '345M 890|'+ // "M" = merged block (2 cols x 3 rows) @@ -1252,7 +674,7 @@ begin end; // Insert column through merged block - with InsDelTestData[42] do begin + with InsDelTestData[24] do begin Layout := '12345678|'+ '23456789|'+ '345M 890|'+ // "M" = merged block (2 cols x 3 rows) @@ -1273,7 +695,7 @@ begin end; // Insert column behind merged block - with InsDelTestData[43] do begin + with InsDelTestData[25] do begin Layout := '12345678|'+ '23456789|'+ '345M 890|'+ // "M" = merged block (2 cols x 3 rows) @@ -1294,7 +716,7 @@ begin end; // Insert row above merged block - with InsDelTestData[44] do begin + with InsDelTestData[26] do begin Layout := '12345678|'+ '23456789|'+ '345M 890|'+ // "M" = merged block (2 cols x 3 rows) @@ -1316,7 +738,7 @@ begin end; // Insert row through merged block - with InsDelTestData[45] do begin + with InsDelTestData[27] do begin Layout := '12345678|'+ '23456789|'+ '345M 890|'+ // "M" = merged block (2 cols x 3 rows) @@ -1338,7 +760,7 @@ begin end; // Insert row below merged block - with InsDelTestData[46] do begin + with InsDelTestData[28] do begin Layout := '12345678|'+ '23456789|'+ '345M 890|'+ // "M" = merged block (2 cols x 3 rows) @@ -1360,7 +782,7 @@ begin end; // Delete column before merged block - with InsDelTestData[47] do begin + with InsDelTestData[29] do begin Layout := '12345678|'+ '23456789|'+ '345M 890|'+ // "M" = merged block (2 cols x 3 rows) @@ -1381,7 +803,7 @@ begin end; // Delete column through merged block - with InsDelTestData[48] do begin + with InsDelTestData[30] do begin Layout := '12345678|'+ '23456789|'+ '345M 890|'+ // "M" = merged block (2 cols x 3 rows) @@ -1402,7 +824,7 @@ begin end; // Delete column behind merged block - with InsDelTestData[49] do begin + with InsDelTestData[31] do begin Layout := '12345678|'+ '23456789|'+ '345M 890|'+ // "M" = merged block (2 cols x 3 rows) @@ -1423,7 +845,7 @@ begin end; // Delete row above merged block - with InsDelTestData[50] do begin + with InsDelTestData[32] do begin Layout := '12345678|'+ '23456789|'+ '345M 890|'+ // "M" = merged block (2 cols x 3 rows) @@ -1444,7 +866,7 @@ begin end; // Delete row through merged block - with InsDelTestData[51] do begin + with InsDelTestData[33] do begin Layout := '12345678|'+ '23456789|'+ '345M 890|'+ // "M" = merged block (2 cols x 3 rows) @@ -1465,7 +887,7 @@ begin end; // Delete row behind merged block - with InsDelTestData[52] do begin + with InsDelTestData[34] do begin Layout := '12345678|'+ '23456789|'+ '345M 890|'+ // "M" = merged block (2 cols x 3 rows) @@ -1559,13 +981,6 @@ begin ' ' : ; // Leave cell empty '0'..'9': MyWorksheet.WriteNumber(row, col, StrToInt(s[col+1])); 'F' : MyWorksheet.WriteFormula(row, col, InsDelTestData[ATestIndex].Formula); - 'S' : MyWorksheet.WriteSharedFormula( - row, - col, - row + InsDelTestData[ATestIndex].SharedFormulaRowCount - 1, - col + InsDelTestData[ATestIndex].SharedFormulaColCount - 1, - InsDelTestData[ATestIndex].Formula - ); 'M' : begin MyWorksheet.WriteUTF8Text(row, col, 'M'); MyWorksheet.MergeCells( @@ -1814,189 +1229,81 @@ begin end; procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_22_BIFF8; -// no insert/delete; just test shared formula +// no insert/delete, just test merged cell block begin TestWriteRead_InsDelColRow(22, sfExcel8); end; procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_23_BIFF8; -// insert column before any cell addressed by the shared formula +// insert column before merged block begin TestWriteRead_InsDelColRow(23, sfExcel8); end; procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_24_BIFF8; -// insert column after any cell addressed by the shared formula +// insert column through merged block begin TestWriteRead_InsDelColRow(24, sfExcel8); end; procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_25_BIFF8; -// insert column through cells addressed by shared formula +// insert column behind merged block begin TestWriteRead_InsDelColRow(25, sfExcel8); end; procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_26_BIFF8; -// insert column through shared formula block +// insert row above merged block begin TestWriteRead_InsDelColRow(26, sfExcel8); end; procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_27_BIFF8; -// insert column behind shared formula block +// insert row through merged block begin TestWriteRead_InsDelColRow(27, sfExcel8); end; procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_28_BIFF8; -// insert row before anything affected by the shared formula -begin - TestWriteRead_InsDelColRow(28, sfExcel8); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_29_BIFF8; -// insert row after shared formula cells -begin - TestWriteRead_InsDelColRow(29, sfExcel8); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_30_BIFF8; -// insert row through shared formula block -begin - TestWriteRead_InsDelColRow(30, sfExcel8); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_31_BIFF8; -// insert row below shared formula block -begin - TestWriteRead_InsDelColRow(31, sfExcel8); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_32_BIFF8; -// delete column before any cell referenced by the shared formula(s) -begin - TestWriteRead_InsDelColRow(32, sfExcel8); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_33_BIFF8; -// delete column after any cell referenced by the shared formula(s) -begin - TestWriteRead_InsDelColRow(33, sfExcel8); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_34_BIFF8; -// delete column in shared formula block, but no formula cell affected -begin - TestWriteRead_InsDelColRow(34, sfExcel8); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_35_BIFF8; -// delete column used in shared formula -begin - TestWriteRead_InsDelColRow(35, sfExcel8); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_36_BIFF8; -// delete row above shared formula and the used cells -begin - TestWriteRead_InsDelColRow(36, sfExcel8); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_37_BIFF8; -// delete row below shared formula and the used cells -begin - TestWriteRead_InsDelColRow(37, sfExcel8); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_38_BIFF8; -// delete row through shared formula block -begin - TestWriteRead_InsDelColRow(38, sfExcel8); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_39_BIFF8; -// delete row with cell used in shared formula block -begin - TestWriteRead_InsDelColRow(39, sfExcel8); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_40_BIFF8; -// no insert/delete, just test merged cell block -begin - TestWriteRead_InsDelColRow(40, sfExcel8); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_41_BIFF8; -// insert column before merged block -begin - TestWriteRead_InsDelColRow(41, sfExcel8); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_42_BIFF8; -// insert column through merged block -begin - TestWriteRead_InsDelColRow(42, sfExcel8); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_43_BIFF8; -// insert column behind merged block -begin - TestWriteRead_InsDelColRow(43, sfExcel8); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_44_BIFF8; -// insert row above merged block -begin - TestWriteRead_InsDelColRow(44, sfExcel8); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_45_BIFF8; -// insert row through merged block -begin - TestWriteRead_InsDelColRow(45, sfExcel8); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_46_BIFF8; // insert row below merged block begin - TestWriteRead_InsDelColRow(46, sfExcel8); + TestWriteRead_InsDelColRow(28, sfExcel8); end; procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_DelColBeforeMerge_BIFF8; // delete column before merged block begin - TestWriteRead_InsDelColRow(47, sfExcel8); + TestWriteRead_InsDelColRow(29, sfExcel8); end; procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_DelColInMerge_BIFF8; // delete column through merged block begin - TestWriteRead_InsDelColRow(48, sfExcel8); + TestWriteRead_InsDelColRow(30, sfExcel8); end; procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_DelColAfterMerge_BIFF8; // delete column behind merged block begin - TestWriteRead_InsDelColRow(49, sfExcel8); + TestWriteRead_InsDelColRow(31, sfExcel8); end; -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_50_BIFF8; +procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_32_BIFF8; // delete row above merged block begin - TestWriteRead_InsDelColRow(50, sfExcel8); + TestWriteRead_InsDelColRow(32, sfExcel8); end; -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_51_BIFF8; +procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_33_BIFF8; // delete row through merged block begin - TestWriteRead_InsDelColRow(51, sfExcel8); + TestWriteRead_InsDelColRow(33, sfExcel8); end; -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_52_BIFF8; +procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_34_BIFF8; // delete row below merged block begin - TestWriteRead_InsDelColRow(52, sfExcel8); + TestWriteRead_InsDelColRow(34, sfExcel8); end; @@ -2137,189 +1444,81 @@ begin end; procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_22_OOXML; -// no insert/delete; just test shared formula +// no insert/delete, just test merged cell block begin TestWriteRead_InsDelColRow(22, sfOOXML); end; procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_23_OOXML; -// insert column before any cell addressed by the shared formula +// insert column before merged block begin TestWriteRead_InsDelColRow(23, sfOOXML); end; procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_24_OOXML; -// insert column after any cell addressed by the shared formula +// insert column through merged block begin TestWriteRead_InsDelColRow(24, sfOOXML); end; procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_25_OOXML; -// insert column through cells addressed by shared formula +// insert column behind merged block begin TestWriteRead_InsDelColRow(25, sfOOXML); end; procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_26_OOXML; -// insert column through shared formula block +// insert row above merged block begin TestWriteRead_InsDelColRow(26, sfOOXML); end; procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_27_OOXML; -// insert column behind shared formula block +// insert row through merged block begin TestWriteRead_InsDelColRow(27, sfOOXML); end; procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_28_OOXML; -// insert row before anything affected by the shared formula -begin - TestWriteRead_InsDelColRow(28, sfOOXML); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_29_OOXML; -// insert row after shared formula cells -begin - TestWriteRead_InsDelColRow(29, sfOOXML); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_30_OOXML; -// insert row through shared formula block -begin - TestWriteRead_InsDelColRow(30, sfOOXML); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_31_OOXML; -// insert row below shared formula block -begin - TestWriteRead_InsDelColRow(31, sfOOXML); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_32_OOXML; -// delete column before any cell referenced by the shared formula(s) -begin - TestWriteRead_InsDelColRow(32, sfOOXML); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_33_OOXML; -// delete column after any cell referenced by the shared formula(s) -begin - TestWriteRead_InsDelColRow(33, sfOOXML); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_34_OOXML; -// delete column in shared formula block, but no formula cell affected -begin - TestWriteRead_InsDelColRow(34, sfOOXML); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_35_OOXML; -// delete column used in shared formula -begin - TestWriteRead_InsDelColRow(35, sfOOXML); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_36_OOXML; -// delete row above shared formula and the used cells -begin - TestWriteRead_InsDelColRow(36, sfOOXML); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_37_OOXML; -// delete row below shared formula and the used cells -begin - TestWriteRead_InsDelColRow(37, sfOOXML); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_38_OOXML; -// delete row through shared formula block -begin - TestWriteRead_InsDelColRow(38, sfOOXML); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_39_OOXML; -// delete row with cell used in shared formula block -begin - TestWriteRead_InsDelColRow(39, sfOOXML); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_40_OOXML; -// no insert/delete, just test merged cell block -begin - TestWriteRead_InsDelColRow(40, sfOOXML); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_41_OOXML; -// insert column before merged block -begin - TestWriteRead_InsDelColRow(41, sfOOXML); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_42_OOXML; -// insert column through merged block -begin - TestWriteRead_InsDelColRow(42, sfOOXML); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_43_OOXML; -// insert column behind merged block -begin - TestWriteRead_InsDelColRow(43, sfOOXML); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_44_OOXML; -// insert row above merged block -begin - TestWriteRead_InsDelColRow(44, sfOOXML); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_45_OOXML; -// insert row through merged block -begin - TestWriteRead_InsDelColRow(45, sfOOXML); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_46_OOXML; // insert row below merged block begin - TestWriteRead_InsDelColRow(46, sfOOXML); + TestWriteRead_InsDelColRow(28, sfOOXML); end; procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_DelColBeforeMerge_OOXML; // delete column before merged block begin - TestWriteRead_InsDelColRow(47, sfOOXML); + TestWriteRead_InsDelColRow(29, sfOOXML); end; procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_DelColInMerge_OOXML; // delete column through merged block begin - TestWriteRead_InsDelColRow(48, sfOOXML); + TestWriteRead_InsDelColRow(30, sfOOXML); end; procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_DelColAfterMerge_OOXML; // delete column behind merged block begin - TestWriteRead_InsDelColRow(49, sfOOXML); + TestWriteRead_InsDelColRow(31, sfOOXML); end; -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_50_OOXML; +procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_32_OOXML; // delete row above merged block begin - TestWriteRead_InsDelColRow(50, sfOOXML); + TestWriteRead_InsDelColRow(32, sfOOXML); end; -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_51_OOXML; +procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_33_OOXML; // delete row through merged block begin - TestWriteRead_InsDelColRow(51, sfOOXML); + TestWriteRead_InsDelColRow(33, sfOOXML); end; -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_52_OOXML; +procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_34_OOXML; // delete row below merged block begin - TestWriteRead_InsDelColRow(52, sfOOXML); + TestWriteRead_InsDelColRow(34, sfOOXML); end; @@ -2460,188 +1659,80 @@ begin end; procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_22_ODS; -// no insert/delete; just test shared formula +// no insert/delete, just test merged cell block begin TestWriteRead_InsDelColRow(22, sfOpenDocument); end; procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_23_ODS; -// insert column before any cell addressed by the shared formula +// insert column before merged block begin TestWriteRead_InsDelColRow(23, sfOpenDocument); end; procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_24_ODS; -// insert column after any cell addressed by the shared formula +// insert column through merged block begin TestWriteRead_InsDelColRow(24, sfOpenDocument); end; procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_25_ODS; -// insert column through cells addressed by shared formula +// insert column behind merged block begin TestWriteRead_InsDelColRow(25, sfOpenDocument); end; procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_26_ODS; -// insert column through shared formula block +// insert row above merged block begin TestWriteRead_InsDelColRow(26, sfOpenDocument); end; procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_27_ODS; -// insert column behind shared formula block +// insert row through merged block begin TestWriteRead_InsDelColRow(27, sfOpenDocument); end; procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_28_ODS; -// insert row before anything affected by the shared formula -begin - TestWriteRead_InsDelColRow(28, sfOpenDocument); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_29_ODS; -// insert row after shared formula cells -begin - TestWriteRead_InsDelColRow(29, sfOpenDocument); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_30_ODS; -// insert row through shared formula block -begin - TestWriteRead_InsDelColRow(30, sfOpenDocument); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_31_ODS; -// insert row below shared formula block -begin - TestWriteRead_InsDelColRow(31, sfOpenDocument); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_32_ODS; -// delete column before any cell referenced by the shared formula(s) -begin - TestWriteRead_InsDelColRow(32, sfOpenDocument); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_33_ODS; -// delete column after any cell referenced by the shared formula(s) -begin - TestWriteRead_InsDelColRow(33, sfOpenDocument); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_34_ODS; -// delete column in shared formula block, but no formula cell affected -begin - TestWriteRead_InsDelColRow(34, sfOpenDocument); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_35_ODS; -// delete column used in shared formula -begin - TestWriteRead_InsDelColRow(35, sfOpenDocument); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_36_ODS; -// delete row above shared formula and the used cells -begin - TestWriteRead_InsDelColRow(36, sfOpenDocument); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_37_ODS; -// delete row below shared formula and the used cells -begin - TestWriteRead_InsDelColRow(37, sfOpenDocument); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_38_ODS; -// delete row through shared formula block -begin - TestWriteRead_InsDelColRow(38, sfOpenDocument); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_39_ODS; -// delete row with cell used in shared formula block -begin - TestWriteRead_InsDelColRow(39, sfOpenDocument); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_40_ODS; -// no insert/delete, just test merged cell block -begin - TestWriteRead_InsDelColRow(40, sfOpenDocument); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_41_ODS; -// insert column before merged block -begin - TestWriteRead_InsDelColRow(41, sfOpenDocument); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_42_ODS; -// insert column through merged block -begin - TestWriteRead_InsDelColRow(42, sfOpenDocument); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_43_ODS; -// insert column behind merged block -begin - TestWriteRead_InsDelColRow(43, sfOpenDocument); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_44_ODS; -// insert row above merged block -begin - TestWriteRead_InsDelColRow(44, sfOpenDocument); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_45_ODS; -// insert row through merged block -begin - TestWriteRead_InsDelColRow(45, sfOpenDocument); -end; - -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_46_ODS; // insert row below merged block begin - TestWriteRead_InsDelColRow(46, sfOpenDocument); + TestWriteRead_InsDelColRow(28, sfOpenDocument); end; procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_DelColBeforeMerge_ODS; // delete column before merged block begin - TestWriteRead_InsDelColRow(47, sfOpenDocument); + TestWriteRead_InsDelColRow(29, sfOpenDocument); end; procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_DelColInMerge_ODS; begin - TestWriteRead_InsDelColRow(48, sfOpenDocument); + TestWriteRead_InsDelColRow(30, sfOpenDocument); end; procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_DelColAfterMerge_ODS; // delete column behind merged block begin - TestWriteRead_InsDelColRow(49, sfOpenDocument); + TestWriteRead_InsDelColRow(31, sfOpenDocument); end; -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_50_ODS; +procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_32_ODS; // delete row above merged block begin - TestWriteRead_InsDelColRow(50, sfOpenDocument); + TestWriteRead_InsDelColRow(32, sfOpenDocument); end; -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_51_ODS; +procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_33_ODS; // delete row through merged block begin - TestWriteRead_InsDelColRow(51, sfOpenDocument); + TestWriteRead_InsDelColRow(33, sfOpenDocument); end; -procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_52_ODS; +procedure TSpreadWriteRead_InsDelColRow_Tests.TestWriteRead_InsDelColRow_34_ODS; // delete row below merged block begin - TestWriteRead_InsDelColRow(52, sfOpenDocument); + TestWriteRead_InsDelColRow(34, sfOpenDocument); end; diff --git a/components/fpspreadsheet/xlsbiff2.pas b/components/fpspreadsheet/xlsbiff2.pas index 0dc2275cf..ba542c3f9 100755 --- a/components/fpspreadsheet/xlsbiff2.pas +++ b/components/fpspreadsheet/xlsbiff2.pas @@ -128,10 +128,12 @@ type procedure WriteRPNFormula(AStream: TStream; const ARow, ACol: Cardinal; const AFormula: TsRPNFormula; ACell: PCell); override; function WriteRPNFunc(AStream: TStream; AIdentifier: Word): Word; override; + { procedure WriteRPNSharedFormulaLink(AStream: TStream; ACell: PCell; var RPNLength: Word); override; + } procedure WriteRPNTokenArraySize(AStream: TStream; ASize: Word); override; - procedure WriteSharedFormula(AStream: TStream; ACell: PCell); override; +// procedure WriteSharedFormula(AStream: TStream; ACell: PCell); override; procedure WriteStringRecord(AStream: TStream; AString: String); override; procedure WriteWindow1(AStream: TStream); override; procedure WriteWindow2(AStream: TStream; ASheet: TsWorksheet); @@ -1670,10 +1672,11 @@ begin AStream.WriteByte(1); { Formula data (RPN token array) } + { if ACell^.SharedFormulaBase <> nil then WriteRPNSharedFormulaLink(AStream, ACell, RPNLength) - else - WriteRPNTokenArray(AStream, ACell, AFormula, false, RPNLength); + else} + WriteRPNTokenArray(AStream, ACell, AFormula, false, RPNLength); { Finally write sizes after we know them } FinalPos := AStream.Position; @@ -1683,7 +1686,7 @@ begin { Write following STRING record if formula result is a non-empty string } if (ACell^.ContentType = cctUTF8String) and (ACell^.UTF8StringValue <> '') then - WriteStringRecord(AStream, ACell^.UTF8StringValue); + WriteSTRINGRecord(AStream, ACell^.UTF8StringValue); end; {@@ ---------------------------------------------------------------------------- @@ -1696,7 +1699,7 @@ begin AStream.WriteByte(Lo(AIdentifier)); Result := 1; end; - + (* {@@ ---------------------------------------------------------------------------- This method is intended to write a link to the cell containing the shared formula used by the cell. But since BIFF2 does not support shared formulas @@ -1721,7 +1724,7 @@ begin // Clean up SetLength(formula, 0); end; - + *) {@@ ---------------------------------------------------------------------------- Writes the size of the RPN token array. Called from WriteRPNFormula. Overrides xlscommon. @@ -1731,7 +1734,7 @@ procedure TsSpreadBIFF2Writer.WriteRPNTokenArraySize(AStream: TStream; begin AStream.WriteByte(ASize); end; - + (* {@@ ---------------------------------------------------------------------------- Is intended to write the token array of a shared formula stored in ACell. But since BIFF2 does not support shared formulas this method must not do @@ -1740,7 +1743,7 @@ end; procedure TsSpreadBIFF2Writer.WriteSharedFormula(AStream: TStream; ACell: PCell); begin Unused(AStream, ACell); -end; +end; *) {@@ ---------------------------------------------------------------------------- Writes an Excel 2 STRING record which immediately follows a FORMULA record diff --git a/components/fpspreadsheet/xlsbiff8.pas b/components/fpspreadsheet/xlsbiff8.pas index fd6dcc09e..b140afb7d 100755 --- a/components/fpspreadsheet/xlsbiff8.pas +++ b/components/fpspreadsheet/xlsbiff8.pas @@ -355,8 +355,8 @@ const MASK_HLINK_ABSOLUTE = $00000002; MASK_HLINK_DESCRIPTION = $00000014; MASK_HLINK_TEXTMARK = $00000008; - MASK_HLINK_TARGETFRAME = $00000080; - MASK_HLINK_UNCPATH = $00000100; +{%H-}MASK_HLINK_TARGETFRAME = $00000080; +{%H-}MASK_HLINK_UNCPATH = $00000100; SHAPEID_BASE = 1024; @@ -1446,7 +1446,7 @@ begin col2 := WordLEToN(AStream.ReadWord); { GUID of standard link } - AStream.ReadBuffer(guid, SizeOf(guid)); + AStream.ReadBuffer(guid{%H-}, SizeOf(guid)); { unknown DWord } AStream.ReadDWord; @@ -2648,7 +2648,7 @@ procedure TsSpreadBIFF8Writer.WriteMergedCells(AStream: TStream; const MAX_PER_RECORD = 1026; var - n0, n, i: Integer; + n0, n: Integer; rng: PsCellRange; newRecord: Boolean; begin @@ -2678,31 +2678,6 @@ begin n := Min(n0, MAX_PER_RECORD); end; end; - (* - while n0 > 0 do begin - n := Min(n0, MAX_PER_RECORD); - // at most 1026 merged ranges per BIFF record, the rest goes into a new record - - { BIFF record header } - WriteBIFFHeader(AStream, INT_EXCEL_ID_MERGEDCELLS, 2 + n*8); - - { Number of cell ranges in this record } - AStream.WriteWord(WordToLE(n)); - - { Loop for writing the merged cell ranges } - rng := PsCellRange(AWorksheet.MergedCells.GetFirst); - while (n > 0) do begin - AStream.WriteWord(WordToLE(rng^.Row1)); - AStream.WriteWord(WordToLE(rng^.Row2)); - AStream.WriteWord(WordToLE(rng^.Col1)); - AStream.WriteWord(WordToLE(rng^.Col2)); - dec(n); - rng := PsCellRange(AWorksheet.MergedCells.GetNext); - end; - - dec(n0, MAX_PER_RECORD); - end; - *) end; {@@----------------------------------------------------------------------------- diff --git a/components/fpspreadsheet/xlscommon.pas b/components/fpspreadsheet/xlscommon.pas index 340dfbcda..1928c5907 100644 --- a/components/fpspreadsheet/xlscommon.pas +++ b/components/fpspreadsheet/xlscommon.pas @@ -313,7 +313,8 @@ type out AFlags: TsRelFlags); virtual; function ReadRPNFunc(AStream: TStream): Word; virtual; procedure ReadRPNSharedFormulaBase(AStream: TStream; out ARow, ACol: Cardinal); virtual; - function ReadRPNTokenArray(AStream: TStream; ACell: PCell): Boolean; + function ReadRPNTokenArray(AStream: TStream; ACell: PCell; + ASharedFormulaBase: PCell = nil): Boolean; function ReadRPNTokenArraySize(AStream: TStream): word; virtual; procedure ReadSharedFormula(AStream: TStream); @@ -404,8 +405,10 @@ type const AFormula: TsRPNFormula; ACell: PCell); virtual; function WriteRPNFunc(AStream: TStream; AIdentifier: Word): Word; virtual; procedure WriteRPNResult(AStream: TStream; ACell: PCell); + { procedure WriteRPNSharedFormulaLink(AStream: TStream; ACell: PCell; var RPNLength: Word); virtual; + } procedure WriteRPNTokenArray(AStream: TStream; ACell: PCell; const AFormula: TsRPNFormula; UseRelAddr: Boolean; var RPNLength: Word); procedure WriteRPNTokenArraySize(AStream: TStream; ASize: Word); virtual; @@ -413,10 +416,12 @@ type // Writes out a SELECTION record procedure WriteSelection(AStream: TStream; ASheet: TsWorksheet; APane: Byte); procedure WriteSelections(AStream: TStream; ASheet: TsWorksheet); + (* // Writes out a shared formula procedure WriteSharedFormula(AStream: TStream; ACell: PCell); virtual; procedure WriteSharedFormulaRange(AStream: TStream; AFirstRow, AFirstCol, ALastRow, ALastCol: Cardinal); virtual; + *) procedure WriteSheetPR(AStream: TStream); procedure WriteStringRecord(AStream: TStream; AString: String); virtual; // Writes cell content received by workbook in OnNeedCellData event @@ -1591,7 +1596,7 @@ end; rpn formula, converts it to a string formula and stores it in the cell. -------------------------------------------------------------------------------} function TsSpreadBIFFReader.ReadRPNTokenArray(AStream: TStream; - ACell: PCell): Boolean; + ACell: PCell; ASharedFormulaBase: PCell = nil): Boolean; var n: Word; p0: Int64; @@ -1607,7 +1612,8 @@ var funcCode: Word; b: Byte; found: Boolean; - formula: TsRPNformula; + rpnFormula: TsRPNformula; + strFormula: String; begin rpnItem := nil; n := ReadRPNTokenArraySize(AStream); @@ -1652,16 +1658,16 @@ begin // For compatibility with other formats, convert offsets back to regular indexes. if (rfRelRow in flags) then r := LongInt(ACell^.Row) + dr - else r := LongInt(ACell^.SharedFormulaBase^.Row) + dr; + else r := LongInt(ASharedFormulaBase^.Row) + dr; if (rfRelRow2 in flags) then r2 := LongInt(ACell^.Row) + dr2 - else r2 := LongInt(ACell^.SharedFormulaBase^.Row) + dr2; + else r2 := LongInt(ASharedFormulaBase^.Row) + dr2; if (rfRelCol in flags) then c := LongInt(ACell^.Col) + dc - else c := LongInt(ACell^.SharedFormulaBase^.Col) + dc; + else c := LongInt(ASharedFormulaBase^.Col) + dc; if (rfRelCol2 in flags) then c2 := LongInt(ACell^.Col) + dc2 - else c2 := LongInt(ACell^.SharedFormulaBase^.Col) + dc2; + else c2 := LongInt(ASharedFormulaBase^.Col) + dc2; rpnItem := RPNCellRange(r, c, r2, c2, flags, rpnItem); end; INT_EXCEL_TOKEN_TMISSARG: @@ -1710,12 +1716,9 @@ begin end; INT_EXCEL_TOKEN_TEXP: - // Indicates that cell belongs to a shared or array formula. We determine - // the base cell of the shared formula and store it in the current cell. - begin - ReadRPNSharedFormulaBase(AStream, r, c); - ACell^.SharedFormulaBase := FWorksheet.FindCell(r, c); - end; + // Indicates that cell belongs to a shared or array formula. + // This information is not needed any more. + ReadRPNSharedFormulaBase(AStream, r, c); else found := false; @@ -1734,11 +1737,16 @@ begin Result := false; end else begin - formula := CreateRPNFormula(rpnItem, true); // true --> we have to flip the order of items! + rpnFormula := CreateRPNFormula(rpnItem, true); // true --> we have to flip the order of items! + strFormula := FWorksheet.ConvertRPNFormulaToStringFormula(rpnFormula); + if strFormula <> '' then + ACell^.FormulaValue := strFormula; + { if (ACell^.SharedFormulaBase = nil) or (ACell = ACell^.SharedFormulaBase) then ACell^.FormulaValue := FWorksheet.ConvertRPNFormulaToStringFormula(formula) else ACell^.FormulaValue := ''; + } Result := true; end; end; @@ -1760,7 +1768,7 @@ end; -------------------------------------------------------------------------------} procedure TsSpreadBIFFReader.ReadSharedFormula(AStream: TStream); var - r1, {%H-}r2, c1, {%H-}c2: Cardinal; + r, r1, r2, c, c1, c2: Cardinal; cell: PCell; begin // Cell range in which the formula is valid @@ -1769,12 +1777,12 @@ begin c1 := AStream.ReadByte; // 8 bit, even for BIFF8 c2 := AStream.ReadByte; - { Create cell } + { Create cell - this is the "base" of the shared formula } if FIsVirtualMode then begin // "Virtual" cell InitCell(r1, c1, FVirtualCell); cell := @FVirtualCell; end else - cell := FWorksheet.GetCell(r1, c1); // "Real" cell + cell := FWorksheet.GetCell(r1, c1); // "Real" cell // Unused AStream.ReadByte; @@ -1783,7 +1791,12 @@ begin AStream.ReadByte; // RPN formula tokens - ReadRPNTokenArray(AStream, cell); + ReadRPNTokenArray(AStream, cell, cell); //base); + + // Copy shared formula to individual cells in the specified range + for r := r1 to r2 do + for c := c1 to c2 do + FWorksheet.CopyFormula(cell, r, c); end; {@@ ---------------------------------------------------------------------------- @@ -2534,8 +2547,12 @@ begin if (ARow >= FLimitations.MaxRowCount) or (ACol >= FLimitations.MaxColCount) then exit; + if Length(AFormula) = 0 then + exit; + { if not ((Length(AFormula) > 0) or (ACell^.SharedFormulaBase <> nil)) then exit; + } { BIFF Record header } AStream.WriteWord(WordToLE(INT_EXCEL_ID_FORMULA)); @@ -2560,18 +2577,19 @@ begin AStream.WriteDWord(0); { Formula data (RPN token array) } + { if ACell^.SharedFormulaBase <> nil then WriteRPNSharedFormulaLink(AStream, ACell, RPNLength) else - WriteRPNTokenArray(AStream, ACell, AFormula, false, RPNLength); + } + WriteRPNTokenArray(AStream, ACell, AFormula, false, RPNLength); { Write sizes in the end, after we known them } FinalPos := AStream.Position; AStream.Position := RecordSizePos; AStream.WriteWord(WordToLE(FinalPos - StartPos)); -// AStream.WriteWord(WordToLE(22 + RPNLength)); AStream.Position := FinalPos; - + (* { If the cell is the first cell of a range with a shared formula write the shared formula RECORD here. The shared formula RECORD must follow the first FORMULA record referring to the shared formula} @@ -2580,10 +2598,11 @@ begin (ACol = ACell^.SharedFormulaBase^.Col) then WriteSharedFormula(AStream, ACell^.SharedFormulaBase); + *) { Write following STRING record if formula result is a non-empty string. } if (ACell^.ContentType = cctUTF8String) and (ACell^.UTF8StringValue <> '') then - WriteStringRecord(AStream, ACell^.UTF8StringValue); + WriteSTRINGRecord(AStream, ACell^.UTF8StringValue); end; {@@ ---------------------------------------------------------------------------- @@ -2642,7 +2661,7 @@ begin { Write result of the formula, encoded above } AStream.WriteBuffer(Data, 8); end; - + (* {@@ ---------------------------------------------------------------------------- Is called from WriteRPNFormula in the case that the cell uses a shared formula and writes the token "array" pointing to the shared formula base. @@ -2669,6 +2688,7 @@ begin AStream.WriteBuffer(rec, SizeOf(rec)); RPNLength := SizeOf(rec); end; + *) {@@ ---------------------------------------------------------------------------- Writes the token array of the given RPN formula and returns its size @@ -3014,7 +3034,7 @@ begin end; end; end; - + (* {@@ ---------------------------------------------------------------------------- Writes the token array of a shared formula stored in ACell. Note: Relative cell addresses of a shared formula are defined by @@ -3083,7 +3103,7 @@ begin AStream.WriteByte(AFirstCol); // Index to last rcolumn AStream.WriteByte(ALastCol); -end; +end; *) {@@ ---------------------------------------------------------------------------- Writes a SHEETPR Record. diff --git a/components/fpspreadsheet/xlsxooxml.pas b/components/fpspreadsheet/xlsxooxml.pas index 691a1b00f..8c6156950 100755 --- a/components/fpspreadsheet/xlsxooxml.pas +++ b/components/fpspreadsheet/xlsxooxml.pas @@ -67,7 +67,7 @@ type FBorderList: TFPList; FHyperlinkList: TFPList; FThemeColors: array of TsColorValue; - FSharedFormulas: TStringList; +// FSharedFormulas: TStringList; FWrittenByFPS: Boolean; procedure ApplyCellFormatting(ACell: PCell; XfIndex: Integer); procedure ApplyHyperlinks(AWorksheet: TsWorksheet); @@ -467,7 +467,7 @@ begin // Set up the default palette in order to have the default color names correct. Workbook.UseDefaultPalette; - FSharedFormulas := TStringList.Create; +// FSharedFormulas := TStringList.Create; FSharedStrings := TStringList.Create; FFillList := TFPList.Create; FBorderList := TFPList.Create; @@ -493,7 +493,7 @@ begin FHyperlinkList.Free; FSharedStrings.Free; - FSharedFormulas.Free; +// FSharedFormulas.Free; // FCellFormatList is destroyed by ancestor inherited Destroy; @@ -677,6 +677,8 @@ var sstIndex: Integer; number: Double; fmt: TsCellFormat; + rng: TsCellRange; + r,c: Cardinal; begin if ANode = nil then exit; @@ -720,14 +722,21 @@ begin begin // Shared formula s := GetAttrValue(datanode, 'ref'); - if (s <> '') then // This is the shared formula base + if (s <> '') then // This is the shared formula range begin + // Split shared formula into single-cell formulas + ParseCellRangeString(s, rng); + for r := rng.Row1 to rng.Row2 do + for c := rng.Col1 to rng.Col2 do + FWorksheet.CopyFormula(cell, r, c); +(* s := GetAttrValue(datanode, 'si'); if s <> '' then FSharedFormulas.AddObject(addr, {%H-}Pointer(PtrInt(StrToInt(s)))); FWorksheet.WriteFormula(cell, formulaStr); cell^.SharedFormulaBase := cell; - //AWorksheet.WriteSharedFormula(s, formulaStr); + AWorksheet.WriteSharedFormula(s, formulaStr); + end else begin s := GetAttrValue(datanode, 'si'); @@ -736,6 +745,7 @@ begin s := FSharedFormulas[FSharedFormulas.IndexOfObject({%H-}Pointer(PtrInt(StrToInt(s))))]; cell^.SharedFormulaBase := FWorksheet.FindCell(s); end; + *) end; end else @@ -3279,9 +3289,6 @@ procedure TsSpreadOOXMLWriter.WriteFormula(AStream: TStream; var cellPosText: String; lStyleIndex: Integer; - r, r1, r2: Cardinal; - c, c1, c2: Cardinal; - cell: PCell; t, v: String; begin cellPosText := TsWorksheet.CellPosToText(ARow, ACol); @@ -3323,62 +3330,7 @@ begin end; end; - // Cell uses a shared formula - if Assigned(ACell^.SharedFormulaBase) then begin - // Cell is base of the shared formula, i.e. contains the shared formula - if (ACell = ACell^.SharedFormulaBase) then - begin - // Find range of cells using this shared formula - // The base of the shared formula is the left/top edge of the range - r1 := ACell^.Row; - r2 := r1; - r := r1 + 1; - while r <= FWorksheet.GetLastRowIndex do - begin - cell := FWorksheet.FindCell(r, ACell^.Col); - if (cell <> nil) and (cell^.SharedFormulaBase = ACell^.SharedFormulaBase) then - r2 := r - else - break; - inc(r); - end; - c1 := ACell^.Col; - c2 := c1; - c := c1 + 1; - while c <= FWorksheet.GetLastColIndex do - begin - cell := FWorksheet.FindCell(ACell^.Row, c); - if (cell <> nil) and (cell^.SharedFormulaBase = ACell^.SharedFormulaBase) then - c2 := c - else - break; - inc(c); - end; - AppendToStream(AStream, Format( - '' + - '%s' + - '%s' + - '', [ - CellPosText, lStyleIndex, t, - GetCellRangeString(ACell^.Row, ACell^.Col, r2, c2), - {%H-}PtrInt(ACell), // Use the cell pointer as ID of the shared formula - PrepareFormula(ACell^.FormulaValue), - v - ])); - end else - // Cell uses the shared formula - AppendToStream(AStream, Format( - '' + - '' + - '%s' + - '', [ - CellPosText, lStyleIndex, t, - {%H-}PtrInt(ACell^.SharedFormulaBase), // ID of the shared formula - v - ])); - end else begin - // "normal" formula - AppendToStream(AStream, Format( + AppendToStream(AStream, Format( '' + '%s' + '%s' + @@ -3386,8 +3338,7 @@ begin CellPosText, lStyleIndex, t, PrepareFormula(ACell^.FormulaValue), v - ])); - end; + ])); end; {@@ ----------------------------------------------------------------------------