You've already forked lazarus-ccr
fpspreadsheet: OOXML reading/writing support for frozen panes. Simplify OOXML's cell writing strategy by omitting empty cells.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3422 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -493,6 +493,8 @@ type
|
|||||||
FLeftPaneWidth: Integer;
|
FLeftPaneWidth: Integer;
|
||||||
FTopPaneHeight: Integer;
|
FTopPaneHeight: Integer;
|
||||||
FOptions: TsSheetOptions;
|
FOptions: TsSheetOptions;
|
||||||
|
FFirstRowIndex: Cardinal;
|
||||||
|
FFirstColIndex: Cardinal;
|
||||||
FLastRowIndex: Cardinal;
|
FLastRowIndex: Cardinal;
|
||||||
FLastColIndex: Cardinal;
|
FLastColIndex: Cardinal;
|
||||||
FOnChangeCell: TsCellEvent;
|
FOnChangeCell: TsCellEvent;
|
||||||
@ -620,16 +622,24 @@ type
|
|||||||
procedure WriteBorderStyles(ARow, ACol: Cardinal; const AStyles: TsCellBorderStyles); overload;
|
procedure WriteBorderStyles(ARow, ACol: Cardinal; const AStyles: TsCellBorderStyles); overload;
|
||||||
procedure WriteBorderStyles(ACell: PCell; const AStyles: TsCellBorderStyles); overload;
|
procedure WriteBorderStyles(ACell: PCell; const AStyles: TsCellBorderStyles); overload;
|
||||||
|
|
||||||
|
procedure WriteDateTimeFormat(ARow, ACol: Cardinal; ANumberFormat: TsNumberFormat;
|
||||||
|
const AFormatString: String = ''); overload;
|
||||||
|
procedure WriteDateTimeFormat(ACell: PCell; ANumberFormat: TsNumberFormat;
|
||||||
|
const AFormatString: String = ''); overload;
|
||||||
|
|
||||||
procedure WriteDecimals(ARow, ACol: Cardinal; ADecimals: byte); overload;
|
procedure WriteDecimals(ARow, ACol: Cardinal; ADecimals: byte); overload;
|
||||||
procedure WriteDecimals(ACell: PCell; ADecimals: Byte); overload;
|
procedure WriteDecimals(ACell: PCell; ADecimals: Byte); overload;
|
||||||
|
|
||||||
function WriteFont(ARow, ACol: Cardinal; const AFontName: String;
|
function WriteFont(ARow, ACol: Cardinal; const AFontName: String;
|
||||||
AFontSize: Single; AFontStyle: TsFontStyles; AFontColor: TsColor): Integer; overload;
|
AFontSize: Single; AFontStyle: TsFontStyles; AFontColor: TsColor): Integer; overload;
|
||||||
|
function WriteFont(ACell: PCell; const AFontName: String;
|
||||||
|
AFontSize: Single; AFontStyle: TsFontStyles; AFontColor: TsColor): Integer; overload;
|
||||||
procedure WriteFont(ARow, ACol: Cardinal; AFontIndex: Integer); overload;
|
procedure WriteFont(ARow, ACol: Cardinal; AFontIndex: Integer); overload;
|
||||||
function WriteFontColor(ARow, ACol: Cardinal; AFontColor: TsColor): Integer;
|
function WriteFontColor(ARow, ACol: Cardinal; AFontColor: TsColor): Integer;
|
||||||
function WriteFontName(ARow, ACol: Cardinal; AFontName: String): Integer;
|
function WriteFontName(ARow, ACol: Cardinal; AFontName: String): Integer;
|
||||||
function WriteFontSize(ARow, ACol: Cardinal; ASize: Single): Integer;
|
function WriteFontSize(ARow, ACol: Cardinal; ASize: Single): Integer;
|
||||||
function WriteFontStyle(ARow, ACol: Cardinal; AStyle: TsFontStyles): Integer;
|
function WriteFontStyle(ARow, ACol: Cardinal; AStyle: TsFontStyles): Integer; overload;
|
||||||
|
function WriteFontStyle(ACell: PCell; AStyle: TsFontStyles): Integer; overload;
|
||||||
|
|
||||||
procedure WriteHorAlignment(ARow, ACol: Cardinal; AValue: TsHorAlignment);
|
procedure WriteHorAlignment(ARow, ACol: Cardinal; AValue: TsHorAlignment);
|
||||||
|
|
||||||
@ -666,8 +676,10 @@ type
|
|||||||
function GetNextCell(): PCell;
|
function GetNextCell(): PCell;
|
||||||
function GetFirstCellOfRow(ARow: Cardinal): PCell;
|
function GetFirstCellOfRow(ARow: Cardinal): PCell;
|
||||||
function GetLastCellOfRow(ARow: Cardinal): PCell;
|
function GetLastCellOfRow(ARow: Cardinal): PCell;
|
||||||
|
function GetFirstColIndex(AForceCalculation: Boolean = false): Cardinal;
|
||||||
function GetLastColIndex(AForceCalculation: Boolean = false): Cardinal;
|
function GetLastColIndex(AForceCalculation: Boolean = false): Cardinal;
|
||||||
function GetLastColNumber: Cardinal; deprecated 'Use GetLastColIndex';
|
function GetLastColNumber: Cardinal; deprecated 'Use GetLastColIndex';
|
||||||
|
function GetFirstRowIndex(AForceCalculation: Boolean = false): Cardinal;
|
||||||
function GetLastRowIndex(AForceCalculation: Boolean = false): Cardinal;
|
function GetLastRowIndex(AForceCalculation: Boolean = false): Cardinal;
|
||||||
function GetLastRowNumber: Cardinal; deprecated 'Use GetLastRowIndex';
|
function GetLastRowNumber: Cardinal; deprecated 'Use GetLastRowIndex';
|
||||||
|
|
||||||
@ -1573,6 +1585,8 @@ begin
|
|||||||
FRows := TIndexedAVLTree.Create(@CompareRows);
|
FRows := TIndexedAVLTree.Create(@CompareRows);
|
||||||
FCols := TIndexedAVLTree.Create(@CompareCols);
|
FCols := TIndexedAVLTree.Create(@CompareCols);
|
||||||
|
|
||||||
|
FFirstRowIndex := $FFFFFFFF;
|
||||||
|
FFirstColIndex := $FFFFFFFF;
|
||||||
FLastRowIndex := 0;
|
FLastRowIndex := 0;
|
||||||
FLastColIndex := 0;
|
FLastColIndex := 0;
|
||||||
|
|
||||||
@ -1923,6 +1937,10 @@ begin
|
|||||||
Result^.BorderStyles := DEFAULT_BORDERSTYLES;
|
Result^.BorderStyles := DEFAULT_BORDERSTYLES;
|
||||||
|
|
||||||
Cells.Add(Result);
|
Cells.Add(Result);
|
||||||
|
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)
|
if FLastColIndex = 0 then FLastColIndex := GetLastColIndex(true)
|
||||||
else FLastColIndex := Max(FLastColIndex, ACol);
|
else FLastColIndex := Max(FLastColIndex, ACol);
|
||||||
if FLastRowIndex = 0 then FLastRowIndex := GetLastRowIndex(true)
|
if FLastRowIndex = 0 then FLastRowIndex := GetLastRowIndex(true)
|
||||||
@ -2055,6 +2073,46 @@ begin
|
|||||||
else Result := nil;
|
else Result := nil;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Returns the 0-based index of the first column with a cell with contents.
|
||||||
|
|
||||||
|
If no cells have contents, zero will be returned, which is also a valid value.
|
||||||
|
|
||||||
|
Use GetCellCount to verify if there is at least one cell with contents in the
|
||||||
|
worksheet.
|
||||||
|
|
||||||
|
@param AForceCalculation The index of the first column is continuously updated
|
||||||
|
whenever a new cell is created. If AForceCalculation
|
||||||
|
is true all cells are scanned to determine the index
|
||||||
|
of the first column.
|
||||||
|
@see GetCellCount
|
||||||
|
}
|
||||||
|
function TsWorksheet.GetFirstColIndex(AForceCalculation: Boolean = false): Cardinal;
|
||||||
|
var
|
||||||
|
AVLNode: TAVLTreeNode;
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
if AForceCalculation then begin
|
||||||
|
Result := $FFFFFFFF;
|
||||||
|
// Traverse the tree from lowest to highest.
|
||||||
|
// Since tree primary sort order is on row lowest col could exist anywhere.
|
||||||
|
AVLNode := FCells.FindLowest;
|
||||||
|
While Assigned(AVLNode) do begin
|
||||||
|
Result := Math.Min(Result, PCell(AVLNode.Data)^.Col);
|
||||||
|
AVLNode := FCells.FindSuccessor(AVLNode);
|
||||||
|
end;
|
||||||
|
// In addition, there may be column records defining the column width even
|
||||||
|
// without content
|
||||||
|
for i:=0 to FCols.Count-1 do
|
||||||
|
if FCols[i] <> nil then
|
||||||
|
Result := Math.Min(Result, PCol(FCols[i])^.Col);
|
||||||
|
// Store the result
|
||||||
|
FFirstColIndex := Result;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Result := FFirstColIndex;
|
||||||
|
end;
|
||||||
|
|
||||||
{@@
|
{@@
|
||||||
Returns the 0-based index of the last column with a cell with contents.
|
Returns the 0-based index of the last column with a cell with contents.
|
||||||
|
|
||||||
@ -2145,6 +2203,41 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Returns the 0-based index of the first row with a cell with contents.
|
||||||
|
|
||||||
|
If no cells have contents, zero will be returned, which is also a valid value.
|
||||||
|
|
||||||
|
Use GetCellCount to verify if there is at least one cell with contents in the
|
||||||
|
worksheet.
|
||||||
|
|
||||||
|
@param AForceCalculation The index of the first row is continuously updated
|
||||||
|
whenever a new cell is created. If AForceCalculation
|
||||||
|
is true all cells are scanned to determine the index
|
||||||
|
of the first row.
|
||||||
|
@see GetCellCount
|
||||||
|
}
|
||||||
|
function TsWorksheet.GetFirstRowIndex(AForceCalculation: Boolean = false): Cardinal;
|
||||||
|
var
|
||||||
|
AVLNode: TAVLTreeNode;
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
if AForceCalculation then begin
|
||||||
|
Result := $FFFFFFFF;
|
||||||
|
AVLNode := FCells.FindLowest;
|
||||||
|
if Assigned(AVLNode) then
|
||||||
|
Result := PCell(AVLNode.Data).Row;
|
||||||
|
// In addition, there may be row records even for rows without cells.
|
||||||
|
for i:=0 to FRows.Count-1 do
|
||||||
|
if FRows[i] <> nil then
|
||||||
|
Result := Math.Min(Result, PRow(FRows[i])^.Row);
|
||||||
|
// Store result
|
||||||
|
FFirstRowIndex := Result;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Result := FFirstRowIndex
|
||||||
|
end;
|
||||||
|
|
||||||
{@@
|
{@@
|
||||||
Returns the 0-based index of the last row with a cell with contents.
|
Returns the 0-based index of the last row with a cell with contents.
|
||||||
|
|
||||||
@ -2620,6 +2713,8 @@ end;
|
|||||||
}
|
}
|
||||||
procedure TsWorksheet.UpdateCaches;
|
procedure TsWorksheet.UpdateCaches;
|
||||||
begin
|
begin
|
||||||
|
FFirstColIndex := GetFirstColIndex(true);
|
||||||
|
FFirstRowIndex := GetFirstRowIndex(true);
|
||||||
FLastColIndex := GetLastColIndex(true);
|
FLastColIndex := GetLastColIndex(true);
|
||||||
FLastRowIndex := GetLastRowIndex(true);
|
FLastRowIndex := GetLastRowIndex(true);
|
||||||
end;
|
end;
|
||||||
@ -3164,6 +3259,62 @@ begin
|
|||||||
WriteDateTime(ACell, AValue, nfCustom, AFormatStr);
|
WriteDateTime(ACell, AValue, nfCustom, AFormatStr);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Adds a date/time format to the formatting of a cell
|
||||||
|
|
||||||
|
@param ARow The row of the cell
|
||||||
|
@param ACol The column of the cell
|
||||||
|
@param ANumberFormat Identifier of the format to be applied (nfXXXX constant)
|
||||||
|
@param AFormatString optional string of formatting codes. Is only considered
|
||||||
|
if ANumberFormat is nfCustom.
|
||||||
|
|
||||||
|
@see TsNumberFormat
|
||||||
|
}
|
||||||
|
procedure TsWorksheet.WriteDateTimeFormat(ARow, ACol: Cardinal;
|
||||||
|
ANumberFormat: TsNumberFormat; const AFormatString: String = '');
|
||||||
|
begin
|
||||||
|
WriteDateTimeFormat(GetCell(ARow, ACol), ANumberFormat, AFormatString);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Adds a date/time format to the formatting of a cell
|
||||||
|
|
||||||
|
@param ACell Pointer to the cell considered
|
||||||
|
@param ANumberFormat Identifier of the format to be applied (nxXXXX constant)
|
||||||
|
@param AFormatString optional string of formatting codes. Is only considered
|
||||||
|
if ANumberFormat is nfCustom.
|
||||||
|
|
||||||
|
@see TsNumberFormat
|
||||||
|
}
|
||||||
|
procedure TsWorksheet.WriteDateTimeFormat(ACell: PCell;
|
||||||
|
ANumberFormat: TsNumberFormat; const AFormatString: String = '');
|
||||||
|
begin
|
||||||
|
if ACell = nil then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
if not ((ANumberFormat in [nfGeneral, nfCustom]) or IsDateTimeFormat(ANumberFormat)) then
|
||||||
|
raise Exception.Create('WriteDateTimeFormat can only be called with date/time formats.');
|
||||||
|
|
||||||
|
ACell^.NumberFormat := ANumberFormat;
|
||||||
|
if (ANumberFormat <> nfGeneral) then begin
|
||||||
|
Include(ACell^.UsedFormattingFields, uffNumberFormat);
|
||||||
|
if (AFormatString = '') then
|
||||||
|
ACell^.NumberFormatStr := BuildDateTimeFormatString(ANumberFormat, Workbook.FormatSettings)
|
||||||
|
else
|
||||||
|
ACell^.NumberFormatStr := AFormatString;
|
||||||
|
end else begin
|
||||||
|
Exclude(ACell^.UsedFormattingFields, uffNumberFormat);
|
||||||
|
ACell^.NumberFormatStr := '';
|
||||||
|
end;
|
||||||
|
ChangedCell(ACell^.Row, ACell^.Col);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{@@
|
{@@
|
||||||
Formats the number in a cell to show a given count of decimal places.
|
Formats the number in a cell to show a given count of decimal places.
|
||||||
Is ignored for non-decimal formats (such as most date/time formats).
|
Is ignored for non-decimal formats (such as most date/time formats).
|
||||||
@ -3401,16 +3552,36 @@ end;
|
|||||||
}
|
}
|
||||||
function TsWorksheet.WriteFont(ARow, ACol: Cardinal; const AFontName: String;
|
function TsWorksheet.WriteFont(ARow, ACol: Cardinal; const AFontName: String;
|
||||||
AFontSize: Single; AFontStyle: TsFontStyles; AFontColor: TsColor): Integer;
|
AFontSize: Single; AFontStyle: TsFontStyles; AFontColor: TsColor): Integer;
|
||||||
var
|
|
||||||
lCell: PCell;
|
|
||||||
begin
|
begin
|
||||||
lCell := GetCell(ARow, ACol);
|
Result := WriteFont(GetCell(ARow, ACol), AFontName, AFontSize, AFontStyle, AFontColor);
|
||||||
Include(lCell^.UsedFormattingFields, uffFont);
|
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
|
||||||
|
index of the font in the font list.
|
||||||
|
|
||||||
|
@param ACell Pointer to the cell considered
|
||||||
|
@param AFontName Name of the font
|
||||||
|
@param AFontSize Size of the font, in points
|
||||||
|
@param AFontStyle Set with font style attributes
|
||||||
|
(don't use those of unit "graphics" !)
|
||||||
|
@return Index of the font in the workbook's font list.
|
||||||
|
}
|
||||||
|
function TsWorksheet.WriteFont(ACell: PCell; const AFontName: String;
|
||||||
|
AFontSize: Single; AFontStyle: TsFontStyles; AFontColor: TsColor): Integer;
|
||||||
|
begin
|
||||||
|
if ACell = nil then begin
|
||||||
|
Result := -1;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Include(ACell^.UsedFormattingFields, uffFont);
|
||||||
Result := FWorkbook.FindFont(AFontName, AFontSize, AFontStyle, AFontColor);
|
Result := FWorkbook.FindFont(AFontName, AFontSize, AFontStyle, AFontColor);
|
||||||
if Result = -1 then
|
if Result = -1 then
|
||||||
result := FWorkbook.AddFont(AFontName, AFontSize, AFontStyle, AFontColor);
|
result := FWorkbook.AddFont(AFontName, AFontSize, AFontStyle, AFontColor);
|
||||||
lCell^.FontIndex := Result;
|
ACell^.FontIndex := Result;
|
||||||
ChangedFont(ARow, ACol);
|
ChangedFont(ACell^.Row, ACell^.Col);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@
|
{@@
|
||||||
@ -3513,13 +3684,33 @@ end;
|
|||||||
}
|
}
|
||||||
function TsWorksheet.WriteFontStyle(ARow, ACol: Cardinal;
|
function TsWorksheet.WriteFontStyle(ARow, ACol: Cardinal;
|
||||||
AStyle: TsFontStyles): Integer;
|
AStyle: TsFontStyles): Integer;
|
||||||
|
begin
|
||||||
|
Result := WriteFontStyle(GetCell(ARow, ACol), AStyle);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Replaces the font style (bold, italic, etc) in formatting of a cell.
|
||||||
|
Looks in the workbook's font list if this modified font has already been used.
|
||||||
|
If not a new font entry is created.
|
||||||
|
Returns the index of this font in the font list.
|
||||||
|
|
||||||
|
@param ACell Pointer to the cell considered
|
||||||
|
@param AStyle New font style to be used
|
||||||
|
@return Index of the font in the workbook's font list.
|
||||||
|
|
||||||
|
@see TsFontStyle
|
||||||
|
}
|
||||||
|
function TsWorksheet.WriteFontStyle(ACell: PCell; AStyle: TsFontStyles): Integer;
|
||||||
var
|
var
|
||||||
lCell: PCell;
|
|
||||||
fnt: TsFont;
|
fnt: TsFont;
|
||||||
begin
|
begin
|
||||||
lCell := GetCell(ARow, ACol);
|
if ACell = nil then begin
|
||||||
fnt := Workbook.GetFont(lCell^.FontIndex);
|
Result := -1;
|
||||||
Result := WriteFont(ARow, ACol, fnt.FontName, fnt.Size, AStyle, fnt.Color);
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
fnt := Workbook.GetFont(ACell^.FontIndex);
|
||||||
|
Result := WriteFont(ACell, fnt.FontName, fnt.Size, AStyle, fnt.Color);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@
|
{@@
|
||||||
@ -3893,7 +4084,7 @@ var
|
|||||||
begin
|
begin
|
||||||
Result := 0;
|
Result := 0;
|
||||||
h0 := Workbook.GetDefaultFontSize;
|
h0 := Workbook.GetDefaultFontSize;
|
||||||
for col := 0 to GetLastColIndex do begin
|
for col := GetFirstColIndex to GetLastColIndex do begin
|
||||||
cell := FindCell(ARow, col);
|
cell := FindCell(ARow, col);
|
||||||
if cell <> nil then
|
if cell <> nil then
|
||||||
Result := Max(Result, Workbook.GetFont(cell^.FontIndex).Size / h0);
|
Result := Max(Result, Workbook.GetFont(cell^.FontIndex).Size / h0);
|
||||||
@ -3972,10 +4163,12 @@ begin
|
|||||||
FillChar(Result^, SizeOf(TCol), #0);
|
FillChar(Result^, SizeOf(TCol), #0);
|
||||||
Result^.Col := ACol;
|
Result^.Col := ACol;
|
||||||
FCols.Add(Result);
|
FCols.Add(Result);
|
||||||
if FLastColIndex = 0 then
|
if FFirstColIndex = 0
|
||||||
FLastColIndex := GetLastColIndex(true)
|
then FFirstColIndex := GetFirstColIndex(true)
|
||||||
else
|
else FFirstColIndex := Min(FFirstColIndex, ACol);
|
||||||
FLastColIndex := Max(FLastColIndex, ACol);
|
if FLastColIndex = 0
|
||||||
|
then FLastColIndex := GetLastColIndex(true)
|
||||||
|
else FLastColIndex := Max(FLastColIndex, ACol);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@ -75,6 +75,11 @@ type
|
|||||||
procedure TestWriteRead_OOXML_ShowGridLines_HideHeaders;
|
procedure TestWriteRead_OOXML_ShowGridLines_HideHeaders;
|
||||||
procedure TestWriteRead_OOXML_HideGridLines_ShowHeaders;
|
procedure TestWriteRead_OOXML_HideGridLines_ShowHeaders;
|
||||||
procedure TestWriteRead_OOXML_HideGridLines_HideHeaders;
|
procedure TestWriteRead_OOXML_HideGridLines_HideHeaders;
|
||||||
|
|
||||||
|
procedure TestWriteRead_OOXML_Panes_HorVert;
|
||||||
|
procedure TestWriteRead_OOXML_Panes_Hor;
|
||||||
|
procedure TestWriteRead_OOXML_Panes_Vert;
|
||||||
|
procedure TestWriteRead_OOXML_Panes_None;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
@ -358,6 +363,27 @@ begin
|
|||||||
TestWriteReadPanes(sfOpenDocument, 0, 0);
|
TestWriteReadPanes(sfOpenDocument, 0, 0);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ Tests for OOXML frozen panes }
|
||||||
|
procedure TSpreadWriteReadOptionsTests.TestWriteRead_OOXML_Panes_HorVert;
|
||||||
|
begin
|
||||||
|
TestWriteReadPanes(sfOOXML, 1, 2);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadOptionsTests.TestWriteRead_OOXML_Panes_Hor;
|
||||||
|
begin
|
||||||
|
TestWriteReadPanes(sfOOXML, 1, 0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadOptionsTests.TestWriteRead_OOXML_Panes_Vert;
|
||||||
|
begin
|
||||||
|
TestWriteReadPanes(sfOOXML, 0, 2);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadOptionsTests.TestWriteRead_OOXML_Panes_None;
|
||||||
|
begin
|
||||||
|
TestWriteReadPanes(sfOOXML, 0, 0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
initialization
|
initialization
|
||||||
RegisterTest(TSpreadWriteReadOptionsTests);
|
RegisterTest(TSpreadWriteReadOptionsTests);
|
||||||
|
@ -2676,6 +2676,7 @@ var
|
|||||||
lCell: TCell;
|
lCell: TCell;
|
||||||
value: variant;
|
value: variant;
|
||||||
styleCell: PCell;
|
styleCell: PCell;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
for r := 0 to Workbook.VirtualRowCount-1 do begin
|
for r := 0 to Workbook.VirtualRowCount-1 do begin
|
||||||
for c := 0 to Workbook.VirtualColCount-1 do begin
|
for c := 0 to Workbook.VirtualColCount-1 do begin
|
||||||
@ -2693,12 +2694,10 @@ begin
|
|||||||
lCell.ContentType := cctNumber;
|
lCell.ContentType := cctNumber;
|
||||||
lCell.NumberValue := value;
|
lCell.NumberValue := value;
|
||||||
end else
|
end else
|
||||||
{
|
if VarType(value) = varDate then begin
|
||||||
if VarIsDateTime(value) then begin
|
lCell.ContentType := cctDateTime;
|
||||||
lCell.ContentType := cctNumber;
|
lCell.DateTimeValue := StrToDate(VarToStr(value), Workbook.FormatSettings);
|
||||||
lCell.DateTimeValue := value;
|
|
||||||
end else
|
end else
|
||||||
}
|
|
||||||
if VarIsStr(value) then begin
|
if VarIsStr(value) then begin
|
||||||
lCell.ContentType := cctUTF8String;
|
lCell.ContentType := cctUTF8String;
|
||||||
lCell.UTF8StringValue := VarToStrDef(value, '');
|
lCell.UTF8StringValue := VarToStrDef(value, '');
|
||||||
|
@ -112,11 +112,13 @@ type
|
|||||||
procedure ListAllFills;
|
procedure ListAllFills;
|
||||||
procedure ResetStreams;
|
procedure ResetStreams;
|
||||||
procedure WriteBorderList(AStream: TStream);
|
procedure WriteBorderList(AStream: TStream);
|
||||||
procedure WriteCols(AStream: TStream; ASheet: TsWorksheet);
|
procedure WriteCols(AStream: TStream; AWorksheet: TsWorksheet);
|
||||||
procedure WriteFillList(AStream: TStream);
|
procedure WriteFillList(AStream: TStream);
|
||||||
procedure WriteFontList(AStream: TStream);
|
procedure WriteFontList(AStream: TStream);
|
||||||
procedure WriteNumFormatList(AStream: TStream);
|
procedure WriteNumFormatList(AStream: TStream);
|
||||||
procedure WritePalette(AStream: TStream);
|
procedure WritePalette(AStream: TStream);
|
||||||
|
procedure WriteSheetData(AStream: TStream; AWorksheet: TsWorksheet);
|
||||||
|
procedure WriteSheetViews(AStream: TStream; AWorksheet: TsWorksheet);
|
||||||
procedure WriteStyleList(AStream: TStream; ANodeName: String);
|
procedure WriteStyleList(AStream: TStream; ANodeName: String);
|
||||||
protected
|
protected
|
||||||
{ Streams with the contents of files }
|
{ Streams with the contents of files }
|
||||||
@ -133,7 +135,7 @@ type
|
|||||||
{ Routines to write the files }
|
{ Routines to write the files }
|
||||||
procedure WriteGlobalFiles;
|
procedure WriteGlobalFiles;
|
||||||
procedure WriteContent;
|
procedure WriteContent;
|
||||||
procedure WriteWorksheet(CurSheet: TsWorksheet);
|
procedure WriteWorksheet(AWorksheet: TsWorksheet);
|
||||||
protected
|
protected
|
||||||
{ Record writing methods }
|
{ Record writing methods }
|
||||||
//todo: add WriteDate
|
//todo: add WriteDate
|
||||||
@ -153,7 +155,7 @@ type
|
|||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
variants, fileutil, fpsStreams, fpsNumFormatParser;
|
variants, fileutil, StrUtils, fpsStreams, fpsNumFormatParser;
|
||||||
|
|
||||||
const
|
const
|
||||||
{ OOXML general XML constants }
|
{ OOXML general XML constants }
|
||||||
@ -1018,12 +1020,25 @@ end;
|
|||||||
procedure TsSpreadOOXMLReader.ReadSheetViews(ANode: TDOMNode; AWorksheet: TsWorksheet);
|
procedure TsSpreadOOXMLReader.ReadSheetViews(ANode: TDOMNode; AWorksheet: TsWorksheet);
|
||||||
var
|
var
|
||||||
sheetViewNode: TDOMNode;
|
sheetViewNode: TDOMNode;
|
||||||
|
childNode: TDOMNode;
|
||||||
nodeName: String;
|
nodeName: String;
|
||||||
s: String;
|
s: String;
|
||||||
begin
|
begin
|
||||||
if ANode = nil then
|
if ANode = nil then
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
'<sheetViews>' +
|
||||||
|
'<sheetView workbookViewId="0" %s%s>'+
|
||||||
|
'<pane xSplit="%d" ySplit="%d" topLeftCell="%s" activePane="bottomRight" state="frozen" />' +
|
||||||
|
'<selection pane="topRight" activeCell="%s" sqref="%s" />' +
|
||||||
|
'<selection pane="bottomLeft" activeCell="%s" sqref="%s" />' +
|
||||||
|
'<selection pane="bottomRight" activeCell="%s" sqref="%s" />' +
|
||||||
|
'</sheetView>' +
|
||||||
|
'</sheetViews>', [
|
||||||
|
}
|
||||||
|
|
||||||
sheetViewNode := ANode.FirstChild;
|
sheetViewNode := ANode.FirstChild;
|
||||||
while Assigned(sheetViewNode) do begin
|
while Assigned(sheetViewNode) do begin
|
||||||
nodeName := sheetViewNode.NodeName;
|
nodeName := sheetViewNode.NodeName;
|
||||||
@ -1034,6 +1049,22 @@ begin
|
|||||||
s := GetAttrValue(sheetViewNode, 'showRowColHeaders');
|
s := GetAttrValue(sheetViewNode, 'showRowColHeaders');
|
||||||
if s = '0' then
|
if s = '0' then
|
||||||
AWorksheet.Options := AWorksheet.Options - [soShowHeaders];
|
AWorksheet.Options := AWorksheet.Options - [soShowHeaders];
|
||||||
|
|
||||||
|
childNode := sheetViewNode.FirstChild;
|
||||||
|
while Assigned(childNode) do begin
|
||||||
|
nodeName := childNode.NodeName;
|
||||||
|
if nodeName = 'pane' then begin
|
||||||
|
s := GetAttrValue(childNode, 'state');
|
||||||
|
if s = 'frozen' then begin
|
||||||
|
AWorksheet.Options := AWorksheet.Options + [soHasFrozenPanes];
|
||||||
|
s := GetAttrValue(childNode, 'xSplit');
|
||||||
|
if s <> '' then AWorksheet.LeftPaneWidth := StrToInt(s);
|
||||||
|
s := GetAttrValue(childNode, 'ySplit');
|
||||||
|
if s <> '' then AWorksheet.TopPaneHeight := StrToInt(s);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
childNode := childNode.NextSibling;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
sheetViewNode := sheetViewNode.NextSibling;
|
sheetViewNode := sheetViewNode.NextSibling;
|
||||||
end;
|
end;
|
||||||
@ -1422,19 +1453,19 @@ begin
|
|||||||
'</borders>');
|
'</borders>');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TsSpreadOOXMLWriter.WriteCols(AStream: TStream; ASheet: TsWorksheet);
|
procedure TsSpreadOOXMLWriter.WriteCols(AStream: TStream; AWorksheet: TsWorksheet);
|
||||||
var
|
var
|
||||||
col: PCol;
|
col: PCol;
|
||||||
c: Integer;
|
c: Integer;
|
||||||
begin
|
begin
|
||||||
if ASheet.Cols.Count = 0 then
|
if AWorksheet.Cols.Count = 0 then
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
AppendToStream(AStream,
|
AppendToStream(AStream,
|
||||||
'<cols>');
|
'<cols>');
|
||||||
|
|
||||||
for c:=0 to ASheet.GetLastColIndex do begin
|
for c:=0 to AWorksheet.GetLastColIndex do begin
|
||||||
col := ASheet.FindCol(c);
|
col := AWorksheet.FindCol(c);
|
||||||
if col <> nil then
|
if col <> nil then
|
||||||
AppendToStream(AStream, Format(
|
AppendToStream(AStream, Format(
|
||||||
'<col min="%d" max="%d" width="%g" customWidth="1" />',
|
'<col min="%d" max="%d" width="%g" customWidth="1" />',
|
||||||
@ -1580,6 +1611,175 @@ begin
|
|||||||
'</colors>');
|
'</colors>');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TsSpreadOOXMLWriter.WriteSheetData(AStream: TStream;
|
||||||
|
AWorksheet: TsWorksheet);
|
||||||
|
var
|
||||||
|
r, c, c1, c2: Cardinal;
|
||||||
|
row: PRow;
|
||||||
|
value: Variant;
|
||||||
|
lCell: TCell;
|
||||||
|
styleCell: PCell;
|
||||||
|
AVLNode: TAVLTreeNode;
|
||||||
|
rh: String;
|
||||||
|
h0: Single;
|
||||||
|
begin
|
||||||
|
h0 := Workbook.GetDefaultFontSize; // Point size of default font
|
||||||
|
|
||||||
|
AppendToStream(AStream,
|
||||||
|
'<sheetData>');
|
||||||
|
|
||||||
|
if (boVirtualMode in Workbook.Options) and Assigned(Workbook.OnWriteCellData)
|
||||||
|
then begin
|
||||||
|
for r := 0 to Workbook.VirtualRowCount-1 do begin
|
||||||
|
row := AWorksheet.FindRow(r);
|
||||||
|
if row <> nil then
|
||||||
|
rh := Format(' ht="%g" customHeight="1"', [
|
||||||
|
(row^.Height + ROW_HEIGHT_CORRECTION)*h0])
|
||||||
|
else
|
||||||
|
rh := '';
|
||||||
|
AppendToStream(AStream, Format(
|
||||||
|
'<row r="%d" spans="1:%d"%s>', [r+1, Workbook.VirtualColCount, rh]));
|
||||||
|
for c := 0 to Workbook.VirtualColCount-1 do begin
|
||||||
|
InitCell(lCell);
|
||||||
|
value := varNull;
|
||||||
|
styleCell := nil;
|
||||||
|
Workbook.OnWriteCellData(Workbook, r, c, value, styleCell);
|
||||||
|
if styleCell <> nil then
|
||||||
|
lCell := styleCell^;
|
||||||
|
lCell.Row := r;
|
||||||
|
lCell.Col := c;
|
||||||
|
if VarIsNull(value) then
|
||||||
|
lCell.ContentType := cctEmpty
|
||||||
|
else
|
||||||
|
if VarIsNumeric(value) then begin
|
||||||
|
lCell.ContentType := cctNumber;
|
||||||
|
lCell.NumberValue := value;
|
||||||
|
end else
|
||||||
|
if VarType(value) = varDate then begin
|
||||||
|
lCell.ContentType := cctDateTime;
|
||||||
|
lCell.DateTimeValue := StrToDate(VarToStr(value), Workbook.FormatSettings);
|
||||||
|
end else
|
||||||
|
if VarIsStr(value) then begin
|
||||||
|
lCell.ContentType := cctUTF8String;
|
||||||
|
lCell.UTF8StringValue := VarToStrDef(value, '');
|
||||||
|
end else
|
||||||
|
if VarIsBool(value) then begin
|
||||||
|
lCell.ContentType := cctBool;
|
||||||
|
lCell.BoolValue := value <> 0;
|
||||||
|
end;
|
||||||
|
WriteCellCallback(@lCell, AStream);
|
||||||
|
varClear(value);
|
||||||
|
end;
|
||||||
|
AppendToStream(AStream,
|
||||||
|
'</row>');
|
||||||
|
end;
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
// The cells need to be written in order, row by row, cell by cell
|
||||||
|
for r := 0 to AWorksheet.GetLastRowIndex do begin
|
||||||
|
// If the row has a custom height add this value to the <row> specification
|
||||||
|
row := AWorksheet.FindRow(r);
|
||||||
|
if row <> nil then
|
||||||
|
rh := Format(' ht="%g" customHeight="1"', [
|
||||||
|
(row^.Height + ROW_HEIGHT_CORRECTION)*h0])
|
||||||
|
else
|
||||||
|
rh := '';
|
||||||
|
c1 := AWorksheet.GetFirstColIndex;
|
||||||
|
c2 := AWorksheet.GetLastColIndex;
|
||||||
|
AppendToStream(AStream, Format(
|
||||||
|
'<row r="%d" spans="%d:%d"%s>', [r+1, c1+1, c2+1, rh]));
|
||||||
|
// Write cells belonging to this row.
|
||||||
|
for c := c1 to c2 do begin
|
||||||
|
lCell.Row := r;
|
||||||
|
lCell.Col := c;
|
||||||
|
AVLNode := AWorksheet.Cells.Find(@lCell);
|
||||||
|
if Assigned(AVLNode) then
|
||||||
|
WriteCellCallback(PCell(AVLNode.Data), AStream);
|
||||||
|
end;
|
||||||
|
AppendToStream(AStream,
|
||||||
|
'</row>');
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
AppendToStream(AStream,
|
||||||
|
'</sheetData>');
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TsSpreadOOXMLWriter.WriteSheetViews(AStream: TStream;
|
||||||
|
AWorksheet: TsWorksheet);
|
||||||
|
var
|
||||||
|
showGridLines: String;
|
||||||
|
showHeaders: String;
|
||||||
|
topRightCell: String;
|
||||||
|
bottomLeftCell: String;
|
||||||
|
bottomRightCell: String;
|
||||||
|
begin
|
||||||
|
// Show gridlines ?
|
||||||
|
showGridLines := IfThen(soShowGridLines in AWorksheet.Options, ' ', 'showGridLines="0" ');
|
||||||
|
|
||||||
|
// Show headers?
|
||||||
|
showHeaders := IfThen(soShowHeaders in AWorksheet.Options, ' ', 'showRowColHeaders="0" ');
|
||||||
|
|
||||||
|
// No frozen panes
|
||||||
|
if not (soHasFrozenPanes in AWorksheet.Options) or
|
||||||
|
((AWorksheet.LeftPaneWidth = 0) and (AWorksheet.TopPaneHeight = 0))
|
||||||
|
then
|
||||||
|
AppendToStream(AStream, Format(
|
||||||
|
'<sheetViews>' +
|
||||||
|
'<sheetView workbookViewId="0" %s%s/>' +
|
||||||
|
// <sheetView workbookViewID="0" />
|
||||||
|
'</sheetViews>', [
|
||||||
|
showGridLines, showHeaders
|
||||||
|
]))
|
||||||
|
else
|
||||||
|
begin // Frozen panes
|
||||||
|
topRightCell := GetCellString(0, AWorksheet.LeftPaneWidth, [rfRelRow, rfRelCol]);
|
||||||
|
bottomLeftCell := GetCellString(AWorksheet.TopPaneHeight, 0, [rfRelRow, rfRelCol]);
|
||||||
|
bottomRightCell := GetCellString(AWorksheet.TopPaneHeight, AWorksheet.LeftPaneWidth, [rfRelRow, rfRelCol]);
|
||||||
|
if (AWorksheet.LeftPaneWidth > 0) and (AWorksheet.TopPaneHeight > 0) then
|
||||||
|
AppendToStream(AStream, Format(
|
||||||
|
'<sheetViews>' +
|
||||||
|
'<sheetView workbookViewId="0" %s%s>'+
|
||||||
|
'<pane xSplit="%d" ySplit="%d" topLeftCell="%s" activePane="bottomRight" state="frozen" />' +
|
||||||
|
'<selection pane="topRight" activeCell="%s" sqref="%s" />' +
|
||||||
|
'<selection pane="bottomLeft" activeCell="%s" sqref="%s" />' +
|
||||||
|
'<selection pane="bottomRight" activeCell="%s" sqref="%s" />' +
|
||||||
|
'</sheetView>' +
|
||||||
|
'</sheetViews>', [
|
||||||
|
showGridLines, showHeaders,
|
||||||
|
AWorksheet.LeftPaneWidth, AWorksheet.TopPaneHeight, bottomRightCell,
|
||||||
|
topRightCell, topRightCell,
|
||||||
|
bottomLeftCell, bottomLeftCell,
|
||||||
|
bottomRightCell, bottomrightCell
|
||||||
|
]))
|
||||||
|
else
|
||||||
|
if (AWorksheet.LeftPaneWidth > 0) then
|
||||||
|
AppendToStream(AStream, Format(
|
||||||
|
'<sheetViews>' +
|
||||||
|
'<sheetView workbookViewId="0" %s%s>'+
|
||||||
|
'<pane xSplit="%d" topLeftCell="%s" activePane="topRight" state="frozen" />' +
|
||||||
|
'<selection pane="topRight" activeCell="%s" sqref="%s" />' +
|
||||||
|
'</sheetView>' +
|
||||||
|
'</sheetViews>', [
|
||||||
|
showGridLines, showHeaders,
|
||||||
|
AWorksheet.LeftPaneWidth, topRightCell,
|
||||||
|
topRightCell, topRightCell
|
||||||
|
]))
|
||||||
|
else
|
||||||
|
if (AWorksheet.TopPaneHeight > 0) then
|
||||||
|
AppendToStream(AStream, Format(
|
||||||
|
'<sheetViews>'+
|
||||||
|
'<sheetView workbookViewId="0" %s%s>'+
|
||||||
|
'<pane ySplit="%d" topLeftCell="%s" activePane="bottomLeft" state="frozen" />'+
|
||||||
|
'<selection pane="bottomLeft" activeCell="%s" sqref="%s" />' +
|
||||||
|
'</sheetView>'+
|
||||||
|
'</sheetViews>', [
|
||||||
|
showGridLines, showHeaders,
|
||||||
|
AWorksheet.TopPaneHeight, bottomLeftCell,
|
||||||
|
bottomLeftCell, bottomLeftCell
|
||||||
|
]));
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
{ Writes the style list which the writer has collected in FFormattingStyles. }
|
{ Writes the style list which the writer has collected in FFormattingStyles. }
|
||||||
procedure TsSpreadOOXMLWriter.WriteStyleList(AStream: TStream; ANodeName: String);
|
procedure TsSpreadOOXMLWriter.WriteStyleList(AStream: TStream; ANodeName: String);
|
||||||
var
|
var
|
||||||
@ -1793,8 +1993,8 @@ begin
|
|||||||
AppendToStream(FSWorkbook,
|
AppendToStream(FSWorkbook,
|
||||||
'<workbookPr defaultThemeVersion="124226" />');
|
'<workbookPr defaultThemeVersion="124226" />');
|
||||||
AppendToStream(FSWorkbook,
|
AppendToStream(FSWorkbook,
|
||||||
'<bookViews>',
|
'<bookViews>' +
|
||||||
'<workbookView xWindow="480" yWindow="90" windowWidth="15195" windowHeight="12525" />',
|
'<workbookView xWindow="480" yWindow="90" windowWidth="15195" windowHeight="12525" />' +
|
||||||
'</bookViews>');
|
'</bookViews>');
|
||||||
AppendToStream(FSWorkbook,
|
AppendToStream(FSWorkbook,
|
||||||
'<sheets>');
|
'<sheets>');
|
||||||
@ -1826,63 +2026,10 @@ begin
|
|||||||
'</sst>');
|
'</sst>');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{
|
procedure TsSpreadOOXMLWriter.WriteWorksheet(AWorksheet: TsWorksheet);
|
||||||
FSheets[CurStr] :=
|
|
||||||
XML_HEADER + LineEnding +
|
|
||||||
'<worksheet xmlns="' + SCHEMAS_SPREADML + '" xmlns:r="' + SCHEMAS_DOC_RELS + '">' + LineEnding +
|
|
||||||
' <sheetViews>' + LineEnding +
|
|
||||||
' <sheetView workbookViewId="0" />' + LineEnding +
|
|
||||||
' </sheetViews>' + LineEnding +
|
|
||||||
' <sheetData>' + LineEnding +
|
|
||||||
' <row r="1" spans="1:4">' + LineEnding +
|
|
||||||
' <c r="A1">' + LineEnding +
|
|
||||||
' <v>1</v>' + LineEnding +
|
|
||||||
' </c>' + LineEnding +
|
|
||||||
' <c r="B1">' + LineEnding +
|
|
||||||
' <v>2</v>' + LineEnding +
|
|
||||||
' </c>' + LineEnding +
|
|
||||||
' <c r="C1">' + LineEnding +
|
|
||||||
' <v>3</v>' + LineEnding +
|
|
||||||
' </c>' + LineEnding +
|
|
||||||
' <c r="D1">' + LineEnding +
|
|
||||||
' <v>4</v>' + LineEnding +
|
|
||||||
' </c>' + LineEnding +
|
|
||||||
' </row>' + LineEnding +
|
|
||||||
' <row r="2" spans="1:4">' + LineEnding +
|
|
||||||
' <c r="A2" t="s">' + LineEnding +
|
|
||||||
' <v>0</v>' + LineEnding +
|
|
||||||
' </c>' + LineEnding +
|
|
||||||
' <c r="B2" t="s">' + LineEnding +
|
|
||||||
' <v>1</v>' + LineEnding +
|
|
||||||
' </c>' + LineEnding +
|
|
||||||
' <c r="C2" t="s">' + LineEnding +
|
|
||||||
' <v>2</v>' + LineEnding +
|
|
||||||
' </c>' + LineEnding +
|
|
||||||
' <c r="D2" t="s">' + LineEnding +
|
|
||||||
' <v>3</v>' + LineEnding +
|
|
||||||
' </c>' + LineEnding +
|
|
||||||
' </row>' + LineEnding +
|
|
||||||
' </sheetData>' + LineEnding +
|
|
||||||
'</worksheet>';
|
|
||||||
}
|
|
||||||
procedure TsSpreadOOXMLWriter.WriteWorksheet(CurSheet: TsWorksheet);
|
|
||||||
var
|
|
||||||
r, c: Cardinal;
|
|
||||||
LastColIndex: Cardinal;
|
|
||||||
lCell: TCell;
|
|
||||||
AVLNode: TAVLTreeNode;
|
|
||||||
CellPosText: string;
|
|
||||||
value: Variant;
|
|
||||||
styleCell: PCell;
|
|
||||||
row: PRow;
|
|
||||||
rh: String;
|
|
||||||
h0: Single;
|
|
||||||
showGridLines: String;
|
|
||||||
showHeaders: String;
|
|
||||||
begin
|
begin
|
||||||
FCurSheetNum := Length(FSSheets);
|
FCurSheetNum := Length(FSSheets);
|
||||||
SetLength(FSSheets, FCurSheetNum + 1);
|
SetLength(FSSheets, FCurSheetNum + 1);
|
||||||
h0 := Workbook.GetDefaultFontSize; // Point size of default font
|
|
||||||
|
|
||||||
// Create the stream
|
// Create the stream
|
||||||
if (boBufStream in Workbook.Options) then
|
if (boBufStream in Workbook.Options) then
|
||||||
@ -1891,117 +2038,17 @@ begin
|
|||||||
FSSheets[FCurSheetNum] := TMemoryStream.Create;
|
FSSheets[FCurSheetNum] := TMemoryStream.Create;
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
if not (soShowGridLines in CurSheet.Options) then
|
|
||||||
showGridLines := 'showGridLines="0"'
|
|
||||||
else
|
|
||||||
showGridLines := '';
|
|
||||||
|
|
||||||
if not (soShowHeaders in CurSheet.Options) then
|
|
||||||
showHeaders := 'showRowColHeaders="0"'
|
|
||||||
else
|
|
||||||
showHeaders := '';
|
|
||||||
|
|
||||||
AppendToStream(FSSheets[FCurSheetNum],
|
AppendToStream(FSSheets[FCurSheetNum],
|
||||||
XML_HEADER);
|
XML_HEADER);
|
||||||
AppendToStream(FSSheets[FCurSheetNum], Format(
|
AppendToStream(FSSheets[FCurSheetNum], Format(
|
||||||
'<worksheet xmlns="%s" xmlns:r="%s">', [SCHEMAS_SPREADML, SCHEMAS_DOC_RELS]));
|
'<worksheet xmlns="%s" xmlns:r="%s">', [SCHEMAS_SPREADML, SCHEMAS_DOC_RELS]));
|
||||||
AppendToStream(FSSheets[FCurSheetNum],
|
|
||||||
'<sheetViews>');
|
|
||||||
AppendToStream(FSSheets[FCurSheetNum], Format(
|
|
||||||
'<sheetView workbookViewId="0" %s %s />', [showGridLines, showHeaders]));
|
|
||||||
AppendToStream(FSSheets[FCurSheetNum],
|
|
||||||
'</sheetViews>');
|
|
||||||
|
|
||||||
WriteCols(FSSheets[FCurSheetNum], CurSheet);
|
WriteSheetViews(FSSheets[FCurSheetNum], AWorksheet);
|
||||||
|
WriteCols(FSSheets[FCurSheetNum], AWorksheet);
|
||||||
AppendToStream(FSSheets[FCurSheetNum],
|
WriteSheetData(FSSheets[FCurSheetNum], AWorksheet);
|
||||||
'<sheetData>');
|
|
||||||
|
|
||||||
if (boVirtualMode in Workbook.Options) and Assigned(Workbook.OnWriteCellData)
|
|
||||||
then begin
|
|
||||||
for r := 0 to Workbook.VirtualRowCount-1 do begin
|
|
||||||
row := CurSheet.FindRow(r);
|
|
||||||
if row <> nil then
|
|
||||||
rh := Format(' ht="%g" customHeight="1"', [
|
|
||||||
(row^.Height + ROW_HEIGHT_CORRECTION)*h0])
|
|
||||||
else
|
|
||||||
rh := '';
|
|
||||||
AppendToStream(FSSheets[FCurSheetNum], Format(
|
|
||||||
'<row r="%d" spans="1:%d"%s>', [r+1, Workbook.VirtualColCount, rh]));
|
|
||||||
for c := 0 to Workbook.VirtualColCount-1 do begin
|
|
||||||
InitCell(lCell);
|
|
||||||
CellPosText := CurSheet.CellPosToText(r, c);
|
|
||||||
value := varNull;
|
|
||||||
styleCell := nil;
|
|
||||||
Workbook.OnWriteCellData(Workbook, r, c, value, styleCell);
|
|
||||||
if styleCell <> nil then
|
|
||||||
lCell := styleCell^;
|
|
||||||
lCell.Row := r;
|
|
||||||
lCell.Col := c;
|
|
||||||
if VarIsNull(value) then
|
|
||||||
lCell.ContentType := cctEmpty
|
|
||||||
else
|
|
||||||
if VarIsNumeric(value) then begin
|
|
||||||
lCell.ContentType := cctNumber;
|
|
||||||
lCell.NumberValue := value;
|
|
||||||
end
|
|
||||||
{
|
|
||||||
else if VarIsDateTime(value) then begin
|
|
||||||
lCell.ContentType := cctNumber;
|
|
||||||
lCell.DateTimeValue := value;
|
|
||||||
end
|
|
||||||
}
|
|
||||||
else if VarIsStr(value) then begin
|
|
||||||
lCell.ContentType := cctUTF8String;
|
|
||||||
lCell.UTF8StringValue := VarToStrDef(value, '');
|
|
||||||
end else
|
|
||||||
if VarIsBool(value) then begin
|
|
||||||
lCell.ContentType := cctBool;
|
|
||||||
lCell.BoolValue := value <> 0;
|
|
||||||
end;
|
|
||||||
WriteCellCallback(@lCell, FSSheets[FCurSheetNum]);
|
|
||||||
varClear(value);
|
|
||||||
end;
|
|
||||||
AppendToStream(FSSheets[FCurSheetNum],
|
|
||||||
'</row>');
|
|
||||||
end;
|
|
||||||
end else
|
|
||||||
begin
|
|
||||||
// The cells need to be written in order, row by row, cell by cell
|
|
||||||
LastColIndex := CurSheet.GetLastColIndex;
|
|
||||||
for r := 0 to CurSheet.GetLastRowIndex do begin
|
|
||||||
// If the row has a custom height add this value to the <row> specification
|
|
||||||
row := CurSheet.FindRow(r);
|
|
||||||
if row <> nil then
|
|
||||||
rh := Format(' ht="%g" customHeight="1"', [
|
|
||||||
(row^.Height + ROW_HEIGHT_CORRECTION)*h0])
|
|
||||||
else
|
|
||||||
rh := '';
|
|
||||||
AppendToStream(FSSheets[FCurSheetNum], Format(
|
|
||||||
'<row r="%d" spans="1:%d"%s>', [r+1, LastColIndex+1, rh]));
|
|
||||||
// Write cells belonging to this row.
|
|
||||||
for c := 0 to LastColIndex do begin
|
|
||||||
LCell.Row := r;
|
|
||||||
LCell.Col := c;
|
|
||||||
AVLNode := CurSheet.Cells.Find(@LCell);
|
|
||||||
if Assigned(AVLNode) then
|
|
||||||
WriteCellCallback(PCell(AVLNode.Data), FSSheets[FCurSheetNum])
|
|
||||||
else begin
|
|
||||||
CellPosText := CurSheet.CellPosToText(r, c);
|
|
||||||
AppendToStream(FSSheets[FCurSheetNum], Format(
|
|
||||||
'<c r="%s">', [CellPosText]),
|
|
||||||
'<v></v>',
|
|
||||||
'</c>');
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
AppendToStream(FSSheets[FCurSheetNum],
|
|
||||||
'</row>');
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
// Footer
|
// Footer
|
||||||
AppendToStream(FSSheets[FCurSheetNum],
|
AppendToStream(FSSheets[FCurSheetNum],
|
||||||
'</sheetData>' +
|
|
||||||
'</worksheet>');
|
'</worksheet>');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user