diff --git a/components/fpspreadsheet/fpspreadsheet.pas b/components/fpspreadsheet/fpspreadsheet.pas index 1314385f6..0dfec3745 100755 --- a/components/fpspreadsheet/fpspreadsheet.pas +++ b/components/fpspreadsheet/fpspreadsheet.pas @@ -1809,9 +1809,15 @@ begin parser := TsSpreadsheetParser.Create(self); try if ACell^.SharedFormulaBase = nil then - formula := ACell^.FormulaValue + begin + formula := ACell^.FormulaValue; + parser.ActiveCell := nil; + end else + begin formula := ACell^.SharedFormulaBase^.FormulaValue; + parser.ActiveCell := ACell; + end; parser.Expression := formula; parser.EvaluateExpression(res); case res.ResultType of @@ -2654,6 +2660,7 @@ 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 @@ -2674,7 +2681,13 @@ begin begin parser := TsSpreadsheetParser.Create(self); try - parser.Expression := ACell^.FormulaValue; + if ACell^.SharedFormulaBase <> nil then begin + parser.ActiveCell := ACell; + parser.Expression := ACell^.SharedFormulaBase^.FormulaValue; + end else begin + parser.ActiveCell := nil; + parser.Expression := ACell^.FormulaValue; + end; Result := parser.LocalizedExpression[Workbook.FormatSettings]; finally parser.Free; diff --git a/components/fpspreadsheet/xlsxooxml.pas b/components/fpspreadsheet/xlsxooxml.pas index b18505353..512871b56 100755 --- a/components/fpspreadsheet/xlsxooxml.pas +++ b/components/fpspreadsheet/xlsxooxml.pas @@ -652,30 +652,25 @@ begin begin // Formula to cell formulaStr := GetNodeValue(datanode); - if formulaStr <> '' then + + s := GetAttrValue(datanode, 't'); + if s = 'shared' then begin - s := GetAttrValue(datanode, 't'); - if s = 'shared' then + s := GetAttrValue(datanode, 'ref'); + if (s <>'') then begin - s := GetAttrValue(datanode, 'ref'); - if (s <>'') then - begin - cell^.FormulaValue := formulaStr; - FWorksheet.UseSharedFormula(s, cell); - end; - end - else - cell^.FormulaValue := formulaStr; - end; + AWorksheet.WriteFormula(cell, formulaStr); +// cell^.FormulaValue := formulaStr; + FWorksheet.UseSharedFormula(s, cell); + end; + end + else + AWorksheet.WriteFormula(cell, formulaStr); +// cell^.FormulaValue := formulaStr; end; datanode := datanode.NextSibling; end; -{ // formula to cell - if formulaStr <> '' then - cell^.FormulaValue.FormulaStr := '=' + formulaStr; - } - // get data type s := GetAttrValue(ANode, 't'); // "t" = data type if (s = '') and (dataStr = '') then @@ -2533,7 +2528,8 @@ procedure TsSpreadOOXMLWriter.WriteFormula(AStream: TStream; var cellPosText: String; lStyleIndex: Integer; - r, c, r2, c2: Cardinal; + r, r1, r2: Cardinal; + c, c1, c2: Cardinal; cell: PCell; id: Cardinal; t, v: String; @@ -2541,91 +2537,97 @@ begin cellPosText := TsWorksheet.CellPosToText(ARow, ACol); lStyleIndex := GetStyleIndex(ACell); + case ACell^.ContentType of + cctFormula: + begin + t := ''; + v := ''; + end; + cctUTF8String: + begin + t := ' t="str"'; + v := Format('%s', [UTF8TextToXMLText(ACell^.UTF8StringValue)]); + end; + cctNumber: + begin + t := ''; + v := Format('%g', [ACell^.NumberValue], FPointSeparatorSettings); + end; + cctDateTime: + begin + t := ''; + v := Format('%g', [ACell^.DateTimeValue], FPointSeparatorSettings); + end; + cctBool: + begin + t := ' t="b"'; + if ACell^.BoolValue then + v := '1' + else + v := '0'; + end; + cctError: + begin + t := ' t="e"'; + v := Format('%s', [GetErrorValueStr(ACell^.ErrorValue)]); + 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 - r2 := ACell^.Row; - c2 := ACell^.Col; - c := c2; - r := r2; + // 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(r, c); + cell := FWorksheet.FindCell(ACell^.Row, c); if (cell <> nil) and (cell^.SharedFormulaBase = ACell^.SharedFormulaBase) then c2 := c else break; inc(c); end; - c := ACell^.Col; - while r <= FWorksheet.GetLastRowIndex do - begin - cell := FWorksheet.FindCell(r, c); - if (cell <> nil) and (cell^.SharedFormulaBase <> ACell^.SharedFormulaBase) then - r2 := r - else - break; - inc(r); - end; - AppendToStream(AStream, Format( - '' + + '' + '%s' + + '%s' + '', [ - CellPosText, lStyleIndex, + CellPosText, lStyleIndex, t, GetCellRangeString(ACell^.Row, ACell^.Col, r2, c2), PtrInt(ACell), // Use the cell pointer as ID of the shared formula - PrepareFormula(ACell^.FormulaValue) + PrepareFormula(ACell^.FormulaValue), + v ])); end else // Cell uses the shared formula AppendToStream(AStream, Format( - '' + + '' + '' + + '%s' + '', [ - CellPosText, lStyleIndex, - PtrInt(ACell^.SharedFormulaBase) // ID of the shared formula + CellPosText, lStyleIndex, t, + PtrInt(ACell^.SharedFormulaBase), // ID of the shared formula + v ])); end else begin // "normal" formula - case ACell^.ContentType of - cctFormula: - begin - t := ''; - v := ''; - end; - cctUTF8String: - begin - t := ' t="str"'; - v := Format('%s', [UTF8TextToXMLText(ACell^.UTF8StringValue)]); - end; - cctNumber: - begin - t := ''; - v := Format('%g', [ACell^.NumberValue], FPointSeparatorSettings); - end; - cctDateTime: - begin - t := ''; - v := Format('%g', [ACell^.DateTimeValue], FPointSeparatorSettings); - end; - cctBool: - begin - t := ' t="b"'; - if ACell^.BoolValue then - v := '1' - else - v := '0'; - end; - cctError: - begin - t := ' t="e"'; - v := Format('%s', [GetErrorValueStr(ACell^.ErrorValue)]); - end; - end; AppendToStream(AStream, Format( '' + '%s' +