You've already forked lazarus-ccr
fpspreadsheet: Merged cell, hyperlink and row height support for html writer. Fix reading order of rich-text and asian phonetic info for biff8 reader.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@4220 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
htmltablewrite.lpr
|
htmlwrite.lpr
|
||||||
|
|
||||||
Demonstrates how to write a table in html format using the fpspreadsheet library
|
Demonstrates how to write a table in html format using the fpspreadsheet library
|
||||||
}
|
}
|
||||||
|
@ -34,14 +34,19 @@ type (*
|
|||||||
*)
|
*)
|
||||||
TsHTMLWriter = class(TsCustomSpreadWriter)
|
TsHTMLWriter = class(TsCustomSpreadWriter)
|
||||||
private
|
private
|
||||||
FFormatSettings: TFormatSettings;
|
FPointSeparatorSettings: TFormatSettings;
|
||||||
function GetBackgroundAsStyle(AFill: TsFillPattern): String;
|
function GetBackgroundAsStyle(AFill: TsFillPattern): String;
|
||||||
function GetBorderAsStyle(ABorder: TsCellBorders; const ABorderStyles: TsCellBorderStyles): String;
|
function GetBorderAsStyle(ABorder: TsCellBorders; const ABorderStyles: TsCellBorderStyles): String;
|
||||||
|
function GetColWidthAsAttr(AColIndex: Integer): String;
|
||||||
function GetFontAsStyle(AFontIndex: Integer): String;
|
function GetFontAsStyle(AFontIndex: Integer): String;
|
||||||
|
function GetGridBorderAsStyle: String;
|
||||||
function GetHorAlignAsStyle(AHorAlign: TsHorAlignment): String;
|
function GetHorAlignAsStyle(AHorAlign: TsHorAlignment): String;
|
||||||
function GetTextRotation(ATextRot: TsTextRotation): String;
|
function GetMergedRangeAsStyle(AMergeBase: PCell): String;
|
||||||
|
function GetRowHeightAsAttr(ARowIndex: Integer): String;
|
||||||
|
function GetTextRotationAsStyle(ATextRot: TsTextRotation): String;
|
||||||
function GetVertAlignAsStyle(AVertAlign: TsVertAlignment): String;
|
function GetVertAlignAsStyle(AVertAlign: TsVertAlignment): String;
|
||||||
function GetWordWrapAsStyle(AWordWrap: Boolean): String;
|
function GetWordWrapAsStyle(AWordWrap: Boolean): String;
|
||||||
|
function IsHyperlinkTarget(ACell: PCell; out ABookmark: String): Boolean;
|
||||||
procedure WriteBody(AStream: TStream);
|
procedure WriteBody(AStream: TStream);
|
||||||
procedure WriteWorksheet(AStream: TStream; ASheet: TsWorksheet);
|
procedure WriteWorksheet(AStream: TStream; ASheet: TsWorksheet);
|
||||||
|
|
||||||
@ -64,19 +69,22 @@ type (*
|
|||||||
|
|
||||||
public
|
public
|
||||||
constructor Create(AWorkbook: TsWorkbook); override;
|
constructor Create(AWorkbook: TsWorkbook); override;
|
||||||
|
destructor Destroy; override;
|
||||||
procedure WriteToStream(AStream: TStream); override;
|
procedure WriteToStream(AStream: TStream); override;
|
||||||
procedure WriteToStrings(AStrings: TStrings); override;
|
procedure WriteToStrings(AStrings: TStrings); override;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
TsHTMLParams = record
|
TsHTMLParams = record
|
||||||
SheetIndex: Integer; // W: Index of the sheet to be written
|
SheetIndex: Integer; // W: Index of the sheet to be written
|
||||||
|
ShowRowColHeaders: Boolean; // RW: Show row/column headers
|
||||||
TrueText: String; // RW: String for boolean TRUE
|
TrueText: String; // RW: String for boolean TRUE
|
||||||
FalseText: String; // RW: String for boolean FALSE
|
FalseText: String; // RW: String for boolean FALSE
|
||||||
end;
|
end;
|
||||||
|
|
||||||
var
|
var
|
||||||
HTMLParams: TsHTMLParams = (
|
HTMLParams: TsHTMLParams = (
|
||||||
SheetIndex: -1; // -1 = active sheet, MaxInt = all sheets
|
SheetIndex: -1; // -1 = active sheet, MaxInt = all sheets
|
||||||
|
ShowRowColHeaders: false;
|
||||||
TrueText: 'TRUE';
|
TrueText: 'TRUE';
|
||||||
FalseText: 'FALSE';
|
FalseText: 'FALSE';
|
||||||
);
|
);
|
||||||
@ -84,11 +92,24 @@ var
|
|||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
LazUTF8, fpsUtils;
|
LazUTF8, URIParser, Math,
|
||||||
|
fpsUtils;
|
||||||
|
|
||||||
constructor TsHTMLWriter.Create(AWorkbook: TsWorkbook);
|
constructor TsHTMLWriter.Create(AWorkbook: TsWorkbook);
|
||||||
begin
|
begin
|
||||||
inherited Create(AWorkbook);
|
inherited Create(AWorkbook);
|
||||||
|
FPointSeparatorSettings := DefaultFormatSettings;
|
||||||
|
FPointSeparatorSettings.DecimalSeparator := '.';
|
||||||
|
|
||||||
|
// No design limiations in table size
|
||||||
|
// http://stackoverflow.com/questions/4311283/max-columns-in-html-table
|
||||||
|
FLimitations.MaxColCount := MaxInt;
|
||||||
|
FLimitations.MaxRowCount := MaxInt;
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TsHTMLWriter.Destroy;
|
||||||
|
begin
|
||||||
|
inherited Destroy;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TsHTMLWriter.CellFormatAsString(ACell: PCell; ForThisTag: String): String;
|
function TsHTMLWriter.CellFormatAsString(ACell: PCell; ForThisTag: String): String;
|
||||||
@ -104,9 +125,9 @@ begin
|
|||||||
'td':
|
'td':
|
||||||
if ACell = nil then
|
if ACell = nil then
|
||||||
begin
|
begin
|
||||||
Result := 'border-collapse:collapse; ';
|
Result := 'border-collapse:collapse;';
|
||||||
if soShowGridLines in FWorksheet.Options then
|
if soShowGridLines in FWorksheet.Options then
|
||||||
Result := Result + 'border:1px solid lightgrey; '
|
Result := Result + GetGridBorderAsStyle;
|
||||||
end else
|
end else
|
||||||
begin
|
begin
|
||||||
if (uffVertAlign in fmt^.UsedFormattingFields) then
|
if (uffVertAlign in fmt^.UsedFormattingFields) then
|
||||||
@ -114,16 +135,15 @@ begin
|
|||||||
if (uffBorder in fmt^.UsedFormattingFields) then
|
if (uffBorder in fmt^.UsedFormattingFields) then
|
||||||
Result := Result + GetBorderAsStyle(fmt^.Border, fmt^.BorderStyles)
|
Result := Result + GetBorderAsStyle(fmt^.Border, fmt^.BorderStyles)
|
||||||
else begin
|
else begin
|
||||||
Result := Result + 'border-collapse:collapse; ';
|
|
||||||
if soShowGridLines in FWorksheet.Options then
|
if soShowGridLines in FWorksheet.Options then
|
||||||
Result := Result + 'border:1px solid lightgrey; ';
|
Result := Result + GetGridBorderAsStyle;
|
||||||
end;
|
end;
|
||||||
if (uffBackground in fmt^.UsedFormattingFields) then
|
if (uffBackground in fmt^.UsedFormattingFields) then
|
||||||
Result := Result + GetBackgroundAsStyle(fmt^.Background);
|
Result := Result + GetBackgroundAsStyle(fmt^.Background);
|
||||||
if (uffFont in fmt^.UsedFormattingFields) then
|
if (uffFont in fmt^.UsedFormattingFields) then
|
||||||
Result := Result + GetFontAsStyle(fmt^.FontIndex);
|
Result := Result + GetFontAsStyle(fmt^.FontIndex);
|
||||||
if (uffTextRotation in fmt^.UsedFormattingFields) then
|
if (uffTextRotation in fmt^.UsedFormattingFields) then
|
||||||
Result := Result + GetTextRotation(fmt^.TextRotation);
|
Result := Result + GetTextRotationAsStyle(fmt^.TextRotation);
|
||||||
end;
|
end;
|
||||||
'div', 'p':
|
'div', 'p':
|
||||||
begin
|
begin
|
||||||
@ -161,7 +181,12 @@ function TsHTMLWriter.GetBorderAsStyle(ABorder: TsCellBorders;
|
|||||||
const ABorderStyles: TsCellBorderStyles): String;
|
const ABorderStyles: TsCellBorderStyles): String;
|
||||||
const
|
const
|
||||||
BORDER_NAMES: array[TsCellBorder] of string = (
|
BORDER_NAMES: array[TsCellBorder] of string = (
|
||||||
'border-top', 'border-left', 'border-right', 'border-bottom', '', ''
|
'border-top', // cbNorth
|
||||||
|
'border-left', // cbWest
|
||||||
|
'border-right', // cbEast
|
||||||
|
'border-bottom', // cbSouth
|
||||||
|
'', // cbDiagUp
|
||||||
|
'' // cbDiagDown
|
||||||
);
|
);
|
||||||
LINESTYLE_NAMES: array[TsLineStyle] of string = (
|
LINESTYLE_NAMES: array[TsLineStyle] of string = (
|
||||||
'thin solid', // lsThin
|
'thin solid', // lsThin
|
||||||
@ -169,33 +194,80 @@ const
|
|||||||
'thin dashed', // lsDashed
|
'thin dashed', // lsDashed
|
||||||
'thin dotted', // lsDotted
|
'thin dotted', // lsDotted
|
||||||
'thick solid', // lsThick,
|
'thick solid', // lsThick,
|
||||||
'thin double', // lsDouble,
|
'double', // lsDouble,
|
||||||
'1px solid' // lsHair
|
'1px solid' // lsHair
|
||||||
);
|
);
|
||||||
var
|
var
|
||||||
cb: TsCellBorder;
|
cb: TsCellBorder;
|
||||||
|
allEqual: Boolean;
|
||||||
|
bs: TsCellBorderStyle;
|
||||||
begin
|
begin
|
||||||
Result := 'border-collape:collapse';
|
Result := 'border-collape:collapse;';
|
||||||
|
if ABorder = [cbNorth, cbEast, cbWest, cbSouth] then
|
||||||
|
begin
|
||||||
|
allEqual := true;
|
||||||
|
bs := ABorderStyles[cbNorth];
|
||||||
|
for cb in TsCellBorder do
|
||||||
|
begin
|
||||||
|
if bs.LineStyle <> ABorderStyles[cb].LineStyle then
|
||||||
|
begin
|
||||||
|
allEqual := false;
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
if bs.Color <> ABorderStyles[cb].Color then
|
||||||
|
begin
|
||||||
|
allEqual := false;
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
if allEqual then
|
||||||
|
begin
|
||||||
|
Result := 'border:' +
|
||||||
|
LINESTYLE_NAMES[bs.LineStyle] + ' ' +
|
||||||
|
ColorToHTMLColorStr(bs.Color) + ';';
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
for cb in TsCellBorder do
|
for cb in TsCellBorder do
|
||||||
begin
|
begin
|
||||||
if BORDER_NAMES[cb] = '' then
|
if BORDER_NAMES[cb] = '' then
|
||||||
continue;
|
continue;
|
||||||
Result := Result + BORDER_NAMES[cb] + ':' +
|
if cb in ABorder then
|
||||||
LINESTYLE_NAMES[ABorderStyles[cb].LineStyle] + ' ' +
|
Result := Result + BORDER_NAMES[cb] + ':' +
|
||||||
ColorToHTMLColorStr(ABorderStyles[cb].Color) + ';';
|
LINESTYLE_NAMES[ABorderStyles[cb].LineStyle] + ' ' +
|
||||||
|
ColorToHTMLColorStr(ABorderStyles[cb].Color) + ';';
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TsHTMLWriter.GetColWidthAsAttr(AColIndex: Integer): String;
|
||||||
|
var
|
||||||
|
col: PCol;
|
||||||
|
w: Single;
|
||||||
|
rLast: Cardinal;
|
||||||
|
begin
|
||||||
|
if AColIndex < 0 then // Row header column
|
||||||
|
begin
|
||||||
|
rLast := FWorksheet.GetLastRowIndex;
|
||||||
|
w := Length(IntToStr(rLast)) + 2;
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
w := FWorksheet.DefaultColWidth;
|
||||||
|
col := FWorksheet.FindCol(AColIndex);
|
||||||
|
if col <> nil then
|
||||||
|
w := col^.Width;
|
||||||
|
end;
|
||||||
|
w := w * FWorkbook.GetDefaultFont.Size;
|
||||||
|
Result:= Format(' width="%.1fpt"', [w], FPointSeparatorSettings);
|
||||||
|
end;
|
||||||
|
|
||||||
function TsHTMLWriter.GetFontAsStyle(AFontIndex: Integer): String;
|
function TsHTMLWriter.GetFontAsStyle(AFontIndex: Integer): String;
|
||||||
var
|
var
|
||||||
fs: TFormatSettings;
|
|
||||||
font: TsFont;
|
font: TsFont;
|
||||||
begin
|
begin
|
||||||
fs := DefaultFormatSettings;
|
|
||||||
fs.DecimalSeparator := '.';
|
|
||||||
font := FWorkbook.GetFont(AFontIndex);
|
font := FWorkbook.GetFont(AFontIndex);
|
||||||
Result := Format('font-family:''%s'';font-size:%.1fpt;color:%s;', [
|
Result := Format('font-family:''%s'';font-size:%.1fpt;color:%s;', [
|
||||||
font.FontName, font.Size, ColorToHTMLColorStr(font.Color)], fs);
|
font.FontName, font.Size, ColorToHTMLColorStr(font.Color)], FPointSeparatorSettings);
|
||||||
if fssBold in font.Style then
|
if fssBold in font.Style then
|
||||||
Result := Result + 'font-weight:700;';
|
Result := Result + 'font-weight:700;';
|
||||||
if fssItalic in font.Style then
|
if fssItalic in font.Style then
|
||||||
@ -210,6 +282,11 @@ begin
|
|||||||
Result := Result + 'text-decoration:line-through;';
|
Result := Result + 'text-decoration:line-through;';
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TsHTMLWriter.GetGridBorderAsStyle: String;
|
||||||
|
begin
|
||||||
|
Result := 'border:1px solid lightgrey;';
|
||||||
|
end;
|
||||||
|
|
||||||
function TsHTMLWriter.GetHorAlignAsStyle(AHorAlign: TsHorAlignment): String;
|
function TsHTMLWriter.GetHorAlignAsStyle(AHorAlign: TsHorAlignment): String;
|
||||||
begin
|
begin
|
||||||
case AHorAlign of
|
case AHorAlign of
|
||||||
@ -219,7 +296,33 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TsHTMLWriter.GetTextRotation(ATextRot: TsTextRotation): String;
|
function TsHTMLWriter.GetMergedRangeAsStyle(AMergeBase: PCell): String;
|
||||||
|
var
|
||||||
|
r1, r2, c1, c2: Cardinal;
|
||||||
|
begin
|
||||||
|
Result := '';
|
||||||
|
FWorksheet.FindMergedRange(AMergeBase, r1, c1, r2, c2);
|
||||||
|
if c1 <> c2 then
|
||||||
|
Result := Result + ' colspan="' + IntToStr(c2-c1+1) + '"';
|
||||||
|
if r1 <> r2 then
|
||||||
|
Result := Result + ' rowspan="' + IntToStr(r2-r1+1) + '"';
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsHTMLWriter.GetRowHeightAsAttr(ARowIndex: Integer): String;
|
||||||
|
var
|
||||||
|
h: Single;
|
||||||
|
row: PRow;
|
||||||
|
begin
|
||||||
|
h := FWorksheet.DefaultRowHeight;
|
||||||
|
row := FWorksheet.FindRow(ARowIndex);
|
||||||
|
if row <> nil then
|
||||||
|
h := row^.Height;
|
||||||
|
h := (h + ROW_HEIGHT_CORRECTION) * FWorkbook.GetDefaultFont.Size;
|
||||||
|
Result := Format(' height="%.1fpt"', [h], FPointSeparatorSettings);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TsHTMLWriter.GetTextRotationAsStyle(ATextRot: TsTextRotation): String;
|
||||||
begin
|
begin
|
||||||
Result := '';
|
Result := '';
|
||||||
case ATextRot of
|
case ATextRot of
|
||||||
@ -249,8 +352,38 @@ begin
|
|||||||
if AWordwrap then
|
if AWordwrap then
|
||||||
Result := 'word-wrap:break-word;'
|
Result := 'word-wrap:break-word;'
|
||||||
else
|
else
|
||||||
Result := 'white-space:nowrap'; //-moz-pre-wrap -o-pre-wrap pre-wrap;';
|
Result := 'white-space:nowrap';
|
||||||
{ Firefox Opera Chrome }
|
end;
|
||||||
|
|
||||||
|
function TsHTMLWriter.IsHyperlinkTarget(ACell: PCell; out ABookmark: String): Boolean;
|
||||||
|
var
|
||||||
|
sheet: TsWorksheet;
|
||||||
|
hyperlink: PsHyperlink;
|
||||||
|
target, sh: String;
|
||||||
|
i, r, c: Cardinal;
|
||||||
|
begin
|
||||||
|
Result := false;
|
||||||
|
if ACell = nil then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
for i:=0 to FWorkbook.GetWorksheetCount-1 do
|
||||||
|
begin
|
||||||
|
sheet := FWorkbook.GetWorksheetByIndex(i);
|
||||||
|
for hyperlink in sheet.Hyperlinks do
|
||||||
|
begin
|
||||||
|
SplitHyperlink(hyperlink^.Target, target, ABookmark);
|
||||||
|
if (target <> '') or (ABookmark = '') then
|
||||||
|
continue;
|
||||||
|
if ParseSheetCellString(ABookmark, sh, r, c) then
|
||||||
|
if (sh = TsWorksheet(ACell^.Worksheet).Name) and
|
||||||
|
(r = ACell^.Row) and (c = ACell^.Col)
|
||||||
|
then
|
||||||
|
exit(true);
|
||||||
|
if (sheet = FWorksheet) and ParseCellString(ABookmark, r, c) then
|
||||||
|
if (r = ACell^.Row) and (c = ACell^.Col) then
|
||||||
|
exit(true);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TsHTMLWriter.WriteBlank(AStream: TStream; const ARow, ACol: Cardinal;
|
procedure TsHTMLWriter.WriteBlank(AStream: TStream; const ARow, ACol: Cardinal;
|
||||||
@ -347,13 +480,15 @@ procedure TsHTMLWriter.WriteLabel(AStream: TStream; const ARow, ACol: Cardinal;
|
|||||||
const
|
const
|
||||||
ESCAPEMENT_TAG: Array[TsFontPosition] of String = ('', 'sup', 'sub');
|
ESCAPEMENT_TAG: Array[TsFontPosition] of String = ('', 'sup', 'sub');
|
||||||
var
|
var
|
||||||
L: TStringList;
|
|
||||||
style: String;
|
style: String;
|
||||||
i, n, len: Integer;
|
i, n, len: Integer;
|
||||||
txt, textp: String;
|
txt, textp, target, bookmark: String;
|
||||||
rtParam: TsRichTextParam;
|
rtParam: TsRichTextParam;
|
||||||
fnt, cellfnt: TsFont;
|
fnt, cellfnt: TsFont;
|
||||||
escapement: String;
|
escapement: String;
|
||||||
|
hyperlink: PsHyperlink;
|
||||||
|
isTargetCell: Boolean;
|
||||||
|
u: TUri;
|
||||||
begin
|
begin
|
||||||
Unused(ARow, ACol, AValue);
|
Unused(ARow, ACol, AValue);
|
||||||
|
|
||||||
@ -363,19 +498,51 @@ begin
|
|||||||
|
|
||||||
style := CellFormatAsString(ACell, 'div');
|
style := CellFormatAsString(ACell, 'div');
|
||||||
|
|
||||||
|
// Hyperlink
|
||||||
|
target := '';
|
||||||
|
if FWorksheet.HasHyperlink(ACell) then
|
||||||
|
begin
|
||||||
|
hyperlink := FWorksheet.FindHyperlink(ACell);
|
||||||
|
SplitHyperlink(hyperlink^.Target, target, bookmark);
|
||||||
|
|
||||||
|
n := Length(hyperlink^.Target);
|
||||||
|
i := Length(target);
|
||||||
|
len := Length(bookmark);
|
||||||
|
|
||||||
|
if (target <> '') and (pos('file:', target) = 0) then
|
||||||
|
begin
|
||||||
|
u := ParseURI(target);
|
||||||
|
if u.Protocol = '' then
|
||||||
|
target := '../' + target;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// ods absolutely wants "/" path delimiters in the file uri!
|
||||||
|
FixHyperlinkPathdelims(target);
|
||||||
|
|
||||||
|
if (bookmark <> '') then
|
||||||
|
target := target + '#' + bookmark;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Activate hyperlink target if it is within the same file
|
||||||
|
isTargetCell := IsHyperlinkTarget(ACell, bookmark);
|
||||||
|
if isTargetCell then bookmark := ' id="' + bookmark + '"' else bookmark := '';
|
||||||
|
|
||||||
// No hyperlink, normal text only
|
// No hyperlink, normal text only
|
||||||
if Length(ACell^.RichTextParams) = 0 then
|
if Length(ACell^.RichTextParams) = 0 then
|
||||||
begin
|
begin
|
||||||
// Standard text formatting
|
// Standard text formatting
|
||||||
ValidXMLText(txt);
|
ValidXMLText(txt);
|
||||||
|
if target <> '' then txt := Format('<a href="%s">%s</a>', [target, txt]);
|
||||||
AppendToStream(AStream,
|
AppendToStream(AStream,
|
||||||
'<div' + style + '>' + txt + '</div>')
|
'<div' + bookmark + style + '>' + txt + '</div>')
|
||||||
end else
|
end else
|
||||||
begin
|
begin
|
||||||
// "Rich-text" formatting
|
// "Rich-text" formatting
|
||||||
cellfnt := FWorksheet.ReadCellFont(ACell);
|
cellfnt := FWorksheet.ReadCellFont(ACell);
|
||||||
len := UTF8Length(AValue);
|
len := UTF8Length(AValue);
|
||||||
textp := '<div' + style + '>';
|
textp := '<div' + bookmark + style + '>';
|
||||||
|
if target <> '' then
|
||||||
|
textp := textp + '<a href="' + target + '">';
|
||||||
rtParam := ACell^.RichTextParams[0];
|
rtParam := ACell^.RichTextParams[0];
|
||||||
if rtParam.StartIndex > 0 then
|
if rtParam.StartIndex > 0 then
|
||||||
begin
|
begin
|
||||||
@ -412,24 +579,11 @@ begin
|
|||||||
textp := textp + txt;
|
textp := textp + txt;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
textp := textp + '</div>';
|
if target <> '' then
|
||||||
|
textp := textp + '</a></div>' else
|
||||||
|
textp := textp + '</div>';
|
||||||
AppendToStream(AStream, textp);
|
AppendToStream(AStream, textp);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{
|
|
||||||
L := TStringList.Create;
|
|
||||||
try
|
|
||||||
L.Text := ACell^.UTF8StringValue;
|
|
||||||
if L.Count = 1 then
|
|
||||||
AppendToStream(AStream,
|
|
||||||
'<div' + style + '>' + s + '</div>')
|
|
||||||
else
|
|
||||||
for i := 0 to L.Count-1 do
|
|
||||||
AppendToStream(AStream, '<p><div'+ style + '>' + L[i] + '</div></p>');
|
|
||||||
finally
|
|
||||||
L.Free;
|
|
||||||
end;
|
|
||||||
}
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ Writes a number cell to the stream. }
|
{ Writes a number cell to the stream. }
|
||||||
@ -439,17 +593,11 @@ var
|
|||||||
s: String;
|
s: String;
|
||||||
style: String;
|
style: String;
|
||||||
begin
|
begin
|
||||||
Unused(AStream);
|
|
||||||
Unused(ARow, ACol);
|
Unused(ARow, ACol);
|
||||||
|
|
||||||
style := CellFormatAsString(ACell, 'div');
|
style := CellFormatAsString(ACell, 'div');
|
||||||
|
|
||||||
{
|
s := FWorksheet.ReadAsUTF8Text(ACell, FWorkbook.FormatSettings);
|
||||||
if HTMLParams.NumberFormat <> '' then
|
|
||||||
s := Format(HTMLParams.NumberFormat, [AValue], FFormatSettings)
|
|
||||||
else
|
|
||||||
}
|
|
||||||
s := FWorksheet.ReadAsUTF8Text(ACell, FFormatSettings);
|
|
||||||
AppendToStream(AStream,
|
AppendToStream(AStream,
|
||||||
'<div' + style + '>' + s + '</div>');
|
'<div' + style + '>' + s + '</div>');
|
||||||
end;
|
end;
|
||||||
@ -461,7 +609,6 @@ begin
|
|||||||
'<!DOCTYPE html>' +
|
'<!DOCTYPE html>' +
|
||||||
'<html>' +
|
'<html>' +
|
||||||
'<head>'+
|
'<head>'+
|
||||||
// '<title>Written by FPSpreadsheet</title>' +
|
|
||||||
'<meta charset="utf-8">' +
|
'<meta charset="utf-8">' +
|
||||||
'</head>');
|
'</head>');
|
||||||
WriteBody(AStream);
|
WriteBody(AStream);
|
||||||
@ -492,8 +639,8 @@ var
|
|||||||
style: String;
|
style: String;
|
||||||
fixedLayout: Boolean;
|
fixedLayout: Boolean;
|
||||||
col: PCol;
|
col: PCol;
|
||||||
w: Single;
|
row: PRow;
|
||||||
fs: TFormatSettings;
|
w, h: Single;
|
||||||
begin
|
begin
|
||||||
FWorksheet := ASheet;
|
FWorksheet := ASheet;
|
||||||
|
|
||||||
@ -502,9 +649,6 @@ begin
|
|||||||
rLast := FWorksheet.GetLastOccupiedRowIndex;
|
rLast := FWorksheet.GetLastOccupiedRowIndex;
|
||||||
cLast := FWorksheet.GetLastOccupiedColIndex;
|
cLast := FWorksheet.GetLastOccupiedColIndex;
|
||||||
|
|
||||||
fs := DefaultFormatSettings;
|
|
||||||
fs.DecimalSeparator := '.';
|
|
||||||
|
|
||||||
fixedLayout := false;
|
fixedLayout := false;
|
||||||
for c:=cFirst to cLast do
|
for c:=cFirst to cLast do
|
||||||
begin
|
begin
|
||||||
@ -520,7 +664,7 @@ begin
|
|||||||
|
|
||||||
style := style + 'border-collapse:collapse; ';
|
style := style + 'border-collapse:collapse; ';
|
||||||
if soShowGridLines in FWorksheet.Options then
|
if soShowGridLines in FWorksheet.Options then
|
||||||
style := style + 'border:1px solid lightgrey; ';
|
style := style + GetGridBorderAsStyle;
|
||||||
|
|
||||||
if fixedLayout then
|
if fixedLayout then
|
||||||
style := style + 'table-layout:fixed; '
|
style := style + 'table-layout:fixed; '
|
||||||
@ -530,37 +674,89 @@ begin
|
|||||||
AppendToStream(AStream,
|
AppendToStream(AStream,
|
||||||
'<div>' +
|
'<div>' +
|
||||||
'<table style="' + style + '">');
|
'<table style="' + style + '">');
|
||||||
|
|
||||||
|
if HTMLParams.ShowRowColHeaders then
|
||||||
|
begin
|
||||||
|
// width of row-header column
|
||||||
|
style := '';
|
||||||
|
if soShowGridLines in FWorksheet.Options then
|
||||||
|
style := style + GetGridBorderAsStyle;
|
||||||
|
if style <> '' then
|
||||||
|
style := ' style="' + style + '"';
|
||||||
|
style := style + GetColWidthAsAttr(-1);
|
||||||
|
AppendToStream(AStream,
|
||||||
|
'<th' + style + '/>');
|
||||||
|
// Column headers
|
||||||
|
for c := cFirst to cLast do
|
||||||
|
begin
|
||||||
|
style := '';
|
||||||
|
if soShowGridLines in FWorksheet.Options then
|
||||||
|
style := style + GetGridBorderAsStyle;
|
||||||
|
if style <> '' then
|
||||||
|
style := ' style="' + style + '"';
|
||||||
|
if fixedLayout then
|
||||||
|
style := style + GetColWidthAsAttr(c);
|
||||||
|
AppendToStream(AStream,
|
||||||
|
'<th' + style + '>' + GetColString(c) + '</th>');
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
for r := rFirst to rLast do begin
|
for r := rFirst to rLast do begin
|
||||||
AppendToStream(AStream,
|
AppendToStream(AStream,
|
||||||
'<tr>');
|
'<tr>');
|
||||||
for c := cFirst to cLast do begin
|
|
||||||
cell := FWorksheet.FindCell(r, c);
|
|
||||||
style := CellFormatAsString(cell, 'td');
|
|
||||||
|
|
||||||
if (c = cFirst) then
|
// Row headers
|
||||||
begin
|
if HTMLParams.ShowRowColHeaders then begin
|
||||||
w := FWorksheet.DefaultColWidth;
|
style := '';
|
||||||
if fixedLayout then
|
if soShowGridLines in FWorksheet.Options then
|
||||||
begin
|
style := style + GetGridBorderAsStyle;
|
||||||
col := FWorksheet.GetCol(c);
|
if style <> '' then
|
||||||
if col <> nil then
|
style := ' style="' + style + '"';
|
||||||
w := col^.Width;
|
style := style + GetRowHeightAsAttr(r);
|
||||||
style := Format(' width="%.1fpt"', [w*FWorkbook.GetDefaultFont.Size], fs) + style;
|
AppendToStream(AStream,
|
||||||
end;
|
'<th' + style + '>' + IntToStr(r+1) + '</th>');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if (cell = nil) or (cell^.ContentType = cctEmpty) then
|
for c := cFirst to cLast do begin
|
||||||
AppendToStream(AStream,
|
// Pointer to current cell in loop
|
||||||
'<td' + style + ' />')
|
cell := FWorksheet.FindCell(r, c);
|
||||||
else
|
|
||||||
begin
|
// Cell formatting
|
||||||
AppendToStream(AStream,
|
style := CellFormatAsString(cell, 'td'); // this contains the 'style="..."'
|
||||||
'<td' + style + '>');
|
|
||||||
WriteCellToStream(AStream, cell);
|
if not HTMLParams.ShowRowColHeaders then
|
||||||
AppendToStream(AStream,
|
begin
|
||||||
'</td>');
|
// Column width
|
||||||
end;
|
if fixedLayout then
|
||||||
|
style := GetColWidthAsAttr(c) + style;
|
||||||
|
|
||||||
|
// Row heights (should be in "tr", but does not work there)
|
||||||
|
style := GetRowHeightAsAttr(r) + style;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
// Merged cells
|
||||||
|
if FWorksheet.IsMerged(cell) then
|
||||||
|
begin
|
||||||
|
if FWorksheet.IsMergeBase(cell) then
|
||||||
|
style := style + GetMergedRangeAsStyle(cell)
|
||||||
|
else
|
||||||
|
Continue;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if (cell = nil) or (cell^.ContentType = cctEmpty) then
|
||||||
|
// Empty cell
|
||||||
|
AppendToStream(AStream,
|
||||||
|
'<td' + style + ' />')
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
// Cell with data
|
||||||
|
AppendToStream(AStream,
|
||||||
|
'<td' + style + '>');
|
||||||
|
WriteCellToStream(AStream, cell);
|
||||||
|
AppendToStream(AStream,
|
||||||
|
'</td>');
|
||||||
|
end;
|
||||||
|
end;
|
||||||
AppendToStream(AStream,
|
AppendToStream(AStream,
|
||||||
'</tr>');
|
'</tr>');
|
||||||
end;
|
end;
|
||||||
|
@ -658,7 +658,7 @@ var
|
|||||||
RunsCounter: WORD;
|
RunsCounter: WORD;
|
||||||
AsianPhoneticBytes: DWORD;
|
AsianPhoneticBytes: DWORD;
|
||||||
i: Integer;
|
i: Integer;
|
||||||
j: SizeUInt;
|
j: Integer; //j: SizeUInt;
|
||||||
lLen: SizeInt;
|
lLen: SizeInt;
|
||||||
RecordType: WORD;
|
RecordType: WORD;
|
||||||
RecordSize: WORD;
|
RecordSize: WORD;
|
||||||
@ -666,17 +666,17 @@ var
|
|||||||
begin
|
begin
|
||||||
StringFlags := AStream.ReadByte;
|
StringFlags := AStream.ReadByte;
|
||||||
Dec(PendingRecordSize);
|
Dec(PendingRecordSize);
|
||||||
|
if StringFlags and 8 = 8 then begin
|
||||||
|
// Rich string
|
||||||
|
RunsCounter := WordLEtoN(AStream.ReadWord);
|
||||||
|
dec(PendingRecordSize,2);
|
||||||
|
end;
|
||||||
if StringFlags and 4 = 4 then begin
|
if StringFlags and 4 = 4 then begin
|
||||||
// Asian phonetics
|
// Asian phonetics
|
||||||
// Read Asian phonetics Length (not used)
|
// Read Asian phonetics Length (not used)
|
||||||
AsianPhoneticBytes := DWordLEtoN(AStream.ReadDWord);
|
AsianPhoneticBytes := DWordLEtoN(AStream.ReadDWord);
|
||||||
dec(PendingRecordSize,4);
|
dec(PendingRecordSize,4);
|
||||||
end;
|
end;
|
||||||
if StringFlags and 8 = 8 then begin
|
|
||||||
// Rich string
|
|
||||||
RunsCounter := WordLEtoN(AStream.ReadWord);
|
|
||||||
dec(PendingRecordSize,2);
|
|
||||||
end;
|
|
||||||
if StringFlags and 1 = 1 Then begin
|
if StringFlags and 1 = 1 Then begin
|
||||||
// String is WideStringLE
|
// String is WideStringLE
|
||||||
if (ALength*SizeOf(WideChar)) > PendingRecordSize then begin
|
if (ALength*SizeOf(WideChar)) > PendingRecordSize then begin
|
||||||
@ -717,7 +717,7 @@ begin
|
|||||||
if StringFlags and 8 = 8 then begin
|
if StringFlags and 8 = 8 then begin
|
||||||
// Rich string (This only occurs in BIFF8)
|
// Rich string (This only occurs in BIFF8)
|
||||||
SetLength(ARichTextRuns, RunsCounter);
|
SetLength(ARichTextRuns, RunsCounter);
|
||||||
for j := 0 to RunsCounter - 1 do begin
|
for j := 0 to SmallInt(RunsCounter) - 1 do begin
|
||||||
if (PendingRecordSize <= 0) then begin
|
if (PendingRecordSize <= 0) then begin
|
||||||
// A CONTINUE may happened here
|
// A CONTINUE may happened here
|
||||||
RecordType := WordLEToN(AStream.ReadWord);
|
RecordType := WordLEToN(AStream.ReadWord);
|
||||||
@ -1814,10 +1814,15 @@ begin
|
|||||||
begin
|
begin
|
||||||
// Size of character array incl trailing zero
|
// Size of character array incl trailing zero
|
||||||
size := DWordLEToN(AStream.ReadDWord);
|
size := DWordLEToN(AStream.ReadDWord);
|
||||||
len := size div 2 -1;
|
|
||||||
// Character array of URL (16-bit-characters, with trailing zero word)
|
// Character array of URL (16-bit-characters, with trailing zero word)
|
||||||
|
// See 3 lines below: This buffer is too large!
|
||||||
|
len := size div 2 - 1;
|
||||||
SetLength(wideStr, len);
|
SetLength(wideStr, len);
|
||||||
AStream.ReadBuffer(wideStr[1], size);
|
AStream.ReadBuffer(wideStr[1], size);
|
||||||
|
// The buffer can be larger than the space occupied by the wideStr.
|
||||||
|
// --> Find true string length and convert wide string to utf-8.
|
||||||
|
len := StrLen(PWideChar(widestr));
|
||||||
|
SetLength(widestr, len);
|
||||||
link := UTF8Encode(widestr);
|
link := UTF8Encode(widestr);
|
||||||
end else
|
end else
|
||||||
// Check for local file
|
// Check for local file
|
||||||
|
Reference in New Issue
Block a user