You've already forked lazarus-ccr
fpspreadsheet: Implement cell comments for biff2 and biff5 (reading and writing). Complete cell comments for ods.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3915 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -3415,11 +3415,15 @@ var
|
|||||||
colsSpannedStr: String;
|
colsSpannedStr: String;
|
||||||
rowsSpannedStr: String;
|
rowsSpannedStr: String;
|
||||||
spannedStr: String;
|
spannedStr: String;
|
||||||
|
comment: String;
|
||||||
r1,c1,r2,c2: Cardinal;
|
r1,c1,r2,c2: Cardinal;
|
||||||
fmt: TsCellFormat;
|
fmt: TsCellFormat;
|
||||||
begin
|
begin
|
||||||
Unused(ARow, ACol);
|
Unused(ARow, ACol);
|
||||||
|
|
||||||
|
// Comment
|
||||||
|
comment := WriteCommentXMLAsString(ACell^.Comment);
|
||||||
|
|
||||||
// Merged?
|
// Merged?
|
||||||
if FWorksheet.IsMergeBase(ACell) then
|
if FWorksheet.IsMergeBase(ACell) then
|
||||||
begin
|
begin
|
||||||
@ -3434,6 +3438,7 @@ begin
|
|||||||
if fmt.UsedFormattingFields <> [] then
|
if fmt.UsedFormattingFields <> [] then
|
||||||
AppendToStream(AStream, Format(
|
AppendToStream(AStream, Format(
|
||||||
'<table:table-cell table:style-name="ce%d" %s>', [ACell^.FormatIndex, spannedStr]),
|
'<table:table-cell table:style-name="ce%d" %s>', [ACell^.FormatIndex, spannedStr]),
|
||||||
|
comment,
|
||||||
'</table:table-cell>')
|
'</table:table-cell>')
|
||||||
else
|
else
|
||||||
AppendToStream(AStream,
|
AppendToStream(AStream,
|
||||||
@ -3449,6 +3454,7 @@ var
|
|||||||
lStyle, valType: String;
|
lStyle, valType: String;
|
||||||
r1,c1,r2,c2: Cardinal;
|
r1,c1,r2,c2: Cardinal;
|
||||||
rowsSpannedStr, colsSpannedStr, spannedStr: String;
|
rowsSpannedStr, colsSpannedStr, spannedStr: String;
|
||||||
|
comment: String;
|
||||||
strValue: String;
|
strValue: String;
|
||||||
displayStr: String;
|
displayStr: String;
|
||||||
fmt: TsCellFormat;
|
fmt: TsCellFormat;
|
||||||
@ -3463,6 +3469,9 @@ begin
|
|||||||
else
|
else
|
||||||
lStyle := '';
|
lStyle := '';
|
||||||
|
|
||||||
|
// Comment
|
||||||
|
comment := WriteCommentXMLAsString(ACell^.Comment);
|
||||||
|
|
||||||
// Merged?
|
// Merged?
|
||||||
if FWorksheet.IsMergeBase(ACell) then
|
if FWorksheet.IsMergeBase(ACell) then
|
||||||
begin
|
begin
|
||||||
@ -3486,6 +3495,7 @@ begin
|
|||||||
|
|
||||||
AppendToStream(AStream, Format(
|
AppendToStream(AStream, Format(
|
||||||
'<table:table-cell office:value-type="%s" office:boolean-value="%s" %s %s >' +
|
'<table:table-cell office:value-type="%s" office:boolean-value="%s" %s %s >' +
|
||||||
|
comment +
|
||||||
'<text:p>%s</text:p>' +
|
'<text:p>%s</text:p>' +
|
||||||
'</table:table-cell>', [
|
'</table:table-cell>', [
|
||||||
valType, StrValue, lStyle, spannedStr,
|
valType, StrValue, lStyle, spannedStr,
|
||||||
@ -3923,6 +3933,7 @@ var
|
|||||||
colsSpannedStr: String;
|
colsSpannedStr: String;
|
||||||
rowsSpannedStr: String;
|
rowsSpannedStr: String;
|
||||||
spannedStr: String;
|
spannedStr: String;
|
||||||
|
comment: String;
|
||||||
r1,c1,r2,c2: Cardinal;
|
r1,c1,r2,c2: Cardinal;
|
||||||
fmt: TsCellFormat;
|
fmt: TsCellFormat;
|
||||||
begin
|
begin
|
||||||
@ -3935,6 +3946,9 @@ begin
|
|||||||
else
|
else
|
||||||
lStyle := '';
|
lStyle := '';
|
||||||
|
|
||||||
|
// Comment
|
||||||
|
comment := WriteCommentXMLAsString(ACell^.Comment);
|
||||||
|
|
||||||
// Merged?
|
// Merged?
|
||||||
if FWorksheet.IsMergeBase(ACell) then
|
if FWorksheet.IsMergeBase(ACell) then
|
||||||
begin
|
begin
|
||||||
@ -4009,6 +4023,7 @@ begin
|
|||||||
if ACell^.CalcState=csCalculated then
|
if ACell^.CalcState=csCalculated then
|
||||||
AppendToStream(AStream, Format(
|
AppendToStream(AStream, Format(
|
||||||
'<table:table-cell table:formula="=%s" office:value-type="%s" %s %s %s>' +
|
'<table:table-cell table:formula="=%s" office:value-type="%s" %s %s %s>' +
|
||||||
|
comment +
|
||||||
valueStr +
|
valueStr +
|
||||||
'</table:table-cell>', [
|
'</table:table-cell>', [
|
||||||
formula, valuetype, value, lStyle, spannedStr
|
formula, valuetype, value, lStyle, spannedStr
|
||||||
@ -4048,6 +4063,9 @@ begin
|
|||||||
else
|
else
|
||||||
lStyle := '';
|
lStyle := '';
|
||||||
|
|
||||||
|
// Comment
|
||||||
|
comment := WriteCommentXMLAsString(ACell^.Comment);
|
||||||
|
|
||||||
// Merged?
|
// Merged?
|
||||||
if FWorksheet.IsMergeBase(ACell) then
|
if FWorksheet.IsMergeBase(ACell) then
|
||||||
begin
|
begin
|
||||||
@ -4066,8 +4084,6 @@ begin
|
|||||||
GetCellString(ARow, ACol)
|
GetCellString(ARow, ACol)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
comment := WriteCommentXMLAsString(ACell^.Comment);
|
|
||||||
|
|
||||||
// Write it ...
|
// Write it ...
|
||||||
AppendToStream(AStream, Format(
|
AppendToStream(AStream, Format(
|
||||||
'<table:table-cell office:value-type="string" %s %s>' +
|
'<table:table-cell office:value-type="string" %s %s>' +
|
||||||
@ -4089,6 +4105,7 @@ var
|
|||||||
colsSpannedStr: String;
|
colsSpannedStr: String;
|
||||||
rowsSpannedStr: String;
|
rowsSpannedStr: String;
|
||||||
spannedStr: String;
|
spannedStr: String;
|
||||||
|
comment: String;
|
||||||
r1,c1,r2,c2: Cardinal;
|
r1,c1,r2,c2: Cardinal;
|
||||||
fmt: TsCellFormat;
|
fmt: TsCellFormat;
|
||||||
begin
|
begin
|
||||||
@ -4106,6 +4123,9 @@ begin
|
|||||||
end else
|
end else
|
||||||
lStyle := '';
|
lStyle := '';
|
||||||
|
|
||||||
|
// Comment
|
||||||
|
comment := WriteCommentXMLAsString(ACell^.Comment);
|
||||||
|
|
||||||
// Merged?
|
// Merged?
|
||||||
if FWorksheet.IsMergeBase(ACell) then
|
if FWorksheet.IsMergeBase(ACell) then
|
||||||
begin
|
begin
|
||||||
@ -4128,6 +4148,7 @@ begin
|
|||||||
|
|
||||||
AppendToStream(AStream, Format(
|
AppendToStream(AStream, Format(
|
||||||
'<table:table-cell office:value-type="%s" office:value="%s" %s %s >' +
|
'<table:table-cell office:value-type="%s" office:value="%s" %s %s >' +
|
||||||
|
comment +
|
||||||
'<text:p>%s</text:p>' +
|
'<text:p>%s</text:p>' +
|
||||||
'</table:table-cell>', [
|
'</table:table-cell>', [
|
||||||
valType, StrValue, lStyle, spannedStr,
|
valType, StrValue, lStyle, spannedStr,
|
||||||
@ -4152,6 +4173,7 @@ var
|
|||||||
colsSpannedStr: String;
|
colsSpannedStr: String;
|
||||||
rowsSpannedStr: String;
|
rowsSpannedStr: String;
|
||||||
spannedStr: String;
|
spannedStr: String;
|
||||||
|
comment: String;
|
||||||
r1,c1,r2,c2: Cardinal;
|
r1,c1,r2,c2: Cardinal;
|
||||||
fmt: TsCellFormat;
|
fmt: TsCellFormat;
|
||||||
begin
|
begin
|
||||||
@ -4173,6 +4195,9 @@ begin
|
|||||||
else
|
else
|
||||||
lStyle := '';
|
lStyle := '';
|
||||||
|
|
||||||
|
// Comment
|
||||||
|
comment := WriteCommentXMLAsString(ACell^.Comment);
|
||||||
|
|
||||||
// nfTimeInterval is a special case - let's handle it first:
|
// nfTimeInterval is a special case - let's handle it first:
|
||||||
|
|
||||||
if (fmt.NumberFormat = nfTimeInterval) then
|
if (fmt.NumberFormat = nfTimeInterval) then
|
||||||
@ -4181,6 +4206,7 @@ begin
|
|||||||
displayStr := FormatDateTime(fmt.NumberFormatStr, AValue, [fdoInterval]);
|
displayStr := FormatDateTime(fmt.NumberFormatStr, AValue, [fdoInterval]);
|
||||||
AppendToStream(AStream, Format(
|
AppendToStream(AStream, Format(
|
||||||
'<table:table-cell office:value-type="time" office:time-value="%s" %s %s>' +
|
'<table:table-cell office:value-type="time" office:time-value="%s" %s %s>' +
|
||||||
|
comment +
|
||||||
'<text:p>%s</text:p>' +
|
'<text:p>%s</text:p>' +
|
||||||
'</table:table-cell>', [
|
'</table:table-cell>', [
|
||||||
strValue, lStyle, spannedStr,
|
strValue, lStyle, spannedStr,
|
||||||
@ -4194,6 +4220,7 @@ begin
|
|||||||
displayStr := FormatDateTime(fmt.NumberFormatStr, AValue);
|
displayStr := FormatDateTime(fmt.NumberFormatStr, AValue);
|
||||||
AppendToStream(AStream, Format(
|
AppendToStream(AStream, Format(
|
||||||
'<table:table-cell office:value-type="%s" office:%s-value="%s" %s %s>' +
|
'<table:table-cell office:value-type="%s" office:%s-value="%s" %s %s>' +
|
||||||
|
comment +
|
||||||
'<text:p>%s</text:p> ' +
|
'<text:p>%s</text:p> ' +
|
||||||
'</table:table-cell>', [
|
'</table:table-cell>', [
|
||||||
DT[isTimeOnly], DT[isTimeOnly], strValue, lStyle, spannedStr,
|
DT[isTimeOnly], DT[isTimeOnly], strValue, lStyle, spannedStr,
|
||||||
|
@ -901,6 +901,8 @@ type
|
|||||||
{@@ Abstract method for writing a boolean cell. Must be overridden by descendent classes. }
|
{@@ Abstract method for writing a boolean cell. Must be overridden by descendent classes. }
|
||||||
procedure WriteBool(AStream: TStream; const ARow, ACol: Cardinal;
|
procedure WriteBool(AStream: TStream; const ARow, ACol: Cardinal;
|
||||||
const AValue: Boolean; ACell: PCell); virtual; abstract;
|
const AValue: Boolean; ACell: PCell); virtual; abstract;
|
||||||
|
{@@ (Pseudo-)abstract method for writing a cell comment. Must be overridden by descendent classes }
|
||||||
|
procedure WriteComment(AStream: TStream; ACell: PCell); virtual;
|
||||||
{@@ Abstract method for writing a date/time value to a cell. Must be overridden by descendent classes. }
|
{@@ Abstract method for writing a date/time value to a cell. Must be overridden by descendent classes. }
|
||||||
procedure WriteDateTime(AStream: TStream; const ARow, ACol: Cardinal;
|
procedure WriteDateTime(AStream: TStream; const ARow, ACol: Cardinal;
|
||||||
const AValue: TDateTime; ACell: PCell); virtual; abstract;
|
const AValue: TDateTime; ACell: PCell); virtual; abstract;
|
||||||
@ -8708,6 +8710,8 @@ begin
|
|||||||
cctUTF8String:
|
cctUTF8String:
|
||||||
WriteLabel(AStream, ACell^.Row, ACell^.Col, ACell^.UTF8StringValue, ACell);
|
WriteLabel(AStream, ACell^.Row, ACell^.Col, ACell^.UTF8StringValue, ACell);
|
||||||
end;
|
end;
|
||||||
|
if ACell^.Comment <> '' then
|
||||||
|
WriteComment(AStream, ACell);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
@ -8724,6 +8728,16 @@ begin
|
|||||||
IterateThroughCells(AStream, ACells, WriteCellCallback);
|
IterateThroughCells(AStream, ACells, WriteCellCallback);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
(Pseudo-) abstract method writing a cell comment to the stream.
|
||||||
|
Must be overridden by descendents.
|
||||||
|
|
||||||
|
@param ACell Pointer to the cell to be written
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
procedure TsCustomSpreadWriter.WriteComment(AStream: TStream; ACell: PCell);
|
||||||
|
begin
|
||||||
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
A generic method to iterate through all cells in a worksheet and call a callback
|
A generic method to iterate through all cells in a worksheet and call a callback
|
||||||
routine for each cell.
|
routine for each cell.
|
||||||
|
@ -531,6 +531,7 @@ begin
|
|||||||
case RecordType of
|
case RecordType of
|
||||||
INT_EXCEL_ID_BLANK : ReadBlank(AStream);
|
INT_EXCEL_ID_BLANK : ReadBlank(AStream);
|
||||||
INT_EXCEL_ID_BOOLERROR : ReadBool(AStream);
|
INT_EXCEL_ID_BOOLERROR : ReadBool(AStream);
|
||||||
|
INT_EXCEL_ID_NOTE : ReadComment(AStream);
|
||||||
INT_EXCEL_ID_FONT : ReadFont(AStream);
|
INT_EXCEL_ID_FONT : ReadFont(AStream);
|
||||||
INT_EXCEL_ID_FONTCOLOR : ReadFontColor(AStream);
|
INT_EXCEL_ID_FONTCOLOR : ReadFontColor(AStream);
|
||||||
INT_EXCEL_ID_FORMAT : ReadFormat(AStream);
|
INT_EXCEL_ID_FORMAT : ReadFormat(AStream);
|
||||||
|
@ -390,6 +390,7 @@ begin
|
|||||||
INT_EXCEL_ID_BLANK : ReadBlank(AStream);
|
INT_EXCEL_ID_BLANK : ReadBlank(AStream);
|
||||||
INT_EXCEL_ID_BOOLERROR : ReadBool(AStream);
|
INT_EXCEL_ID_BOOLERROR : ReadBool(AStream);
|
||||||
INT_EXCEL_ID_MULBLANK : ReadMulBlank(AStream);
|
INT_EXCEL_ID_MULBLANK : ReadMulBlank(AStream);
|
||||||
|
INT_EXCEL_ID_NOTE : ReadComment(AStream);
|
||||||
INT_EXCEL_ID_NUMBER : ReadNumber(AStream);
|
INT_EXCEL_ID_NUMBER : ReadNumber(AStream);
|
||||||
INT_EXCEL_ID_LABEL : ReadLabel(AStream);
|
INT_EXCEL_ID_LABEL : ReadLabel(AStream);
|
||||||
INT_EXCEL_ID_RSTRING : ReadRichString(AStream); //(RSTRING) This record stores a formatted text cell (Rich-Text). In BIFF8 it is usually replaced by the LABELSST record. Excel still uses this record, if it copies formatted text cells to the clipboard.
|
INT_EXCEL_ID_RSTRING : ReadRichString(AStream); //(RSTRING) This record stores a formatted text cell (Rich-Text). In BIFF8 it is usually replaced by the LABELSST record. Excel still uses this record, if it copies formatted text cells to the clipboard.
|
||||||
|
@ -23,6 +23,7 @@ uses
|
|||||||
const
|
const
|
||||||
{ RECORD IDs which didn't change across versions 2-8 }
|
{ RECORD IDs which didn't change across versions 2-8 }
|
||||||
INT_EXCEL_ID_EOF = $000A;
|
INT_EXCEL_ID_EOF = $000A;
|
||||||
|
INT_EXCEL_ID_NOTE = $001C;
|
||||||
INT_EXCEL_ID_SELECTION = $001D;
|
INT_EXCEL_ID_SELECTION = $001D;
|
||||||
INT_EXCEL_ID_CONTINUE = $003C;
|
INT_EXCEL_ID_CONTINUE = $003C;
|
||||||
INT_EXCEL_ID_DATEMODE = $0022;
|
INT_EXCEL_ID_DATEMODE = $0022;
|
||||||
@ -221,6 +222,8 @@ type
|
|||||||
FDateMode: TDateMode;
|
FDateMode: TDateMode;
|
||||||
FPaletteFound: Boolean;
|
FPaletteFound: Boolean;
|
||||||
FIncompleteCell: PCell;
|
FIncompleteCell: PCell;
|
||||||
|
FIncompleteNote: String;
|
||||||
|
FIncompleteNoteLength: Word;
|
||||||
procedure ApplyCellFormatting(ACell: PCell; XFIndex: Word); virtual; //overload;
|
procedure ApplyCellFormatting(ACell: PCell; XFIndex: Word); virtual; //overload;
|
||||||
procedure CreateNumFormatList; override;
|
procedure CreateNumFormatList; override;
|
||||||
// Extracts a number out of an RK value
|
// Extracts a number out of an RK value
|
||||||
@ -238,6 +241,8 @@ type
|
|||||||
procedure ReadCodePage(AStream: TStream);
|
procedure ReadCodePage(AStream: TStream);
|
||||||
// Read column info
|
// Read column info
|
||||||
procedure ReadColInfo(const AStream: TStream);
|
procedure ReadColInfo(const AStream: TStream);
|
||||||
|
// Read attached comment
|
||||||
|
procedure ReadComment(const AStream: TStream);
|
||||||
// Figures out what the base year for dates is for this file
|
// Figures out what the base year for dates is for this file
|
||||||
procedure ReadDateMode(AStream: TStream);
|
procedure ReadDateMode(AStream: TStream);
|
||||||
// Reads the default column width
|
// Reads the default column width
|
||||||
@ -320,6 +325,8 @@ type
|
|||||||
// Writes out column info(s)
|
// Writes out column info(s)
|
||||||
procedure WriteColInfo(AStream: TStream; ACol: PCol);
|
procedure WriteColInfo(AStream: TStream; ACol: PCol);
|
||||||
procedure WriteColInfos(AStream: TStream; ASheet: TsWorksheet);
|
procedure WriteColInfos(AStream: TStream; ASheet: TsWorksheet);
|
||||||
|
// Writes out NOTE record(s)
|
||||||
|
procedure WriteComment(AStream: TStream; ACell: PCell); override;
|
||||||
// Writes out DATEMODE record depending on FDateMode
|
// Writes out DATEMODE record depending on FDateMode
|
||||||
procedure WriteDateMode(AStream: TStream);
|
procedure WriteDateMode(AStream: TStream);
|
||||||
// Writes out a TIME/DATE/TIMETIME
|
// Writes out a TIME/DATE/TIMETIME
|
||||||
@ -462,6 +469,14 @@ type
|
|||||||
Value: Double;
|
Value: Double;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
TBIFF25NoteRecord = packed record
|
||||||
|
RecordID: Word;
|
||||||
|
RecordSize: Word;
|
||||||
|
Row: Word;
|
||||||
|
Col: Word;
|
||||||
|
TextLen: Word;
|
||||||
|
end;
|
||||||
|
|
||||||
function ConvertExcelDateTimeToDateTime(const AExcelDateNum: Double;
|
function ConvertExcelDateTimeToDateTime(const AExcelDateNum: Double;
|
||||||
ADateMode: TDateMode): TDateTime;
|
ADateMode: TDateMode): TDateTime;
|
||||||
begin
|
begin
|
||||||
@ -882,6 +897,74 @@ begin
|
|||||||
FWorksheet.WriteColInfo(c, col);
|
FWorksheet.WriteColInfo(c, col);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
// Read a NOTE record which describes an attached comment
|
||||||
|
// Valid for BIFF2-BIFF5
|
||||||
|
procedure TsSpreadBIFFReader.ReadComment(const AStream: TStream);
|
||||||
|
var
|
||||||
|
rec: TBIFF25NoteRecord;
|
||||||
|
r, c: Cardinal;
|
||||||
|
n: Word;
|
||||||
|
s: ansiString;
|
||||||
|
List: TStringList;
|
||||||
|
begin
|
||||||
|
rec.Row := 0; // to silence the compiler...
|
||||||
|
AStream.ReadBuffer(rec.Row, SizeOf(TBIFF25NoteRecord) - 2*SizeOf(Word));
|
||||||
|
r := WordLEToN(rec.Row);
|
||||||
|
c := WordLEToN(rec.Col);
|
||||||
|
n := WordLEToN(rec.TextLen);
|
||||||
|
// First NOTE record
|
||||||
|
if r <> $FFFF then
|
||||||
|
begin
|
||||||
|
// entire note is in this record
|
||||||
|
if n <= self.RecordSize - 3*SizeOf(word) then
|
||||||
|
begin
|
||||||
|
SetLength(s, n);
|
||||||
|
AStream.ReadBuffer(s[1], n);
|
||||||
|
FIncompleteNote := '';
|
||||||
|
FIncompleteNoteLength := 0;
|
||||||
|
List := TStringList.Create;
|
||||||
|
try
|
||||||
|
List.Text := s; // Fix line endings which are #10 in file
|
||||||
|
s := Copy(List.Text, 1, Length(List.Text) - Length(LineEnding));
|
||||||
|
FWorksheet.WriteComment(r, c, s);
|
||||||
|
finally
|
||||||
|
List.Free;
|
||||||
|
end;
|
||||||
|
end else
|
||||||
|
// note will be continued in following record(s): Store partial string
|
||||||
|
begin
|
||||||
|
FIncompleteNoteLength := n;
|
||||||
|
n := self.RecordSize - 3*SizeOf(Word);
|
||||||
|
SetLength(s, n);
|
||||||
|
AStream.ReadBuffer(s[1], n);
|
||||||
|
FIncompleteNote := s;
|
||||||
|
FIncompleteCell := FWorksheet.GetCell(r, c);
|
||||||
|
end;
|
||||||
|
end else
|
||||||
|
// One of the continuation records
|
||||||
|
begin
|
||||||
|
SetLength(s, n);
|
||||||
|
AStream.ReadBuffer(s[1], n);
|
||||||
|
FIncompleteNote := FIncompleteNote + s;
|
||||||
|
// last continuation record
|
||||||
|
if Length(FIncompleteNote) = FIncompleteNoteLength then
|
||||||
|
begin
|
||||||
|
List := TStringList.Create;
|
||||||
|
try
|
||||||
|
List.Text := FIncompleteNote; // Fix line endings which are #10 in file
|
||||||
|
s := Copy(List.Text, 1, Length(List.Text) - Length(LineEnding));
|
||||||
|
FIncompleteCell^.Comment := s;
|
||||||
|
finally
|
||||||
|
List.Free;
|
||||||
|
end;
|
||||||
|
FIncompleteNote := '';
|
||||||
|
FIncompleteCell := nil;
|
||||||
|
FIncompleteNoteLength := 0;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure TsSpreadBIFFReader.ReadDateMode(AStream: TStream);
|
procedure TsSpreadBIFFReader.ReadDateMode(AStream: TStream);
|
||||||
var
|
var
|
||||||
lBaseMode: Word;
|
lBaseMode: Word;
|
||||||
@ -1875,6 +1958,61 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ Writes a NOTE record which describes a comment attached to a cell }
|
||||||
|
procedure TsSpreadBIFFWriter.WriteComment(AStream: TStream; ACell: PCell);
|
||||||
|
const
|
||||||
|
CHUNK_SIZE = 2048;
|
||||||
|
var
|
||||||
|
rec: TBIFF25NoteRecord;
|
||||||
|
L: Integer;
|
||||||
|
base_size: Word;
|
||||||
|
p: Integer;
|
||||||
|
comment: ansistring;
|
||||||
|
List: TStringList;
|
||||||
|
begin
|
||||||
|
Unused(ACell);
|
||||||
|
|
||||||
|
if (ACell^.Comment = '') then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
List := TStringList.Create;
|
||||||
|
try
|
||||||
|
List.Text := UTF8ToAnsi(ACell^.Comment);
|
||||||
|
comment := List[0];
|
||||||
|
for p := 1 to List.Count-1 do
|
||||||
|
comment := comment + #$0A + List[p];
|
||||||
|
finally
|
||||||
|
List.Free;
|
||||||
|
end;
|
||||||
|
|
||||||
|
L := Length(comment);
|
||||||
|
base_size := SizeOf(rec) - 2*SizeOf(word);
|
||||||
|
|
||||||
|
// First NOTE record
|
||||||
|
rec.RecordID := WordToLE(INT_EXCEL_ID_NOTE);
|
||||||
|
rec.Row := WordToLE(ACell^.Row);
|
||||||
|
rec.Col := WordToLE(ACell^.Col);
|
||||||
|
rec.TextLen := L;
|
||||||
|
rec.RecordSize := base_size + Min(L, CHUNK_SIZE);
|
||||||
|
AStream.WriteBuffer(rec, SizeOf(rec));
|
||||||
|
AStream.WriteBuffer(comment[1], Min(L, CHUNK_SIZE)); // Write text
|
||||||
|
|
||||||
|
// If the comment text does not fit into 2048 bytes continuation records
|
||||||
|
// have to be written.
|
||||||
|
rec.Row := $FFFF; // indicator that this will be a continuation record
|
||||||
|
rec.Col := 0;
|
||||||
|
p := CHUNK_SIZE;
|
||||||
|
dec(L, CHUNK_SIZE);
|
||||||
|
while L > 0 do begin
|
||||||
|
rec.TextLen := Min(L, CHUNK_SIZE);
|
||||||
|
rec.RecordSize := base_size + rec.TextLen;
|
||||||
|
AStream.WriteBuffer(rec, SizeOf(rec));
|
||||||
|
AStream.WriteBuffer(comment[p], rec.TextLen);
|
||||||
|
dec(L, CHUNK_SIZE);
|
||||||
|
inc(p, CHUNK_SIZE);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TsSpreadBIFFWriter.WriteDateMode(AStream: TStream);
|
procedure TsSpreadBIFFWriter.WriteDateMode(AStream: TStream);
|
||||||
begin
|
begin
|
||||||
{ BIFF Record header }
|
{ BIFF Record header }
|
||||||
|
Reference in New Issue
Block a user