diff --git a/components/fpspreadsheet/fpscsv.pas b/components/fpspreadsheet/fpscsv.pas index 14b59eb28..6b43714c6 100644 --- a/components/fpspreadsheet/fpscsv.pas +++ b/components/fpspreadsheet/fpscsv.pas @@ -383,15 +383,18 @@ var warning: String; nf: TsNumberFormat; decs: Integer; + cell: PCell; begin // Empty strings are blank cells -- nothing to do if AText = '' then exit; + cell := FWorksheet.AddCell(ARow, ACol); + // Do not try to interpret the strings. --> everything is a LABEL cell. if not CSVParams.DetectContentType then begin - FWorksheet.WriteUTF8Text(ARow, aCol, AText); + FWorksheet.WriteUTF8Text(cell, AText); exit; end; @@ -399,9 +402,9 @@ begin if IsNumber(AText, dblValue, nf, decs, currSym, warning) then begin if currSym <> '' then - FWorksheet.WriteCurrency(ARow, ACol, dblValue, nfCurrency, decs, currSym) + FWorksheet.WriteCurrency(cell, dblValue, nfCurrency, decs, currSym) else - FWorksheet.WriteNumber(ARow, ACol, dblValue, nf, decs); + FWorksheet.WriteNumber(cell, dblValue, nf, decs); if warning <> '' then FWorkbook.AddErrorMsg('Cell %s: %s', [GetCellString(ARow, ACol), warning]); exit; @@ -411,19 +414,19 @@ begin // No idea how to apply the date/time formatsettings here... if IsDateTime(AText, dtValue, nf) then begin - FWorksheet.WriteDateTime(ARow, ACol, dtValue, nf); + FWorksheet.WriteDateTime(cell, dtValue, nf); exit; end; // Check for a BOOLEAN cell if IsBool(AText, boolValue) then begin - FWorksheet.WriteBoolValue(ARow, aCol, boolValue); + FWorksheet.WriteBoolValue(cell, boolValue); exit; end; // What is left is handled as a TEXT cell - FWorksheet.WriteUTF8Text(ARow, ACol, AText); + FWorksheet.WriteUTF8Text(cell, AText); end; procedure TsCSVReader.ReadFormula(AStream: TStream); diff --git a/components/fpspreadsheet/fpsopendocument.pas b/components/fpspreadsheet/fpsopendocument.pas index fb3727f8a..c83c8f038 100755 --- a/components/fpspreadsheet/fpsopendocument.pas +++ b/components/fpspreadsheet/fpsopendocument.pas @@ -951,7 +951,7 @@ begin InitCell(ARow, ACol, FVirtualCell); cell := @FVirtualCell; end else - cell := FWorksheet.GetCell(ARow, ACol); + cell := FWorksheet.AddCell(ARow, ACol); FWorkSheet.WriteBlank(cell); FWorksheet.CopyFormat(@lCell, cell); @@ -971,7 +971,7 @@ begin InitCell(ARow, ACol, FVirtualCell); cell := @FVirtualCell; end else - cell := FWorksheet.GetCell(ARow, ACol); + cell := FWorksheet.AddCell(ARow, ACol); boolValue := ExtractBoolFromNode(ACellNode); FWorkSheet.WriteBoolValue(cell, boolValue); @@ -1144,7 +1144,7 @@ begin InitCell(ARow, ACol, FVirtualCell); cell := @FVirtualCell; end else - cell := FWorksheet.GetCell(ARow, ACol); + cell := FWorksheet.AddCell(ARow, ACol); styleName := GetAttrValue(ACellNode, 'table:style-name'); ApplyStyleToCell(cell, stylename); @@ -1269,7 +1269,7 @@ begin InitCell(ARow, ACol, FVirtualCell); cell := @FVirtualCell; end else - cell := FWorksheet.GetCell(ARow, ACol); + cell := FWorksheet.AddCell(ARow, ACol); styleName := GetAttrValue(ACellNode, 'table:style-name'); ApplyStyleToCell(cell, stylename); @@ -1521,7 +1521,7 @@ begin InitCell(ARow, ACol, FVirtualCell); cell := @FVirtualCell; end else - cell := FWorksheet.GetCell(ARow, ACol); + cell := FWorksheet.AddCell(ARow, ACol); FWorkSheet.WriteUTF8Text(cell, cellText); if hyperlink <> '' then @@ -1556,7 +1556,7 @@ begin InitCell(ARow, ACol, FVirtualCell); cell := @FVirtualCell; end else - cell := FWorksheet.GetCell(ARow, ACol); + cell := FWorksheet.AddCell(ARow, ACol); Value := GetAttrValue(ACellNode,'office:value'); if UpperCase(Value)='1.#INF' then diff --git a/components/fpspreadsheet/fpspreadsheet.pas b/components/fpspreadsheet/fpspreadsheet.pas index da409b05e..66609ede7 100755 --- a/components/fpspreadsheet/fpspreadsheet.pas +++ b/components/fpspreadsheet/fpspreadsheet.pas @@ -98,6 +98,9 @@ type FLeftPaneWidth: Integer; FTopPaneHeight: Integer; FOptions: TsSheetOptions; + FLastFoundCell: PCell; + FLastFoundRow: Cardinal; + FLastFoundCol: Cardinal; FFirstRowIndex: Cardinal; FFirstColIndex: Cardinal; FLastRowIndex: Cardinal; @@ -346,6 +349,7 @@ type procedure DeleteCell(ACell: PCell); procedure EraseCell(ACell: PCell); + function AddCell(ARow, ACol: Cardinal): PCell; function FindCell(ARow, ACol: Cardinal): PCell; overload; function FindCell(AddressStr: String): PCell; overload; function GetCell(ARow, ACol: Cardinal): PCell; overload; @@ -1067,6 +1071,10 @@ begin FActiveCellRow := Cardinal(-1); FActiveCellCol := Cardinal(-1); + FLastFoundCell := nil; + FLastFoundRow := Cardinal(-1); + FLastFoundCol := Cardinal(-1); + FOptions := [soShowGridLines, soShowHeaders]; end; @@ -1991,6 +1999,26 @@ begin FHyperlinks.Exchange(ARow1, ACol1, ARow2, ACol2); end; +{@@ ---------------------------------------------------------------------------- + Adds a new cell at a specified row and column index to the Cells list. + + NOTE: It is not checked if there exists already another cell at this location. + This case must be avoided. USE CAREFULLY WITHOUT FindCell + (e.g., during reading into empty worksheets). +-------------------------------------------------------------------------------} +function TsWorksheet.AddCell(ARow, ACol: Cardinal): PCell; +begin + Result := Cells.AddCell(ARow, ACol); + if FFirstColIndex = $FFFFFFFF then FFirstColIndex := GetFirstColIndex(true) + else FFirstColIndex := Min(FFirstColIndex, ACol); + if FFirstRowIndex = $FFFFFFFF then FFirstRowIndex := GetFirstRowIndex(true) + else FFirstRowIndex := Min(FFirstRowIndex, ARow); + if FLastColIndex = 0 then FLastColIndex := GetLastColIndex(true) + else FLastColIndex := Max(FLastColIndex, ACol); + if FLastRowIndex = 0 then FLastRowIndex := GetLastRowIndex(true) + else FLastRowIndex := Max(FLastRowIndex, ARow); +end; + {@@ ---------------------------------------------------------------------------- Tries to locate a Cell in the list of already written Cells @@ -2002,6 +2030,17 @@ end; function TsWorksheet.FindCell(ARow, ACol: Cardinal): PCell; begin Result := PCell(FCells.Find(ARow, ACol)); +{ + if (ARow = FLastFoundRow) and (ACol = FLastFoundCol) then + Result := FLastFoundCell + else + begin + Result := PCell(FCells.Find(ARow, ACol)); + FLastFoundCell := Result; + FLastFoundRow := ARow; + FLastFoundCol := ACol; + end; + } end; {@@ ---------------------------------------------------------------------------- @@ -2040,17 +2079,7 @@ function TsWorksheet.GetCell(ARow, ACol: Cardinal): PCell; begin Result := Cells.FindCell(ARow, ACol); if Result = nil then - begin - Result := Cells.AddCell(ARow, ACol); - if FFirstColIndex = $FFFFFFFF then FFirstColIndex := GetFirstColIndex(true) - else FFirstColIndex := Min(FFirstColIndex, ACol); - if FFirstRowIndex = $FFFFFFFF then FFirstRowIndex := GetFirstRowIndex(true) - else FFirstRowIndex := Min(FFirstRowIndex, ARow); - if FLastColIndex = 0 then FLastColIndex := GetLastColIndex(true) - else FLastColIndex := Max(FLastColIndex, ACol); - if FLastRowIndex = 0 then FLastRowIndex := GetLastRowIndex(true) - else FLastRowIndex := Max(FLastRowIndex, ARow); - end; + Result := AddCell(ARow, ACol); end; {@@ ---------------------------------------------------------------------------- diff --git a/components/fpspreadsheet/xlsbiff2.pas b/components/fpspreadsheet/xlsbiff2.pas index df33a3b56..f68c3464e 100755 --- a/components/fpspreadsheet/xlsbiff2.pas +++ b/components/fpspreadsheet/xlsbiff2.pas @@ -403,7 +403,7 @@ begin InitCell(ARow, ACol, FVirtualCell); cell := @FVirtualCell; end else - cell := FWorksheet.GetCell(ARow, ACol); + cell := FWorksheet.AddCell(ARow, ACol); ApplyCellFormatting(cell, XF); if FIsVirtualMode then Workbook.OnReadCellData(Workbook, ARow, ACol, cell); @@ -433,7 +433,7 @@ begin InitCell(r, c, FVirtualCell); cell := @FVirtualCell; end else - cell := FWorksheet.GetCell(r, c); + cell := FWorksheet.AddCell(r, c); { Retrieve boolean or error value depending on the "ValueType" } case rec.ValueType of @@ -609,7 +609,7 @@ begin InitCell(ARow, ACol, FVirtualCell); cell := @FVirtualCell; end else - cell := FWorksheet.GetCell(ARow, ACol); + cell := FWorksheet.AddCell(ARow, ACol); // Now determine the type of the formula result if (Data[6] = $FF) and (Data[7] = $FF) then @@ -704,7 +704,7 @@ begin InitCell(ARow, ACol, FVirtualCell); cell := @FVirtualCell; end else - cell := FWorksheet.GetCell(ARow, ACol); + cell := FWorksheet.AddCell(ARow, ACol); FWorksheet.WriteUTF8Text(cell, valueStr); { Apply formatting to cell } @@ -739,7 +739,7 @@ begin InitCell(ARow, ACol, FVirtualCell); cell := @FVirtualCell; end else - cell := FWorksheet.GetCell(ARow, ACol); + cell := FWorksheet.AddCell(ARow, ACol); {Find out what cell type, set content type and value} ExtractNumberFormat(XF, nf, nfs); @@ -778,7 +778,7 @@ begin InitCell(ARow, ACol, FVirtualCell); cell := @FVirtualCell; end else - cell := FWorksheet.GetCell(ARow, ACol); + cell := FWorksheet.AddCell(ARow, ACol); { Save the data } FWorksheet.WriteNumber(cell, AWord); diff --git a/components/fpspreadsheet/xlsbiff5.pas b/components/fpspreadsheet/xlsbiff5.pas index d6293cfa6..e8cbc02cc 100755 --- a/components/fpspreadsheet/xlsbiff5.pas +++ b/components/fpspreadsheet/xlsbiff5.pas @@ -509,7 +509,7 @@ begin InitCell(ARow, ACol, FVirtualCell); cell := @FVirtualCell; end else - cell := FWorksheet.GetCell(ARow, ACol); + cell := FWorksheet.AddCell(ARow, ACol); { Save the data } FWorksheet.WriteUTF8Text(cell, ISO_8859_1ToUTF8(AStrValue)); @@ -896,7 +896,7 @@ begin InitCell(ARow, ACol, FVirtualCell); cell := @FVirtualCell; end else - cell := FWorksheet.GetCell(ARow, ACol); + cell := FWorksheet.AddCell(ARow, ACol); { Save the data } valueStr := ConvertEncoding(ansistr, FCodePage, encodingUTF8); diff --git a/components/fpspreadsheet/xlsbiff8.pas b/components/fpspreadsheet/xlsbiff8.pas index 2660798dd..417032188 100755 --- a/components/fpspreadsheet/xlsbiff8.pas +++ b/components/fpspreadsheet/xlsbiff8.pas @@ -850,7 +850,7 @@ begin InitCell(ARow, ACol, FVirtualCell); // "virtual" cell cell := @FVirtualCell; end else - cell := FWorksheet.GetCell(ARow, ACol); // "real" cell + cell := FWorksheet.AddCell(ARow, ACol); // "real" cell FWorksheet.WriteUTF8Text(cell, UTF16ToUTF8(WideStrValue)); @@ -902,7 +902,7 @@ begin InitCell(ARow, ACol, FVirtualCell); cell := @FVirtualCell; end else - cell := FWorksheet.GetCell(ARow, ACol); + cell := FWorksheet.AddCell(ARow, ACol); { Save the data } FWorksheet.WriteUTF8Text(cell, AStrValue); @@ -1119,7 +1119,7 @@ begin InitCell(ARow, ACol, FVirtualCell); cell := @FVirtualCell; end else - cell := FWorksheet.GetCell(ARow, ACol); + cell := FWorksheet.AddCell(ARow, ACol); FWorksheet.WriteUTF8Text(cell, FSharedStringTable[SSTIndex]); diff --git a/components/fpspreadsheet/xlscommon.pas b/components/fpspreadsheet/xlscommon.pas index 0298ff7d2..31438829e 100644 --- a/components/fpspreadsheet/xlscommon.pas +++ b/components/fpspreadsheet/xlscommon.pas @@ -828,7 +828,7 @@ begin InitCell(ARow, ACol, FVirtualCell); cell := @FVirtualCell; end else - cell := FWorksheet.GetCell(ARow, ACol); + cell := FWorksheet.AddCell(ARow, ACol); FWorksheet.WriteBlank(cell); @@ -863,7 +863,7 @@ begin InitCell(r, c, FVirtualCell); cell := @FVirtualCell; end else - cell := FWorksheet.GetCell(r, c); + cell := FWorksheet.AddCell(r, c); { Retrieve boolean or error value depending on the "ValueType" } case rec.ValueType of @@ -998,7 +998,7 @@ begin SetLength(s, n); AStream.ReadBuffer(s[1], n); FIncompleteNote := s; - FIncompleteCell := FWorksheet.GetCell(r, c); + FIncompleteCell := FWorksheet.GetCell(r, c); // no AddCell here! end; end else // One of the continuation records @@ -1121,7 +1121,7 @@ begin InitCell(ARow, ACol, FVirtualCell); cell := @FVirtualCell; end else - cell := FWorksheet.GetCell(ARow, ACol); // "Real" cell + cell := FWorksheet.AddCell(ARow, ACol); // "Real" cell // Now determine the type of the formula result if (Data[6] = $FF) and (Data[7] = $FF) then @@ -1189,7 +1189,7 @@ begin if FIsVirtualMode then cell^.Col := fc else - cell := FWorksheet.GetCell(ARow, fc); + cell := FWorksheet.AddCell(ARow, fc); FWorksheet.WriteBlank(cell); ApplyCellFormatting(cell, XF); if FIsVirtualMode then @@ -1233,7 +1233,7 @@ begin if FIsVirtualMode then cell^.Col := fc else - cell := FWorksheet.GetCell(ARow, fc); + cell := FWorksheet.AddCell(ARow, fc); RK := DWordLEtoN(AStream.ReadDWord); lNumber := DecodeRKValue(RK); {Find out what cell type, set contenttype and value} @@ -1288,7 +1288,7 @@ begin InitCell(ARow, ACol, FVirtualCell); cell := @FVirtualCell; end else - cell := FWorksheet.GetCell(ARow, ACol); // "real" cell + cell := FWorksheet.AddCell(ARow, ACol); // "real" cell if IsDateTime(value, nf, nfs, dt) then FWorksheet.WriteDateTime(cell, dt, nf, nfs) @@ -1391,7 +1391,7 @@ begin InitCell(ARow, ACol, FVirtualCell); cell := @FVirtualCell; end else - cell := FWorksheet.GetCell(ARow, ACol); + cell := FWorksheet.AddCell(ARow, ACol); {Find out what cell type, set contenttype and value} ExtractNumberFormat(XF, nf, nfs); @@ -1782,7 +1782,7 @@ begin InitCell(r1, c1, FVirtualCell); cell := @FVirtualCell; end else - cell := FWorksheet.GetCell(r1, c1); // "Real" cell + cell := FWorksheet.AddCell(r1, c1); // "Real" cell // Unused AStream.ReadByte; diff --git a/components/fpspreadsheet/xlsxooxml.pas b/components/fpspreadsheet/xlsxooxml.pas index 40511947a..ffbd75732 100755 --- a/components/fpspreadsheet/xlsxooxml.pas +++ b/components/fpspreadsheet/xlsxooxml.pas @@ -687,7 +687,7 @@ begin InitCell(rowIndex, colIndex, FVirtualCell); cell := @FVirtualCell; end else - cell := AWorksheet.GetCell(rowIndex, colIndex); + cell := AWorksheet.AddCell(rowIndex, colIndex); // get style index s := GetAttrValue(ANode, 's');