You've already forked lazarus-ccr
fpspreadsheet: Rearrange cell comment architecture: to save memory cell comments are now stored in the worksheet's avltree "Comments". Replace cell's "CalcState" by more general "Flags" which signals that a cell contains a comment (to be extended...)
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3943 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -36,22 +36,10 @@ begin
|
|||||||
worksheet.WriteUTF8Text(0, 0, '=B2+1');
|
worksheet.WriteUTF8Text(0, 0, '=B2+1');
|
||||||
// B1
|
// B1
|
||||||
worksheet.WriteFormula(0, 1, 'B2+1');
|
worksheet.WriteFormula(0, 1, 'B2+1');
|
||||||
{
|
|
||||||
worksheet.WriteRPNFormula(0, 1, CreateRPNFormula(
|
|
||||||
RPNCellValue('B2',
|
|
||||||
RPNInteger(1,
|
|
||||||
RPNFunc(fekAdd, nil)))));
|
|
||||||
}
|
|
||||||
// A2
|
// A2
|
||||||
worksheet.WriteUTF8Text(1, 0, '=B3+1');
|
worksheet.WriteUTF8Text(1, 0, '=B3+1');
|
||||||
// B2
|
// B2
|
||||||
worksheet.WriteFormula(1, 1, 'B3+1');
|
worksheet.WriteFormula(1, 1, 'B3+1');
|
||||||
{
|
|
||||||
worksheet.WriteRPNFormula(1, 1, CreateRPNFormula(
|
|
||||||
RPNCellValue('B3',
|
|
||||||
RPNInteger(1,
|
|
||||||
RPNFunc(fekAdd, nil)))));
|
|
||||||
}
|
|
||||||
// A3
|
// A3
|
||||||
worksheet.WriteUTF8Text(2, 0, '(not dependent)');
|
worksheet.WriteUTF8Text(2, 0, '(not dependent)');
|
||||||
// B3
|
// B3
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
If this is not wanted, define FPS_DONT_USE_CLOCALE. }
|
If this is not wanted, define FPS_DONT_USE_CLOCALE. }
|
||||||
{.$DEFINE FPS_DONT_USE_CLOCALE}
|
{.$DEFINE FPS_DONT_USE_CLOCALE}
|
||||||
|
|
||||||
|
|
||||||
{ In older versions of fpspreadsheet, the formatting fields had belonged to the
|
{ In older versions of fpspreadsheet, the formatting fields had belonged to the
|
||||||
cell record. This has been given up to reduce memory consumption.
|
cell record. This has been given up to reduce memory consumption.
|
||||||
For fpc >2.6, however, record helpers allow to get this feature back. In case
|
For fpc >2.6, however, record helpers allow to get this feature back. In case
|
||||||
@ -17,6 +16,10 @@
|
|||||||
methods can only be used to change cell formatting then. }
|
methods can only be used to change cell formatting then. }
|
||||||
{.$DEFINE FPS_NO_RECORD_HELPERS}
|
{.$DEFINE FPS_NO_RECORD_HELPERS}
|
||||||
|
|
||||||
|
{ In new versions of fpc, records can contain private fields. Activate the
|
||||||
|
define FPS_NO_PRIVATE_FIELDS_IN_RECORDS if this is not supported. }
|
||||||
|
{.$DEFINE FPS_NO_PRIVATE_FIELDS_IN_RECORDS}
|
||||||
|
|
||||||
{ The next defines activate code duplicated from new compiler versions in case
|
{ The next defines activate code duplicated from new compiler versions in case
|
||||||
an old compiler is used. }
|
an old compiler is used. }
|
||||||
|
|
||||||
|
@ -3843,7 +3843,7 @@ begin
|
|||||||
cell := FCell;
|
cell := FCell;
|
||||||
|
|
||||||
if (cell <> nil) and HasFormula(cell) then
|
if (cell <> nil) and HasFormula(cell) then
|
||||||
case cell^.CalcState of
|
case FWorksheet.GetCalcState(cell) of
|
||||||
csNotCalculated:
|
csNotCalculated:
|
||||||
Worksheet.CalcFormula(cell);
|
Worksheet.CalcFormula(cell);
|
||||||
csCalculating:
|
csCalculating:
|
||||||
@ -3942,9 +3942,11 @@ begin
|
|||||||
begin
|
begin
|
||||||
cell := FWorksheet.FindCell(r, c);
|
cell := FWorksheet.FindCell(r, c);
|
||||||
if HasFormula(cell) then
|
if HasFormula(cell) then
|
||||||
case cell^.CalcState of
|
case FWorksheet.GetCalcState(cell) of
|
||||||
csNotCalculated: FWorksheet.CalcFormula(cell);
|
csNotCalculated:
|
||||||
csCalculating : raise Exception.Create(SErrCircularReference);
|
FWorksheet.CalcFormula(cell);
|
||||||
|
csCalculating:
|
||||||
|
raise ECalcEngine.Create(SErrCircularReference);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@ -3442,7 +3442,7 @@ begin
|
|||||||
Unused(ARow, ACol);
|
Unused(ARow, ACol);
|
||||||
|
|
||||||
// Comment
|
// Comment
|
||||||
comment := WriteCommentXMLAsString(ACell^.Comment);
|
comment := WriteCommentXMLAsString(FWorksheet.ReadComment(ACell));
|
||||||
|
|
||||||
// Merged?
|
// Merged?
|
||||||
if FWorksheet.IsMergeBase(ACell) then
|
if FWorksheet.IsMergeBase(ACell) then
|
||||||
@ -3494,7 +3494,7 @@ begin
|
|||||||
lStyle := '';
|
lStyle := '';
|
||||||
|
|
||||||
// Comment
|
// Comment
|
||||||
comment := WriteCommentXMLAsString(ACell^.Comment);
|
comment := WriteCommentXMLAsString(FWorksheet.ReadComment(ACell));
|
||||||
|
|
||||||
// Merged?
|
// Merged?
|
||||||
if FWorksheet.IsMergeBase(ACell) then
|
if FWorksheet.IsMergeBase(ACell) then
|
||||||
@ -3971,7 +3971,7 @@ begin
|
|||||||
lStyle := '';
|
lStyle := '';
|
||||||
|
|
||||||
// Comment
|
// Comment
|
||||||
comment := WriteCommentXMLAsString(ACell^.Comment);
|
comment := WriteCommentXMLAsString(FWorksheet.ReadComment(ACell));
|
||||||
|
|
||||||
// Merged?
|
// Merged?
|
||||||
if FWorksheet.IsMergeBase(ACell) then
|
if FWorksheet.IsMergeBase(ACell) then
|
||||||
@ -4044,7 +4044,7 @@ begin
|
|||||||
|
|
||||||
{ We are writing a very rudimentary formula here without result and result
|
{ We are writing a very rudimentary formula here without result and result
|
||||||
data type. Seems to work... }
|
data type. Seems to work... }
|
||||||
if ACell^.CalcState=csCalculated then
|
if FWorksheet.GetCalcState(ACell) = 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 +
|
comment +
|
||||||
@ -4093,7 +4093,7 @@ begin
|
|||||||
lStyle := '';
|
lStyle := '';
|
||||||
|
|
||||||
// Comment
|
// Comment
|
||||||
comment := WriteCommentXMLAsString(ACell^.Comment);
|
comment := WriteCommentXMLAsString(FWorksheet.ReadComment(ACell));
|
||||||
|
|
||||||
// Merged?
|
// Merged?
|
||||||
if FWorksheet.IsMergeBase(ACell) then
|
if FWorksheet.IsMergeBase(ACell) then
|
||||||
@ -4153,7 +4153,7 @@ begin
|
|||||||
lStyle := '';
|
lStyle := '';
|
||||||
|
|
||||||
// Comment
|
// Comment
|
||||||
comment := WriteCommentXMLAsString(ACell^.Comment);
|
comment := WriteCommentXMLAsString(FWorksheet.ReadComment(ACell));
|
||||||
|
|
||||||
// Merged?
|
// Merged?
|
||||||
if FWorksheet.IsMergeBase(ACell) then
|
if FWorksheet.IsMergeBase(ACell) then
|
||||||
@ -4225,7 +4225,7 @@ begin
|
|||||||
lStyle := '';
|
lStyle := '';
|
||||||
|
|
||||||
// Comment
|
// Comment
|
||||||
comment := WriteCommentXMLAsString(ACell^.Comment);
|
comment := WriteCommentXMLAsString(FWorksheet.ReadComment(ACell));
|
||||||
|
|
||||||
// nfTimeInterval is a special case - let's handle it first:
|
// nfTimeInterval is a special case - let's handle it first:
|
||||||
|
|
||||||
|
@ -46,18 +46,24 @@ type
|
|||||||
|
|
||||||
@see ReadAsUTF8Text }
|
@see ReadAsUTF8Text }
|
||||||
TCell = record
|
TCell = record
|
||||||
|
{$IFNDEF NO_PRIVATE_FIELDS_IN_RECORDS}
|
||||||
|
private
|
||||||
|
{$ENDIF}
|
||||||
|
{ Status flags }
|
||||||
|
Flags: TsCellFlags;
|
||||||
|
|
||||||
|
{$IFNDEF NO_PRIVATE_FIELDS_IN_RECORDS}
|
||||||
|
public
|
||||||
|
{$ENDIF}
|
||||||
{ Location of the cell }
|
{ Location of the cell }
|
||||||
Worksheet: TsWorksheet;
|
Worksheet: TsWorksheet;
|
||||||
Col: Cardinal; // zero-based
|
Col: Cardinal; // zero-based
|
||||||
Row: Cardinal; // zero-based
|
Row: Cardinal; // zero-based
|
||||||
{ Index of format record }
|
{ Index of format record }
|
||||||
FormatIndex: Integer;
|
FormatIndex: Integer;
|
||||||
{ Status flags }
|
|
||||||
CalcState: TsCalcState;
|
|
||||||
{ Special information }
|
{ Special information }
|
||||||
SharedFormulaBase: PCell; // Cell containing the shared formula
|
SharedFormulaBase: PCell; // Cell containing the shared formula
|
||||||
MergeBase: PCell; // Upper left cell of a merged range
|
MergeBase: PCell; // Upper left cell of a merged range
|
||||||
Comment: String; // Comment attached to the cell
|
|
||||||
{ Cell content }
|
{ Cell content }
|
||||||
UTF8StringValue: String; // Strings cannot be part of a variant record
|
UTF8StringValue: String; // Strings cannot be part of a variant record
|
||||||
FormulaValue: String;
|
FormulaValue: String;
|
||||||
@ -96,6 +102,18 @@ type
|
|||||||
{@@ Pointer to a TCol record }
|
{@@ Pointer to a TCol record }
|
||||||
PCol = ^TCol;
|
PCol = ^TCol;
|
||||||
|
|
||||||
|
{@@ The record TsComment contains a comment attached to a cell.
|
||||||
|
@param Row (0-based) index of the row containing the cell with the comment
|
||||||
|
@param Col (0-based) index of the column containing the coll with the comment
|
||||||
|
@param Text Comment text }
|
||||||
|
TsComment = record
|
||||||
|
Row, Col: Cardinal;
|
||||||
|
Text: String;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@ Pointer to a TsComment record }
|
||||||
|
PsComment = ^TsComment;
|
||||||
|
|
||||||
{@@ Worksheet user interface options:
|
{@@ Worksheet user interface options:
|
||||||
@param soShowGridLines Show or hide the grid lines in the spreadsheet
|
@param soShowGridLines Show or hide the grid lines in the spreadsheet
|
||||||
@param soShowHeaders Show or hide the column or row headers of the spreadsheet
|
@param soShowHeaders Show or hide the column or row headers of the spreadsheet
|
||||||
@ -127,6 +145,7 @@ type
|
|||||||
FWorkbook: TsWorkbook;
|
FWorkbook: TsWorkbook;
|
||||||
FName: String; // Name of the worksheet (displayed at the tab)
|
FName: String; // Name of the worksheet (displayed at the tab)
|
||||||
FCells: TAvlTree; // Items are TCell
|
FCells: TAvlTree; // Items are TCell
|
||||||
|
FComments: TAvlTree; // Items are TsComment
|
||||||
FCurrentNode: TAVLTreeNode; // For GetFirstCell and GetNextCell
|
FCurrentNode: TAVLTreeNode; // For GetFirstCell and GetNextCell
|
||||||
FRows, FCols: TIndexedAVLTree; // This lists contain only rows or cols with styles different from default
|
FRows, FCols: TIndexedAVLTree; // This lists contain only rows or cols with styles different from default
|
||||||
FActiveCellRow: Cardinal;
|
FActiveCellRow: Cardinal;
|
||||||
@ -158,10 +177,12 @@ type
|
|||||||
procedure DeleteRowCallback(data, arg: Pointer);
|
procedure DeleteRowCallback(data, arg: Pointer);
|
||||||
procedure InsertColCallback(data, arg: Pointer);
|
procedure InsertColCallback(data, arg: Pointer);
|
||||||
procedure InsertRowCallback(data, arg: Pointer);
|
procedure InsertRowCallback(data, arg: Pointer);
|
||||||
procedure RemoveCallback(data, arg: pointer);
|
procedure RemoveCellsCallback(data, arg: pointer);
|
||||||
|
procedure RemoveCommentsCallback(data, arg: pointer);
|
||||||
|
|
||||||
protected
|
protected
|
||||||
function CellUsedInFormula(ARow, ACol: Cardinal): Boolean;
|
function CellUsedInFormula(ARow, ACol: Cardinal): Boolean;
|
||||||
|
procedure RemoveAllAVLTreeNodes(ATree: TAvlTree; ARemoveCallback: TsCallback);
|
||||||
|
|
||||||
// Remove and delete cells
|
// Remove and delete cells
|
||||||
function RemoveCell(ARow, ACol: Cardinal): PCell;
|
function RemoveCell(ARow, ACol: Cardinal): PCell;
|
||||||
@ -196,7 +217,7 @@ type
|
|||||||
function ReadAsDateTime(ACell: PCell; out AResult: TDateTime): Boolean; overload;
|
function ReadAsDateTime(ACell: PCell; out AResult: TDateTime): Boolean; overload;
|
||||||
function ReadFormulaAsString(ACell: PCell; ALocalized: Boolean = false): String;
|
function ReadFormulaAsString(ACell: PCell; ALocalized: Boolean = false): String;
|
||||||
function ReadNumericValue(ACell: PCell; out AValue: Double): Boolean;
|
function ReadNumericValue(ACell: PCell; out AValue: Double): Boolean;
|
||||||
function ReadComment(ACell: PCell): String;
|
// function ReadComment(ACell: PCell): String;
|
||||||
|
|
||||||
{ Reading of cell attributes }
|
{ Reading of cell attributes }
|
||||||
function GetDisplayedDecimals(ACell: PCell): Byte;
|
function GetDisplayedDecimals(ACell: PCell): Byte;
|
||||||
@ -238,8 +259,8 @@ type
|
|||||||
function WriteCellValueAsString(ARow, ACol: Cardinal; AValue: String): PCell; overload;
|
function WriteCellValueAsString(ARow, ACol: Cardinal; AValue: String): PCell; overload;
|
||||||
procedure WriteCellValueAsString(ACell: PCell; AValue: String); overload;
|
procedure WriteCellValueAsString(ACell: PCell; AValue: String); overload;
|
||||||
|
|
||||||
function WriteComment(ARow, ACol: Cardinal; const AComment: String): PCell; overload;
|
// function WriteComment(ARow, ACol: Cardinal; const AComment: String): PCell; overload;
|
||||||
procedure WriteComment(ACell: PCell; const AComment: String); overload;
|
// procedure WriteComment(ACell: PCell; const AComment: String); overload;
|
||||||
|
|
||||||
function WriteCurrency(ARow, ACol: Cardinal; AValue: Double;
|
function WriteCurrency(ARow, ACol: Cardinal; AValue: Double;
|
||||||
ANumFormat: TsNumberFormat = nfCurrency; ADecimals: Integer = 2;
|
ANumFormat: TsNumberFormat = nfCurrency; ADecimals: Integer = 2;
|
||||||
@ -379,6 +400,8 @@ type
|
|||||||
procedure FixSharedFormulas;
|
procedure FixSharedFormulas;
|
||||||
procedure SplitSharedFormula(ACell: PCell);
|
procedure SplitSharedFormula(ACell: PCell);
|
||||||
function UseSharedFormula(ARow, ACol: Cardinal; ASharedFormulaBase: PCell): PCell;
|
function UseSharedFormula(ARow, ACol: Cardinal; ASharedFormulaBase: PCell): PCell;
|
||||||
|
function GetCalcState(ACell: PCell): TsCalcState;
|
||||||
|
procedure SetCalcState(ACell: PCell; AValue: TsCalcState);
|
||||||
|
|
||||||
{ Data manipulation methods - For Cells }
|
{ Data manipulation methods - For Cells }
|
||||||
procedure CopyCell(AFromCell, AToCell: PCell); overload;
|
procedure CopyCell(AFromCell, AToCell: PCell); overload;
|
||||||
@ -452,6 +475,17 @@ type
|
|||||||
function GetSelectionCount: Integer;
|
function GetSelectionCount: Integer;
|
||||||
procedure SetSelection(const ASelection: TsCellRangeArray);
|
procedure SetSelection(const ASelection: TsCellRangeArray);
|
||||||
|
|
||||||
|
// Comments
|
||||||
|
function FindComment(ARow, ACol: Cardinal): PsComment; overload;
|
||||||
|
function FindComment(ACell: PCell): PsComment; overload;
|
||||||
|
function HasComment(ACell: PCell): Boolean;
|
||||||
|
function ReadComment(ARow, ACol: Cardinal): String; overload;
|
||||||
|
function ReadComment(ACell: PCell): string; overload;
|
||||||
|
procedure RemoveAllComments;
|
||||||
|
procedure RemoveComment(ACell: PCell);
|
||||||
|
function WriteComment(ARow, ACol: Cardinal; AText: String): PCell; overload;
|
||||||
|
procedure WriteComment(ACell: PCell; AText: String); overload;
|
||||||
|
|
||||||
// Notification of changed cells content and format
|
// Notification of changed cells content and format
|
||||||
procedure ChangedCell(ARow, ACol: Cardinal);
|
procedure ChangedCell(ARow, ACol: Cardinal);
|
||||||
procedure ChangedFont(ARow, ACol: Cardinal);
|
procedure ChangedFont(ARow, ACol: Cardinal);
|
||||||
@ -463,6 +497,8 @@ type
|
|||||||
property Cells: TAVLTree read FCells;
|
property Cells: TAVLTree read FCells;
|
||||||
{@@ List of all column records of the worksheet having a non-standard column width }
|
{@@ List of all column records of the worksheet having a non-standard column width }
|
||||||
property Cols: TIndexedAVLTree read FCols;
|
property Cols: TIndexedAVLTree read FCols;
|
||||||
|
{@@ List of all comment records }
|
||||||
|
property Comments: TAVLTree read FComments;
|
||||||
{@@ FormatSettings for localization of some formatting strings }
|
{@@ FormatSettings for localization of some formatting strings }
|
||||||
property FormatSettings: TFormatSettings read GetFormatSettings;
|
property FormatSettings: TFormatSettings read GetFormatSettings;
|
||||||
{@@ Name of the sheet. In the popular spreadsheet applications this is
|
{@@ Name of the sheet. In the popular spreadsheet applications this is
|
||||||
@ -880,8 +916,11 @@ type
|
|||||||
{@@ Callback function when iterating cells while accessing a stream }
|
{@@ Callback function when iterating cells while accessing a stream }
|
||||||
TCellsCallback = procedure (ACell: PCell; AStream: TStream) of object;
|
TCellsCallback = procedure (ACell: PCell; AStream: TStream) of object;
|
||||||
|
|
||||||
{@@
|
{@@ Callback function when iterating comments while accessing a stream }
|
||||||
Custom writer of spreadsheet files. "Custom" means that it provides only
|
TCommentsCallback = procedure (AComment: PsComment; ACommentIndex: Integer;
|
||||||
|
AStream: TStream) of object;
|
||||||
|
|
||||||
|
{@@ Custom writer of spreadsheet files. "Custom" means that it provides only
|
||||||
the basic functionality. The main implementation is done in derived classes
|
the basic functionality. The main implementation is done in derived classes
|
||||||
for each individual file format. }
|
for each individual file format. }
|
||||||
TsCustomSpreadWriter = class(TsCustomSpreadReaderWriter)
|
TsCustomSpreadWriter = class(TsCustomSpreadReaderWriter)
|
||||||
@ -920,11 +959,16 @@ type
|
|||||||
{@@ Abstract method for writing a number value to a cell. Must be overridden by descendent classes. }
|
{@@ Abstract method for writing a number value to a cell. Must be overridden by descendent classes. }
|
||||||
procedure WriteNumber(AStream: TStream; const ARow, ACol: Cardinal;
|
procedure WriteNumber(AStream: TStream; const ARow, ACol: Cardinal;
|
||||||
const AValue: double; ACell: PCell); virtual; abstract;
|
const AValue: double; ACell: PCell); virtual; abstract;
|
||||||
|
|
||||||
public
|
public
|
||||||
constructor Create(AWorkbook: TsWorkbook); override;
|
constructor Create(AWorkbook: TsWorkbook); override;
|
||||||
{ General writing methods }
|
{ General writing methods }
|
||||||
procedure IterateThroughCells(AStream: TStream; ACells: TAVLTree; ACallback: TCellsCallback);
|
procedure IterateThroughCells(AStream: TStream; ACells: TAVLTree;
|
||||||
procedure WriteToFile(const AFileName: string; const AOverwriteExisting: Boolean = False); virtual;
|
ACallback: TCellsCallback);
|
||||||
|
procedure IterateThroughComments(AStream: TStream; AComments: TAVLTree;
|
||||||
|
ACallback: TCommentsCallback);
|
||||||
|
procedure WriteToFile(const AFileName: string;
|
||||||
|
const AOverwriteExisting: Boolean = False); virtual;
|
||||||
procedure WriteToStream(AStream: TStream); virtual;
|
procedure WriteToStream(AStream: TStream); virtual;
|
||||||
procedure WriteToStrings(AStrings: TStrings); virtual;
|
procedure WriteToStrings(AStrings: TStrings); virtual;
|
||||||
end;
|
end;
|
||||||
@ -1247,6 +1291,12 @@ begin
|
|||||||
Result := LongInt(PCol(Item1).Col) - PCol(Item2).Col;
|
Result := LongInt(PCol(Item1).Col) - PCol(Item2).Col;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function CompareCommentCells(Item1, ITem2: Pointer): Integer;
|
||||||
|
begin
|
||||||
|
result := LongInt(PsComment(Item1).Row) - PsComment(Item2).Row;
|
||||||
|
if Result = 0 then
|
||||||
|
Result := LongInt(PsComment(Item1).Col) - PsComment(Item2).Col;
|
||||||
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Write the fonts stored for a given workbook to a file.
|
Write the fonts stored for a given workbook to a file.
|
||||||
@ -1297,6 +1347,7 @@ begin
|
|||||||
FCells := TAVLTree.Create(@CompareCells);
|
FCells := TAVLTree.Create(@CompareCells);
|
||||||
FRows := TIndexedAVLTree.Create(@CompareRows);
|
FRows := TIndexedAVLTree.Create(@CompareRows);
|
||||||
FCols := TIndexedAVLTree.Create(@CompareCols);
|
FCols := TIndexedAVLTree.Create(@CompareCols);
|
||||||
|
FComments := TAVLTree.Create(@CompareCommentCells);
|
||||||
|
|
||||||
FDefaultColWidth := 12;
|
FDefaultColWidth := 12;
|
||||||
FDefaultRowHeight := 1;
|
FDefaultRowHeight := 1;
|
||||||
@ -1323,10 +1374,12 @@ begin
|
|||||||
RemoveAllCells;
|
RemoveAllCells;
|
||||||
RemoveAllRows;
|
RemoveAllRows;
|
||||||
RemoveAllCols;
|
RemoveAllCols;
|
||||||
|
RemoveAllComments;
|
||||||
|
|
||||||
FCells.Free;
|
FCells.Free;
|
||||||
FRows.Free;
|
FRows.Free;
|
||||||
FCols.Free;
|
FCols.Free;
|
||||||
|
FComments.Free;
|
||||||
|
|
||||||
inherited Destroy;
|
inherited Destroy;
|
||||||
end;
|
end;
|
||||||
@ -1393,7 +1446,7 @@ var
|
|||||||
formula: String;
|
formula: String;
|
||||||
cell: PCell;
|
cell: PCell;
|
||||||
begin
|
begin
|
||||||
ACell^.CalcState := csCalculating;
|
ACell^.Flags := ACell^.Flags + [cfCalculating] - [cfCalculated];
|
||||||
|
|
||||||
parser := TsSpreadsheetParser.Create(self);
|
parser := TsSpreadsheetParser.Create(self);
|
||||||
try
|
try
|
||||||
@ -1443,7 +1496,7 @@ begin
|
|||||||
parser.Free;
|
parser.Free;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
ACell^.CalcState := csCalculated;
|
ACell^.Flags := ACell^.Flags + [cfCalculated] - [cfCalculating];
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
@ -1494,9 +1547,8 @@ var
|
|||||||
begin
|
begin
|
||||||
Unused(arg);
|
Unused(arg);
|
||||||
cell := PCell(data);
|
cell := PCell(data);
|
||||||
|
|
||||||
if HasFormula(cell) then
|
if HasFormula(cell) then
|
||||||
cell^.CalcState := csNotCalculated;
|
SetCalcState(cell, csNotCalculated);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
@ -1565,6 +1617,133 @@ begin
|
|||||||
SetLength(rpnFormula, 0);
|
SetLength(rpnFormula, 0);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Checks whether the cell at a specified row/column contains a comment and
|
||||||
|
returns a pointer to the comment data.
|
||||||
|
|
||||||
|
@param ARow (0-based) index to the row
|
||||||
|
@param ACol (0-based) index to the column
|
||||||
|
@return Pointer to the TsComment record (nil, if the cell does not have a
|
||||||
|
comment)
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
function TsWorksheet.FindComment(ARow, ACol: Cardinal): PsComment;
|
||||||
|
var
|
||||||
|
comment: TsComment;
|
||||||
|
AVLNode: TAVLTreeNode;
|
||||||
|
begin
|
||||||
|
Result := nil;
|
||||||
|
if FComments.Count = 0 then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
comment.Row := ARow;
|
||||||
|
comment.Col := ACol;
|
||||||
|
AVLNode := FComments.Find(@comment);
|
||||||
|
if Assigned(AVLNode) then
|
||||||
|
result := PsComment(AVLNode.Data);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Checks whether a cell contains a comment and returns a pointer to the
|
||||||
|
comment data.
|
||||||
|
|
||||||
|
@param ACell Pointer to the cell
|
||||||
|
@return Pointer to the TsComment record (nil, if the cell does not have a
|
||||||
|
comment)
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
function TsWorksheet.FindComment(ACell: PCell): PsComment;
|
||||||
|
begin
|
||||||
|
if ACell = nil then
|
||||||
|
Result := nil
|
||||||
|
else
|
||||||
|
Result := FindComment(ACell^.Row, ACell^.Col);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Checks whether a specific cell contains a comment
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
function TsWorksheet.HasComment(ACell: PCell): Boolean;
|
||||||
|
begin
|
||||||
|
Result := (ACell <> nil) and (cfHasComment in ACell^.Flags);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Returns the comment text attached to a specific cell
|
||||||
|
|
||||||
|
@param ARow (0-based) index to the row
|
||||||
|
@param ACol (0-based) index to the column
|
||||||
|
@return Text assigned to the cell as a comment
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
function TsWorksheet.ReadComment(ARow, ACol: Cardinal): String;
|
||||||
|
var
|
||||||
|
comment: PsComment;
|
||||||
|
begin
|
||||||
|
Result := '';
|
||||||
|
comment := FindComment(ARow, ACol);
|
||||||
|
if comment <> nil then
|
||||||
|
Result := comment^.Text;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Returns the comment text attached to a specific cell
|
||||||
|
|
||||||
|
@param ACell Pointer to the cell
|
||||||
|
@return Text assigned to the cell as a comment
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
function TsWorksheet.ReadComment(ACell: PCell): String;
|
||||||
|
var
|
||||||
|
comment: PsComment;
|
||||||
|
begin
|
||||||
|
Result := '';
|
||||||
|
comment := FindComment(ACell);
|
||||||
|
if comment <> nil then
|
||||||
|
Result := comment^.Text;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Adds a comment to a specific cell
|
||||||
|
|
||||||
|
@param ARow (0-based) index to the row
|
||||||
|
@param ACol (0-based) index to the column
|
||||||
|
@param AText Comment text
|
||||||
|
@return Pointer to the cell containing the comment
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
function TsWorksheet.WriteComment(ARow, ACol: Cardinal; AText: String): PCell;
|
||||||
|
begin
|
||||||
|
Result := GetCell(ARow, ACol);
|
||||||
|
WriteComment(Result, AText);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Adds a comment to a specific cell
|
||||||
|
|
||||||
|
@param ACell Pointer to the cell
|
||||||
|
@param AText Comment text
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
procedure TsWorksheet.WriteComment(ACell: PCell; AText: String);
|
||||||
|
var
|
||||||
|
comment: PsComment;
|
||||||
|
begin
|
||||||
|
if ACell = nil then
|
||||||
|
exit;
|
||||||
|
if AText = '' then
|
||||||
|
begin
|
||||||
|
if (cfHasComment) in ACell^.Flags then
|
||||||
|
begin
|
||||||
|
RemoveComment(ACell);
|
||||||
|
ACell^.Flags := ACell^.Flags - [cfHasComment];
|
||||||
|
end;
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
New(comment);
|
||||||
|
comment.Row := ACell^.Row;
|
||||||
|
comment.Col := ACell^.Col;
|
||||||
|
comment.Text := AText;
|
||||||
|
FComments.Add(comment);
|
||||||
|
ACell^.Flags := ACell^.Flags + [cfHasComment];
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Is called whenever a cell value or formatting has changed. Fires an event
|
Is called whenever a cell value or formatting has changed. Fires an event
|
||||||
"OnChangeCell". This is handled by TsWorksheetGrid to update the grid cell.
|
"OnChangeCell". This is handled by TsWorksheetGrid to update the grid cell.
|
||||||
@ -2744,7 +2923,7 @@ begin
|
|||||||
end else
|
end else
|
||||||
Result := False;
|
Result := False;
|
||||||
end;
|
end;
|
||||||
|
(*
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Returns the comment assigned to a cell
|
Returns the comment assigned to a cell
|
||||||
|
|
||||||
@ -2757,7 +2936,7 @@ begin
|
|||||||
Result := ACell^.Comment
|
Result := ACell^.Comment
|
||||||
else
|
else
|
||||||
Result := '';
|
Result := '';
|
||||||
end;
|
end; *)
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Converts an RPN formula (as read from an xls biff file, for example) to a
|
Converts an RPN formula (as read from an xls biff file, for example) to a
|
||||||
@ -2781,6 +2960,60 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Returns the CalcState flag of the specified cell. This flag tells whether a
|
||||||
|
formula in the cell has not yet been calculated (csNotCalculated), is
|
||||||
|
currently being calculated (csCalculating), or has already been calculated
|
||||||
|
(csCalculated.
|
||||||
|
|
||||||
|
@param ACell Pointer to cell considered
|
||||||
|
@return Enumerated value of the cell's calculation state
|
||||||
|
(csNotCalculated, csCalculating, csCalculated)
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
function TsWorksheet.GetCalcState(ACell: PCell): TsCalcState;
|
||||||
|
var
|
||||||
|
calcState: TsCellFlags;
|
||||||
|
begin
|
||||||
|
Result := csNotCalculated;
|
||||||
|
if (ACell = nil) then
|
||||||
|
exit;
|
||||||
|
calcState := ACell^.Flags * [cfCalculating, cfCalculated];
|
||||||
|
if calcState = [] then
|
||||||
|
Result := csNotCalculated
|
||||||
|
else
|
||||||
|
if calcState = [cfCalculating] then
|
||||||
|
Result := csCalculating
|
||||||
|
else
|
||||||
|
if calcState = [cfCalculated] then
|
||||||
|
Result := csCalculated
|
||||||
|
else
|
||||||
|
raise Exception.Create('[TsWorksheet.GetCalcState] Illegal cell flags.');
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Set the CalcState flag of the specified cell. This flag tells whether a
|
||||||
|
formula in the cell has not yet been calculated (csNotCalculated), is
|
||||||
|
currently being calculated (csCalculating), or has already been calculated
|
||||||
|
(csCalculated).
|
||||||
|
|
||||||
|
For internal use only!
|
||||||
|
|
||||||
|
@param ACell Pointer to cell considered
|
||||||
|
@param AValue New value for the calculation state of the cell
|
||||||
|
(csNotCalculated, csCalculating, csCalculated)
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
procedure TsWorksheet.SetCalcState(ACell: PCell; AValue: TsCalcState);
|
||||||
|
begin
|
||||||
|
case AValue of
|
||||||
|
csNotCalculated:
|
||||||
|
ACell^.Flags := ACell^.Flags - [cfCalculated, cfCalculating];
|
||||||
|
csCalculating:
|
||||||
|
ACell^.Flags := ACell^.Flags + [cfCalculating] - [cfCalculated];
|
||||||
|
csCalculated:
|
||||||
|
ACell^.Flags := ACell^.Flags + [cfCalculated] - [cfCalculating];
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Reads the set of used formatting fields of a cell.
|
Reads the set of used formatting fields of a cell.
|
||||||
|
|
||||||
@ -3300,28 +3533,76 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Helper method for clearing the records in a spreadsheet.
|
Helper method for clearing the cell records in a spreadsheet.
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
procedure TsWorksheet.RemoveCallback(data, arg: pointer);
|
procedure TsWorksheet.RemoveCellsCallback(data, arg: pointer);
|
||||||
begin
|
begin
|
||||||
Unused(arg);
|
Unused(arg);
|
||||||
Dispose(PCell(data));
|
Dispose(PCell(data));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Helper method for clearing the cell comments in a spreadsheet.
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
procedure TsWorksheet.RemoveCommentsCallback(data, arg: pointer);
|
||||||
|
begin
|
||||||
|
Unused(arg);
|
||||||
|
Dispose(PsComment(data));
|
||||||
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Clears the list of cells and releases their memory.
|
Clears the list of cells and releases their memory.
|
||||||
--------------------------------------------------------------------------------}
|
--------------------------------------------------------------------------------}
|
||||||
procedure TsWorksheet.RemoveAllCells;
|
procedure TsWorksheet.RemoveAllCells;
|
||||||
var
|
|
||||||
Node: TAVLTreeNode;
|
|
||||||
begin
|
begin
|
||||||
Node:=FCells.FindLowest;
|
RemoveAllAvlTreeNodes(FCells, RemoveCellsCallback);
|
||||||
while Assigned(Node) do begin
|
|
||||||
RemoveCallback(Node.Data,nil);
|
|
||||||
Node.Data:=nil;
|
|
||||||
Node:=FCells.FindSuccessor(Node);
|
|
||||||
end;
|
end;
|
||||||
FCells.Clear;
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Clears the list of comments and releases their memory
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
procedure TsWorksheet.RemoveAllComments;
|
||||||
|
begin
|
||||||
|
RemoveAllAvlTreeNodes(FComments, RemoveCommentsCallback);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Removes the comment from a cell and releases the memory occupied by the node.
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
procedure TsWorksheet.RemoveComment(ACell: PCell);
|
||||||
|
var
|
||||||
|
comment: TsComment;
|
||||||
|
commentNode: TAvlTreeNode;
|
||||||
|
begin
|
||||||
|
if ACell = nil then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
comment.Row := ACell^.Row;
|
||||||
|
comment.Col := ACell^.Col;
|
||||||
|
commentNode := FComments.Find(@comment);
|
||||||
|
if commentNode <> nil then begin
|
||||||
|
Dispose(PsComment(commentNode.Data));
|
||||||
|
FComments.Delete(commentNode);
|
||||||
|
ACell^.Flags := ACell^.Flags - [cfHasComment];
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Clears the AVLTree specified and releases the memory occupied by the nodes
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
procedure TsWorksheet.RemoveAllAVLTreeNodes(ATree: TAvlTree;
|
||||||
|
ARemoveCallback: TsCallback);
|
||||||
|
var
|
||||||
|
node: TAvlTreeNode;
|
||||||
|
begin
|
||||||
|
node := ATree.FindLowest;
|
||||||
|
while Assigned(node) do begin
|
||||||
|
ARemoveCallback(node.Data, nil);
|
||||||
|
node.Data := nil;
|
||||||
|
node := ATree.FindSuccessor(node);
|
||||||
|
end;
|
||||||
|
ATree.Clear;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
@ -3338,7 +3619,9 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Removes a cell and releases its memory.
|
Removes a cell and releases its memory. If a comment is attached to the
|
||||||
|
cell then it is removed and releaded as well.
|
||||||
|
|
||||||
Just for internal usage since it does not modify the other cells affected
|
Just for internal usage since it does not modify the other cells affected
|
||||||
|
|
||||||
@param ARow Row index of the cell to be removed
|
@param ARow Row index of the cell to be removed
|
||||||
@ -3348,6 +3631,8 @@ procedure TsWorksheet.RemoveAndFreeCell(ARow, ACol: Cardinal);
|
|||||||
var
|
var
|
||||||
cellnode: TAVLTreeNode;
|
cellnode: TAVLTreeNode;
|
||||||
cell: TCell;
|
cell: TCell;
|
||||||
|
comment: TsComment;
|
||||||
|
commentnode: TAVLTreeNode;
|
||||||
begin
|
begin
|
||||||
cell.Row := ARow;
|
cell.Row := ARow;
|
||||||
cell.Col := ACol;
|
cell.Col := ACol;
|
||||||
@ -3356,6 +3641,14 @@ begin
|
|||||||
Dispose(PCell(cellnode.Data));
|
Dispose(PCell(cellnode.Data));
|
||||||
FCells.Delete(cellnode);
|
FCells.Delete(cellnode);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
comment.Row := ARow;
|
||||||
|
comment.Col := ACol;
|
||||||
|
commentNode := FComments.Find(@comment);
|
||||||
|
if commentNode <> nil then begin
|
||||||
|
Dispose(PsComment(commentNode.Data));
|
||||||
|
FComments.Delete(commentNode);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
@ -4134,7 +4427,7 @@ begin
|
|||||||
|
|
||||||
WriteUTF8Text(ACell, AValue);
|
WriteUTF8Text(ACell, AValue);
|
||||||
end;
|
end;
|
||||||
|
(*
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Assigns a comment to a cell
|
Assigns a comment to a cell
|
||||||
|
|
||||||
@ -4163,7 +4456,7 @@ begin
|
|||||||
ChangedCell(ACell^.Row, ACell^.Col);
|
ChangedCell(ACell^.Row, ACell^.Col);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
*)
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Writes a currency value to a given cell. Its number format can be provided
|
Writes a currency value to a given cell. Its number format can be provided
|
||||||
optionally by specifying various parameters.
|
optionally by specifying various parameters.
|
||||||
@ -8715,7 +9008,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
|
//if ACell^.Comment <> '' then
|
||||||
|
if FWorksheet.ReadComment(ACell) <> '' then
|
||||||
WriteComment(AStream, ACell);
|
WriteComment(AStream, ACell);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -8769,6 +9063,31 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
A generic method to iterate through all comments in a worksheet and call a
|
||||||
|
callback routine for each cell.
|
||||||
|
|
||||||
|
@param AStream The output stream, passed to the callback routine.
|
||||||
|
@param AComments List of comments to be iterated
|
||||||
|
@param ACallback Callback routine; it requires as arguments a pointer to the
|
||||||
|
comment record as well as the destination stream.
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
procedure TsCustomSpreadWriter.IterateThroughComments(AStream: TStream;
|
||||||
|
AComments: TAVLTree; ACallback: TCommentsCallback);
|
||||||
|
var
|
||||||
|
AVLNode: TAVLTreeNode;
|
||||||
|
index: Integer;
|
||||||
|
begin
|
||||||
|
index := 0;
|
||||||
|
AVLNode := AComments.FindLowest;
|
||||||
|
while Assigned(AVLNode) do
|
||||||
|
begin
|
||||||
|
ACallback(PsComment(AVLNode.Data), index, AStream);
|
||||||
|
AVLNode := AComments.FindSuccessor(AVLNode);
|
||||||
|
inc(index);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Default file writing method.
|
Default file writing method.
|
||||||
|
|
||||||
|
@ -1712,7 +1712,7 @@ begin
|
|||||||
begin
|
begin
|
||||||
// single cell
|
// single cell
|
||||||
FDrawingCell := cell;
|
FDrawingCell := cell;
|
||||||
if (cell <> nil) and (cell^.Comment <> '') then
|
if Worksheet.HasComment(cell) then
|
||||||
commentcell_rct := CellRect(gc, gr)
|
commentcell_rct := CellRect(gc, gr)
|
||||||
else
|
else
|
||||||
commentcell_rct := Rect(0,0,0,0);
|
commentcell_rct := Rect(0,0,0,0);
|
||||||
@ -1744,7 +1744,7 @@ begin
|
|||||||
begin
|
begin
|
||||||
gds := GetGridDrawState(gc, gr);
|
gds := GetGridDrawState(gc, gr);
|
||||||
DoDrawCell(gc, gr, rct, temp_rct);
|
DoDrawCell(gc, gr, rct, temp_rct);
|
||||||
if (FDrawingCell <> nil) and (FDrawingCell^.Comment <> '') then
|
if Worksheet.HasComment(FDrawingCell) then
|
||||||
DrawCommentMarker(temp_rct);
|
DrawCommentMarker(temp_rct);
|
||||||
end;
|
end;
|
||||||
FTextOverflowing := false;
|
FTextOverflowing := false;
|
||||||
@ -1761,7 +1761,7 @@ begin
|
|||||||
FDrawingCell := Worksheet.FindMergeBase(cell);
|
FDrawingCell := Worksheet.FindMergeBase(cell);
|
||||||
Worksheet.FindMergedRange(FDrawingCell, sr1, sc1, sr2, sc2);
|
Worksheet.FindMergedRange(FDrawingCell, sr1, sc1, sr2, sc2);
|
||||||
gr := GetGridRow(sr1);
|
gr := GetGridRow(sr1);
|
||||||
if (FDrawingCell <> nil) and (FDrawingCell^.Comment <> '') then
|
if Worksheet.HasComment(FDrawingCell) then
|
||||||
commentcell_rct := CellRect(GetGridCol(sc2), gr)
|
commentcell_rct := CellRect(GetGridCol(sc2), gr)
|
||||||
else
|
else
|
||||||
commentcell_rct := Rect(0,0,0,0);
|
commentcell_rct := Rect(0,0,0,0);
|
||||||
|
@ -128,6 +128,9 @@ type
|
|||||||
TCellContentType = (cctEmpty, cctFormula, cctNumber, cctUTF8String,
|
TCellContentType = (cctEmpty, cctFormula, cctNumber, cctUTF8String,
|
||||||
cctDateTime, cctBool, cctError);
|
cctDateTime, cctBool, cctError);
|
||||||
|
|
||||||
|
{@@ Callback function, e.g. for iterating the internal AVL trees of the workbook/sheet}
|
||||||
|
TsCallback = procedure (data, arg: Pointer) of object;
|
||||||
|
|
||||||
{@@ Error code values }
|
{@@ Error code values }
|
||||||
TsErrorValue = (
|
TsErrorValue = (
|
||||||
errOK, // no error
|
errOK, // no error
|
||||||
@ -382,9 +385,15 @@ type
|
|||||||
coEqual, coNotEqual, coLess, coGreater, coLessEqual, coGreaterEqual
|
coEqual, coNotEqual, coLess, coGreater, coLessEqual, coGreaterEqual
|
||||||
);
|
);
|
||||||
|
|
||||||
{@@ State flags while calculating formulas }
|
{@@ Cell calculation state }
|
||||||
TsCalcState = (csNotCalculated, csCalculating, csCalculated);
|
TsCalcState = (csNotCalculated, csCalculating, csCalculated);
|
||||||
|
|
||||||
|
{@@ Cell flag }
|
||||||
|
TsCellFlag = (cfCalculating, cfCalculated, cfHasComment);
|
||||||
|
|
||||||
|
{@@ Set of cell flags }
|
||||||
|
TsCellFlags = set of TsCellFlag;
|
||||||
|
|
||||||
{@@ Record combining a cell's row and column indexes }
|
{@@ Record combining a cell's row and column indexes }
|
||||||
TsCellCoord = record
|
TsCellCoord = record
|
||||||
Row, Col: Cardinal;
|
Row, Col: Cardinal;
|
||||||
|
@ -118,8 +118,8 @@ type
|
|||||||
|
|
||||||
TsSpreadBIFF8Writer = class(TsSpreadBIFFWriter)
|
TsSpreadBIFF8Writer = class(TsSpreadBIFFWriter)
|
||||||
private
|
private
|
||||||
FCommentList: TFPList;
|
procedure WriteCommentsCallback(AComment: PsComment; ACommentIndex: Integer;
|
||||||
procedure WriteCommentsCallback(ACell: PCell; AStream: TStream);
|
AStream: TStream);
|
||||||
|
|
||||||
protected
|
protected
|
||||||
{ Record writing methods }
|
{ Record writing methods }
|
||||||
@ -135,11 +135,11 @@ type
|
|||||||
procedure WriteLabel(AStream: TStream; const ARow, ACol: Cardinal;
|
procedure WriteLabel(AStream: TStream; const ARow, ACol: Cardinal;
|
||||||
const AValue: string; ACell: PCell); override;
|
const AValue: string; ACell: PCell); override;
|
||||||
procedure WriteMergedCells(AStream: TStream; AWorksheet: TsWorksheet);
|
procedure WriteMergedCells(AStream: TStream; AWorksheet: TsWorksheet);
|
||||||
procedure WriteMSODrawing1(AStream: TStream; ANumShapes: Word; ACell: PCell);
|
procedure WriteMSODrawing1(AStream: TStream; ANumShapes: Word; AComment: PsComment);
|
||||||
procedure WriteMSODrawing2(AStream: TStream; ACell: PCell; AObjID: Word);
|
procedure WriteMSODrawing2(AStream: TStream; AComment: PsComment; AObjID: Word);
|
||||||
procedure WriteMSODrawing2_Data(AStream: TStream; ACell: PCell; AShapeID: Word);
|
procedure WriteMSODrawing2_Data(AStream: TStream; AComment: PsComment; AShapeID: Word);
|
||||||
procedure WriteMSODrawing3(AStream: TStream; ACell: PCell);
|
procedure WriteMSODrawing3(AStream: TStream);
|
||||||
procedure WriteNOTE(AStream: TStream; ACell: PCell; AObjID: Word);
|
procedure WriteNOTE(AStream: TStream; AComment: PsComment; AObjID: Word);
|
||||||
procedure WriteNumFormat(AStream: TStream; AFormatData: TsNumFormatData;
|
procedure WriteNumFormat(AStream: TStream; AFormatData: TsNumFormatData;
|
||||||
AListIndex: Integer); override;
|
AListIndex: Integer); override;
|
||||||
procedure WriteOBJ(AStream: TStream; AObjID: Word);
|
procedure WriteOBJ(AStream: TStream; AObjID: Word);
|
||||||
@ -152,7 +152,7 @@ type
|
|||||||
function WriteString_8bitLen(AStream: TStream; AString: String): Integer; override;
|
function WriteString_8bitLen(AStream: TStream; AString: String): Integer; override;
|
||||||
procedure WriteStringRecord(AStream: TStream; AString: string); override;
|
procedure WriteStringRecord(AStream: TStream; AString: string); override;
|
||||||
procedure WriteSTYLE(AStream: TStream);
|
procedure WriteSTYLE(AStream: TStream);
|
||||||
procedure WriteTXO(AStream: TStream; ACell: PCell);
|
procedure WriteTXO(AStream: TStream; AComment: PsComment);
|
||||||
procedure WriteWINDOW2(AStream: TStream; ASheet: TsWorksheet);
|
procedure WriteWINDOW2(AStream: TStream; ASheet: TsWorksheet);
|
||||||
procedure WriteXF(AStream: TStream; AFormatRecord: PsCellFormat;
|
procedure WriteXF(AStream: TStream; AFormatRecord: PsCellFormat;
|
||||||
XFType_Prot: Byte = 0); override;
|
XFType_Prot: Byte = 0); override;
|
||||||
@ -1595,39 +1595,23 @@ begin
|
|||||||
exit; // Remove after comments can be written correctly
|
exit; // Remove after comments can be written correctly
|
||||||
{$warning TODO: Fix writing of cell comments in BIFF8 (file is readable by OpenOffice, but not by Excel)}
|
{$warning TODO: Fix writing of cell comments in BIFF8 (file is readable by OpenOffice, but not by Excel)}
|
||||||
|
|
||||||
FCommentList := TFPList.Create;
|
IterateThroughComments(AStream, AWorksheet.Comments, WriteCommentsCallback);
|
||||||
try
|
|
||||||
IterateThroughCells(AStream, AWorksheet.Cells, WriteCommentsCallback);
|
|
||||||
if FCommentList.Count = 0 then
|
|
||||||
exit;
|
|
||||||
|
|
||||||
for i:=0 to FCommentList.Count-1 do begin
|
|
||||||
if i = 0 then
|
|
||||||
WriteMSODRAWING1(AStream, FCommentList.Count, PCell(FCommentList[i]))
|
|
||||||
else
|
|
||||||
WriteMSODRAWING2(AStream, PCell(FCommentList[i]), i+1);
|
|
||||||
WriteOBJ(AStream, i+1);
|
|
||||||
WriteMSODRAWING3(AStream, PCell(FCommentList[i]));
|
|
||||||
WriteTXO(AStream, PCell(FCommentList[i]));
|
|
||||||
end;
|
|
||||||
|
|
||||||
for i:=0 to FCommentList.Count-1 do
|
|
||||||
WriteNOTE(AStream, PCell(FCommentList[i]), i+1);
|
|
||||||
finally
|
|
||||||
FreeAndNil(FCommentList);
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Helper method which stores the pointer to a cell in the FCommentsList if the
|
Helper method which stores the pointer to a cell in the FCommentsList if the
|
||||||
cell contains a comment
|
cell contains a comment
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
procedure TsSpreadBIFF8Writer.WriteCommentsCallback(ACell: PCell;
|
procedure TsSpreadBIFF8Writer.WriteCommentsCallback(AComment: PsComment;
|
||||||
AStream: TStream);
|
ACommentIndex: Integer; AStream: TStream);
|
||||||
begin
|
begin
|
||||||
Unused(AStream);
|
if ACommentIndex = 0 then
|
||||||
if (ACell <> nil) and (ACell^.Comment <> '') then
|
WriteMSODrawing1(AStream, FWorksheet.Comments.Count, AComment)
|
||||||
FCommentList.Add(ACell);
|
else
|
||||||
|
WriteMSODrawing2(AStream, AComment, ACommentIndex+1);
|
||||||
|
WriteOBJ(AStream, ACommentIndex+1);
|
||||||
|
WriteMSODrawing3(AStream);
|
||||||
|
WriteTXO(AStream, AComment);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
@ -1777,7 +1761,7 @@ MSODRAWING2 |---- Sp container (child shape) $F004 0
|
|||||||
</pre>
|
</pre>
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
procedure TsSpreadBiff8Writer.WriteMSODrawing1(AStream: TStream; ANumShapes: Word;
|
procedure TsSpreadBiff8Writer.WriteMSODrawing1(AStream: TStream; ANumShapes: Word;
|
||||||
ACell: PCell);
|
AComment: PsComment);
|
||||||
const
|
const
|
||||||
DRAWING_ID = 1;
|
DRAWING_ID = 1;
|
||||||
var
|
var
|
||||||
@ -1808,9 +1792,9 @@ begin
|
|||||||
MSO_FSP_BITS_GROUP + MSO_FSP_BITS_PATRIARCH); // 8 + 8 bytes
|
MSO_FSP_BITS_GROUP + MSO_FSP_BITS_PATRIARCH); // 8 + 8 bytes
|
||||||
|
|
||||||
{ Data for the 1st comment }
|
{ Data for the 1st comment }
|
||||||
WriteMSODrawing2_Data(tmpStream, ACell, SHAPEID_BASE + 1);
|
WriteMSODrawing2_Data(tmpStream, AComment, SHAPEID_BASE + 1);
|
||||||
|
|
||||||
// Write the BIFF stream
|
{ Write the BIFF stream }
|
||||||
tmpStream.Position := 0;
|
tmpStream.Position := 0;
|
||||||
len := tmpStream.Size;
|
len := tmpStream.Size;
|
||||||
WriteBiffHeader(AStream, INT_EXCEL_ID_MSODRAWING, tmpStream.Size);
|
WriteBiffHeader(AStream, INT_EXCEL_ID_MSODRAWING, tmpStream.Size);
|
||||||
@ -1822,9 +1806,9 @@ end;
|
|||||||
|
|
||||||
{ Write the MSODRAWING record which occurs before the OBJ record.
|
{ Write the MSODRAWING record which occurs before the OBJ record.
|
||||||
Do not use for the very first OBJ record where the record must be
|
Do not use for the very first OBJ record where the record must be
|
||||||
WriteMSODrawing1 + WriteMSODrawing2_Data + WriteMSODrawing3_Data}
|
WriteMSODrawing1 + WriteMSODrawing2_Data}
|
||||||
procedure TsSpreadBiff8Writer.WriteMSODrawing2(AStream: TStream; ACell: PCell;
|
procedure TsSpreadBiff8Writer.WriteMSODrawing2(AStream: TStream;
|
||||||
AObjID: Word);
|
AComment: PsComment; AObjID: Word);
|
||||||
var
|
var
|
||||||
tmpStream: TStream;
|
tmpStream: TStream;
|
||||||
len: Word;
|
len: Word;
|
||||||
@ -1832,7 +1816,7 @@ begin
|
|||||||
tmpStream := TMemoryStream.Create;
|
tmpStream := TMemoryStream.Create;
|
||||||
try
|
try
|
||||||
{ Shape data for cell comment }
|
{ Shape data for cell comment }
|
||||||
WriteMSODrawing2_Data(tmpStream, ACell, SHAPEID_BASE + AObjID);
|
WriteMSODrawing2_Data(tmpStream, AComment, SHAPEID_BASE + AObjID);
|
||||||
|
|
||||||
{ Get size of data stream }
|
{ Get size of data stream }
|
||||||
len := tmpStream.Size;
|
len := tmpStream.Size;
|
||||||
@ -1849,7 +1833,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TsSpreadBiff8Writer.WriteMSODrawing2_Data(AStream: TStream;
|
procedure TsSpreadBiff8Writer.WriteMSODrawing2_Data(AStream: TStream;
|
||||||
ACell: PCell; AShapeID: Word);
|
AComment: PsComment; AShapeID: Word);
|
||||||
var
|
var
|
||||||
tmpStream: TStream;
|
tmpStream: TStream;
|
||||||
len: Cardinal;
|
len: Cardinal;
|
||||||
@ -1869,7 +1853,7 @@ begin
|
|||||||
|
|
||||||
{ OfficeArtClientAnchor record }
|
{ OfficeArtClientAnchor record }
|
||||||
WriteMSOClientAnchorSheetRecord(tmpStream,
|
WriteMSOClientAnchorSheetRecord(tmpStream,
|
||||||
ACell^.Row + 1, ACell^.Col + 1, ACell.Row + 3, ACell^.Col + 5,
|
AComment^.Row + 1, AComment^.Col + 1, AComment^.Row + 3, AComment^.Col + 5,
|
||||||
691, 486, 38, 26,
|
691, 486, 38, 26,
|
||||||
true, true
|
true, true
|
||||||
);
|
);
|
||||||
@ -1893,7 +1877,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
{ Writes the MSODRAWING record which must occur immediately before a TXO record }
|
{ Writes the MSODRAWING record which must occur immediately before a TXO record }
|
||||||
procedure TsSpreadBiff8Writer.WriteMSODRAWING3(AStream: TStream; ACell: PCell);
|
procedure TsSpreadBiff8Writer.WriteMSODRAWING3(AStream: TStream);
|
||||||
begin
|
begin
|
||||||
{ BIFF Header }
|
{ BIFF Header }
|
||||||
WriteBiffHeader(AStream, INT_EXCEL_ID_MSODRAWING, 8);
|
WriteBiffHeader(AStream, INT_EXCEL_ID_MSODRAWING, 8);
|
||||||
@ -1903,10 +1887,10 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
{ Writes a NOTE record for a comment attached to a cell }
|
{ Writes a NOTE record for a comment attached to a cell }
|
||||||
procedure TsSpreadBiff8Writer.WriteNOTE(AStream: TStream; ACell: PCell;
|
procedure TsSpreadBiff8Writer.WriteNOTE(AStream: TStream; AComment: PsComment;
|
||||||
AObjID: Word);
|
AObjID: Word);
|
||||||
const
|
const
|
||||||
AUTHOR: ansistring = 'Werner';
|
AUTHOR: ansistring = 'author';
|
||||||
var
|
var
|
||||||
len: Integer;
|
len: Integer;
|
||||||
begin
|
begin
|
||||||
@ -1917,8 +1901,8 @@ begin
|
|||||||
AStream.WriteWord(WordToLE(12+len)); // Size of NOTE record
|
AStream.WriteWord(WordToLE(12+len)); // Size of NOTE record
|
||||||
|
|
||||||
{ Record data }
|
{ Record data }
|
||||||
AStream.WriteWord(WordToLE(ACell^.Row)); // Row index of cell
|
AStream.WriteWord(WordToLE(AComment^.Row)); // Row index of cell
|
||||||
AStream.WriteWord(WordToLE(ACell^.Col)); // Column index of cell
|
AStream.WriteWord(WordToLE(AComment^.Col)); // Column index of cell
|
||||||
AStream.WriteWord(0); // Flags
|
AStream.WriteWord(0); // Flags
|
||||||
AStream.WriteWord(WordToLE(AObjID)); // Object identifier (1, ...)
|
AStream.WriteWord(WordToLE(AObjID)); // Object identifier (1, ...)
|
||||||
AStream.WriteWord(len); // Char length of author string
|
AStream.WriteWord(len); // Char length of author string
|
||||||
@ -2261,7 +2245,7 @@ end;
|
|||||||
Writes a TXO and two CONTINUE records as needed for cell comments.
|
Writes a TXO and two CONTINUE records as needed for cell comments.
|
||||||
It can safely be assumed that the cell exists and contains a comment.
|
It can safely be assumed that the cell exists and contains a comment.
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
procedure TsSpreadBIFF8Writer.WriteTXO(AStream: TStream; ACell: PCell);
|
procedure TsSpreadBIFF8Writer.WriteTXO(AStream: TStream; AComment: PsComment);
|
||||||
var
|
var
|
||||||
recTXO: TBIFF8TXORecord;
|
recTXO: TBIFF8TXORecord;
|
||||||
comment: widestring;
|
comment: widestring;
|
||||||
@ -2272,7 +2256,7 @@ var
|
|||||||
bytesFmtRuns: Integer;
|
bytesFmtRuns: Integer;
|
||||||
begin
|
begin
|
||||||
{ Prepare comment string. It is stored as a string with 8-bit characters }
|
{ Prepare comment string. It is stored as a string with 8-bit characters }
|
||||||
comment := UTF8Decode(ACell^.Comment);
|
comment := UTF8Decode(AComment^.Text);
|
||||||
SetLength(compressed, length(comment));
|
SetLength(compressed, length(comment));
|
||||||
for i:= 1 to Length(comment) do
|
for i:= 1 to Length(comment) do
|
||||||
begin
|
begin
|
||||||
|
@ -955,7 +955,7 @@ begin
|
|||||||
try
|
try
|
||||||
List.Text := FIncompleteNote; // Fix line endings which are #10 in file
|
List.Text := FIncompleteNote; // Fix line endings which are #10 in file
|
||||||
s := Copy(List.Text, 1, Length(List.Text) - Length(LineEnding));
|
s := Copy(List.Text, 1, Length(List.Text) - Length(LineEnding));
|
||||||
FIncompleteCell^.Comment := s;
|
FWorksheet.WriteComment(FIncompleteCell, s);
|
||||||
finally
|
finally
|
||||||
List.Free;
|
List.Free;
|
||||||
end;
|
end;
|
||||||
@ -2004,25 +2004,27 @@ var
|
|||||||
L: Integer;
|
L: Integer;
|
||||||
base_size: Word;
|
base_size: Word;
|
||||||
p: Integer;
|
p: Integer;
|
||||||
comment: ansistring;
|
cmnt: ansistring;
|
||||||
List: TStringList;
|
List: TStringList;
|
||||||
|
comment: PsComment;
|
||||||
begin
|
begin
|
||||||
Unused(ACell);
|
Unused(ACell);
|
||||||
|
|
||||||
if (ACell^.Comment = '') then
|
comment := FWorksheet.FindComment(ACell);
|
||||||
|
if (comment = nil) or (comment^.Text = '') then
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
List := TStringList.Create;
|
List := TStringList.Create;
|
||||||
try
|
try
|
||||||
List.Text := ConvertEncoding(ACell^.Comment, encodingUTF8, FCodePage);
|
List.Text := ConvertEncoding(comment^.Text, encodingUTF8, FCodePage);
|
||||||
comment := List[0];
|
cmnt := List[0];
|
||||||
for p := 1 to List.Count-1 do
|
for p := 1 to List.Count-1 do
|
||||||
comment := comment + #$0A + List[p];
|
cmnt := cmnt + #$0A + List[p];
|
||||||
finally
|
finally
|
||||||
List.Free;
|
List.Free;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
L := Length(comment);
|
L := Length(cmnt);
|
||||||
base_size := SizeOf(rec) - 2*SizeOf(word);
|
base_size := SizeOf(rec) - 2*SizeOf(word);
|
||||||
|
|
||||||
// First NOTE record
|
// First NOTE record
|
||||||
@ -2032,7 +2034,7 @@ begin
|
|||||||
rec.TextLen := L;
|
rec.TextLen := L;
|
||||||
rec.RecordSize := base_size + Min(L, CHUNK_SIZE);
|
rec.RecordSize := base_size + Min(L, CHUNK_SIZE);
|
||||||
AStream.WriteBuffer(rec, SizeOf(rec));
|
AStream.WriteBuffer(rec, SizeOf(rec));
|
||||||
AStream.WriteBuffer(comment[1], Min(L, CHUNK_SIZE)); // Write text
|
AStream.WriteBuffer(cmnt[1], Min(L, CHUNK_SIZE)); // Write text
|
||||||
|
|
||||||
// If the comment text does not fit into 2048 bytes continuation records
|
// If the comment text does not fit into 2048 bytes continuation records
|
||||||
// have to be written.
|
// have to be written.
|
||||||
@ -2044,7 +2046,7 @@ begin
|
|||||||
rec.TextLen := Min(L, CHUNK_SIZE);
|
rec.TextLen := Min(L, CHUNK_SIZE);
|
||||||
rec.RecordSize := base_size + rec.TextLen;
|
rec.RecordSize := base_size + rec.TextLen;
|
||||||
AStream.WriteBuffer(rec, SizeOf(rec));
|
AStream.WriteBuffer(rec, SizeOf(rec));
|
||||||
AStream.WriteBuffer(comment[p], rec.TextLen);
|
AStream.WriteBuffer(cmnt[p], rec.TextLen);
|
||||||
dec(L, CHUNK_SIZE);
|
dec(L, CHUNK_SIZE);
|
||||||
inc(p, CHUNK_SIZE);
|
inc(p, CHUNK_SIZE);
|
||||||
end;
|
end;
|
||||||
|
@ -104,8 +104,10 @@ type
|
|||||||
|
|
||||||
TsSpreadOOXMLWriter = class(TsCustomSpreadWriter)
|
TsSpreadOOXMLWriter = class(TsCustomSpreadWriter)
|
||||||
private
|
private
|
||||||
procedure WriteCommentsCallback(ACell: PCell; AStream: TStream);
|
procedure WriteCommentsCallback(AComment: PsComment;
|
||||||
procedure WriteVmlDrawingsCallback(ACell: PCell; AStream: TStream);
|
ACommentIndex: Integer; AStream: TStream);
|
||||||
|
procedure WriteVmlDrawingsCallback(AComment: PsComment;
|
||||||
|
ACommentIndex: Integer; AStream: TStream);
|
||||||
|
|
||||||
protected
|
protected
|
||||||
FDateMode: TDateMode;
|
FDateMode: TDateMode;
|
||||||
@ -113,8 +115,6 @@ type
|
|||||||
FSharedStringsCount: Integer;
|
FSharedStringsCount: Integer;
|
||||||
FFillList: array of PsCellFormat;
|
FFillList: array of PsCellFormat;
|
||||||
FBorderList: array of PsCellFormat;
|
FBorderList: array of PsCellFormat;
|
||||||
FDrawingCounter: Integer;
|
|
||||||
FNumCommentsOnSheet: Integer;
|
|
||||||
protected
|
protected
|
||||||
{ Helper routines }
|
{ Helper routines }
|
||||||
procedure CreateNumFormatList; override;
|
procedure CreateNumFormatList; override;
|
||||||
@ -1837,7 +1837,7 @@ begin
|
|||||||
'<commentList>');
|
'<commentList>');
|
||||||
|
|
||||||
// Comments
|
// Comments
|
||||||
IterateThroughCells(FSComments[FCurSheetNum], AWorksheet.Cells, WriteCommentsCallback);
|
IterateThroughComments(FSComments[FCurSheetNum], AWorksheet.Comments, WriteCommentsCallback);
|
||||||
|
|
||||||
// Footer
|
// Footer
|
||||||
AppendToStream(FSComments[FCurSheetNum],
|
AppendToStream(FSComments[FCurSheetNum],
|
||||||
@ -1846,20 +1846,19 @@ begin
|
|||||||
'</comments>');
|
'</comments>');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TsSpreadOOXMLWriter.WriteCommentsCallback(ACell: PCell;
|
procedure TsSpreadOOXMLWriter.WriteCommentsCallback(AComment: PsComment;
|
||||||
AStream: TStream);
|
ACommentIndex: Integer; AStream: TStream);
|
||||||
var
|
var
|
||||||
comment: String;
|
comment: String;
|
||||||
begin
|
begin
|
||||||
if (ACell = nil) or (ACell^.Comment = '') then
|
Unused(ACommentIndex);
|
||||||
exit;
|
|
||||||
|
|
||||||
comment := ACell^.Comment;
|
comment := AComment^.Text;
|
||||||
ValidXMLText(comment);
|
ValidXMLText(comment);
|
||||||
|
|
||||||
// Write comment to Comments stream
|
// Write comment to Comments stream
|
||||||
AppendToStream(AStream, Format(
|
AppendToStream(AStream, Format(
|
||||||
'<comment ref="%s" authorId="0">', [GetCellString(ACell^.Row, ACell^.Col)]));
|
'<comment ref="%s" authorId="0">', [GetCellString(AComment^.Row, AComment^.Col)]));
|
||||||
AppendToStream(AStream,
|
AppendToStream(AStream,
|
||||||
'<text>'+
|
'<text>'+
|
||||||
'<r>'+
|
'<r>'+
|
||||||
@ -2141,7 +2140,10 @@ begin
|
|||||||
AVLNode := AWorksheet.Cells.Find(@lCell);
|
AVLNode := AWorksheet.Cells.Find(@lCell);
|
||||||
if Assigned(AVLNode) then begin
|
if Assigned(AVLNode) then begin
|
||||||
WriteCellCallback(PCell(AVLNode.Data), AStream);
|
WriteCellCallback(PCell(AVLNode.Data), AStream);
|
||||||
if PCell(AVLNode.Data)^.Comment <> '' then inc(FNumCommentsOnSheet);
|
{
|
||||||
|
if (cfHasComment in PCell(AVLNode.Data)^.Flags) then
|
||||||
|
inc(FNumCommentsOnSheet);
|
||||||
|
}
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
AppendToStream(AStream,
|
AppendToStream(AStream,
|
||||||
@ -2338,7 +2340,7 @@ begin
|
|||||||
else
|
else
|
||||||
FSVmlDrawings[FCurSheetNum] := TMemoryStream.Create;
|
FSVmlDrawings[FCurSheetNum] := TMemoryStream.Create;
|
||||||
|
|
||||||
FDrawingCounter := 0;
|
// FDrawingCounter := 0;
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
AppendToStream(FSVmlDrawings[FCurSheetNum],
|
AppendToStream(FSVmlDrawings[FCurSheetNum],
|
||||||
@ -2358,24 +2360,25 @@ begin
|
|||||||
' </v:shapetype>' + LineEnding);
|
' </v:shapetype>' + LineEnding);
|
||||||
|
|
||||||
// Write vmlDrawings for each comment (formatting and position of comment box)
|
// Write vmlDrawings for each comment (formatting and position of comment box)
|
||||||
IterateThroughCells(FSVmlDrawings[FCurSheetNum], AWorksheet.Cells, WriteVmlDrawingsCallback);
|
IterateThroughComments(FSVmlDrawings[FCurSheetNum], AWorksheet.Comments, WriteVmlDrawingsCallback);
|
||||||
|
// IterateThroughCells(FSVmlDrawings[FCurSheetNum], AWorksheet.Cells, WriteVmlDrawingsCallback);
|
||||||
|
|
||||||
// Footer
|
// Footer
|
||||||
AppendToStream(FSVmlDrawings[FCurSheetNum],
|
AppendToStream(FSVmlDrawings[FCurSheetNum],
|
||||||
'</xml>');
|
'</xml>');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TsSpreadOOXMLWriter.WriteVmlDrawingsCallback(ACell: PCell;
|
procedure TsSpreadOOXMLWriter.WriteVmlDrawingsCallback(AComment: PsComment;
|
||||||
AStream: TStream);
|
ACommentIndex: integer; AStream: TStream);
|
||||||
var
|
var
|
||||||
id: Integer;
|
id: Integer;
|
||||||
begin
|
begin
|
||||||
// id := (FCurSheetNum+1) * 1024 + ACell^.Col + ACell^.Row;
|
id := 1025 + ACommentIndex; // if more than 1024 comments then use data="1,2,etc" above! -- not implemented yet
|
||||||
id := 1025 + FDrawingCounter; // if more than 1024 comments then use data="1,2,etc" above! -- not implemented yet
|
|
||||||
// My xml viewer does not format vml files property --> format in code.
|
// My xml viewer does not format vml files property --> format in code.
|
||||||
AppendToStream(AStream, LineEnding + Format(
|
AppendToStream(AStream, LineEnding + Format(
|
||||||
' <v:shape id="_x0000_s%d" type="#_x0000_t202" ', [id]) + LineEnding + Format(
|
' <v:shape id="_x0000_s%d" type="#_x0000_t202" ', [id]) + LineEnding + Format(
|
||||||
' style="position:absolute; width:108pt; height:52.5pt; z-index:%d; visibility:hidden" ', [FDrawingCounter+1]) + LineEnding +
|
' style="position:absolute; width:108pt; height:52.5pt; z-index:%d; visibility:hidden" ', [ACommentIndex+1]) + LineEnding +
|
||||||
// it is not necessary to specify margin-left and margin-top here!
|
// it is not necessary to specify margin-left and margin-top here!
|
||||||
|
|
||||||
// 'style=''position:absolute; margin-left:71.25pt; margin-top:1.5pt; ' + Format(
|
// 'style=''position:absolute; margin-left:71.25pt; margin-top:1.5pt; ' + Format(
|
||||||
@ -2394,11 +2397,10 @@ begin
|
|||||||
' <x:SizeWithCells />'+LineEnding+
|
' <x:SizeWithCells />'+LineEnding+
|
||||||
' <x:Anchor> 1, 15, 0, 2, 2, 79, 4, 4</x:Anchor>'+LineEnding+
|
' <x:Anchor> 1, 15, 0, 2, 2, 79, 4, 4</x:Anchor>'+LineEnding+
|
||||||
' <x:AutoFill>False</x:AutoFill>'+LineEnding + Format(
|
' <x:AutoFill>False</x:AutoFill>'+LineEnding + Format(
|
||||||
' <x:Row>%d</x:Row>', [ACell^.Row]) + LineEnding + Format(
|
' <x:Row>%d</x:Row>', [AComment^.Row]) + LineEnding + Format(
|
||||||
' <x:Column>%d</x:Column>', [ACell^.Col]) + LineEnding +
|
' <x:Column>%d</x:Column>', [AComment^.Col]) + LineEnding +
|
||||||
' </x:ClientData>'+ LineEnding+
|
' </x:ClientData>'+ LineEnding+
|
||||||
' </v:shape>' + LineEnding);
|
' </v:shape>' + LineEnding);
|
||||||
inc(FDrawingCounter);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TsSpreadOOXMLWriter.WriteWorksheetRels(AWorksheet: TsWorksheet);
|
procedure TsSpreadOOXMLWriter.WriteWorksheetRels(AWorksheet: TsWorksheet);
|
||||||
@ -2553,7 +2555,7 @@ begin
|
|||||||
begin
|
begin
|
||||||
FWorksheet := Workbook.GetWorksheetByIndex(i);
|
FWorksheet := Workbook.GetWorksheetByIndex(i);
|
||||||
WriteWorksheet(FWorksheet);
|
WriteWorksheet(FWorksheet);
|
||||||
if FNumCommentsOnSheet <> 0 then
|
if FWorksheet.Comments.Count > 0 then
|
||||||
begin
|
begin
|
||||||
WriteComments(FWorksheet);
|
WriteComments(FWorksheet);
|
||||||
WriteVmlDrawings(FWorksheet);
|
WriteVmlDrawings(FWorksheet);
|
||||||
@ -2618,7 +2620,6 @@ procedure TsSpreadOOXMLWriter.WriteWorksheet(AWorksheet: TsWorksheet);
|
|||||||
begin
|
begin
|
||||||
FCurSheetNum := Length(FSSheets);
|
FCurSheetNum := Length(FSSheets);
|
||||||
SetLength(FSSheets, FCurSheetNum + 1);
|
SetLength(FSSheets, FCurSheetNum + 1);
|
||||||
FNumCommentsOnSheet := 0;
|
|
||||||
|
|
||||||
// Create the stream
|
// Create the stream
|
||||||
if (boBufStream in Workbook.Options) then
|
if (boBufStream in Workbook.Options) then
|
||||||
@ -2639,7 +2640,7 @@ begin
|
|||||||
WriteMergedCells(FSSheets[FCurSheetNum], AWorksheet);
|
WriteMergedCells(FSSheets[FCurSheetNum], AWorksheet);
|
||||||
|
|
||||||
// Footer
|
// Footer
|
||||||
if FNumCommentsOnSheet > 0 then
|
if AWorksheet.Comments.Count > 0 then
|
||||||
AppendToStream(FSSheets[FCurSheetNum],
|
AppendToStream(FSSheets[FCurSheetNum],
|
||||||
'<legacyDrawing r:id="rId1" />');
|
'<legacyDrawing r:id="rId1" />');
|
||||||
AppendToStream(FSSheets[FCurSheetNum],
|
AppendToStream(FSSheets[FCurSheetNum],
|
||||||
|
Reference in New Issue
Block a user