You've already forked lazarus-ccr
fpspreadsheet: In fpspreadsheet.pas, extract cells AVLTree to fpsclasses.pas. Implement enumerator for the avl trees. Add unit tests for cell and comment enumeration.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3988 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -23,7 +23,7 @@ object MainFrm: TMainFrm
|
|||||||
TabOrder = 6
|
TabOrder = 6
|
||||||
object EdFrozenCols: TSpinEdit
|
object EdFrozenCols: TSpinEdit
|
||||||
Left = 429
|
Left = 429
|
||||||
Height = 27
|
Height = 23
|
||||||
Top = 8
|
Top = 8
|
||||||
Width = 52
|
Width = 52
|
||||||
OnChange = EdFrozenColsChange
|
OnChange = EdFrozenColsChange
|
||||||
@ -31,7 +31,7 @@ object MainFrm: TMainFrm
|
|||||||
end
|
end
|
||||||
object EdFrozenRows: TSpinEdit
|
object EdFrozenRows: TSpinEdit
|
||||||
Left = 429
|
Left = 429
|
||||||
Height = 27
|
Height = 23
|
||||||
Top = 39
|
Top = 39
|
||||||
Width = 52
|
Width = 52
|
||||||
OnChange = EdFrozenRowsChange
|
OnChange = EdFrozenRowsChange
|
||||||
@ -123,7 +123,7 @@ object MainFrm: TMainFrm
|
|||||||
Action = AcSaveAs
|
Action = AcSaveAs
|
||||||
end
|
end
|
||||||
object ToolButton3: TToolButton
|
object ToolButton3: TToolButton
|
||||||
Left = 200
|
Left = 228
|
||||||
Top = 0
|
Top = 0
|
||||||
Action = AcQuit
|
Action = AcQuit
|
||||||
end
|
end
|
||||||
@ -181,6 +181,19 @@ object MainFrm: TMainFrm
|
|||||||
Caption = 'ToolButton31'
|
Caption = 'ToolButton31'
|
||||||
Style = tbsDivider
|
Style = tbsDivider
|
||||||
end
|
end
|
||||||
|
object ToolButton32: TToolButton
|
||||||
|
Left = 200
|
||||||
|
Top = 0
|
||||||
|
Action = AcCommentAdd
|
||||||
|
end
|
||||||
|
object ToolButton33: TToolButton
|
||||||
|
Left = 223
|
||||||
|
Height = 24
|
||||||
|
Top = 0
|
||||||
|
Width = 5
|
||||||
|
Caption = 'ToolButton33'
|
||||||
|
Style = tbsDivider
|
||||||
|
end
|
||||||
end
|
end
|
||||||
object FormatToolBar: TToolBar
|
object FormatToolBar: TToolBar
|
||||||
Left = 0
|
Left = 0
|
||||||
@ -401,7 +414,7 @@ object MainFrm: TMainFrm
|
|||||||
TabOrder = 2
|
TabOrder = 2
|
||||||
object EdCellAddress: TEdit
|
object EdCellAddress: TEdit
|
||||||
Left = 0
|
Left = 0
|
||||||
Height = 27
|
Height = 23
|
||||||
Top = 0
|
Top = 0
|
||||||
Width = 170
|
Width = 170
|
||||||
Align = alTop
|
Align = alTop
|
||||||
@ -1406,7 +1419,7 @@ object MainFrm: TMainFrm
|
|||||||
left = 272
|
left = 272
|
||||||
top = 264
|
top = 264
|
||||||
Bitmap = {
|
Bitmap = {
|
||||||
4C69280000001000000010000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
|
4C692B0000001000000010000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
|
||||||
FF00FFFFFF00EAC39DFFE6BF96FFE4BB92FFE4BB92FFD1A06CF5D09E6DF6CC96
|
FF00FFFFFF00EAC39DFFE6BF96FFE4BB92FFE4BB92FFD1A06CF5D09E6DF6CC96
|
||||||
5FDAC479427EB2673C09FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
|
5FDAC479427EB2673C09FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
|
||||||
FF00FFFFFF00E5BE96FFFFFFFEFFFDF3E9FFFDF3EAFFFCF2E8FFFAEFE3FFFAF2
|
FF00FFFFFF00E5BE96FFFFFFFEFFFDF3E9FFFDF3EAFFFCF2E8FFFAEFE3FFFAF2
|
||||||
@ -2686,7 +2699,103 @@ object MainFrm: TMainFrm
|
|||||||
63FFCB8E5EFFC98A5BFFC78756FFC38452FFC38452FFC38452FFC38452FFC384
|
63FFCB8E5EFFC98A5BFFC78756FFC38452FFC38452FFC38452FFC38452FFC384
|
||||||
52FFC38452FFBB7742B0FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
|
52FFC38452FFBB7742B0FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
|
||||||
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
|
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
|
||||||
FF00FFFFFF00FFFFFF00FFFFFF00
|
FF00FFFFFF00FFFFFF00FFFFFF00000000000000000000000000000000000000
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
000000000000000000000000000000000000026EB628026EB669026EB679026E
|
||||||
|
B679026EB679026EB679026EB679026EB679026EB679026EB679026EB679026E
|
||||||
|
B679026EB669026EB6280000000000000000026DB46BC1E3F1D9E6FBFFFFE5FA
|
||||||
|
FFFFE5FAFFFFE5FAFFFFE5FAFFFFE5FAFFFFE5FAFFFFE4FAFFFFE4FAFFFFE5FA
|
||||||
|
FFFFBDE2F1D9026DB46B0000000000000000026BB17EE5FAFFFFD9F4FFFFD9F4
|
||||||
|
FFFFD9F4FFFFD9F4FFFFD9F4FFFFD9F4FFFFD9F4FFFFD9F4FFFFD9F4FFFFD9F4
|
||||||
|
FFFFE0F8FFFF026BB17E0000000000000000026AAE81E0F9FFFFD4F2FFFFD4F2
|
||||||
|
FFFFD4F2FFFFD4F2FFFFD4F2FFFFD4F2FFFFD4F2FFFFD4F2FFFFD4F2FFFFD4F2
|
||||||
|
FFFFD9F5FFFF026AAE8100000000000000000268AB84DCF7FFFFCFF0FFFFCFF0
|
||||||
|
FFFFCFF0FFFFC2EDFCFFA8E8F4FF91E3EDFF84E0E9FF7CDEE7FF7CDEE7FF84E0
|
||||||
|
E9FF9CE6EFFF0268AB8400000000000000000266A788D8F4FFFFCCEEFFFFC2EC
|
||||||
|
FCFF9DE5F1FF85E0EAFF82E0E9FF82E0E9FF82E0E9FF82E0E9FF82E0E9FF82E0
|
||||||
|
E9FF8AE2EBFF0266A78800000000000000000264A48CD6F3FFFFB6EBF9FF94E4
|
||||||
|
F0FF8FE3EEFF8FE3EEFF8FE3EEFF8FE3EEFF8FE3EEFF45C05FFF2DB42FFF45C0
|
||||||
|
5FFF91E4EFFF0264A48C00000000000000000261A090C1EFFBFF9EE7F4FF9DE6
|
||||||
|
F4FF9DE6F4FF9DE6F4FF9DE6F4FF9DE6F4FF9DE6F4FF2FB130FF75EE64FF2FB1
|
||||||
|
30FF9DE6F4FF0261A0900000000000000000025F9C8191D0E6E1B0ECF9FFAEEB
|
||||||
|
F9FFADEBF9FFACEBF9FFABEAF9FF4EBB63FF30AC31FF30AC31FF66EB55FF30AC
|
||||||
|
31FF26A529F90D8C27CD0000000000000000025C9832025C9785025C9799025C
|
||||||
|
9799B7EDFDFF025C9799025C97990E8D13EB52E741FF52E741FF52E741FF52E7
|
||||||
|
41FF52E741FF0F9207D600000000000000000000000000000000000000000355
|
||||||
|
8BA603558BA603568D39035993020E8D00990E8C00CC0E8C00CC3DE22CFF0E8C
|
||||||
|
00CC0E8C00CC0E8D00990000000000000000000000000000000000000000034D
|
||||||
|
7DB5034E7F3D000000000000000000000000000000000C8300CC2BDF1AFF0C83
|
||||||
|
00CC000000000000000000000000000000000000000000000000000000000000
|
||||||
|
00000000000000000000000000000000000000000000066D0099056900CC066D
|
||||||
|
0099000000000000000000000000000000000000000000000000000000000000
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
000000000000000000000000000000000000026EB628026EB669026EB679026E
|
||||||
|
B679026EB679026EB679026EB679026EB679026EB679026EB679026EB679026E
|
||||||
|
B679026EB669026EB6280000000000000000026DB46BC1E3F1D9E6FBFFFFE5FA
|
||||||
|
FFFFE5FAFFFFE5FAFFFFE5FAFFFFE5FAFFFFE5FAFFFFE4FAFFFFE4FAFFFFE5FA
|
||||||
|
FFFFBDE2F1D9026DB46B0000000000000000026BB17EE5FAFFFFD9F4FFFFD9F4
|
||||||
|
FFFFD9F4FFFFD9F4FFFFD9F4FFFFD9F4FFFFD9F4FFFFD9F4FFFFD9F4FFFFD9F4
|
||||||
|
FFFFE0F8FFFF026BB17E0000000000000000026AAE81E0F9FFFFD4F2FFFFD4F2
|
||||||
|
FFFFD4F2FFFFD4F2FFFFD4F2FFFFD4F2FFFFD4F2FFFFD4F2FFFFD4F2FFFFD4F2
|
||||||
|
FFFFD9F5FFFF026AAE8100000000000000000268AB84DCF7FFFFCFF0FFFFCFF0
|
||||||
|
FFFFCFF0FFFFC2EDFCFFA8E8F4FF91E3EDFF84E0E9FF7CDEE7FF7CDEE7FF84E0
|
||||||
|
E9FF9CE6EFFF0268AB8400000000000000000266A788D8F4FFFFCCEEFFFFC2EC
|
||||||
|
FCFF9DE5F1FF85E0EAFF82E0E9FF82E0E9FF82E0E9FF82E0E9FF82E0E9FF82E0
|
||||||
|
E9FF8AE2EBFF0266A78800000000000000000264A48CD6F3FFFFB6EBF9FF94E4
|
||||||
|
F0FF8FE3EEFF8FE3EEFF8FE3EEFF8FE3EEFF8FE3EEFF8FE3EEFF8FE3EEFF8FE3
|
||||||
|
EEFF91E4EFFF0264A48C00000000000000000261A090C1EFFBFF9EE7F4FF9DE6
|
||||||
|
F4FF9DE6F4FF9DE6F4FF9DE6F4FF9DE6F4FF9DE6F4FF9DE6F4FF9DE6F4FF9DE6
|
||||||
|
F4FF9DE6F4FF0261A0900000000000000000025F9C8191D0E6E1B0ECF9FFAEEB
|
||||||
|
F9FFADEBF9FFACEBF9FFABEAF9FF445DC7FF222EB7FF222EB7FF222EB7FF222E
|
||||||
|
B7FF1824B2F90018A3CD0000000000000000025C9832025C9785025C9799025C
|
||||||
|
9799B7EDFDFF025C9799025C9799000C97EB5E5EF7FF5E5EF7FF5E5EF7FF5E5E
|
||||||
|
F7FF5E5EF7FF000498D600000000000000000000000000000000000000000355
|
||||||
|
8BA603558BA603568D390359930200008499000080CC000080CC000080CC0000
|
||||||
|
80CC000080CC000084990000000000000000000000000000000000000000034D
|
||||||
|
7DB5034E7F3D0000000000000000000000000000000000000000000000000000
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
000000000000000000000000000000000000026EB628026EB669026EB679026E
|
||||||
|
B679026EB679026EB679026EB679026EB679026EB679026EB679026EB679026E
|
||||||
|
B679026EB669026EB6280000000000000000026DB46BC1E3F1D9E6FBFFFFE5FA
|
||||||
|
FFFFE5FAFFFFE5FAFFFFE5FAFFFFE5FAFFFFE5FAFFFFE4FAFFFFE4FAFFFFE5FA
|
||||||
|
FFFFBDE2F1D9026DB46B0000000000000000026BB17EE5FAFFFFD9F4FFFFD9F4
|
||||||
|
FFFFD9F4FFFFD9F4FFFFD9F4FFFFD9F4FFFFD9F4FFFFD9F4FFFFD9F4FFFFD9F4
|
||||||
|
FFFFE0F8FFFF026BB17E0000000000000000026AAE81E0F9FFFFD4F2FFFFD4F2
|
||||||
|
FFFFD4F2FFFFD4F2FFFFD4F2FFFFD4F2FFFFD4F2FFFFD4F2FFFFD4F2FFFFD4F2
|
||||||
|
FFFFD9F5FFFF026AAE8100000000000000000268AB84DCF7FFFFCFF0FFFFCFF0
|
||||||
|
FFFFCFF0FFFFC2EDFCFFA8E8F4FF91E3EDFF84E0E9FF7CDEE7FF7CDEE7FF70B7
|
||||||
|
D8FF3148E3FF013FB5A300000000000000000266A788D8F4FFFFCCEEFFFFC2EC
|
||||||
|
FCFF9DE5F1FF85E0EAFF82E0E9FF82E0E9FF82E0E9FF82E0E9FF7BCCD3FF5E8E
|
||||||
|
ADFF8080FFFF010FAFE200000000000000000264A48CD6F3FFFFB6EBF9FF94E4
|
||||||
|
F0FF8FE3EEFF8FE3EEFF8FE3EEFF8FE3EEFF8FE3EEFF6BD2E1FF71A2A8FFF7F7
|
||||||
|
F7FF4E7390FF013BA1AC00000000000000000261A090C1EFFBFF9EE7F4FF9DE6
|
||||||
|
F4FF9DE6F4FF9DE6F4FF9DE6F4FF9DE6F4FF76D5E5FF2EADC3FF79E6F7FF6085
|
||||||
|
8DFF83BFCBFF0261A0900000000000000000025F9C8191D0E6E1B0ECF9FFAEEB
|
||||||
|
F9FFADEBF9FFACEBF9FFABEAF9FF80D8E9FF32AFC5FF79E6F7FF2C99AEFF80BF
|
||||||
|
CDFF86CCE5E1025F9C810000000000000000025C9832025C9785025C9799025C
|
||||||
|
9799B7EDFDFF025C97990174A3B2018BABE179E6F7FF017895E5016491B4025C
|
||||||
|
9799025C9785025C983200000000000000000000000000000000000000000355
|
||||||
|
8BA603558BA6016798570196AFB679E6F7FF017E95BE00728944000000000000
|
||||||
|
000000000000000000000000000000000000000000000000000000000000034D
|
||||||
|
7DB5034E7F3D016D917FD9F4FFFF017E95BE0072894400000000000000000000
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
000000000000000000FF014F68AB015F773D0000000000000000000000000000
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
0000000000000000000000000000
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
object ActionList: TActionList
|
object ActionList: TActionList
|
||||||
@ -3203,6 +3312,24 @@ object MainFrm: TMainFrm
|
|||||||
Hint = 'Names and symbols known as valid currencies'
|
Hint = 'Names and symbols known as valid currencies'
|
||||||
OnExecute = AcCurrencySymbolsExecute
|
OnExecute = AcCurrencySymbolsExecute
|
||||||
end
|
end
|
||||||
|
object AcCommentAdd: TAction
|
||||||
|
Caption = 'New comment..'
|
||||||
|
Hint = 'Add comment'
|
||||||
|
ImageIndex = 40
|
||||||
|
OnExecute = AcCommentAddExecute
|
||||||
|
end
|
||||||
|
object AcCommentDelete: TAction
|
||||||
|
Caption = 'Delete comment'
|
||||||
|
Hint = 'Delete comment'
|
||||||
|
ImageIndex = 41
|
||||||
|
OnExecute = AcCommentDeleteExecute
|
||||||
|
end
|
||||||
|
object AcCommentEdit: TAction
|
||||||
|
Caption = 'Edit comment...'
|
||||||
|
Hint = 'Edit comment'
|
||||||
|
ImageIndex = 42
|
||||||
|
OnExecute = AcCommentAddExecute
|
||||||
|
end
|
||||||
end
|
end
|
||||||
object FontDialog: TFontDialog
|
object FontDialog: TFontDialog
|
||||||
MinFontSize = 0
|
MinFontSize = 0
|
||||||
|
@ -83,6 +83,9 @@ type
|
|||||||
AcSortColAsc: TAction;
|
AcSortColAsc: TAction;
|
||||||
AcSort: TAction;
|
AcSort: TAction;
|
||||||
AcCurrencySymbols: TAction;
|
AcCurrencySymbols: TAction;
|
||||||
|
AcCommentAdd: TAction;
|
||||||
|
AcCommentDelete: TAction;
|
||||||
|
AcCommentEdit: TAction;
|
||||||
AcViewInspector: TAction;
|
AcViewInspector: TAction;
|
||||||
AcWordwrap: TAction;
|
AcWordwrap: TAction;
|
||||||
AcVAlignDefault: TAction;
|
AcVAlignDefault: TAction;
|
||||||
@ -248,6 +251,8 @@ type
|
|||||||
ToolButton29: TToolButton;
|
ToolButton29: TToolButton;
|
||||||
ToolButton30: TToolButton;
|
ToolButton30: TToolButton;
|
||||||
ToolButton31: TToolButton;
|
ToolButton31: TToolButton;
|
||||||
|
ToolButton32: TToolButton;
|
||||||
|
ToolButton33: TToolButton;
|
||||||
WorksheetGrid: TsWorksheetGrid;
|
WorksheetGrid: TsWorksheetGrid;
|
||||||
ToolBar1: TToolBar;
|
ToolBar1: TToolBar;
|
||||||
FormatToolBar: TToolBar;
|
FormatToolBar: TToolBar;
|
||||||
@ -280,6 +285,8 @@ type
|
|||||||
procedure AcAddColumnExecute(Sender: TObject);
|
procedure AcAddColumnExecute(Sender: TObject);
|
||||||
procedure AcAddRowExecute(Sender: TObject);
|
procedure AcAddRowExecute(Sender: TObject);
|
||||||
procedure AcBorderExecute(Sender: TObject);
|
procedure AcBorderExecute(Sender: TObject);
|
||||||
|
procedure AcCommentAddExecute(Sender: TObject);
|
||||||
|
procedure AcCommentDeleteExecute(Sender: TObject);
|
||||||
procedure AcCopyFormatExecute(Sender: TObject);
|
procedure AcCopyFormatExecute(Sender: TObject);
|
||||||
procedure AcCSVParamsExecute(Sender: TObject);
|
procedure AcCSVParamsExecute(Sender: TObject);
|
||||||
procedure AcCurrencySymbolsExecute(Sender: TObject);
|
procedure AcCurrencySymbolsExecute(Sender: TObject);
|
||||||
@ -327,10 +334,13 @@ type
|
|||||||
|
|
||||||
private
|
private
|
||||||
FCopiedFormat: TCell;
|
FCopiedFormat: TCell;
|
||||||
|
|
||||||
|
function EditComment(ACaption: String; var AText: String): Boolean;
|
||||||
procedure LoadFile(const AFileName: String);
|
procedure LoadFile(const AFileName: String);
|
||||||
procedure SetupBackgroundColorBox;
|
procedure SetupBackgroundColorBox;
|
||||||
procedure UpdateBackgroundColorIndex;
|
procedure UpdateBackgroundColorIndex;
|
||||||
procedure UpdateCellInfo(ACell: PCell);
|
procedure UpdateCellInfo(ACell: PCell);
|
||||||
|
procedure UpdateCommentActions;
|
||||||
procedure UpdateFontNameIndex;
|
procedure UpdateFontNameIndex;
|
||||||
procedure UpdateFontSizeIndex;
|
procedure UpdateFontSizeIndex;
|
||||||
procedure UpdateFontStyleActions;
|
procedure UpdateFontStyleActions;
|
||||||
@ -353,7 +363,7 @@ var
|
|||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
TypInfo, LCLIntf, LCLType, LCLVersion, fpcanvas,
|
TypInfo, LCLIntf, LCLType, LCLVersion, fpcanvas, Buttons,
|
||||||
fpsutils, fpscsv, fpsNumFormat,
|
fpsutils, fpscsv, fpsNumFormat,
|
||||||
sFormatSettingsForm, sCSVParamsForm, sSortParamsForm, sfCurrencyForm;
|
sFormatSettingsForm, sCSVParamsForm, sSortParamsForm, sfCurrencyForm;
|
||||||
|
|
||||||
@ -479,6 +489,42 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TMainFrm.AcCommentAddExecute(Sender: TObject);
|
||||||
|
var
|
||||||
|
r,c: Cardinal;
|
||||||
|
cell: PCell;
|
||||||
|
comment: String;
|
||||||
|
begin
|
||||||
|
with WorksheetGrid do
|
||||||
|
begin
|
||||||
|
r := GetWorksheetRow(Row);
|
||||||
|
c := GetWorksheetCol(Col);
|
||||||
|
cell := Worksheet.FindCell(r, c);
|
||||||
|
if Worksheet.HasComment(cell) then
|
||||||
|
comment := Worksheet.ReadComment(cell)
|
||||||
|
else
|
||||||
|
comment := '';
|
||||||
|
if EditComment(Format('Comment for cell %s', [GetCellString(r, c)]), comment)
|
||||||
|
then
|
||||||
|
Worksheet.WriteComment(r, c, comment);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TMainFrm.AcCommentDeleteExecute(Sender: TObject);
|
||||||
|
var
|
||||||
|
r, c: Cardinal;
|
||||||
|
cell: PCell;
|
||||||
|
begin
|
||||||
|
with WorksheetGrid do
|
||||||
|
begin
|
||||||
|
r := GetWorksheetRow(Row);
|
||||||
|
c := GetWorksheetCol(Col);
|
||||||
|
cell := Worksheet.FindCell(r, c);
|
||||||
|
if Worksheet.HasComment(cell) then
|
||||||
|
Worksheet.RemoveComment(cell);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TMainFrm.AcAddColumnExecute(Sender: TObject);
|
procedure TMainFrm.AcAddColumnExecute(Sender: TObject);
|
||||||
begin
|
begin
|
||||||
WorksheetGrid.InsertCol(WorksheetGrid.Col);
|
WorksheetGrid.InsertCol(WorksheetGrid.Col);
|
||||||
@ -934,6 +980,53 @@ begin
|
|||||||
WorksheetGrid.FrozenRows := EdFrozenRows.Value;
|
WorksheetGrid.FrozenRows := EdFrozenRows.Value;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TMainFrm.EditComment(ACaption: String; var AText: String): Boolean;
|
||||||
|
var
|
||||||
|
F: TForm;
|
||||||
|
memo: TMemo;
|
||||||
|
panel: TPanel;
|
||||||
|
btn: TBitBtn;
|
||||||
|
begin
|
||||||
|
F := TForm.Create(nil);
|
||||||
|
try
|
||||||
|
F.Caption := ACaption;
|
||||||
|
F.Width := 400;
|
||||||
|
F.Height := 300;
|
||||||
|
F.Position := poMainFormCenter;
|
||||||
|
memo := TMemo.Create(F);
|
||||||
|
memo.Parent := F;
|
||||||
|
memo.Align := alClient;
|
||||||
|
memo.BorderSpacing.Around := 4;
|
||||||
|
memo.Lines.Text := AText;
|
||||||
|
panel := TPanel.Create(F);
|
||||||
|
panel.Parent := F;
|
||||||
|
panel.Align := alBottom;
|
||||||
|
panel.Height := 44;
|
||||||
|
panel.BevelOuter := bvNone;
|
||||||
|
panel.Caption := '';
|
||||||
|
btn := TBitBtn.Create(F);
|
||||||
|
btn.Parent := panel;
|
||||||
|
btn.Kind := bkOK;
|
||||||
|
btn.Left := panel.ClientWidth - 2*btn.Width - 2*8;
|
||||||
|
btn.Top := 6;
|
||||||
|
btn.Anchors := [akTop, akRight];
|
||||||
|
btn := TBitBtn.Create(F);
|
||||||
|
btn.Parent := panel;
|
||||||
|
btn.Kind := bkCancel;
|
||||||
|
btn.Left := panel.ClientWidth - btn.Width - 8;
|
||||||
|
btn.Top := 6;
|
||||||
|
btn.Anchors := [akTop, akRight];
|
||||||
|
if F.ShowModal = mrOK then
|
||||||
|
begin
|
||||||
|
Result := true;
|
||||||
|
AText := memo.Lines.Text;
|
||||||
|
end else
|
||||||
|
Result := false;
|
||||||
|
finally
|
||||||
|
F.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TMainFrm.FontComboBoxSelect(Sender: TObject);
|
procedure TMainFrm.FontComboBoxSelect(Sender: TObject);
|
||||||
var
|
var
|
||||||
fname: String;
|
fname: String;
|
||||||
@ -1246,6 +1339,24 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TMainFrm.UpdateCommentActions;
|
||||||
|
var
|
||||||
|
r, c: Cardinal;
|
||||||
|
cell: PCell;
|
||||||
|
hasCmnt: Boolean;
|
||||||
|
begin
|
||||||
|
with WorksheetGrid do
|
||||||
|
begin
|
||||||
|
r := GetWorksheetRow(Row);
|
||||||
|
c := GetWorksheetCol(Col);
|
||||||
|
cell := Worksheet.FindCell(row, col);
|
||||||
|
hasCmnt := Worksheet.HasComment(cell);
|
||||||
|
end;
|
||||||
|
AcCommentAdd.Enabled := not hasCmnt;
|
||||||
|
AcCommentEdit.Enabled := hasCmnt;
|
||||||
|
AcCommentDelete.Enabled := hasCmnt;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TMainFrm.UpdateFontNameIndex;
|
procedure TMainFrm.UpdateFontNameIndex;
|
||||||
var
|
var
|
||||||
fname: String;
|
fname: String;
|
||||||
@ -1418,6 +1529,7 @@ begin
|
|||||||
UpdateFontStyleActions;
|
UpdateFontStyleActions;
|
||||||
UpdateTextRotationActions;
|
UpdateTextRotationActions;
|
||||||
UpdateNumFormatActions;
|
UpdateNumFormatActions;
|
||||||
|
UpdateCommentActions;
|
||||||
|
|
||||||
UpdateCellInfo(cell);
|
UpdateCellInfo(cell);
|
||||||
end;
|
end;
|
||||||
|
@ -44,7 +44,9 @@ type
|
|||||||
procedure SetWordwrap(const AValue: Boolean);
|
procedure SetWordwrap(const AValue: Boolean);
|
||||||
|
|
||||||
protected
|
protected
|
||||||
function GetWorkbook: TsWorkbook;
|
function GetWorkbook: TsWorkbook; inline;
|
||||||
|
function GetWorksheet: TsWorksheet; inline;
|
||||||
|
|
||||||
public
|
public
|
||||||
property BackgroundColor: TsColor
|
property BackgroundColor: TsColor
|
||||||
read GetBackgroundColor write SetBackgroundColor;
|
read GetBackgroundColor write SetBackgroundColor;
|
||||||
@ -84,37 +86,37 @@ implementation
|
|||||||
|
|
||||||
function TCellHelper.GetBackgroundColor: TsColor;
|
function TCellHelper.GetBackgroundColor: TsColor;
|
||||||
begin
|
begin
|
||||||
Result := Worksheet.ReadBackgroundColor(@self);
|
Result := GetWorksheet.ReadBackgroundColor(@self);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TCellHelper.GetBorder: TsCellBorders;
|
function TCellHelper.GetBorder: TsCellBorders;
|
||||||
begin
|
begin
|
||||||
Result := Worksheet.ReadCellBorders(@self);
|
Result := GetWorksheet.ReadCellBorders(@self);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TCellHelper.GetBorderStyle(const ABorder: TsCellBorder): TsCellBorderStyle;
|
function TCellHelper.GetBorderStyle(const ABorder: TsCellBorder): TsCellBorderStyle;
|
||||||
begin
|
begin
|
||||||
Result := Worksheet.ReadCellBorderStyle(@self, ABorder);
|
Result := GetWorksheet.ReadCellBorderStyle(@self, ABorder);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TCellHelper.GetBorderStyles: TsCellBorderStyles;
|
function TCellHelper.GetBorderStyles: TsCellBorderStyles;
|
||||||
begin
|
begin
|
||||||
Result := Worksheet.ReadCellBorderStyles(@self);
|
Result := GetWorksheet.ReadCellBorderStyles(@self);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TCellHelper.GetCellFormat: TsCellFormat;
|
function TCellHelper.GetCellFormat: TsCellFormat;
|
||||||
begin
|
begin
|
||||||
Result := Workbook.GetCellFormat(FormatIndex);
|
Result := GetWorkbook.GetCellFormat(FormatIndex);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TCellHelper.GetComment: String;
|
function TCellHelper.GetComment: String;
|
||||||
begin
|
begin
|
||||||
Result := Worksheet.ReadComment(@self);
|
Result := GetWorksheet.ReadComment(@self);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TCellHelper.GetFont: TsFont;
|
function TCellHelper.GetFont: TsFont;
|
||||||
begin
|
begin
|
||||||
Result := Worksheet.ReadCellFont(@self);
|
Result := GetWorksheet.ReadCellFont(@self);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TCellHelper.GetFontIndex: Integer;
|
function TCellHelper.GetFontIndex: Integer;
|
||||||
@ -127,12 +129,12 @@ end;
|
|||||||
|
|
||||||
function TCellHelper.GetHorAlignment: TsHorAlignment;
|
function TCellHelper.GetHorAlignment: TsHorAlignment;
|
||||||
begin
|
begin
|
||||||
Result := Worksheet.ReadHorAlignment(@Self);
|
Result := GetWorksheet.ReadHorAlignment(@Self);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TCellHelper.GetHyperlink: TsHyperlink;
|
function TCellHelper.GetHyperlink: TsHyperlink;
|
||||||
begin
|
begin
|
||||||
Result := Worksheet.ReadHyperlink(@self);
|
Result := GetWorksheet.ReadHyperlink(@self);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TCellHelper.GetNumberFormat: TsNumberFormat;
|
function TCellHelper.GetNumberFormat: TsNumberFormat;
|
||||||
@ -153,73 +155,78 @@ end;
|
|||||||
|
|
||||||
function TCellHelper.GetTextRotation: TsTextRotation;
|
function TCellHelper.GetTextRotation: TsTextRotation;
|
||||||
begin
|
begin
|
||||||
Result := Worksheet.ReadTextRotation(@Self);
|
Result := GetWorksheet.ReadTextRotation(@Self);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TCellHelper.GetUsedFormattingFields: TsUsedFormattingFields;
|
function TCellHelper.GetUsedFormattingFields: TsUsedFormattingFields;
|
||||||
begin
|
begin
|
||||||
Result := Worksheet.ReadUsedFormatting(@Self);
|
Result := GetWorksheet.ReadUsedFormatting(@Self);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TCellHelper.GetVertAlignment: TsVertAlignment;
|
function TCellHelper.GetVertAlignment: TsVertAlignment;
|
||||||
begin
|
begin
|
||||||
Result := Worksheet.ReadVertAlignment(@self);
|
Result := GetWorksheet.ReadVertAlignment(@self);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TCellHelper.GetWordwrap: Boolean;
|
function TCellHelper.GetWordwrap: Boolean;
|
||||||
begin
|
begin
|
||||||
Result := Worksheet.ReadWordwrap(@self);
|
Result := GetWorksheet.ReadWordwrap(@self);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TCellHelper.GetWorkbook: TsWorkbook;
|
function TCellHelper.GetWorkbook: TsWorkbook;
|
||||||
begin
|
begin
|
||||||
Result := Worksheet.Workbook;
|
Result := GetWorksheet.Workbook;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TCellHelper.GetWorksheet: TsWorksheet;
|
||||||
|
begin
|
||||||
|
Result := TsWorksheet(Worksheet);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCellHelper.SetBackgroundColor(const AValue: TsColor);
|
procedure TCellHelper.SetBackgroundColor(const AValue: TsColor);
|
||||||
begin
|
begin
|
||||||
Worksheet.WriteBackgroundColor(@self, AValue);
|
GetWorksheet.WriteBackgroundColor(@self, AValue);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCellHelper.SetBorder(const AValue: TsCellBorders);
|
procedure TCellHelper.SetBorder(const AValue: TsCellBorders);
|
||||||
begin
|
begin
|
||||||
Worksheet.WriteBorders(@self, AValue);
|
GetWorksheet.WriteBorders(@self, AValue);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCellHelper.SetBorderStyle(const ABorder: TsCellBorder;
|
procedure TCellHelper.SetBorderStyle(const ABorder: TsCellBorder;
|
||||||
const AValue: TsCellBorderStyle);
|
const AValue: TsCellBorderStyle);
|
||||||
begin
|
begin
|
||||||
Worksheet.WriteBorderStyle(@self, ABorder, AValue);
|
GetWorksheet.WriteBorderStyle(@self, ABorder, AValue);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCellHelper.SetBorderStyles(const AValue: TsCellBorderStyles);
|
procedure TCellHelper.SetBorderStyles(const AValue: TsCellBorderStyles);
|
||||||
begin
|
begin
|
||||||
Worksheet.WriteBorderStyles(@self, AValue);
|
GetWorksheet.WriteBorderStyles(@self, AValue);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCellHelper.SetCellFormat(const AValue: TsCellFormat);
|
procedure TCellHelper.SetCellFormat(const AValue: TsCellFormat);
|
||||||
begin
|
begin
|
||||||
Worksheet.WriteCellFormat(@self, AValue);
|
GetWorksheet.WriteCellFormat(@self, AValue);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCellHelper.SetComment(const AValue: String);
|
procedure TCellHelper.SetComment(const AValue: String);
|
||||||
begin
|
begin
|
||||||
Worksheet.WriteComment(@self, AValue);
|
GetWorksheet.WriteComment(@self, AValue);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCellHelper.SetFontIndex(const AValue: Integer);
|
procedure TCellHelper.SetFontIndex(const AValue: Integer);
|
||||||
begin
|
begin
|
||||||
Worksheet.WriteFont(@self, AValue);
|
GetWorksheet.WriteFont(@self, AValue);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCellHelper.SetHorAlignment(const AValue: TsHorAlignment);
|
procedure TCellHelper.SetHorAlignment(const AValue: TsHorAlignment);
|
||||||
begin
|
begin
|
||||||
Worksheet.WriteHorAlignment(@self, AValue);
|
GetWorksheet.WriteHorAlignment(@self, AValue);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCellHelper.SetHyperlink(const AValue: TsHyperlink);
|
procedure TCellHelper.SetHyperlink(const AValue: TsHyperlink);
|
||||||
begin
|
begin
|
||||||
Worksheet.WriteHyperlink(@self, AValue.Target, AValue.Tooltip);
|
GetWorksheet.WriteHyperlink(@self, AValue.Target, AValue.Tooltip);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCellHelper.SetNumberFormat(const AValue: TsNumberFormat);
|
procedure TCellHelper.SetNumberFormat(const AValue: TsNumberFormat);
|
||||||
@ -228,7 +235,7 @@ var
|
|||||||
begin
|
begin
|
||||||
fmt := Workbook.GetCellFormat(FormatIndex);
|
fmt := Workbook.GetCellFormat(FormatIndex);
|
||||||
fmt.NumberFormat := AValue;
|
fmt.NumberFormat := AValue;
|
||||||
Worksheet.WriteCellFormat(@self, fmt);
|
GetWorksheet.WriteCellFormat(@self, fmt);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCellHelper.SetNumberFormatStr(const AValue: String);
|
procedure TCellHelper.SetNumberFormatStr(const AValue: String);
|
||||||
@ -237,27 +244,27 @@ var
|
|||||||
begin
|
begin
|
||||||
fmt := Workbook.GetCellFormat(FormatIndex);
|
fmt := Workbook.GetCellFormat(FormatIndex);
|
||||||
fmt.NumberFormatStr := AValue;
|
fmt.NumberFormatStr := AValue;
|
||||||
Worksheet.WriteCellFormat(@self, fmt);
|
GetWorksheet.WriteCellFormat(@self, fmt);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCellHelper.SetTextRotation(const AValue: TsTextRotation);
|
procedure TCellHelper.SetTextRotation(const AValue: TsTextRotation);
|
||||||
begin
|
begin
|
||||||
Worksheet.WriteTextRotation(@self, AValue);
|
GetWorksheet.WriteTextRotation(@self, AValue);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCellHelper.SetUsedFormattingFields(const AValue: TsUsedFormattingFields);
|
procedure TCellHelper.SetUsedFormattingFields(const AValue: TsUsedFormattingFields);
|
||||||
begin
|
begin
|
||||||
Worksheet.WriteUsedFormatting(@self, AValue);
|
GetWorksheet.WriteUsedFormatting(@self, AValue);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCellHelper.SetVertAlignment(const AValue: TsVertAlignment);
|
procedure TCellHelper.SetVertAlignment(const AValue: TsVertAlignment);
|
||||||
begin
|
begin
|
||||||
Worksheet.WriteVertAlignment(@self, AValue);
|
GetWorksheet.WriteVertAlignment(@self, AValue);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCellHelper.SetWordwrap(const AValue: Boolean);
|
procedure TCellHelper.SetWordwrap(const AValue: Boolean);
|
||||||
begin
|
begin
|
||||||
Worksheet.WriteWordwrap(@self, AValue);
|
GetWorksheet.WriteWordwrap(@self, AValue);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,35 +9,122 @@ uses
|
|||||||
fpstypes;
|
fpstypes;
|
||||||
|
|
||||||
type
|
type
|
||||||
|
{ forward declarations }
|
||||||
|
TsRowColAVLTree = class;
|
||||||
|
|
||||||
{ TsRowCol }
|
{ TsRowCol }
|
||||||
TsRowCol = record
|
TsRowCol = record
|
||||||
Row, Col: Cardinal;
|
Row, Col: LongInt;
|
||||||
end;
|
end;
|
||||||
PsRowCol = ^TsRowCol;
|
PsRowCol = ^TsRowCol;
|
||||||
|
|
||||||
|
{ TAVLTreeNodeStack }
|
||||||
|
TAVLTreeNodeStack = class(TFPList)
|
||||||
|
public
|
||||||
|
procedure Push(ANode: TAVLTreeNode);
|
||||||
|
function Pop: TAVLTreeNode;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TsRowColEnumerator }
|
||||||
|
TsRowColEnumerator = class
|
||||||
|
protected
|
||||||
|
FCurrentNode: TAVLTreeNode;
|
||||||
|
FTree: TsRowColAVLTree;
|
||||||
|
FStartRow, FEndRow, FStartCol, FEndCol: LongInt;
|
||||||
|
FReverse: Boolean;
|
||||||
|
function GetCurrent: PsRowCol;
|
||||||
|
public
|
||||||
|
constructor Create(ATree: TsRowColAVLTree;
|
||||||
|
AStartRow, AStartCol, AEndRow, AEndCol: LongInt; AReverse: Boolean);
|
||||||
|
function GetEnumerator: TsRowColEnumerator; inline;
|
||||||
|
function MoveNext: Boolean;
|
||||||
|
property Current: PsRowCol read GetCurrent;
|
||||||
|
property StartRow: LongInt read FStartRow;
|
||||||
|
property EndRow: LongInt read FEndRow;
|
||||||
|
property StartCol: LongInt read FStartCol;
|
||||||
|
property EndCol: LongInt read FEndCol;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TsRowColAVLTree }
|
{ TsRowColAVLTree }
|
||||||
TsRowColAVLTree = class(TAVLTree)
|
TsRowColAVLTree = class(TAVLTree)
|
||||||
private
|
private
|
||||||
FOwnsData: Boolean;
|
FOwnsData: Boolean;
|
||||||
FCurrentNode: TAVLTreeNode;
|
FCurrentNode: TAVLTreeNode;
|
||||||
|
FCurrentNodeStack: TAVLTreeNodeStack;
|
||||||
protected
|
protected
|
||||||
procedure DisposeData(var AData: Pointer); virtual; abstract;
|
procedure DisposeData(var AData: Pointer); virtual; abstract;
|
||||||
function NewData: Pointer; virtual; abstract;
|
function NewData: Pointer; virtual; abstract;
|
||||||
public
|
public
|
||||||
constructor Create(AOwnsData: Boolean = true);
|
constructor Create(AOwnsData: Boolean = true);
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
function Add(ARow, ACol: Cardinal): PsRowCol;
|
function Add(ARow, ACol: LongInt): PsRowCol;
|
||||||
procedure Clear;
|
procedure Clear;
|
||||||
procedure Delete(ANode: TAVLTreeNode);
|
procedure Delete(ANode: TAVLTreeNode); overload;
|
||||||
procedure DeleteRowOrCol(AIndex: Cardinal; IsRow: Boolean); virtual;
|
procedure Delete(ARow, ACol: LongInt); overload;
|
||||||
function Find(ARow, ACol: Cardinal): PsRowCol;
|
procedure DeleteRowOrCol(AIndex: LongInt; IsRow: Boolean); virtual;
|
||||||
|
procedure Exchange(ARow1, ACol1, ARow2, ACol2: LongInt); virtual;
|
||||||
|
function Find(ARow, ACol: LongInt): PsRowCol; overload;
|
||||||
|
function GetData(ANode: TAVLTreeNode): PsRowCol;
|
||||||
function GetFirst: PsRowCol;
|
function GetFirst: PsRowCol;
|
||||||
|
function GetLast: PsRowCol;
|
||||||
function GetNext: PsRowCol;
|
function GetNext: PsRowCol;
|
||||||
procedure InsertRowOrCol(AIndex: Cardinal; IsRow: Boolean);
|
function GetPrev: PsRowCol;
|
||||||
procedure Remove(ARow, ACol: Cardinal);
|
procedure InsertRowOrCol(AIndex: LongInt; IsRow: Boolean);
|
||||||
|
procedure Remove(ARow, ACol: LongInt); overload;
|
||||||
|
procedure PushCurrent;
|
||||||
|
procedure PopCurrent;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TsCells }
|
||||||
|
TsCellEnumerator = class(TsRowColEnumerator)
|
||||||
|
protected
|
||||||
|
function GetCurrent: PCell;
|
||||||
|
public
|
||||||
|
function GetEnumerator: TsCellEnumerator; inline;
|
||||||
|
property Current: PCell read GetCurrent;
|
||||||
|
end;
|
||||||
|
|
||||||
|
TsCells = class(TsRowColAVLTree)
|
||||||
|
private
|
||||||
|
FWorksheet: Pointer; // Must be cast to TsWorksheet
|
||||||
|
protected
|
||||||
|
procedure DisposeData(var AData: Pointer); override;
|
||||||
|
function NewData: Pointer; override;
|
||||||
|
public
|
||||||
|
constructor Create(AWorksheet: Pointer; AOwnsData: Boolean = true);
|
||||||
|
function AddCell(ARow, ACol: LongInt): PCell;
|
||||||
|
procedure DeleteCell(ARow, ACol: LongInt);
|
||||||
|
function FindCell(ARow, ACol: LongInt): PCell;
|
||||||
|
function GetFirstCell: PCell;
|
||||||
|
function GetLastCell: PCell;
|
||||||
|
function GetNextCell: PCell;
|
||||||
|
function GetPrevCell: PCell;
|
||||||
|
// enumerators
|
||||||
|
function GetEnumerator: TsCellEnumerator;
|
||||||
|
function GetReverseEnumerator: TsCellEnumerator;
|
||||||
|
function GetColEnumerator(ACol: LongInt; AStartRow: Longint = 0;
|
||||||
|
AEndRow: Longint = $7FFFFFFF): TsCellEnumerator;
|
||||||
|
function GetRangeEnumerator(AStartRow, AStartCol,
|
||||||
|
AEndRow, AEndCol: Longint): TsCellEnumerator;
|
||||||
|
function GetRowEnumerator(ARow: LongInt; AStartCol:LongInt = 0;
|
||||||
|
AEndCol: Longint = $7FFFFFFF): TsCellEnumerator;
|
||||||
|
function GetReverseColEnumerator(ACol: LongInt; AStartRow: Longint = 0;
|
||||||
|
AEndRow: Longint = $7FFFFFFF): TsCellEnumerator;
|
||||||
|
function GetReverseRangeEnumerator(AStartRow, AStartCol,
|
||||||
|
AEndRow, AEndCol: Longint): TsCellEnumerator;
|
||||||
|
function GetReverseRowEnumerator(ARow: LongInt; AStartCol:LongInt = 0;
|
||||||
|
AEndCol: Longint = $7FFFFFFF): TsCellEnumerator;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TsComments }
|
{ TsComments }
|
||||||
|
TsCommentEnumerator = class(TsRowColEnumerator)
|
||||||
|
protected
|
||||||
|
function GetCurrent: PsComment;
|
||||||
|
public
|
||||||
|
function GetEnumerator: TsCommentEnumerator; inline;
|
||||||
|
property Current: PsComment read GetCurrent;
|
||||||
|
end;
|
||||||
|
|
||||||
TsComments = class(TsRowColAVLTree)
|
TsComments = class(TsRowColAVLTree)
|
||||||
protected
|
protected
|
||||||
procedure DisposeData(var AData: Pointer); override;
|
procedure DisposeData(var AData: Pointer); override;
|
||||||
@ -45,16 +132,33 @@ type
|
|||||||
public
|
public
|
||||||
function AddComment(ARow, ACol: Cardinal; AComment: String): PsComment;
|
function AddComment(ARow, ACol: Cardinal; AComment: String): PsComment;
|
||||||
procedure DeleteComment(ARow, ACol: Cardinal);
|
procedure DeleteComment(ARow, ACol: Cardinal);
|
||||||
|
// enumerators
|
||||||
|
function GetEnumerator: TsCommentEnumerator;
|
||||||
|
function GetRangeEnumerator(AStartRow, AStartCol,
|
||||||
|
AEndRow, AEndCol: Longint): TsCommentEnumerator;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TsHyperlinks }
|
{ TsHyperlinks }
|
||||||
|
TsHyperlinkEnumerator = class(TsRowColEnumerator)
|
||||||
|
protected
|
||||||
|
function GetCurrent: PsHyperlink;
|
||||||
|
public
|
||||||
|
function GetEnumerator: TsHyperlinkEnumerator; inline;
|
||||||
|
property Current: PsHyperlink read GetCurrent;
|
||||||
|
end;
|
||||||
|
|
||||||
TsHyperlinks = class(TsRowColAVLTree)
|
TsHyperlinks = class(TsRowColAVLTree)
|
||||||
protected
|
protected
|
||||||
procedure DisposeData(var AData: Pointer); override;
|
procedure DisposeData(var AData: Pointer); override;
|
||||||
function NewData: Pointer; override;
|
function NewData: Pointer; override;
|
||||||
public
|
public
|
||||||
function AddHyperlink(ARow, ACol: Cardinal; ATarget: String; ATooltip: String = ''): PsHyperlink;
|
function AddHyperlink(ARow, ACol: Longint; ATarget: String;
|
||||||
procedure DeleteHyperlink(ARow, ACol: Cardinal);
|
ATooltip: String = ''): PsHyperlink;
|
||||||
|
procedure DeleteHyperlink(ARow, ACol: Longint);
|
||||||
|
// enumerators
|
||||||
|
function GetEnumerator: TsHyperlinkEnumerator;
|
||||||
|
function GetRangeEnumerator(AStartRow, AStartCol,
|
||||||
|
AEndRow, AEndCol: Longint): TsHyperlinkEnumerator;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TsMergedCells }
|
{ TsMergedCells }
|
||||||
@ -63,16 +167,17 @@ type
|
|||||||
procedure DisposeData(var AData: Pointer); override;
|
procedure DisposeData(var AData: Pointer); override;
|
||||||
function NewData: Pointer; override;
|
function NewData: Pointer; override;
|
||||||
public
|
public
|
||||||
function AddRange(ARow1, ACol1, ARow2, ACol2: Cardinal): PsCellRange;
|
function AddRange(ARow1, ACol1, ARow2, ACol2: Longint): PsCellRange;
|
||||||
procedure DeleteRange(ARow, ACol: Cardinal);
|
procedure DeleteRange(ARow, ACol: Longint);
|
||||||
procedure DeleteRowOrCol(AIndex: Cardinal; IsRow: Boolean); override;
|
procedure DeleteRowOrCol(AIndex: Longint; IsRow: Boolean); override;
|
||||||
function FindRangeWithCell(ARow, ACol: Cardinal): PsCellRange;
|
procedure Exchange(ARow1, ACol1, ARow2, ACol2: Longint); override;
|
||||||
|
function FindRangeWithCell(ARow, ACol: Longint): PsCellRange;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
fpspreadsheet;
|
Math, fpsUtils;
|
||||||
|
|
||||||
function CompareRowCol(Item1, Item2: Pointer): Integer;
|
function CompareRowCol(Item1, Item2: Pointer): Integer;
|
||||||
begin
|
begin
|
||||||
@ -82,6 +187,103 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TAVLTreeNodeStack.Pop: TAVLTreeNode;
|
||||||
|
begin
|
||||||
|
Result := TAVLTreeNode(Items[Count-1]);
|
||||||
|
Delete(Count-1);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TAVLTreeNodeStack.Push(ANode: TAVLTreeNode);
|
||||||
|
begin
|
||||||
|
Add(ANode);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{******************************************************************************}
|
||||||
|
{ TsRowColEnumerator: A specialized enumerator for TsRowColAVLTree using the }
|
||||||
|
{ pointers to the data records. }
|
||||||
|
{******************************************************************************}
|
||||||
|
|
||||||
|
constructor TsRowColEnumerator.Create(ATree: TsRowColAVLTree;
|
||||||
|
AStartRow, AStartCol, AEndRow, AEndCol: LongInt; AReverse: Boolean);
|
||||||
|
begin
|
||||||
|
FTree := ATree;
|
||||||
|
FReverse := AReverse;
|
||||||
|
// Rearrange col/row indexes such that iteration always begins with "StartXXX"
|
||||||
|
if AStartRow <= AEndRow then
|
||||||
|
begin
|
||||||
|
FStartRow := IfThen(AReverse, AEndRow, AStartRow);
|
||||||
|
FEndRow := IfThen(AReverse, AStartRow, AEndRow);
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
FStartRow := IfThen(AReverse, AStartRow, AEndRow);
|
||||||
|
FEndRow := IfThen(AReverse, AEndRow, AStartRow);
|
||||||
|
end;
|
||||||
|
if AStartCol <= AEndCol then
|
||||||
|
begin
|
||||||
|
FStartCol := IfThen(AReverse, AEndCol, AStartCol);
|
||||||
|
FEndCol := IfThen(AReverse, AStartCol, AEndCol);
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
FStartCol := IfThen(AReverse, AStartCol, AEndCol);
|
||||||
|
FEndCol := IfThen(AReverse, AEndCol, AStartCol);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsRowColEnumerator.GetCurrent: PsRowCol;
|
||||||
|
begin
|
||||||
|
if Assigned(FCurrentNode) then
|
||||||
|
Result := PsRowCol(FCurrentNode.Data)
|
||||||
|
else
|
||||||
|
Result := nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsRowColEnumerator.GetEnumerator: TsRowColEnumerator;
|
||||||
|
begin
|
||||||
|
Result := self;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsRowColEnumerator.MoveNext: Boolean;
|
||||||
|
var
|
||||||
|
r1,c1,r2,c2: LongInt;
|
||||||
|
item: TsRowCol;
|
||||||
|
begin
|
||||||
|
if FCurrentNode <> nil then begin
|
||||||
|
if FReverse then
|
||||||
|
begin
|
||||||
|
FCurrentNode := FTree.FindPrecessor(FCurrentNode);
|
||||||
|
while (FCurrentNode <> nil) and
|
||||||
|
( (Current^.Col < FEndCol) or (Current^.Col > FStartCol) or
|
||||||
|
(Current^.Row < FEndRow) or (Current^.Row > FStartRow) )
|
||||||
|
do
|
||||||
|
FCurrentNode := FTree.FindPrecessor(FCurrentNode);
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
FCurrentNode := FTree.FindSuccessor(FCurrentNode);
|
||||||
|
while (FCurrentNode <> nil) and
|
||||||
|
( (Current^.Col < FStartCol) or (Current^.Col > FEndCol) or
|
||||||
|
(Current^.Row < FStartRow) or (Current^.Row > FEndRow) )
|
||||||
|
do
|
||||||
|
FCurrentNode := FTree.FindSuccessor(FCurrentNode);
|
||||||
|
end;
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
if FReverse and (FStartRow = $7FFFFFFF) and (FStartCol = $7FFFFFFF) then
|
||||||
|
FCurrentNode := FTree.FindHighest
|
||||||
|
else
|
||||||
|
if not FReverse and (FStartRow = 0) and (FStartCol = 0) then
|
||||||
|
FCurrentNode := FTree.FindLowest
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
item.Row := FStartRow;
|
||||||
|
item.Col := FStartCol;
|
||||||
|
FCurrentNode := FTree.Find(@item);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
Result := FCurrentNode <> nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
{******************************************************************************}
|
{******************************************************************************}
|
||||||
{ TsRowColAVLTree: A specialized AVLTree working with records containing }
|
{ TsRowColAVLTree: A specialized AVLTree working with records containing }
|
||||||
{ row and column indexes. }
|
{ row and column indexes. }
|
||||||
@ -96,6 +298,7 @@ constructor TsRowColAVLTree.Create(AOwnsData: Boolean = true);
|
|||||||
begin
|
begin
|
||||||
inherited Create(@CompareRowCol);
|
inherited Create(@CompareRowCol);
|
||||||
FOwnsData := AOwnsData;
|
FOwnsData := AOwnsData;
|
||||||
|
FCurrentNodeStack := TAVLTreeNodeStack.Create;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
@ -104,6 +307,7 @@ end;
|
|||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
destructor TsRowColAVLTree.Destroy;
|
destructor TsRowColAVLTree.Destroy;
|
||||||
begin
|
begin
|
||||||
|
FCurrentNodeStack.Free;
|
||||||
Clear;
|
Clear;
|
||||||
inherited;
|
inherited;
|
||||||
end;
|
end;
|
||||||
@ -112,10 +316,8 @@ end;
|
|||||||
Adds a new node to the tree identified by the specified row and column
|
Adds a new node to the tree identified by the specified row and column
|
||||||
indexes.
|
indexes.
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
function TsRowColAVLTree.Add(ARow, ACol: Cardinal): PsRowCol;
|
function TsRowColAVLTree.Add(ARow, ACol: LongInt): PsRowCol;
|
||||||
begin
|
begin
|
||||||
Result := Find(ARow, ACol);
|
|
||||||
if Result = nil then
|
|
||||||
Result := NewData;
|
Result := NewData;
|
||||||
Result^.Row := ARow;
|
Result^.Row := ARow;
|
||||||
Result^.Col := ACol;
|
Result^.Col := ACol;
|
||||||
@ -149,6 +351,18 @@ begin
|
|||||||
inherited Delete(ANode);
|
inherited Delete(ANode);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TsRowColAVLTree.Delete(ARow, ACol: LongInt);
|
||||||
|
var
|
||||||
|
node: TAVLTreeNode;
|
||||||
|
cell: TCell;
|
||||||
|
begin
|
||||||
|
cell.Row := ARow;
|
||||||
|
cell.Col := ACol;
|
||||||
|
node := inherited Find(@cell);
|
||||||
|
if Assigned(node) then
|
||||||
|
Delete(node);
|
||||||
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
This procedure adjusts row or column indexes stored in the tree nodes if a
|
This procedure adjusts row or column indexes stored in the tree nodes if a
|
||||||
row or column will be deleted from the underlying worksheet.
|
row or column will be deleted from the underlying worksheet.
|
||||||
@ -157,7 +371,7 @@ end;
|
|||||||
to be deleted
|
to be deleted
|
||||||
@param IsRow Identifies whether AIndex refers to a row or column index
|
@param IsRow Identifies whether AIndex refers to a row or column index
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
procedure TsRowColAVLTree.DeleteRowOrCol(AIndex: Cardinal; IsRow: Boolean);
|
procedure TsRowColAVLTree.DeleteRowOrCol(AIndex: LongInt; IsRow: Boolean);
|
||||||
var
|
var
|
||||||
node, nextnode: TAVLTreeNode;
|
node, nextnode: TAVLTreeNode;
|
||||||
item: PsRowCol;
|
item: PsRowCol;
|
||||||
@ -189,12 +403,54 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Exchanges two nodes
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
procedure TsRowColAVLTree.Exchange(ARow1, ACol1, ARow2, ACol2: LongInt);
|
||||||
|
var
|
||||||
|
item1, item2: PsRowCol;
|
||||||
|
begin
|
||||||
|
item1 := Find(ARow1, ACol1);
|
||||||
|
item2 := Find(ARow2, ACol2);
|
||||||
|
|
||||||
|
// There are entries for both locations: Exchange row/col indexes
|
||||||
|
if (item1 <> nil) and (item2 <> nil) then
|
||||||
|
begin
|
||||||
|
Remove(item1);
|
||||||
|
Remove(item2);
|
||||||
|
item1^.Row := ARow2;
|
||||||
|
item1^.Col := ACol2;
|
||||||
|
item2^.Row := ARow1;
|
||||||
|
item2^.Col := ACol1;
|
||||||
|
inherited Add(item1);
|
||||||
|
inherited Add(item2);
|
||||||
|
end else
|
||||||
|
|
||||||
|
// Only the 1tst item exists --> give it the row/col indexes of the 2nd item
|
||||||
|
if (item1 <> nil) then
|
||||||
|
begin
|
||||||
|
Remove(item1);
|
||||||
|
item1^.Row := ARow2;
|
||||||
|
item1^.Col := ACol2;
|
||||||
|
inherited Add(item1);
|
||||||
|
end else
|
||||||
|
|
||||||
|
// Only the 2nd item exists --> give it the row/col indexes of the 1st item
|
||||||
|
if (item2 <> nil) then
|
||||||
|
begin
|
||||||
|
Remove(item2);
|
||||||
|
item2^.Row := ARow1;
|
||||||
|
item2^.Col := ACol1;
|
||||||
|
inherited Add(item2); // just adds the existing item at the new position
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Seeks the entire tree for a node of the specified row and column indexes and
|
Seeks the entire tree for a node of the specified row and column indexes and
|
||||||
returns a pointer to the data record.
|
returns a pointer to the data record.
|
||||||
Returns nil if such a node does not exist
|
Returns nil if such a node does not exist
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
function TsRowColAVLTree.Find(ARow, ACol: Cardinal): PsRowCol;
|
function TsRowColAVLTree.Find(ARow, ACol: LongInt): PsRowCol;
|
||||||
var
|
var
|
||||||
data: TsRowCol;
|
data: TsRowCol;
|
||||||
node: TAVLTreeNode;
|
node: TAVLTreeNode;
|
||||||
@ -210,6 +466,33 @@ begin
|
|||||||
Result := PsRowCol(node.Data);
|
Result := PsRowCol(node.Data);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Extracts the pointer to the data record from a tree node
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
function TsRowColAVLTree.GetData(ANode: TAVLTreeNode): PsRowCol;
|
||||||
|
begin
|
||||||
|
if ANode <> nil then
|
||||||
|
Result := PsRowCol(ANode.Data)
|
||||||
|
else
|
||||||
|
Result := nil;
|
||||||
|
end;
|
||||||
|
(*
|
||||||
|
function TsRowColAVLTree.GetEnumerator: TsRowColEnumerator;
|
||||||
|
begin
|
||||||
|
Result := TsRowColEnumerator.Create(self);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsRowColAVLTree.GetColEnumerator(ACol: LongInt): TsRowColEnumerator;
|
||||||
|
begin
|
||||||
|
Result := TsRowColEnumerator.Create(self, -1, ACol, -1, ACol);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsRowColAVLTree.GetRowEnumerator(ARow: LongInt): TsRowColEnumerator;
|
||||||
|
begin
|
||||||
|
Result := TsRowColEnumerator.Create(self, ARow, -1, ARow, -1);
|
||||||
|
end;
|
||||||
|
*)
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
The combination of the methods GetFirst and GetNext allow a fast iteration
|
The combination of the methods GetFirst and GetNext allow a fast iteration
|
||||||
through all nodes of the tree.
|
through all nodes of the tree.
|
||||||
@ -217,19 +500,27 @@ end;
|
|||||||
function TsRowColAVLTree.GetFirst: PsRowCol;
|
function TsRowColAVLTree.GetFirst: PsRowCol;
|
||||||
begin
|
begin
|
||||||
FCurrentNode := FindLowest;
|
FCurrentNode := FindLowest;
|
||||||
if FCurrentNode <> nil then
|
Result := GetData(FCurrentNode);
|
||||||
Result := PsRowCol(FCurrentNode.Data)
|
end;
|
||||||
else
|
|
||||||
Result := nil;
|
function TsRowColAVLTree.GetLast: PsRowCol;
|
||||||
|
begin
|
||||||
|
FCurrentNode := FindHighest;
|
||||||
|
Result := GetData(FCurrentNode);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TsRowColAVLTree.GetNext: PsRowCol;
|
function TsRowColAVLTree.GetNext: PsRowCol;
|
||||||
begin
|
begin
|
||||||
FCurrentNode := FindSuccessor(FCurrentNode);
|
|
||||||
if FCurrentNode <> nil then
|
if FCurrentNode <> nil then
|
||||||
Result := PsRowCol(FCurrentNode.Data)
|
FCurrentNode := FindSuccessor(FCurrentNode);
|
||||||
else
|
Result := GetData(FCurrentNode);
|
||||||
Result := nil;
|
end;
|
||||||
|
|
||||||
|
function TsRowColAVLTree.GetPrev: PsRowCol;
|
||||||
|
begin
|
||||||
|
if FCurrentNode <> nil then
|
||||||
|
FCurrentNode := FindPrecessor(FCurrentNode);
|
||||||
|
Result := GetData(FCurrentNode);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
@ -240,7 +531,7 @@ end;
|
|||||||
to be inserted
|
to be inserted
|
||||||
@param IsRow Identifies whether AIndex refers to a row or column index
|
@param IsRow Identifies whether AIndex refers to a row or column index
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
procedure TsRowColAVLTree.InsertRowOrCol(AIndex: Cardinal; IsRow: Boolean);
|
procedure TsRowColAVLTree.InsertRowOrCol(AIndex: LongInt; IsRow: Boolean);
|
||||||
var
|
var
|
||||||
node: TAVLTreeNode;
|
node: TAVLTreeNode;
|
||||||
item: PsRowCol;
|
item: PsRowCol;
|
||||||
@ -260,10 +551,9 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Removes the node and destroys the associated data reocrd (if the tree has
|
Removes the node, but does NOT destroy the associated data reocrd
|
||||||
been created with AOwnsData=true) for the specified row and column indexes.
|
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
procedure TsRowColAVLTree.Remove(ARow, ACol: Cardinal);
|
procedure TsRowColAVLTree.Remove(ARow, ACol: LongInt);
|
||||||
var
|
var
|
||||||
node: TAVLTreeNode;
|
node: TAVLTreeNode;
|
||||||
item: TsRowCol;
|
item: TsRowCol;
|
||||||
@ -271,12 +561,215 @@ begin
|
|||||||
item.Row := ARow;
|
item.Row := ARow;
|
||||||
item.Col := ACol;
|
item.Col := ACol;
|
||||||
node := inherited Find(@item);
|
node := inherited Find(@item);
|
||||||
Delete(node);
|
Remove(node);
|
||||||
|
// Delete(node);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TsRowColAVLTree.PopCurrent;
|
||||||
|
begin
|
||||||
|
FCurrentNode := FCurrentNodeStack.Pop;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TsRowColAVLTree.PushCurrent;
|
||||||
|
begin
|
||||||
|
FCurrentNodeStack.Push(FCurrentNode);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
{******************************************************************************}
|
{******************************************************************************}
|
||||||
{ TsComments: a AVLTree to store comment records for cells }
|
{ TsCellEnumerator: enumerator for the TsCells AVLTree }
|
||||||
|
{******************************************************************************}
|
||||||
|
|
||||||
|
function TsCellEnumerator.GetEnumerator: TsCellEnumerator;
|
||||||
|
begin
|
||||||
|
Result := self;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsCellEnumerator.GetCurrent: PCell;
|
||||||
|
begin
|
||||||
|
Result := PCell(inherited GetCurrent);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{******************************************************************************}
|
||||||
|
{ TsCells: an AVLTree to store spreadsheet cells }
|
||||||
|
{******************************************************************************}
|
||||||
|
|
||||||
|
constructor TsCells.Create(AWorksheet: Pointer; AOwnsData: Boolean = true);
|
||||||
|
begin
|
||||||
|
inherited Create(AOwnsData);
|
||||||
|
FWorksheet := AWorksheet;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Adds a node with a new TCell record to the tree.
|
||||||
|
Returns a pointer to the cell record.
|
||||||
|
NOTE: It must be checked first that there ia no other record at the same
|
||||||
|
col/row. (Check omitted for better performance).
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
function TsCells.AddCell(ARow, ACol: LongInt): PCell;
|
||||||
|
begin
|
||||||
|
Result := PCell(Add(ARow, ACol));
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Deletes the node for the specified row and column index along with the
|
||||||
|
associated cell data record.
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
procedure TsCells.DeleteCell(ARow, ACol: LongInt);
|
||||||
|
begin
|
||||||
|
Delete(ARow, ACol);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Helper procedure which disposes the memory occupied by the cell data
|
||||||
|
record attached to a tree node.
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
procedure TsCells.DisposeData(var AData: Pointer);
|
||||||
|
begin
|
||||||
|
if AData <> nil then
|
||||||
|
Dispose(PCell(AData));
|
||||||
|
AData := nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Checks whether a specific cell already exists
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
function TsCells.FindCell(ARow, ACol: Longint): PCell;
|
||||||
|
begin
|
||||||
|
Result := PCell(Find(ARow, ACol));
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Cell enumerators (use in "for ... in" syntax)
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
function TsCells.GetEnumerator: TsCellEnumerator;
|
||||||
|
begin
|
||||||
|
Result := TsCellEnumerator.Create(self, 0, 0, $7FFFFFFF, $7FFFFFFF, false);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsCells.GetColEnumerator(ACol: LongInt; AStartRow: Longint = 0;
|
||||||
|
AEndRow: Longint = $7FFFFFFF): TsCellEnumerator;
|
||||||
|
begin
|
||||||
|
Result := TsCellEnumerator.Create(Self, AStartRow, ACol, AEndRow, ACol, false);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsCells.GetRangeEnumerator(AStartRow, AStartCol,
|
||||||
|
AEndRow, AEndCol: Longint): TsCellEnumerator;
|
||||||
|
begin
|
||||||
|
Result := TsCellEnumerator.Create(Self,
|
||||||
|
AStartRow, AStartCol, AEndRow, AEndCol, false);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsCells.GetRowEnumerator(ARow: LongInt; AStartCol: Longint = 0;
|
||||||
|
AEndCol: LongInt = $7FFFFFFF): TsCellEnumerator;
|
||||||
|
begin
|
||||||
|
Result := TsCellEnumerator.Create(Self,
|
||||||
|
ARow, AStartCol, ARow, AEndCol, false);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsCells.GetReverseColEnumerator(ACol: LongInt; AStartRow: Longint = 0;
|
||||||
|
AEndRow: Longint = $7FFFFFFF): TsCellEnumerator;
|
||||||
|
begin
|
||||||
|
Result := TsCellEnumerator.Create(Self,
|
||||||
|
AStartRow, ACol, AEndRow, ACol, true);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsCells.GetReverseEnumerator: TsCellEnumerator;
|
||||||
|
begin
|
||||||
|
Result := TsCellEnumerator.Create(self, 0, 0, $7FFFFFFF, $7FFFFFFF, true);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsCells.GetReverseRangeEnumerator(AStartRow, AStartCol,
|
||||||
|
AEndRow, AEndCol: Longint): TsCellEnumerator;
|
||||||
|
begin
|
||||||
|
Result := TsCellEnumerator.Create(Self,
|
||||||
|
AStartRow, AStartCol, AEndRow, AEndCol, true);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsCells.GetReverseRowEnumerator(ARow: LongInt; AStartCol: Longint = 0;
|
||||||
|
AEndCol: LongInt = $7FFFFFFF): TsCellEnumerator;
|
||||||
|
begin
|
||||||
|
Result := TsCellEnumerator.Create(Self,
|
||||||
|
ARow, AStartCol, ARow, AEndCol, true);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Returns a pointer to the first cell of the tree.
|
||||||
|
Should always be followed by GetNextCell.
|
||||||
|
|
||||||
|
Use to iterate through all cells efficiently.
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
function TsCells.GetFirstCell: PCell;
|
||||||
|
begin
|
||||||
|
Result := PCell(GetFirst);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Returns a pointer to the last cell of the tree.
|
||||||
|
|
||||||
|
Needed for efficient iteration through all nodes in reverse direction by
|
||||||
|
calling GetPrev.
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
function TsCells.GetLastCell: PCell;
|
||||||
|
begin
|
||||||
|
Result := PCell(GetLast);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
After beginning an iteration through all cells with GetFirstCell, the next
|
||||||
|
available cell can be found by calling GetNextCell.
|
||||||
|
|
||||||
|
Use to iterate througt all cells efficiently.
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
function TsCells.GetNextCell: PCell;
|
||||||
|
begin
|
||||||
|
Result := PCell(GetNext);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
After beginning a reverse iteration through all cells with GetLastCell,
|
||||||
|
the next available cell can be found by calling GetPrevCell.
|
||||||
|
|
||||||
|
Use to iterate througt all cells efficiently in reverse order.
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
function TsCells.GetPrevCell: PCell;
|
||||||
|
begin
|
||||||
|
Result := PCell(GetPrev);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Alloates memory for a cell data record.
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
function TsCells.NewData: Pointer;
|
||||||
|
var
|
||||||
|
cell: PCell;
|
||||||
|
begin
|
||||||
|
New(cell);
|
||||||
|
InitCell(cell^);
|
||||||
|
cell^.Worksheet := FWorksheet;
|
||||||
|
Result := cell;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{******************************************************************************}
|
||||||
|
{ TsCommentEnumerator: enumerator for the TsComments AVLTree }
|
||||||
|
{******************************************************************************}
|
||||||
|
|
||||||
|
function TsCommentEnumerator.GetEnumerator: TsCommentEnumerator;
|
||||||
|
begin
|
||||||
|
Result := self;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsCommentEnumerator.GetCurrent: PsComment;
|
||||||
|
begin
|
||||||
|
Result := PsComment(inherited GetCurrent);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{******************************************************************************}
|
||||||
|
{ TsComments: an AVLTree to store comment records for cells }
|
||||||
{******************************************************************************}
|
{******************************************************************************}
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
@ -287,6 +780,8 @@ end;
|
|||||||
function TsComments.AddComment(ARow, ACol: Cardinal;
|
function TsComments.AddComment(ARow, ACol: Cardinal;
|
||||||
AComment: String): PsComment;
|
AComment: String): PsComment;
|
||||||
begin
|
begin
|
||||||
|
Result := PsComment(Find(ARow, ACol));
|
||||||
|
if Result = nil then
|
||||||
Result := PsComment(Add(ARow, ACol));
|
Result := PsComment(Add(ARow, ACol));
|
||||||
Result^.Text := AComment;
|
Result^.Text := AComment;
|
||||||
end;
|
end;
|
||||||
@ -297,7 +792,7 @@ end;
|
|||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
procedure TsComments.DeleteComment(ARow, ACol: Cardinal);
|
procedure TsComments.DeleteComment(ARow, ACol: Cardinal);
|
||||||
begin
|
begin
|
||||||
Remove(ARow, ACol);
|
Delete(ARow, ACol);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
@ -322,9 +817,38 @@ begin
|
|||||||
Result := comment;
|
Result := comment;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Comments enumerators (use in "for ... in" syntax)
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
function TsComments.GetEnumerator: TsCommentEnumerator;
|
||||||
|
begin
|
||||||
|
Result := TsCommentEnumerator.Create(self, 0, 0, $7FFFFFFF, $7FFFFFFF, false);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsComments.GetRangeEnumerator(AStartRow, AStartCol,
|
||||||
|
AEndRow, AEndCol: Longint): TsCommentEnumerator;
|
||||||
|
begin
|
||||||
|
Result := TsCommentEnumerator.Create(Self,
|
||||||
|
AStartRow, AStartCol, AEndRow, AEndCol, false);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
{******************************************************************************}
|
{******************************************************************************}
|
||||||
{ TsHyperlinks: a AVLTree to store hyperlink records for cells }
|
{ TsHyperlinkEnumerator: enumerator for the TsHyperlinks AVLTree }
|
||||||
|
{******************************************************************************}
|
||||||
|
|
||||||
|
function TsHyperlinkEnumerator.GetEnumerator: TsHyperlinkEnumerator;
|
||||||
|
begin
|
||||||
|
Result := self;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsHyperlinkEnumerator.GetCurrent: PsHyperlink;
|
||||||
|
begin
|
||||||
|
Result := PsHyperlink(inherited GetCurrent);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{******************************************************************************}
|
||||||
|
{ TsHyperlinks: an AVLTree to store hyperlink records for cells }
|
||||||
{******************************************************************************}
|
{******************************************************************************}
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
@ -332,9 +856,11 @@ end;
|
|||||||
exists then its data will be replaced by the specified ones.
|
exists then its data will be replaced by the specified ones.
|
||||||
Returns a pointer to the hyperlink record.
|
Returns a pointer to the hyperlink record.
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
function TsHyperlinks.AddHyperlink(ARow, ACol: Cardinal; ATarget: String;
|
function TsHyperlinks.AddHyperlink(ARow, ACol: Longint; ATarget: String;
|
||||||
ATooltip: String = ''): PsHyperlink;
|
ATooltip: String = ''): PsHyperlink;
|
||||||
begin
|
begin
|
||||||
|
Result := PsHyperlink(Find(ARow, ACol));
|
||||||
|
if Result = nil then
|
||||||
Result := PsHyperlink(Add(ARow, ACol));
|
Result := PsHyperlink(Add(ARow, ACol));
|
||||||
Result^.Target := ATarget;
|
Result^.Target := ATarget;
|
||||||
Result^.Tooltip := ATooltip;
|
Result^.Tooltip := ATooltip;
|
||||||
@ -344,9 +870,9 @@ end;
|
|||||||
Deletes the node for the specified row and column index along with the
|
Deletes the node for the specified row and column index along with the
|
||||||
associated hyperlink data record.
|
associated hyperlink data record.
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
procedure TsHyperlinks.DeleteHyperlink(ARow, ACol: Cardinal);
|
procedure TsHyperlinks.DeleteHyperlink(ARow, ACol: Longint);
|
||||||
begin
|
begin
|
||||||
Remove(ARow, ACol);
|
Delete(ARow, ACol);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
@ -360,6 +886,21 @@ begin
|
|||||||
AData := nil;
|
AData := nil;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Hyperlink enumerators (use in "for ... in" syntax)
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
function TsHyperlinks.GetEnumerator: TsHyperlinkEnumerator;
|
||||||
|
begin
|
||||||
|
Result := TsHyperlinkEnumerator.Create(self, 0, 0, $7FFFFFFF, $7FFFFFFF, false);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsHyperlinks.GetRangeEnumerator(AStartRow, AStartCol,
|
||||||
|
AEndRow, AEndCol: Longint): TsHyperlinkEnumerator;
|
||||||
|
begin
|
||||||
|
Result := TsHyperlinkEnumerator.Create(Self,
|
||||||
|
AStartRow, AStartCol, AEndRow, AEndCol, false);
|
||||||
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Alloates memory of a hyperlink data record.
|
Alloates memory of a hyperlink data record.
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
@ -381,8 +922,10 @@ end;
|
|||||||
exists then its data will be replaced by the specified ones.
|
exists then its data will be replaced by the specified ones.
|
||||||
Returns a pointer to the cell range record.
|
Returns a pointer to the cell range record.
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
function TsMergedCells.AddRange(ARow1, ACol1, ARow2, ACol2: Cardinal): PsCellRange;
|
function TsMergedCells.AddRange(ARow1, ACol1, ARow2, ACol2: Longint): PsCellRange;
|
||||||
begin
|
begin
|
||||||
|
Result := PsCellRange(Find(ARow1, ACol1));
|
||||||
|
if Result = nil then
|
||||||
Result := PsCellRange(Add(ARow1, ACol1));
|
Result := PsCellRange(Add(ARow1, ACol1));
|
||||||
Result^.Row2 := ARow2;
|
Result^.Row2 := ARow2;
|
||||||
Result^.Col2 := ACol2;
|
Result^.Col2 := ACol2;
|
||||||
@ -392,9 +935,9 @@ end;
|
|||||||
Deletes the node for which the top/left corner of the cell range matches the
|
Deletes the node for which the top/left corner of the cell range matches the
|
||||||
specified parameters. There is only a single range fulfilling this criterion.
|
specified parameters. There is only a single range fulfilling this criterion.
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
procedure TsMergedCells.DeleteRange(ARow, ACol: Cardinal);
|
procedure TsMergedCells.DeleteRange(ARow, ACol: Longint);
|
||||||
begin
|
begin
|
||||||
Remove(ARow, ACol);
|
Delete(ARow, ACol);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
@ -405,7 +948,7 @@ end;
|
|||||||
to be deleted
|
to be deleted
|
||||||
@param IsRow Identifies whether AIndex refers to a row or column index
|
@param IsRow Identifies whether AIndex refers to a row or column index
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
procedure TsMergedCells.DeleteRowOrCol(AIndex: Cardinal; IsRow: Boolean);
|
procedure TsMergedCells.DeleteRowOrCol(AIndex: Longint; IsRow: Boolean);
|
||||||
var
|
var
|
||||||
rng, nextrng: PsCellRange;
|
rng, nextrng: PsCellRange;
|
||||||
begin
|
begin
|
||||||
@ -465,11 +1008,41 @@ begin
|
|||||||
AData := nil;
|
AData := nil;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TsMergedCells.Exchange(ARow1, ACol1, ARow2, ACol2: Longint);
|
||||||
|
var
|
||||||
|
rng: PsCellrange;
|
||||||
|
dr, dc: LongInt;
|
||||||
|
begin
|
||||||
|
rng := PsCellrange(Find(ARow1, ACol1));
|
||||||
|
if rng <> nil then
|
||||||
|
begin
|
||||||
|
dr := rng^.Row2 - rng^.Row1;
|
||||||
|
dc := rng^.Col2 - rng^.Col1;
|
||||||
|
rng^.Row1 := ARow2;
|
||||||
|
rng^.Col1 := ACol2;
|
||||||
|
rng^.Row2 := ARow2 + dr;
|
||||||
|
rng^.Col2 := ACol2 + dc;
|
||||||
|
end;
|
||||||
|
|
||||||
|
rng := PsCellRange(Find(ARow2, ACol2));
|
||||||
|
if rng <> nil then
|
||||||
|
begin
|
||||||
|
dr := rng^.Row2 - rng^.Row1;
|
||||||
|
dc := rng^.Col2 - rng^.Col1;
|
||||||
|
rng^.Row1 := ARow1;
|
||||||
|
rng^.Col1 := ACol1;
|
||||||
|
rng^.Row2 := ARow1 + dr;
|
||||||
|
rng^.Col2 := ACol1 + dc;
|
||||||
|
end;
|
||||||
|
|
||||||
|
inherited Exchange(ARow1, ACol1, ARow2, ACol2);
|
||||||
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Finds the cell range which contains the cell specified by its row and column
|
Finds the cell range which contains the cell specified by its row and column
|
||||||
index
|
index
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
function TsMergedCells.FindRangeWithCell(ARow, ACol: Cardinal): PsCellRange;
|
function TsMergedCells.FindRangeWithCell(ARow, ACol: Longint): PsCellRange;
|
||||||
var
|
var
|
||||||
node: TAVLTreeNode;
|
node: TAVLTreeNode;
|
||||||
begin
|
begin
|
||||||
|
@ -1284,7 +1284,7 @@ begin
|
|||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
if cell <> nil then
|
if cell <> nil then
|
||||||
cellfmt := cell^.Worksheet.ReadCellFormat(cell)
|
cellfmt := TsWorksheet(cell^.Worksheet).ReadCellFormat(cell)
|
||||||
else
|
else
|
||||||
InitFormatRecord(cellfmt);
|
InitFormatRecord(cellfmt);
|
||||||
|
|
||||||
|
@ -32,43 +32,6 @@ type
|
|||||||
TsBasicSpreadReader = class;
|
TsBasicSpreadReader = class;
|
||||||
TsBasicSpreadWriter = class;
|
TsBasicSpreadWriter = class;
|
||||||
|
|
||||||
{@@ Pointer to a TCell record }
|
|
||||||
PCell = ^TCell;
|
|
||||||
|
|
||||||
{@@ Cell structure for TsWorksheet
|
|
||||||
The cell record contains information on the location of the cell (row and
|
|
||||||
column index), on the value contained (number, date, text, ...), on
|
|
||||||
formatting, etc.
|
|
||||||
|
|
||||||
Never suppose that all *Value fields are valid,
|
|
||||||
only one of the ContentTypes is valid. For other fields
|
|
||||||
use TWorksheet.ReadAsUTF8Text and similar methods
|
|
||||||
|
|
||||||
@see ReadAsUTF8Text }
|
|
||||||
TCell = record
|
|
||||||
{ Location of the cell }
|
|
||||||
Worksheet: TsWorksheet;
|
|
||||||
Col: Cardinal; // zero-based
|
|
||||||
Row: Cardinal; // zero-based
|
|
||||||
{ Status flags }
|
|
||||||
Flags: TsCellFlags;
|
|
||||||
{ Index of format record in the workbook's FCellFormatList }
|
|
||||||
FormatIndex: Integer;
|
|
||||||
{ Special information }
|
|
||||||
SharedFormulaBase: PCell; // Cell containing the shared formula
|
|
||||||
{ Cell content }
|
|
||||||
UTF8StringValue: String; // Strings cannot be part of a variant record
|
|
||||||
FormulaValue: String;
|
|
||||||
case ContentType: TCellContentType of // variant part must be at the end
|
|
||||||
cctEmpty : (); // has no data at all
|
|
||||||
cctFormula : (); // FormulaValue is outside the variant record
|
|
||||||
cctNumber : (Numbervalue: Double);
|
|
||||||
cctUTF8String : (); // UTF8StringValue is outside the variant record
|
|
||||||
cctDateTime : (DateTimevalue: TDateTime);
|
|
||||||
cctBool : (BoolValue: boolean);
|
|
||||||
cctError : (ErrorValue: TsErrorValue);
|
|
||||||
end;
|
|
||||||
|
|
||||||
{@@ The record TRow contains information about a spreadsheet row:
|
{@@ The record TRow contains information about a spreadsheet row:
|
||||||
@param Row The index of the row (beginning with 0)
|
@param Row The index of the row (beginning with 0)
|
||||||
@param Height The height of the row (expressed as lines count of the default font)
|
@param Height The height of the row (expressed as lines count of the default font)
|
||||||
@ -124,11 +87,10 @@ type
|
|||||||
private
|
private
|
||||||
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: TsCells;
|
||||||
FComments: TsComments;
|
FComments: TsComments;
|
||||||
FMergedCells: TsMergedCells;
|
FMergedCells: TsMergedCells;
|
||||||
FHyperlinks: TsHyperlinks;
|
FHyperlinks: TsHyperlinks;
|
||||||
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;
|
||||||
FActiveCellCol: Cardinal;
|
FActiveCellCol: Cardinal;
|
||||||
@ -153,17 +115,13 @@ type
|
|||||||
procedure SetName(const AName: String);
|
procedure SetName(const AName: String);
|
||||||
|
|
||||||
{ Callback procedures called when iterating through all cells }
|
{ Callback procedures called when iterating through all cells }
|
||||||
procedure CalcFormulaCallback(data, arg: Pointer);
|
|
||||||
procedure CalcStateCallback(data, arg: Pointer);
|
|
||||||
procedure DeleteColCallback(data, arg: Pointer);
|
procedure DeleteColCallback(data, arg: Pointer);
|
||||||
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 RemoveCellsCallback(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;
|
||||||
@ -176,6 +134,7 @@ type
|
|||||||
ASortOptions: TsSortOptions): Integer;
|
ASortOptions: TsSortOptions): Integer;
|
||||||
procedure DoExchangeColRow(AIsColumn: Boolean; AIndex, WithIndex: Cardinal;
|
procedure DoExchangeColRow(AIsColumn: Boolean; AIndex, WithIndex: Cardinal;
|
||||||
AFromIndex, AToIndex: Cardinal);
|
AFromIndex, AToIndex: Cardinal);
|
||||||
|
procedure ExchangeCells(ARow1, ACol1, ARow2, ACol2: Cardinal);
|
||||||
|
|
||||||
public
|
public
|
||||||
{ Base methods }
|
{ Base methods }
|
||||||
@ -185,7 +144,7 @@ type
|
|||||||
{ Utils }
|
{ Utils }
|
||||||
class function CellInRange(ARow, ACol: Cardinal; ARange: TsCellRange): Boolean;
|
class function CellInRange(ARow, ACol: Cardinal; ARange: TsCellRange): Boolean;
|
||||||
class function CellPosToText(ARow, ACol: Cardinal): string;
|
class function CellPosToText(ARow, ACol: Cardinal): string;
|
||||||
procedure RemoveAllCells;
|
// procedure RemoveAllCells;
|
||||||
procedure UpdateCaches;
|
procedure UpdateCaches;
|
||||||
|
|
||||||
{ Reading of values }
|
{ Reading of values }
|
||||||
@ -397,16 +356,12 @@ type
|
|||||||
procedure DeleteCell(ACell: PCell);
|
procedure DeleteCell(ACell: PCell);
|
||||||
procedure EraseCell(ACell: PCell);
|
procedure EraseCell(ACell: PCell);
|
||||||
|
|
||||||
procedure ExchangeCells(ARow1, ACol1, ARow2, ACol2: Cardinal);
|
|
||||||
|
|
||||||
function FindCell(ARow, ACol: Cardinal): PCell; overload;
|
function FindCell(ARow, ACol: Cardinal): PCell; overload;
|
||||||
function FindCell(AddressStr: String): PCell; overload;
|
function FindCell(AddressStr: String): PCell; overload;
|
||||||
function GetCell(ARow, ACol: Cardinal): PCell; overload;
|
function GetCell(ARow, ACol: Cardinal): PCell; overload;
|
||||||
function GetCell(AddressStr: String): PCell; overload;
|
function GetCell(AddressStr: String): PCell; overload;
|
||||||
|
|
||||||
function GetCellCount: Cardinal;
|
function GetCellCount: Cardinal;
|
||||||
function GetFirstCell(): PCell;
|
|
||||||
function GetNextCell(): PCell;
|
|
||||||
|
|
||||||
function GetFirstCellOfRow(ARow: Cardinal): PCell;
|
function GetFirstCellOfRow(ARow: Cardinal): PCell;
|
||||||
function GetLastCellOfRow(ARow: Cardinal): PCell;
|
function GetLastCellOfRow(ARow: Cardinal): PCell;
|
||||||
@ -494,7 +449,7 @@ type
|
|||||||
|
|
||||||
{@@ List of cells of the worksheet. Only cells with contents or with formatting
|
{@@ List of cells of the worksheet. Only cells with contents or with formatting
|
||||||
are listed }
|
are listed }
|
||||||
property Cells: TAVLTree read FCells;
|
property Cells: TsCells 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 }
|
{@@ List of all comment records }
|
||||||
@ -828,9 +783,6 @@ procedure MakeLEPalette(APalette: PsPalette; APaletteSize: Integer);
|
|||||||
//function SameCellBorders(ACell1, ACell2: PCell): Boolean; overload;
|
//function SameCellBorders(ACell1, ACell2: PCell): Boolean; overload;
|
||||||
function SameCellBorders(AFormat1, AFormat2: PsCellFormat): Boolean; //overload;
|
function SameCellBorders(AFormat1, AFormat2: PsCellFormat): Boolean; //overload;
|
||||||
|
|
||||||
procedure InitCell(out ACell: TCell); overload;
|
|
||||||
procedure InitCell(ARow, ACol: Cardinal; out ACell: TCell); overload;
|
|
||||||
|
|
||||||
function HasFormula(ACell: PCell): Boolean;
|
function HasFormula(ACell: PCell): Boolean;
|
||||||
|
|
||||||
{ For debugging purposes }
|
{ For debugging purposes }
|
||||||
@ -841,7 +793,7 @@ implementation
|
|||||||
|
|
||||||
uses
|
uses
|
||||||
Math, StrUtils, TypInfo, lazutf8, URIParser,
|
Math, StrUtils, TypInfo, lazutf8, URIParser,
|
||||||
fpsPatches, fpsStrings, fpsStreams, uvirtuallayer_ole,
|
fpsPatches, fpsStrings, uvirtuallayer_ole,
|
||||||
fpsUtils, fpsreaderwriter, fpsCurrency, fpsExprParser,
|
fpsUtils, fpsreaderwriter, fpsCurrency, fpsExprParser,
|
||||||
fpsNumFormat, fpsNumFormatParser;
|
fpsNumFormat, fpsNumFormatParser;
|
||||||
|
|
||||||
@ -1026,32 +978,6 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
|
||||||
Initalizes a new cell.
|
|
||||||
@return New cell record
|
|
||||||
-------------------------------------------------------------------------------}
|
|
||||||
procedure InitCell(out ACell: TCell);
|
|
||||||
begin
|
|
||||||
ACell.FormulaValue := '';
|
|
||||||
ACell.UTF8StringValue := '';
|
|
||||||
FillChar(ACell, SizeOf(ACell), 0);
|
|
||||||
end;
|
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
|
||||||
Initalizes a new cell and presets the row and column fields of the cell record
|
|
||||||
to the parameters passed to the procedure.
|
|
||||||
|
|
||||||
@param ARow Row index of the new cell
|
|
||||||
@param ACol Column index of the new cell
|
|
||||||
@return New cell record with row and column fields preset to passed values.
|
|
||||||
-------------------------------------------------------------------------------}
|
|
||||||
procedure InitCell(ARow, ACol: Cardinal; out ACell: TCell);
|
|
||||||
begin
|
|
||||||
InitCell(ACell);
|
|
||||||
ACell.Row := ARow;
|
|
||||||
ACell.Col := ACol;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Returns TRUE if the cell contains a formula (direct or shared, does not matter).
|
Returns TRUE if the cell contains a formula (direct or shared, does not matter).
|
||||||
|
|
||||||
@ -1135,7 +1061,7 @@ constructor TsWorksheet.Create;
|
|||||||
begin
|
begin
|
||||||
inherited Create;
|
inherited Create;
|
||||||
|
|
||||||
FCells := TAVLTree.Create(@CompareCells);
|
FCells := TsCells.Create(self);
|
||||||
FRows := TIndexedAVLTree.Create(@CompareRows);
|
FRows := TIndexedAVLTree.Create(@CompareRows);
|
||||||
FCols := TIndexedAVLTree.Create(@CompareCols);
|
FCols := TIndexedAVLTree.Create(@CompareCols);
|
||||||
FComments := TsComments.Create;
|
FComments := TsComments.Create;
|
||||||
@ -1164,7 +1090,7 @@ end;
|
|||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
destructor TsWorksheet.Destroy;
|
destructor TsWorksheet.Destroy;
|
||||||
begin
|
begin
|
||||||
RemoveAllCells;
|
// RemoveAllCells;
|
||||||
RemoveAllRows;
|
RemoveAllRows;
|
||||||
RemoveAllCols;
|
RemoveAllCols;
|
||||||
|
|
||||||
@ -1207,24 +1133,6 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
|
||||||
Helper method for calculation of the formulas in a spreadsheet.
|
|
||||||
-------------------------------------------------------------------------------}
|
|
||||||
procedure TsWorksheet.CalcFormulaCallback(data, arg: pointer);
|
|
||||||
var
|
|
||||||
cell: PCell;
|
|
||||||
begin
|
|
||||||
Unused(arg);
|
|
||||||
cell := PCell(data);
|
|
||||||
|
|
||||||
// Empty cell or error cell --> nothing to do
|
|
||||||
if (cell = nil) or (cell^.ContentType = cctError) then
|
|
||||||
exit;
|
|
||||||
|
|
||||||
if HasFormula(cell) or HasFormula(cell^.SharedFormulaBase) then
|
|
||||||
CalcFormula(cell);
|
|
||||||
end;
|
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Calculates the formula in a cell
|
Calculates the formula in a cell
|
||||||
Should not be called by itself because the result may depend on other cells
|
Should not be called by itself because the result may depend on other cells
|
||||||
@ -1253,6 +1161,7 @@ begin
|
|||||||
formula := ACell^.SharedFormulaBase^.FormulaValue;
|
formula := ACell^.SharedFormulaBase^.FormulaValue;
|
||||||
parser.ActiveCell := ACell;
|
parser.ActiveCell := ACell;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
try
|
try
|
||||||
parser.Expression := formula;
|
parser.Expression := formula;
|
||||||
res := parser.Evaluate;
|
res := parser.Evaluate;
|
||||||
@ -1263,6 +1172,7 @@ begin
|
|||||||
Res := ErrorResult(errIllegalRef);
|
Res := ErrorResult(errIllegalRef);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
case res.ResultType of
|
case res.ResultType of
|
||||||
rtEmpty : WriteBlank(ACell);
|
rtEmpty : WriteBlank(ACell);
|
||||||
rtError : WriteErrorValue(ACell, res.ResError);
|
rtError : WriteErrorValue(ACell, res.ResError);
|
||||||
@ -1307,6 +1217,7 @@ end;
|
|||||||
procedure TsWorksheet.CalcFormulas;
|
procedure TsWorksheet.CalcFormulas;
|
||||||
var
|
var
|
||||||
node: TAVLTreeNode;
|
node: TAVLTreeNode;
|
||||||
|
cell: PCell;
|
||||||
begin
|
begin
|
||||||
// prevent infinite loop due to triggering of formula calculation whenever
|
// prevent infinite loop due to triggering of formula calculation whenever
|
||||||
// a cell changes during execution of CalcFormulas.
|
// a cell changes during execution of CalcFormulas.
|
||||||
@ -1315,36 +1226,29 @@ begin
|
|||||||
// Step 1 - mark all formula cells as "not calculated"
|
// Step 1 - mark all formula cells as "not calculated"
|
||||||
node := FCells.FindLowest;
|
node := FCells.FindLowest;
|
||||||
while Assigned(node) do begin
|
while Assigned(node) do begin
|
||||||
CalcStateCallback(node.Data, nil);
|
cell := PCell(node.Data);
|
||||||
|
if HasFormula(cell) then
|
||||||
|
SetCalcState(cell, csNotCalculated);
|
||||||
node := FCells.FindSuccessor(node);
|
node := FCells.FindSuccessor(node);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Step 2 - calculate cells. If a not-yet-calculated cell is found it is
|
// Step 2 - calculate cells. If a not-yet-calculated cell is found it is
|
||||||
// calculated and then marked as such.
|
// calculated and then marked as such.
|
||||||
node := FCells.FindLowest;
|
node := FCells.FindLowest;
|
||||||
while Assigned(Node) do begin
|
while Assigned(node) do begin
|
||||||
CalcFormulaCallback(Node.Data, nil);
|
cell := PCell(node.Data);
|
||||||
|
if (cell^.ContentType <> cctError) and
|
||||||
|
(HasFormula(cell) or HasFormula(cell^.SharedFormulaBase))
|
||||||
|
then
|
||||||
|
CalcFormula(cell);
|
||||||
node := FCells.FindSuccessor(node);
|
node := FCells.FindSuccessor(node);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
finally
|
finally
|
||||||
dec(FWorkbook.FCalculationLock);
|
dec(FWorkbook.FCalculationLock);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
|
||||||
Helper method marking all cells with formulas as "not calculated". This flag
|
|
||||||
is needed for recursive calculation of the entire worksheet.
|
|
||||||
-------------------------------------------------------------------------------}
|
|
||||||
procedure TsWorksheet.CalcStateCallback(data, arg: Pointer);
|
|
||||||
var
|
|
||||||
cell: PCell;
|
|
||||||
begin
|
|
||||||
Unused(arg);
|
|
||||||
cell := PCell(data);
|
|
||||||
if HasFormula(cell) then
|
|
||||||
SetCalcState(cell, csNotCalculated);
|
|
||||||
end;
|
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Checks whether a cell given by its row and column indexes belongs to a
|
Checks whether a cell given by its row and column indexes belongs to a
|
||||||
specified rectangular cell range.
|
specified rectangular cell range.
|
||||||
@ -1376,14 +1280,14 @@ end;
|
|||||||
function TsWorksheet.CellUsedInFormula(ARow, ACol: Cardinal): Boolean;
|
function TsWorksheet.CellUsedInFormula(ARow, ACol: Cardinal): Boolean;
|
||||||
var
|
var
|
||||||
cell: PCell;
|
cell: PCell;
|
||||||
cellNode: TAVLTreeNode;
|
|
||||||
fe: TsFormulaElement;
|
fe: TsFormulaElement;
|
||||||
i: Integer;
|
i: Integer;
|
||||||
rpnFormula: TsRPNFormula;
|
rpnFormula: TsRPNFormula;
|
||||||
begin
|
begin
|
||||||
cellNode := FCells.FindLowest;
|
FCells.PushCurrent;
|
||||||
while Assigned(cellNode) do begin
|
try
|
||||||
cell := PCell(cellNode.Data);
|
cell := FCells.GetFirstCell;
|
||||||
|
while Assigned(cell) do begin
|
||||||
if HasFormula(cell) then begin
|
if HasFormula(cell) then begin
|
||||||
rpnFormula := BuildRPNFormula(cell);
|
rpnFormula := BuildRPNFormula(cell);
|
||||||
for i := 0 to Length(rpnFormula)-1 do
|
for i := 0 to Length(rpnFormula)-1 do
|
||||||
@ -1406,7 +1310,10 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
cellNode := FCells.FindSuccessor(cellNode);
|
cell := FCells.GetNextCell;
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
FCells.PopCurrent;
|
||||||
end;
|
end;
|
||||||
SetLength(rpnFormula, 0);
|
SetLength(rpnFormula, 0);
|
||||||
end;
|
end;
|
||||||
@ -1489,9 +1396,6 @@ end;
|
|||||||
@param AText Comment text
|
@param AText Comment text
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
procedure TsWorksheet.WriteComment(ACell: PCell; AText: String);
|
procedure TsWorksheet.WriteComment(ACell: PCell; AText: String);
|
||||||
var
|
|
||||||
comment: PsComment;
|
|
||||||
addNew: Boolean;
|
|
||||||
begin
|
begin
|
||||||
if ACell = nil then
|
if ACell = nil then
|
||||||
exit;
|
exit;
|
||||||
@ -1504,7 +1408,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
// Add new comment record
|
// Add new comment record
|
||||||
comment := FComments.AddComment(ACell^.Row, ACell^.Col, AText);
|
FComments.AddComment(ACell^.Row, ACell^.Col, AText);
|
||||||
Include(ACell^.Flags, cfHasComment);
|
Include(ACell^.Flags, cfHasComment);
|
||||||
|
|
||||||
ChangedCell(ACell^.Row, ACell^.Col);
|
ChangedCell(ACell^.Row, ACell^.Col);
|
||||||
@ -1728,7 +1632,7 @@ end;
|
|||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
procedure TsWorksheet.CopyCell(AFromCell, AToCell: PCell);
|
procedure TsWorksheet.CopyCell(AFromCell, AToCell: PCell);
|
||||||
var
|
var
|
||||||
toRow, toCol: Cardinal;
|
toRow, toCol: LongInt;
|
||||||
row1, col1, row2, col2: Cardinal;
|
row1, col1, row2, col2: Cardinal;
|
||||||
hyperlink: PsHyperlink;
|
hyperlink: PsHyperlink;
|
||||||
begin
|
begin
|
||||||
@ -2075,27 +1979,15 @@ end;
|
|||||||
@param ACol1 Column index of the first cell
|
@param ACol1 Column index of the first cell
|
||||||
@param ARow2 Row index of the second cell
|
@param ARow2 Row index of the second cell
|
||||||
@param ACol2 Column index of the second cell
|
@param ACol2 Column index of the second cell
|
||||||
|
|
||||||
|
@note This method does not take care of merged cells and does not
|
||||||
|
check for this situation. Therefore, the method is not public!
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
procedure TsWorksheet.ExchangeCells(ARow1, ACol1, ARow2, ACol2: Cardinal);
|
procedure TsWorksheet.ExchangeCells(ARow1, ACol1, ARow2, ACol2: Cardinal);
|
||||||
var
|
|
||||||
cell1, cell2: PCell;
|
|
||||||
begin
|
begin
|
||||||
cell1 := RemoveCell(ARow1, ACol1);
|
FCells.Exchange(ARow1, ACol1, ARow2, ACol2);
|
||||||
cell2 := RemoveCell(ARow2, ACol2);
|
FComments.Exchange(ARow1, ACol1, ARow2, ACol2);
|
||||||
if cell1 <> nil then
|
FHyperlinks.Exchange(ARow1, ACol1, ARow2, ACol2);
|
||||||
begin
|
|
||||||
cell1^.Row := ARow2;
|
|
||||||
cell1^.Col := ACol2;
|
|
||||||
FCells.Add(cell1);
|
|
||||||
ChangedCell(ARow2, ACol2);
|
|
||||||
end;
|
|
||||||
if cell2 <> nil then
|
|
||||||
begin
|
|
||||||
cell2^.Row := ARow1;
|
|
||||||
cell2^.Col := ACol1;
|
|
||||||
FCells.Add(cell2);
|
|
||||||
ChangedCell(ARow1, ACol1);
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
@ -2107,19 +1999,8 @@ end;
|
|||||||
@see TCell
|
@see TCell
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
function TsWorksheet.FindCell(ARow, ACol: Cardinal): PCell;
|
function TsWorksheet.FindCell(ARow, ACol: Cardinal): PCell;
|
||||||
var
|
|
||||||
LCell: TCell;
|
|
||||||
AVLNode: TAVLTreeNode;
|
|
||||||
begin
|
begin
|
||||||
Result := nil;
|
Result := PCell(FCells.Find(ARow, ACol));
|
||||||
if FCells.Count = 0 then
|
|
||||||
exit;
|
|
||||||
|
|
||||||
LCell.Row := ARow;
|
|
||||||
LCell.Col := ACol;
|
|
||||||
AVLNode := FCells.Find(@LCell);
|
|
||||||
if Assigned(AVLNode) then
|
|
||||||
result := PCell(AVLNode.Data);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
@ -2156,15 +2037,10 @@ end;
|
|||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
function TsWorksheet.GetCell(ARow, ACol: Cardinal): PCell;
|
function TsWorksheet.GetCell(ARow, ACol: Cardinal): PCell;
|
||||||
begin
|
begin
|
||||||
Result := FindCell(ARow, ACol);
|
Result := Cells.FindCell(ARow, ACol);
|
||||||
|
if Result = nil then
|
||||||
if (Result = nil) then
|
|
||||||
begin
|
begin
|
||||||
New(Result);
|
Result := Cells.AddCell(ARow, ACol);
|
||||||
InitCell(ARow, ACol, Result^);
|
|
||||||
Result^.Worksheet := self;
|
|
||||||
Cells.Add(Result);
|
|
||||||
|
|
||||||
if FFirstColIndex = $FFFFFFFF then FFirstColIndex := GetFirstColIndex(true)
|
if FFirstColIndex = $FFFFFFFF then FFirstColIndex := GetFirstColIndex(true)
|
||||||
else FFirstColIndex := Min(FFirstColIndex, ACol);
|
else FFirstColIndex := Min(FFirstColIndex, ACol);
|
||||||
if FFirstRowIndex = $FFFFFFFF then FFirstRowIndex := GetFirstRowIndex(true)
|
if FFirstRowIndex = $FFFFFFFF then FFirstRowIndex := GetFirstRowIndex(true)
|
||||||
@ -2203,14 +2079,7 @@ end;
|
|||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Returns the number of cells in the worksheet with contents.
|
Returns the number of cells in the worksheet with contents.
|
||||||
|
|
||||||
This routine is used together with GetFirstCell and GetNextCell
|
|
||||||
to iterate througth all cells in a worksheet efficiently.
|
|
||||||
|
|
||||||
@return The number of cells with contents in the worksheet
|
@return The number of cells with contents in the worksheet
|
||||||
|
|
||||||
@see TCell
|
|
||||||
@see GetFirstCell
|
|
||||||
@see GetNextCell
|
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
function TsWorksheet.GetCellCount: Cardinal;
|
function TsWorksheet.GetCellCount: Cardinal;
|
||||||
begin
|
begin
|
||||||
@ -2294,49 +2163,6 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
|
||||||
Returns the first cell.
|
|
||||||
|
|
||||||
Use together with GetCellCount and GetNextCell
|
|
||||||
to iterate througth all cells in a worksheet efficiently.
|
|
||||||
|
|
||||||
@return The first cell if any exists, nil otherwise
|
|
||||||
|
|
||||||
@see TCell
|
|
||||||
@see GetCellCount
|
|
||||||
@see GetNextCell
|
|
||||||
-------------------------------------------------------------------------------}
|
|
||||||
function TsWorksheet.GetFirstCell(): PCell;
|
|
||||||
begin
|
|
||||||
FCurrentNode := FCells.FindLowest();
|
|
||||||
if FCurrentNode <> nil then
|
|
||||||
Result := PCell(FCurrentNode.Data)
|
|
||||||
else Result := nil;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
|
||||||
Returns the next cell.
|
|
||||||
|
|
||||||
Should always be used either after GetFirstCell or
|
|
||||||
after GetNextCell.
|
|
||||||
|
|
||||||
Use together with GetCellCount and GetFirstCell
|
|
||||||
to iterate througth all cells in a worksheet efficiently.
|
|
||||||
|
|
||||||
@return The first cell if any exists, nil otherwise
|
|
||||||
|
|
||||||
@see TCell
|
|
||||||
@see GetCellCount
|
|
||||||
@see GetFirstCell
|
|
||||||
-------------------------------------------------------------------------------}
|
|
||||||
function TsWorksheet.GetNextCell(): PCell;
|
|
||||||
begin
|
|
||||||
FCurrentNode := FCells.FindSuccessor(FCurrentNode);
|
|
||||||
if FCurrentNode <> nil then
|
|
||||||
Result := PCell(FCurrentNode.Data)
|
|
||||||
else Result := nil;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Returns the 0-based index of the first column with a cell with contents.
|
Returns the 0-based index of the first column with a cell with contents.
|
||||||
|
|
||||||
@ -2353,20 +2179,30 @@ end;
|
|||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
function TsWorksheet.GetFirstColIndex(AForceCalculation: Boolean = false): Cardinal;
|
function TsWorksheet.GetFirstColIndex(AForceCalculation: Boolean = false): Cardinal;
|
||||||
var
|
var
|
||||||
AVLNode: TAVLTreeNode;
|
cell: PCell;
|
||||||
i: Integer;
|
i: Integer;
|
||||||
begin
|
begin
|
||||||
if AForceCalculation then
|
if AForceCalculation then
|
||||||
begin
|
begin
|
||||||
Result := $FFFFFFFF;
|
Result := $FFFFFFFF;
|
||||||
|
for cell in FCells do
|
||||||
|
Result := Math.Min(Result, cell^.Col);
|
||||||
|
|
||||||
|
(*
|
||||||
// Traverse the tree from lowest to highest.
|
// Traverse the tree from lowest to highest.
|
||||||
// Since tree primary sort order is on row lowest col could exist anywhere.
|
// Since tree primary sort order is on row lowest col could exist anywhere.
|
||||||
AVLNode := FCells.FindLowest;
|
FCells.PushCurrent;
|
||||||
while Assigned(AVLNode) do
|
try
|
||||||
|
cell := FCells.GetFirstCell;
|
||||||
|
while Assigned(cell) do
|
||||||
begin
|
begin
|
||||||
Result := Math.Min(Result, PCell(AVLNode.Data)^.Col);
|
Result := Math.Min(Result, cell^.Col);
|
||||||
AVLNode := FCells.FindSuccessor(AVLNode);
|
cell := FCells.GetNextCell;
|
||||||
end;
|
end;
|
||||||
|
finally
|
||||||
|
FCells.PopCurrent;
|
||||||
|
end;
|
||||||
|
*)
|
||||||
// In addition, there may be column records defining the column width even
|
// In addition, there may be column records defining the column width even
|
||||||
// without content
|
// without content
|
||||||
for i:=0 to FCols.Count-1 do
|
for i:=0 to FCols.Count-1 do
|
||||||
@ -2444,17 +2280,26 @@ end;
|
|||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
function TsWorksheet.GetLastOccupiedColIndex: Cardinal;
|
function TsWorksheet.GetLastOccupiedColIndex: Cardinal;
|
||||||
var
|
var
|
||||||
AVLNode: TAVLTreeNode;
|
cell: PCell;
|
||||||
begin
|
begin
|
||||||
Result := 0;
|
Result := 0;
|
||||||
// Traverse the tree from lowest to highest.
|
// Traverse the tree from lowest to highest.
|
||||||
// Since tree's primary sort order is on row, highest col could exist anywhere.
|
// Since tree's primary sort order is on row, highest col could exist anywhere.
|
||||||
AVLNode := FCells.FindLowest;
|
for cell in FCells do
|
||||||
while Assigned(AVLNode) do
|
Result := Math.Max(Result, cell^.Col);
|
||||||
|
{
|
||||||
|
FCells.PushCurrent;
|
||||||
|
try
|
||||||
|
cell := FCells.GetFirstCell;
|
||||||
|
while Assigned(cell) do
|
||||||
begin
|
begin
|
||||||
Result := Math.Max(Result, PCell(AVLNode.Data)^.Col);
|
Result := Math.Max(Result, cell^.Col);
|
||||||
AVLNode := FCells.FindSuccessor(AVLNode);
|
cell := FCells.GetNextCell;
|
||||||
end;
|
end;
|
||||||
|
finally
|
||||||
|
FCells.PopCurrent;
|
||||||
|
end;
|
||||||
|
}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
@ -2509,15 +2354,20 @@ end;
|
|||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
function TsWorksheet.GetFirstRowIndex(AForceCalculation: Boolean = false): Cardinal;
|
function TsWorksheet.GetFirstRowIndex(AForceCalculation: Boolean = false): Cardinal;
|
||||||
var
|
var
|
||||||
AVLNode: TAVLTreeNode;
|
cell: PCell;
|
||||||
i: Integer;
|
i: Integer;
|
||||||
begin
|
begin
|
||||||
if AForceCalculation then
|
if AForceCalculation then
|
||||||
begin
|
begin
|
||||||
Result := $FFFFFFFF;
|
Result := $FFFFFFFF;
|
||||||
AVLNode := FCells.FindLowest;
|
FCells.PushCurrent;
|
||||||
if Assigned(AVLNode) then
|
try
|
||||||
Result := PCell(AVLNode.Data).Row;
|
cell := FCells.GetFirstCell;
|
||||||
|
finally
|
||||||
|
FCells.PopCurrent;
|
||||||
|
end;
|
||||||
|
if Assigned(cell) then
|
||||||
|
Result := cell^.Row;
|
||||||
// In addition, there may be row records even for rows without cells.
|
// In addition, there may be row records even for rows without cells.
|
||||||
for i:=0 to FRows.Count-1 do
|
for i:=0 to FRows.Count-1 do
|
||||||
if FRows[i] <> nil then
|
if FRows[i] <> nil then
|
||||||
@ -2579,12 +2429,12 @@ end;
|
|||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
function TsWorksheet.GetLastOccupiedRowIndex: Cardinal;
|
function TsWorksheet.GetLastOccupiedRowIndex: Cardinal;
|
||||||
var
|
var
|
||||||
AVLNode: TAVLTreeNode;
|
cell: PCell;
|
||||||
begin
|
begin
|
||||||
Result := 0;
|
Result := 0;
|
||||||
AVLNode := FCells.FindHighest;
|
cell := FCells.GetLastCell;
|
||||||
if Assigned(AVLNode) then
|
if Assigned(cell) then
|
||||||
Result := PCell(AVLNode.Data).Row;
|
Result := cell^.Row;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
@ -3360,7 +3210,6 @@ begin
|
|||||||
UnmergeCells(rng.Row1, rng.Col1);
|
UnmergeCells(rng.Row1, rng.Col1);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Finds the upper left cell of a shared formula block to which the specified
|
Finds the upper left cell of a shared formula block to which the specified
|
||||||
cell belongs. This is the "shared formula base".
|
cell belongs. This is the "shared formula base".
|
||||||
@ -3529,23 +3378,6 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
|
||||||
Helper method for clearing the cell records in a spreadsheet.
|
|
||||||
-------------------------------------------------------------------------------}
|
|
||||||
procedure TsWorksheet.RemoveCellsCallback(data, arg: pointer);
|
|
||||||
begin
|
|
||||||
Unused(arg);
|
|
||||||
Dispose(PCell(data));
|
|
||||||
end;
|
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
|
||||||
Clears the list of cells and releases their memory.
|
|
||||||
-------------------------------------------------------------------------------}
|
|
||||||
procedure TsWorksheet.RemoveAllCells;
|
|
||||||
begin
|
|
||||||
RemoveAllAvlTreeNodes(FCells, RemoveCellsCallback);
|
|
||||||
end;
|
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Removes the comment from a cell and releases the memory occupied by the node.
|
Removes the comment from a cell and releases the memory occupied by the node.
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
@ -3558,23 +3390,6 @@ begin
|
|||||||
end;
|
end;
|
||||||
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;
|
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Removes a cell from its tree container. DOES NOT RELEASE ITS MEMORY!
|
Removes a cell from its tree container. DOES NOT RELEASE ITS MEMORY!
|
||||||
|
|
||||||
@ -3584,7 +3399,7 @@ end;
|
|||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
function TsWorksheet.RemoveCell(ARow, ACol: Cardinal): PCell;
|
function TsWorksheet.RemoveCell(ARow, ACol: Cardinal): PCell;
|
||||||
begin
|
begin
|
||||||
Result := FindCell(ARow, ACol);
|
Result := PCell(FCells.Find(ARow, ACol));
|
||||||
if Result <> nil then FCells.Remove(Result);
|
if Result <> nil then FCells.Remove(Result);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -3600,18 +3415,8 @@ end;
|
|||||||
@param ACol Column index of the cell to be removed
|
@param ACol Column index of the cell to be removed
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
procedure TsWorksheet.RemoveAndFreeCell(ARow, ACol: Cardinal);
|
procedure TsWorksheet.RemoveAndFreeCell(ARow, ACol: Cardinal);
|
||||||
var
|
|
||||||
cellnode: TAVLTreeNode;
|
|
||||||
cell: TCell;
|
|
||||||
begin
|
begin
|
||||||
// Delete the cell
|
FCells.DeleteCell(ARow, ACol);
|
||||||
cell.Row := ARow;
|
|
||||||
cell.Col := ACol;
|
|
||||||
cellnode := FCells.Find(@cell);
|
|
||||||
if cellnode <> nil then begin
|
|
||||||
Dispose(PCell(cellnode.Data));
|
|
||||||
FCells.Delete(cellnode);
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
@ -3871,7 +3676,25 @@ procedure TsWorksheet.Sort(const ASortParams: TsSortParams;
|
|||||||
until I >= R;
|
until I >= R;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function ContainsMergedCells: boolean;
|
||||||
|
var
|
||||||
|
r,c: Cardinal;
|
||||||
|
cell: PCell;
|
||||||
begin
|
begin
|
||||||
|
result := false;
|
||||||
|
for r := ARowFrom to ARowTo do
|
||||||
|
for c := AColFrom to AColTo do
|
||||||
|
begin
|
||||||
|
cell := FindCell(r, c);
|
||||||
|
if IsMerged(cell) then
|
||||||
|
exit(true);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
if ContainsMergedCells then
|
||||||
|
raise Exception.Create(rsCannotSortMerged);
|
||||||
|
|
||||||
FSortParams := ASortParams;
|
FSortParams := ASortParams;
|
||||||
if ASortParams.SortByCols then
|
if ASortParams.SortByCols then
|
||||||
QuickSort(ARowFrom, ARowTo)
|
QuickSort(ARowFrom, ARowTo)
|
||||||
@ -6117,13 +5940,11 @@ end;
|
|||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
procedure TsWorksheet.DeleteCol(ACol: Cardinal);
|
procedure TsWorksheet.DeleteCol(ACol: Cardinal);
|
||||||
var
|
var
|
||||||
AVLNode: TAVLTreeNode;
|
|
||||||
col: PCol;
|
col: PCol;
|
||||||
i: Integer;
|
i: Integer;
|
||||||
r, rr, cc: Cardinal;
|
r, rr, cc: Cardinal;
|
||||||
cell, basecell, nextcell: PCell;
|
cell, basecell, nextcell: PCell;
|
||||||
firstRow, lastCol, lastRow: Cardinal;
|
firstRow, lastCol, lastRow: Cardinal;
|
||||||
rng: PsCellRange;
|
|
||||||
begin
|
begin
|
||||||
lastCol := GetLastColIndex;
|
lastCol := GetLastColIndex;
|
||||||
lastRow := GetLastOccupiedRowIndex;
|
lastRow := GetLastOccupiedRowIndex;
|
||||||
@ -6172,10 +5993,15 @@ begin
|
|||||||
RemoveAndFreeCell(r, ACol);
|
RemoveAndFreeCell(r, ACol);
|
||||||
|
|
||||||
// Update column index of cell records
|
// Update column index of cell records
|
||||||
AVLNode := FCells.FindLowest;
|
FCells.PushCurrent;
|
||||||
while Assigned(AVLNode) do begin
|
try
|
||||||
DeleteColCallback(AVLNode.Data, {%H-}pointer(PtrInt(ACol)));
|
cell := FCells.GetFirstCell;
|
||||||
AVLNode := FCells.FindSuccessor(AVLNode);
|
while Assigned(cell) do begin
|
||||||
|
DeleteColCallback(cell, {%H-}pointer(PtrInt(ACol)));
|
||||||
|
cell := FCells.GetNextCell;
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
FCells.PopCurrent;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Update column index of col records
|
// Update column index of col records
|
||||||
@ -6202,13 +6028,11 @@ end;
|
|||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
procedure TsWorksheet.DeleteRow(ARow: Cardinal);
|
procedure TsWorksheet.DeleteRow(ARow: Cardinal);
|
||||||
var
|
var
|
||||||
AVLNode: TAVLTreeNode;
|
|
||||||
row: PRow;
|
row: PRow;
|
||||||
i: Integer;
|
i: Integer;
|
||||||
c, rr, cc: Cardinal;
|
c, rr, cc: Cardinal;
|
||||||
firstCol, lastCol, lastRow: Cardinal;
|
firstCol, lastCol, lastRow: Cardinal;
|
||||||
cell, nextcell, basecell: PCell;
|
cell, nextcell, basecell: PCell;
|
||||||
rng: PsCellRange;
|
|
||||||
begin
|
begin
|
||||||
firstCol := GetFirstColIndex;
|
firstCol := GetFirstColIndex;
|
||||||
lastCol := GetLastOccupiedColIndex;
|
lastCol := GetLastOccupiedColIndex;
|
||||||
@ -6256,10 +6080,10 @@ begin
|
|||||||
RemoveAndFreeCell(ARow, c);
|
RemoveAndFreeCell(ARow, c);
|
||||||
|
|
||||||
// Update row index of cell records
|
// Update row index of cell records
|
||||||
AVLNode := FCells.FindLowest;
|
cell := FCells.GetFirstCell;
|
||||||
while Assigned(AVLNode) do begin
|
while Assigned(cell) do begin
|
||||||
DeleteRowCallback(AVLNode.Data, {%H-}pointer(PtrInt(ARow)));
|
DeleteRowCallback(cell, {%H-}pointer(PtrInt(ARow)));
|
||||||
AVLNode := FCells.FindSuccessor(AVLNode);
|
cell := FCells.GetNextCell;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Update row index of row records
|
// Update row index of row records
|
||||||
@ -6291,16 +6115,14 @@ var
|
|||||||
i: Integer;
|
i: Integer;
|
||||||
r: Cardinal;
|
r: Cardinal;
|
||||||
cell: PCell;
|
cell: PCell;
|
||||||
AVLNode: TAVLTreeNode;
|
|
||||||
rng: PsCellRange;
|
rng: PsCellRange;
|
||||||
begin
|
begin
|
||||||
// Handling of shared formula references is too complicated for me...
|
// Handling of shared formula references is too complicated for me...
|
||||||
// Split them into isolated cell formulas
|
// Split them into isolated cell formulas
|
||||||
AVLNode := FCells.FindLowest;
|
cell := FCells.GetFirstCell;
|
||||||
while Assigned(AVLNode) do begin
|
while Assigned(cell) do begin
|
||||||
cell := PCell(AVLNode.Data);
|
|
||||||
SplitSharedFormula(cell);
|
SplitSharedFormula(cell);
|
||||||
AVLNode := FCells.FindSuccessor(AVLNode);
|
cell := FCells.GetNextCell;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Update column index of comments
|
// Update column index of comments
|
||||||
@ -6310,10 +6132,10 @@ begin
|
|||||||
FHyperlinks.InsertRowOrCol(ACol, false);
|
FHyperlinks.InsertRowOrCol(ACol, false);
|
||||||
|
|
||||||
// Update column index of cell records
|
// Update column index of cell records
|
||||||
AVLNode := FCells.FindLowest;
|
cell := FCells.GetFirstCell;
|
||||||
while Assigned(AVLNode) do begin
|
while Assigned(cell) do begin
|
||||||
InsertColCallback(AVLNode.Data, {%H-}pointer(PtrInt(ACol)));
|
InsertColCallback(cell, {%H-}pointer(PtrInt(ACol)));
|
||||||
AVLNode := FCells.FindSuccessor(AVLNode);
|
cell := FCells.GetNextCell;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Update column index of column records
|
// Update column index of column records
|
||||||
@ -6416,16 +6238,14 @@ var
|
|||||||
i: Integer;
|
i: Integer;
|
||||||
c: Cardinal;
|
c: Cardinal;
|
||||||
cell: PCell;
|
cell: PCell;
|
||||||
AVLNode: TAVLTreeNode;
|
|
||||||
rng: PsCellRange;
|
rng: PsCellRange;
|
||||||
begin
|
begin
|
||||||
// Handling of shared formula references is too complicated for me...
|
// Handling of shared formula references is too complicated for me...
|
||||||
// Splits them into isolated cell formulas
|
// Splits them into isolated cell formulas
|
||||||
AVLNode := FCells.FindLowest;
|
cell := FCells.GetFirstCell;
|
||||||
while Assigned(AVLNode) do begin
|
while Assigned(cell) do begin
|
||||||
cell := PCell(AVLNode.Data);
|
|
||||||
SplitSharedFormula(cell);
|
SplitSharedFormula(cell);
|
||||||
AVLNode := FCells.FindSuccessor(AVLNode);
|
cell := FCells.GetNextCell;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Update row index of cell comments
|
// Update row index of cell comments
|
||||||
@ -6435,10 +6255,10 @@ begin
|
|||||||
FHyperlinks.InsertRowOrCol(ARow, true);
|
FHyperlinks.InsertRowOrCol(ARow, true);
|
||||||
|
|
||||||
// Update row index of cell records
|
// Update row index of cell records
|
||||||
AVLNode := FCells.FindLowest;
|
cell := FCells.GetFirstCell;
|
||||||
while Assigned(AVLNode) do begin
|
while Assigned(cell) do begin
|
||||||
InsertRowCallback(AVLNode.Data, {%H-}pointer(PtrInt(ARow)));
|
InsertRowCallback(cell, {%H-}pointer(PtrInt(ARow)));
|
||||||
AVLNode := FCells.FindSuccessor(AVLNode);
|
cell := FCells.GetNextCell;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Update row index of row records
|
// Update row index of row records
|
||||||
@ -8249,7 +8069,6 @@ end;
|
|||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
function TsWorkbook.UsesColor(AColorIndex: TsColor): Boolean;
|
function TsWorkbook.UsesColor(AColorIndex: TsColor): Boolean;
|
||||||
var
|
var
|
||||||
Node: TAVLTreeNode;
|
|
||||||
sheet: TsWorksheet;
|
sheet: TsWorksheet;
|
||||||
cell: PCell;
|
cell: PCell;
|
||||||
i: Integer;
|
i: Integer;
|
||||||
@ -8261,10 +8080,9 @@ begin
|
|||||||
for i:=0 to GetWorksheetCount-1 do
|
for i:=0 to GetWorksheetCount-1 do
|
||||||
begin
|
begin
|
||||||
sheet := GetWorksheetByIndex(i);
|
sheet := GetWorksheetByIndex(i);
|
||||||
Node := sheet.Cells.FindLowest;
|
cell := sheet.Cells.GetFirstCell;
|
||||||
while Assigned(Node) do
|
while Assigned(cell) do
|
||||||
begin
|
begin
|
||||||
cell := PCell(Node.Data);
|
|
||||||
fmt := GetPointerToCellFormat(cell^.FormatIndex);
|
fmt := GetPointerToCellFormat(cell^.FormatIndex);
|
||||||
if (uffBackground in fmt^.UsedFormattingFields) then
|
if (uffBackground in fmt^.UsedFormattingFields) then
|
||||||
begin
|
begin
|
||||||
@ -8281,7 +8099,7 @@ begin
|
|||||||
if fnt.Color = AColorIndex then
|
if fnt.Color = AColorIndex then
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
Node := sheet.Cells.FindSuccessor(Node);
|
cell := sheet.Cells.GetNextCell;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
Result := false;
|
Result := false;
|
||||||
|
@ -1495,8 +1495,7 @@ begin
|
|||||||
if Worksheet = nil then
|
if Worksheet = nil then
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
cell := Worksheet.GetFirstCell;
|
for cell in Worksheet.Cells do
|
||||||
while cell <> nil do
|
|
||||||
begin
|
begin
|
||||||
if (uffBorder in Worksheet.ReadUsedFormatting(cell)) then
|
if (uffBorder in Worksheet.ReadUsedFormatting(cell)) then
|
||||||
begin
|
begin
|
||||||
@ -1505,7 +1504,6 @@ begin
|
|||||||
rect := CellRect(c, r);
|
rect := CellRect(c, r);
|
||||||
DrawCellBorders(c, r, rect);
|
DrawCellBorders(c, r, rect);
|
||||||
end;
|
end;
|
||||||
cell := Worksheet.GetNextCell;
|
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -2003,7 +2001,6 @@ var
|
|||||||
P1, P2: TPoint;
|
P1, P2: TPoint;
|
||||||
cell: PCell;
|
cell: PCell;
|
||||||
r1,c1,r2,c2: Cardinal;
|
r1,c1,r2,c2: Cardinal;
|
||||||
rng: PsCellRange;
|
|
||||||
begin
|
begin
|
||||||
// Selected cell
|
// Selected cell
|
||||||
cell := Worksheet.FindCell(GetWorksheetRow(Selection.Top), GetWorksheetCol(Selection.Left));
|
cell := Worksheet.FindCell(GetWorksheetRow(Selection.Top), GetWorksheetCol(Selection.Left));
|
||||||
|
@ -20,7 +20,7 @@ interface
|
|||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, Sysutils, AVL_Tree,
|
Classes, Sysutils, AVL_Tree,
|
||||||
fpsTypes, fpSpreadsheet, fpsNumFormat;
|
fpsTypes, fpsClasses, fpSpreadsheet, fpsNumFormat;
|
||||||
|
|
||||||
type
|
type
|
||||||
{@@
|
{@@
|
||||||
@ -101,7 +101,7 @@ type
|
|||||||
|
|
||||||
{ Helpers for writing }
|
{ Helpers for writing }
|
||||||
procedure WriteCellCallback(ACell: PCell; AStream: TStream);
|
procedure WriteCellCallback(ACell: PCell; AStream: TStream);
|
||||||
procedure WriteCellsToStream(AStream: TStream; ACells: TAVLTree);
|
procedure WriteCellsToStream(AStream: TStream; ACells: TsCells);
|
||||||
|
|
||||||
{ Record writing methods }
|
{ Record writing methods }
|
||||||
procedure WriteBlank(AStream: TStream; const ARow, ACol: Cardinal;
|
procedure WriteBlank(AStream: TStream; const ARow, ACol: Cardinal;
|
||||||
@ -124,11 +124,11 @@ type
|
|||||||
constructor Create(AWorkbook: TsWorkbook); override;
|
constructor Create(AWorkbook: TsWorkbook); override;
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
{ General writing methods }
|
{ General writing methods }
|
||||||
procedure IterateThroughCells(AStream: TStream; ACells: TAVLTree;
|
procedure IterateThroughCells(AStream: TStream; ACells: TsCells;
|
||||||
ACallback: TCellsCallback);
|
ACallback: TCellsCallback);
|
||||||
procedure IterateThroughComments(AStream: TStream; AComments: TAVLTree;
|
procedure IterateThroughComments(AStream: TStream; AComments: TsComments;
|
||||||
ACallback: TCommentsCallback);
|
ACallback: TCommentsCallback);
|
||||||
procedure IterateThroughHyperlinks(AStream: TStream; AHyperlinks: TAVLTree;
|
procedure IterateThroughHyperlinks(AStream: TStream; AHyperlinks: TsHyperlinks;
|
||||||
ACallback: THyperlinksCallback);
|
ACallback: THyperlinksCallback);
|
||||||
procedure WriteToFile(const AFileName: string;
|
procedure WriteToFile(const AFileName: string;
|
||||||
const AOverwriteExisting: Boolean = False); override;
|
const AOverwriteExisting: Boolean = False); override;
|
||||||
@ -471,16 +471,29 @@ end;
|
|||||||
cell as well as the destination stream.
|
cell as well as the destination stream.
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
procedure TsCustomSpreadWriter.IterateThroughCells(AStream: TStream;
|
procedure TsCustomSpreadWriter.IterateThroughCells(AStream: TStream;
|
||||||
ACells: TAVLTree; ACallback: TCellsCallback);
|
ACells: TsCells; ACallback: TCellsCallback);
|
||||||
var
|
var
|
||||||
AVLNode: TAVLTreeNode;
|
cell: PCell;
|
||||||
|
node: TAVLTreeNode;
|
||||||
begin
|
begin
|
||||||
AVLNode := ACells.FindLowest;
|
node := ACells.FindLowest;
|
||||||
while Assigned(AVLNode) do
|
while Assigned(node) do begin
|
||||||
begin
|
ACallback(PCell(node.Data), AStream);
|
||||||
ACallback(PCell(AVLNode.Data), AStream);
|
node := ACells.FindSuccessor(node);
|
||||||
AVLNode := ACells.FindSuccessor(AVLNode);
|
|
||||||
end;
|
end;
|
||||||
|
{
|
||||||
|
ACells.PushCurrent;
|
||||||
|
try
|
||||||
|
cell := ACells.GetFirstCell;
|
||||||
|
while Assigned(cell) do
|
||||||
|
begin
|
||||||
|
ACallback(cell, AStream);
|
||||||
|
cell := ACells.GetNextCell;
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
ACells.PopCurrent;
|
||||||
|
end;
|
||||||
|
}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
@ -493,19 +506,24 @@ end;
|
|||||||
comment record as well as the destination stream.
|
comment record as well as the destination stream.
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
procedure TsCustomSpreadWriter.IterateThroughComments(AStream: TStream;
|
procedure TsCustomSpreadWriter.IterateThroughComments(AStream: TStream;
|
||||||
AComments: TAVLTree; ACallback: TCommentsCallback);
|
AComments: TsComments; ACallback: TCommentsCallback);
|
||||||
var
|
var
|
||||||
AVLNode: TAVLTreeNode;
|
|
||||||
index: Integer;
|
index: Integer;
|
||||||
|
comment: PsComment;
|
||||||
begin
|
begin
|
||||||
index := 0;
|
index := 0;
|
||||||
AVLNode := AComments.FindLowest;
|
AComments.PushCurrent;
|
||||||
while Assigned(AVLNode) do
|
try
|
||||||
|
comment := PsComment(AComments.GetFirst);
|
||||||
|
while Assigned(comment) do
|
||||||
begin
|
begin
|
||||||
ACallback(PsComment(AVLNode.Data), index, AStream);
|
ACallback(comment, index, AStream);
|
||||||
AVLNode := AComments.FindSuccessor(AVLNode);
|
comment := PsComment(AComments.GetNext);
|
||||||
inc(index);
|
inc(index);
|
||||||
end;
|
end;
|
||||||
|
finally
|
||||||
|
AComments.PopCurrent;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
@ -518,18 +536,20 @@ end;
|
|||||||
the hyperlink record as well as the destination stream.
|
the hyperlink record as well as the destination stream.
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
procedure TsCustomSpreadWriter.IterateThroughHyperlinks(AStream: TStream;
|
procedure TsCustomSpreadWriter.IterateThroughHyperlinks(AStream: TStream;
|
||||||
AHyperlinks: TAVLTree; ACallback: THyperlinksCallback);
|
AHyperlinks: TsHyperlinks; ACallback: THyperlinksCallback);
|
||||||
var
|
var
|
||||||
AVLNode: TAVLTreeNode;
|
hyperlink: PsHyperlink;
|
||||||
index: Integer;
|
|
||||||
begin
|
begin
|
||||||
index := 0;
|
AHyperlinks.PushCurrent;
|
||||||
AVLNode := AHyperlinks.FindLowest;
|
try
|
||||||
while Assigned(AVLNode) do
|
hyperlink := PsHyperlink(AHyperlinks.GetFirst);
|
||||||
|
while Assigned(hyperlink) do
|
||||||
begin
|
begin
|
||||||
ACallback(PsHyperlink(AVLNode.Data), AStream);
|
ACallback(hyperlink, AStream);
|
||||||
AVLNode := AHyperlinks.FindSuccessor(AVLNode);
|
hyperlink := PsHyperlink(AHyperlinks.GetNext);
|
||||||
inc(index);
|
end;
|
||||||
|
finally
|
||||||
|
AHyperlinks.PopCurrent;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -595,7 +615,7 @@ end;
|
|||||||
@param ACells List of cells to be writeen
|
@param ACells List of cells to be writeen
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
procedure TsCustomSpreadWriter.WriteCellsToStream(AStream: TStream;
|
procedure TsCustomSpreadWriter.WriteCellsToStream(AStream: TStream;
|
||||||
ACells: TAVLTree);
|
ACells: TsCells);
|
||||||
begin
|
begin
|
||||||
IterateThroughCells(AStream, ACells, WriteCellCallback);
|
IterateThroughCells(AStream, ACells, WriteCellCallback);
|
||||||
end;
|
end;
|
||||||
|
@ -55,12 +55,14 @@ resourcestring
|
|||||||
rsIndexInSSTOutOfRange = 'Index %d in SST out of range (0-%d).';
|
rsIndexInSSTOutOfRange = 'Index %d in SST out of range (0-%d).';
|
||||||
rsAmbiguousDecThouSeparator = 'Assuming usage of decimal separator in "%s".';
|
rsAmbiguousDecThouSeparator = 'Assuming usage of decimal separator in "%s".';
|
||||||
rsCodePageNotSupported = 'Code page "%s" is not supported. Using "cp1252" (Latin 1) instead.';
|
rsCodePageNotSupported = 'Code page "%s" is not supported. Using "cp1252" (Latin 1) instead.';
|
||||||
|
|
||||||
rsNoValidHyperlinkInternal = 'The hyperlink "%s" is not a valid cell address.';
|
rsNoValidHyperlinkInternal = 'The hyperlink "%s" is not a valid cell address.';
|
||||||
rsNoValidHyperlinkURI = 'The hyperlink "%s" is not a valid URI.';
|
rsNoValidHyperlinkURI = 'The hyperlink "%s" is not a valid URI.';
|
||||||
rsEmptyHyperlink = 'The hyperlink is not specified.';
|
rsEmptyHyperlink = 'The hyperlink is not specified.';
|
||||||
rsODSHyperlinksOfTextCellsOnly = 'Cell %s: OpenDocument supports hyperlinks for text cells only.';
|
rsODSHyperlinksOfTextCellsOnly = 'Cell %s: OpenDocument supports hyperlinks for text cells only.';
|
||||||
rsStdHyperlinkTooltip = 'Press the left mouse button a bit longer to activate the hyperlink.';
|
rsStdHyperlinkTooltip = 'Press the left mouse button a bit longer to activate the hyperlink.';
|
||||||
|
|
||||||
|
rsCannotSortMerged = 'The cell range cannot be sorted because it contains merged cells.';
|
||||||
|
|
||||||
rsTRUE = 'TRUE'; // wp: Do we really want to translate these strings?
|
rsTRUE = 'TRUE'; // wp: Do we really want to translate these strings?
|
||||||
rsFALSE = 'FALSE';
|
rsFALSE = 'FALSE';
|
||||||
@ -73,9 +75,10 @@ resourcestring
|
|||||||
rsErrArgError = '#N/A';
|
rsErrArgError = '#N/A';
|
||||||
rsErrFormulaNotSupported = '<FORMULA?>';
|
rsErrFormulaNotSupported = '<FORMULA?>';
|
||||||
|
|
||||||
|
(*
|
||||||
{%H-}rsNoValidDateTimeFormatString = 'No valid date/time format string.';
|
{%H-}rsNoValidDateTimeFormatString = 'No valid date/time format string.';
|
||||||
{%H-}rsIllegalNumberFormat = 'Illegal number format.';
|
{%H-}rsIllegalNumberFormat = 'Illegal number format.';
|
||||||
|
*)
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
|
@ -531,6 +531,44 @@ type
|
|||||||
property Items[AIndex: Integer]: PsCellFormat read GetItem write SetItem; default;
|
property Items[AIndex: Integer]: PsCellFormat read GetItem write SetItem; default;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{@@ Pointer to a TCell record }
|
||||||
|
PCell = ^TCell;
|
||||||
|
|
||||||
|
{@@ Cell structure for TsWorksheet
|
||||||
|
The cell record contains information on the location of the cell (row and
|
||||||
|
column index), on the value contained (number, date, text, ...), on
|
||||||
|
formatting, etc.
|
||||||
|
|
||||||
|
Never suppose that all *Value fields are valid,
|
||||||
|
only one of the ContentTypes is valid. For other fields
|
||||||
|
use TWorksheet.ReadAsUTF8Text and similar methods
|
||||||
|
|
||||||
|
@see ReadAsUTF8Text }
|
||||||
|
TCell = record
|
||||||
|
{ Location of the cell }
|
||||||
|
Row: Cardinal; // zero-based
|
||||||
|
Col: Cardinal; // zero-based
|
||||||
|
Worksheet: Pointer; // Must be cast to TsWorksheet when used
|
||||||
|
{ Status flags }
|
||||||
|
Flags: TsCellFlags;
|
||||||
|
{ Index of format record in the workbook's FCellFormatList }
|
||||||
|
FormatIndex: Integer;
|
||||||
|
{ Special information }
|
||||||
|
SharedFormulaBase: PCell; // Cell containing the shared formula
|
||||||
|
{ Cell content }
|
||||||
|
UTF8StringValue: String; // Strings cannot be part of a variant record
|
||||||
|
FormulaValue: String;
|
||||||
|
case ContentType: TCellContentType of // variant part must be at the end
|
||||||
|
cctEmpty : (); // has no data at all
|
||||||
|
cctFormula : (); // FormulaValue is outside the variant record
|
||||||
|
cctNumber : (Numbervalue: Double);
|
||||||
|
cctUTF8String : (); // UTF8StringValue is outside the variant record
|
||||||
|
cctDateTime : (DateTimevalue: TDateTime);
|
||||||
|
cctBool : (BoolValue: boolean);
|
||||||
|
cctError : (ErrorValue: TsErrorValue);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure InitFormatRecord(out AValue: TsCellFormat);
|
procedure InitFormatRecord(out AValue: TsCellFormat);
|
||||||
|
|
||||||
|
|
||||||
|
@ -148,6 +148,9 @@ function InitSortParams(ASortByCols: Boolean = true; ANumSortKeys: Integer = 1;
|
|||||||
|
|
||||||
procedure SplitHyperlink(AValue: String; out ATarget, ABookmark: String);
|
procedure SplitHyperlink(AValue: String; out ATarget, ABookmark: String);
|
||||||
|
|
||||||
|
procedure InitCell(out ACell: TCell); overload;
|
||||||
|
procedure InitCell(ARow, ACol: Cardinal; out ACell: TCell); overload;
|
||||||
|
|
||||||
procedure AppendToStream(AStream: TStream; const AString: String); inline; overload;
|
procedure AppendToStream(AStream: TStream; const AString: String); inline; overload;
|
||||||
procedure AppendToStream(AStream: TStream; const AString1, AString2: String); inline; overload;
|
procedure AppendToStream(AStream: TStream; const AString1, AString2: String); inline; overload;
|
||||||
procedure AppendToStream(AStream: TStream; const AString1, AString2, AString3: String); inline; overload;
|
procedure AppendToStream(AStream: TStream; const AString1, AString2, AString3: String); inline; overload;
|
||||||
@ -2051,6 +2054,32 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Initalizes a new cell.
|
||||||
|
@return New cell record
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
procedure InitCell(out ACell: TCell);
|
||||||
|
begin
|
||||||
|
ACell.FormulaValue := '';
|
||||||
|
ACell.UTF8StringValue := '';
|
||||||
|
FillChar(ACell, SizeOf(ACell), 0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Initalizes a new cell and presets the row and column fields of the cell record
|
||||||
|
to the parameters passed to the procedure.
|
||||||
|
|
||||||
|
@param ARow Row index of the new cell
|
||||||
|
@param ACol Column index of the new cell
|
||||||
|
@return New cell record with row and column fields preset to passed values.
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
procedure InitCell(ARow, ACol: Cardinal; out ACell: TCell);
|
||||||
|
begin
|
||||||
|
InitCell(ACell);
|
||||||
|
ACell.Row := ARow;
|
||||||
|
ACell.Col := ACol;
|
||||||
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Appends a string to a stream
|
Appends a string to a stream
|
||||||
|
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 471 B After Width: | Height: | Size: 567 B |
Binary file not shown.
Before Width: | Height: | Size: 567 B After Width: | Height: | Size: 471 B |
363
components/fpspreadsheet/tests/enumeratortests.pas
Normal file
363
components/fpspreadsheet/tests/enumeratortests.pas
Normal file
@ -0,0 +1,363 @@
|
|||||||
|
{ Tests for iteration through cells by means of the enumerator of the cells tree.
|
||||||
|
This unit test is not writing anything to file.
|
||||||
|
}
|
||||||
|
|
||||||
|
unit enumeratortests;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
// Not using Lazarus package as the user may be working with multiple versions
|
||||||
|
// Instead, add .. to unit search path
|
||||||
|
Classes, SysUtils, fpcunit, testregistry,
|
||||||
|
fpstypes, fpspreadsheet, fpsclasses, {and a project requirement for lclbase for utf8 handling}
|
||||||
|
testsutility;
|
||||||
|
|
||||||
|
type
|
||||||
|
{ TSpreadEnumeratorTests }
|
||||||
|
TSpreadEnumeratorTests = class(TTestCase)
|
||||||
|
private
|
||||||
|
|
||||||
|
protected
|
||||||
|
procedure SetUp; override;
|
||||||
|
procedure TearDown; override;
|
||||||
|
procedure Test_EnumCells(what: Integer; reverse, withGaps: Boolean);
|
||||||
|
procedure Test_EnumComments(what: Integer; withGaps: Boolean);
|
||||||
|
|
||||||
|
published
|
||||||
|
procedure Test_Enum_Cells_All;
|
||||||
|
procedure Test_Enum_Cells_All_Reverse;
|
||||||
|
procedure Test_Enum_Cells_FullRow;
|
||||||
|
procedure Test_Enum_Cells_FullRow_Reverse;
|
||||||
|
procedure Test_Enum_Cells_FullCol;
|
||||||
|
procedure Test_Enum_Cells_FullCol_Reverse;
|
||||||
|
procedure Test_Enum_Cells_PartialRow;
|
||||||
|
procedure Test_Enum_Cells_PartialRow_Reverse;
|
||||||
|
procedure Test_Enum_Cells_PartialCol;
|
||||||
|
procedure Test_Enum_Cells_PartialCol_Reverse;
|
||||||
|
procedure Test_Enum_Cells_Range;
|
||||||
|
procedure Test_Enum_Cells_Range_Reverse;
|
||||||
|
|
||||||
|
procedure Test_Enum_Cells_WithGaps_All;
|
||||||
|
procedure Test_Enum_Cells_WithGaps_All_Reverse;
|
||||||
|
procedure Test_Enum_Cells_WithGaps_FullRow;
|
||||||
|
procedure Test_Enum_Cells_WithGaps_FullRow_Reverse;
|
||||||
|
procedure Test_Enum_Cells_WithGaps_FullCol;
|
||||||
|
procedure Test_Enum_Cells_WithGaps_FullCol_Reverse;
|
||||||
|
procedure Test_Enum_Cells_WithGaps_PartialRow;
|
||||||
|
procedure Test_Enum_Cells_WithGaps_PartialRow_Reverse;
|
||||||
|
procedure Test_Enum_Cells_WithGaps_PartialCol;
|
||||||
|
procedure Test_Enum_Cells_WithGaps_PartialCol_Reverse;
|
||||||
|
procedure Test_Enum_Cells_WithGaps_Range;
|
||||||
|
procedure Test_Enum_Cells_WithGaps_Range_Reverse;
|
||||||
|
|
||||||
|
procedure Test_Enum_Comments_All;
|
||||||
|
procedure Test_Enum_Comments_Range;
|
||||||
|
|
||||||
|
procedure Test_Enum_Comments_WithGaps_All;
|
||||||
|
procedure Test_Enum_Comments_WithGaps_Range;
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
const
|
||||||
|
NUM_ROWS = 100;
|
||||||
|
NUM_COLS = 100;
|
||||||
|
TEST_ROW = 10;
|
||||||
|
TEST_COL = 20;
|
||||||
|
TEST_ROW1 = 20;
|
||||||
|
TEST_ROW2 = 50;
|
||||||
|
TEST_COL1 = 30;
|
||||||
|
TEST_COL2 = 60;
|
||||||
|
|
||||||
|
procedure TSpreadEnumeratorTests.Setup;
|
||||||
|
begin
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadEnumeratorTests.TearDown;
|
||||||
|
begin
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadEnumeratorTests.Test_EnumCells(what: Integer; reverse: Boolean;
|
||||||
|
withGaps: Boolean);
|
||||||
|
{ what = 1 ---> iterate through entire worksheet
|
||||||
|
what = 2 ---> iterate along full row
|
||||||
|
what = 3 ---> iterate along full column
|
||||||
|
what = 4 ---> iterate along partial row
|
||||||
|
what = 5 ---> iterate along partial column
|
||||||
|
what = 6 ---> iterate through rectangular cell range
|
||||||
|
|
||||||
|
The test writes numbers into the worksheet calculated by <row>*10000 + <col>.
|
||||||
|
Then the test iterates through the designed range (according to "what") and
|
||||||
|
compares the read number with the soll values.
|
||||||
|
|
||||||
|
If "withGaps" is true then numbers are only written at cells where
|
||||||
|
<col>+<row> is odd. }
|
||||||
|
var
|
||||||
|
row, col: Cardinal;
|
||||||
|
cell: PCell;
|
||||||
|
MyWorkbook: TsWorkbook;
|
||||||
|
MyWorksheet: TsWorksheet;
|
||||||
|
expected, actual: Double;
|
||||||
|
enumerator: TsCellEnumerator;
|
||||||
|
begin
|
||||||
|
MyWorkbook := TsWorkbook.Create;
|
||||||
|
try
|
||||||
|
MyWorksheet := MyWorkbook.AddWorksheet('Sheet1');
|
||||||
|
for row := 0 to NUM_ROWS-1 do
|
||||||
|
for col := 0 to NUM_COLS-1 do
|
||||||
|
if (withGaps and odd(row + col)) or (not withGaps) then
|
||||||
|
MyWorksheet.WriteNumber(row, col, row*10000.0 + col);
|
||||||
|
|
||||||
|
if reverse then
|
||||||
|
case what of
|
||||||
|
1: enumerator := MyWorksheet.Cells.GetReverseRangeEnumerator(0, 0, $7FFFFFFF, $7FFFFFFF);
|
||||||
|
2: enumerator := Myworksheet.Cells.GetReverseRowEnumerator(TEST_ROW);
|
||||||
|
3: enumerator := MyWorksheet.Cells.GetReverseColEnumerator(TEST_COL);
|
||||||
|
4: enumerator := MyWorksheet.Cells.GetReverseRowEnumerator(TEST_ROW, TEST_COL1, TEST_COL2);
|
||||||
|
5: enumerator := Myworksheet.Cells.GetReverseColEnumerator(TEST_COL, TEST_ROW1, TEST_ROW2);
|
||||||
|
6: enumerator := MyWorksheet.Cells.GetReverseRangeEnumerator(TEST_ROW1, TEST_COL1, TEST_ROW2, TEST_COL2);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
case what of
|
||||||
|
1: enumerator := MyWorksheet.Cells.GetEnumerator;
|
||||||
|
2: enumerator := Myworksheet.Cells.GetRowEnumerator(TEST_ROW);
|
||||||
|
3: enumerator := MyWorksheet.Cells.GetColEnumerator(TEST_COL);
|
||||||
|
4: enumerator := MyWorksheet.Cells.GetRowEnumerator(TEST_ROW, TEST_COL1, TEST_COL2);
|
||||||
|
5: enumerator := Myworksheet.Cells.GetColEnumerator(TEST_COL, TEST_ROW1, TEST_ROW2);
|
||||||
|
6: enumerator := MyWorksheet.Cells.GetRangeEnumerator(TEST_ROW1, TEST_COL1, TEST_ROW2, TEST_COL2);
|
||||||
|
end;
|
||||||
|
|
||||||
|
for cell in enumerator do
|
||||||
|
begin
|
||||||
|
row := cell^.Row;
|
||||||
|
col := cell^.Col;
|
||||||
|
if (withgaps and odd(row + col)) or (not withgaps) then
|
||||||
|
expected := row * 10000.0 + col
|
||||||
|
else
|
||||||
|
expected := 0.0;
|
||||||
|
actual := MyWorksheet.ReadAsNumber(cell);
|
||||||
|
CheckEquals(expected, actual,
|
||||||
|
'Enumerated cell value mismatch, cell '+CellNotation(MyWorksheet, row, col));
|
||||||
|
end;
|
||||||
|
|
||||||
|
// for debugging, to see the data file
|
||||||
|
// MyWorkbook.WriteToFile('enumerator-test.xlsx', sfOOXML, true);
|
||||||
|
|
||||||
|
finally
|
||||||
|
MyWorkbook.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadEnumeratorTests.Test_EnumComments(what: Integer;
|
||||||
|
withGaps: Boolean);
|
||||||
|
{ what = 1 ---> iterate through entire worksheet
|
||||||
|
what = 2 ---> iterate through rectangular cell range
|
||||||
|
|
||||||
|
The test writes comments into the worksheet calculated by <row>*10000 + <col>.
|
||||||
|
Then the test iterates through the designed range (according to "what") and
|
||||||
|
compares the read comments with the soll values.
|
||||||
|
|
||||||
|
if "withGaps" is true then comments are only written at cells where
|
||||||
|
<col>+<row> is odd. }
|
||||||
|
var
|
||||||
|
row, col: Cardinal;
|
||||||
|
comment: PsComment;
|
||||||
|
MyWorkbook: TsWorkbook;
|
||||||
|
MyWorksheet: TsWorksheet;
|
||||||
|
expected, actual: string;
|
||||||
|
enumerator: TsCommentEnumerator;
|
||||||
|
begin
|
||||||
|
MyWorkbook := TsWorkbook.Create;
|
||||||
|
try
|
||||||
|
MyWorksheet := MyWorkbook.AddWorksheet('Sheet1');
|
||||||
|
for row := 0 to NUM_ROWS-1 do
|
||||||
|
for col := 0 to NUM_COLS-1 do
|
||||||
|
if (withGaps and odd(row + col)) or (not withGaps) then
|
||||||
|
MyWorksheet.WriteComment(row, col, IntToStr(row*10000 + col));
|
||||||
|
|
||||||
|
case what of
|
||||||
|
1: enumerator := MyWorksheet.Comments.GetEnumerator;
|
||||||
|
2: enumerator := MyWorksheet.Comments.GetRangeEnumerator(TEST_ROW1, TEST_COL1, TEST_ROW2, TEST_COL2);
|
||||||
|
end;
|
||||||
|
|
||||||
|
for comment in enumerator do
|
||||||
|
begin
|
||||||
|
row := comment^.Row;
|
||||||
|
col := comment^.Col;
|
||||||
|
if (withgaps and odd(row + col)) or (not withgaps) then
|
||||||
|
expected := IntToStr(row * 10000 + col)
|
||||||
|
else
|
||||||
|
expected := '';
|
||||||
|
actual := MyWorksheet.ReadComment(row, col);
|
||||||
|
CheckEquals(expected, actual,
|
||||||
|
'Enumerated comment mismatch, cell '+CellNotation(MyWorksheet, row, col));
|
||||||
|
end;
|
||||||
|
|
||||||
|
// for debugging, to see the data file
|
||||||
|
// MyWorkbook.WriteToFile('enumerator-test.xlsx', sfOOXML, true);
|
||||||
|
|
||||||
|
finally
|
||||||
|
MyWorkbook.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{ Fully filled worksheet }
|
||||||
|
procedure TSpreadEnumeratorTests.Test_Enum_Cells_All;
|
||||||
|
begin
|
||||||
|
Test_Enumcells(1, false, false);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadEnumeratorTests.Test_Enum_Cells_All_Reverse;
|
||||||
|
begin
|
||||||
|
Test_EnumCells(1, true, false);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadEnumeratorTests.Test_Enum_Cells_FullRow;
|
||||||
|
begin
|
||||||
|
Test_EnumCells(2, false, false);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadEnumeratorTests.Test_Enum_Cells_FullRow_Reverse;
|
||||||
|
begin
|
||||||
|
Test_EnumCells(2, true, false);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadEnumeratorTests.Test_Enum_Cells_FullCol;
|
||||||
|
begin
|
||||||
|
Test_EnumCells(3, false, false);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadEnumeratorTests.Test_Enum_Cells_FullCol_Reverse;
|
||||||
|
begin
|
||||||
|
Test_EnumCells(3, true, false);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadEnumeratorTests.Test_Enum_Cells_PartialRow;
|
||||||
|
begin
|
||||||
|
Test_EnumCells(4, false, false);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadEnumeratorTests.Test_Enum_Cells_PartialRow_Reverse;
|
||||||
|
begin
|
||||||
|
Test_EnumCells(4, true, false);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadEnumeratorTests.Test_Enum_Cells_PartialCol;
|
||||||
|
begin
|
||||||
|
Test_EnumCells(5, false, false);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadEnumeratorTests.Test_Enum_Cells_PartialCol_Reverse;
|
||||||
|
begin
|
||||||
|
Test_EnumCells(5, true, false);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadEnumeratorTests.Test_Enum_Cells_Range;
|
||||||
|
begin
|
||||||
|
Test_EnumCells(6, false, false);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadEnumeratorTests.Test_Enum_Cells_Range_Reverse;
|
||||||
|
begin
|
||||||
|
Test_EnumCells(6, true, false);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{ Worksheet with gaps}
|
||||||
|
|
||||||
|
procedure TSpreadEnumeratorTests.Test_Enum_Cells_WithGaps_All;
|
||||||
|
begin
|
||||||
|
Test_Enumcells(1, false, true);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadEnumeratorTests.Test_Enum_Cells_WithGaps_All_Reverse;
|
||||||
|
begin
|
||||||
|
Test_EnumCells(1, true, true);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadEnumeratorTests.Test_Enum_Cells_WithGaps_FullRow;
|
||||||
|
begin
|
||||||
|
Test_EnumCells(2, false, true);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadEnumeratorTests.Test_Enum_Cells_WithGaps_FullRow_Reverse;
|
||||||
|
begin
|
||||||
|
Test_EnumCells(2, true, true);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadEnumeratorTests.Test_Enum_Cells_WithGaps_FullCol;
|
||||||
|
begin
|
||||||
|
Test_EnumCells(3, false, true);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadEnumeratorTests.Test_Enum_Cells_WithGaps_FullCol_Reverse;
|
||||||
|
begin
|
||||||
|
Test_EnumCells(3, true, true);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadEnumeratorTests.Test_Enum_Cells_WithGaps_PartialRow;
|
||||||
|
begin
|
||||||
|
Test_EnumCells(4, false, true);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadEnumeratorTests.Test_Enum_Cells_WithGaps_PartialRow_Reverse;
|
||||||
|
begin
|
||||||
|
Test_EnumCells(4, true, true);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadEnumeratorTests.Test_Enum_Cells_WithGaps_PartialCol;
|
||||||
|
begin
|
||||||
|
Test_EnumCells(5, false, true);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadEnumeratorTests.Test_Enum_Cells_WithGaps_PartialCol_Reverse;
|
||||||
|
begin
|
||||||
|
Test_EnumCells(5, true, true);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadEnumeratorTests.Test_Enum_Cells_WithGaps_Range;
|
||||||
|
begin
|
||||||
|
Test_EnumCells(6, false, true);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadEnumeratorTests.Test_Enum_Cells_WithGaps_Range_Reverse;
|
||||||
|
begin
|
||||||
|
Test_EnumCells(6, true, true);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{ Fully filled worksheet }
|
||||||
|
|
||||||
|
procedure TSpreadEnumeratorTests.Test_Enum_Comments_All;
|
||||||
|
begin
|
||||||
|
Test_EnumComments(1, false);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadEnumeratorTests.Test_Enum_Comments_Range;
|
||||||
|
begin
|
||||||
|
Test_EnumComments(2, false);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Every other cell empty }
|
||||||
|
|
||||||
|
procedure TSpreadEnumeratorTests.Test_Enum_Comments_WithGaps_All;
|
||||||
|
begin
|
||||||
|
Test_EnumComments(1, true);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadEnumeratorTests.Test_Enum_Comments_WithGaps_Range;
|
||||||
|
begin
|
||||||
|
Test_EnumComments(2, true);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
initialization
|
||||||
|
RegisterTest(TSpreadEnumeratorTests);
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
@ -18,6 +18,11 @@ var
|
|||||||
SollSortNumbers: array[0..9] of Double;
|
SollSortNumbers: array[0..9] of Double;
|
||||||
SollSortStrings: array[0..9] of String;
|
SollSortStrings: array[0..9] of String;
|
||||||
|
|
||||||
|
CommentIsSortedToStringIndex: Integer;
|
||||||
|
CommentIsSortedToNumberIndex: Integer;
|
||||||
|
HyperlinkIsSortedToStringIndex: Integer;
|
||||||
|
HyperlinkIsSortedToNumberIndex: Integer;
|
||||||
|
|
||||||
procedure InitUnsortedData;
|
procedure InitUnsortedData;
|
||||||
|
|
||||||
type
|
type
|
||||||
@ -74,7 +79,7 @@ procedure InitUnsortedData;
|
|||||||
// The logics of the detection requires equal count of numbers and strings.
|
// The logics of the detection requires equal count of numbers and strings.
|
||||||
begin
|
begin
|
||||||
// When sorted the value is equal to the index
|
// When sorted the value is equal to the index
|
||||||
SollSortNumbers[0] := 9;
|
SollSortNumbers[0] := 9; // --> A1 --> will contain comment and hyperlink
|
||||||
SollSortNumbers[1] := 8;
|
SollSortNumbers[1] := 8;
|
||||||
SollSortNumbers[2] := 5;
|
SollSortNumbers[2] := 5;
|
||||||
SollSortNumbers[3] := 2;
|
SollSortNumbers[3] := 2;
|
||||||
@ -85,8 +90,11 @@ begin
|
|||||||
SollSortNumbers[8] := 4;
|
SollSortNumbers[8] := 4;
|
||||||
SollSortNumbers[9] := 0;
|
SollSortNumbers[9] := 0;
|
||||||
|
|
||||||
|
CommentIsSortedToNumberIndex := 9;
|
||||||
|
HyperlinkIsSortedToNumberIndex := 9;
|
||||||
|
|
||||||
// When sorted the value is equal to 'A' + index
|
// When sorted the value is equal to 'A' + index
|
||||||
SollSortStrings[0] := 'C';
|
SollSortStrings[0] := 'C'; // --> Ar --> will contain hyperlink and comment
|
||||||
SollSortStrings[1] := 'G';
|
SollSortStrings[1] := 'G';
|
||||||
SollSortStrings[2] := 'F';
|
SollSortStrings[2] := 'F';
|
||||||
SollSortStrings[3] := 'I';
|
SollSortStrings[3] := 'I';
|
||||||
@ -96,6 +104,9 @@ begin
|
|||||||
SollSortStrings[7] := 'H';
|
SollSortStrings[7] := 'H';
|
||||||
SollSortStrings[8] := 'E';
|
SollSortStrings[8] := 'E';
|
||||||
SollSortStrings[9] := 'A';
|
SollSortStrings[9] := 'A';
|
||||||
|
|
||||||
|
CommentIsSortedToStringIndex := 2;
|
||||||
|
HyperlinkIsSortedToStringIndex := 2;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -120,17 +131,15 @@ var
|
|||||||
MyWorksheet: TsWorksheet;
|
MyWorksheet: TsWorksheet;
|
||||||
MyWorkbook: TsWorkbook;
|
MyWorkbook: TsWorkbook;
|
||||||
i, ilast, n, row, col: Integer;
|
i, ilast, n, row, col: Integer;
|
||||||
MyCell: PCell;
|
|
||||||
TempFile: string; //write xls/xml to this file and read back from it
|
TempFile: string; //write xls/xml to this file and read back from it
|
||||||
L: TStringList;
|
L: TStringList;
|
||||||
s: String;
|
s: String;
|
||||||
sortParams: TsSortParams;
|
sortParams: TsSortParams;
|
||||||
sortOptions: TsSortOptions;
|
|
||||||
r1,r2,c1,c2: Cardinal;
|
|
||||||
actualNumber: Double;
|
actualNumber: Double;
|
||||||
actualString: String;
|
actualString: String;
|
||||||
expectedNumber: Double;
|
expectedNumber: Double;
|
||||||
expectedString: String;
|
expectedString: String;
|
||||||
|
cell: PCell;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
sortParams := InitSortParams(ASortByCols, 1);
|
sortParams := InitSortParams(ASortByCols, 1);
|
||||||
@ -145,11 +154,11 @@ begin
|
|||||||
row := 0;
|
row := 0;
|
||||||
if ASortByCols then begin
|
if ASortByCols then begin
|
||||||
case AWhat of
|
case AWhat of
|
||||||
0: for i :=0 to High(SollSortNumbers) do
|
0: for i :=0 to High(SollSortNumbers) do // Numbers only
|
||||||
MyWorksheet.WriteNumber(i, col, SollSortNumbers[i]);
|
MyWorksheet.WriteNumber(i, col, SollSortNumbers[i]);
|
||||||
1: for i := 0 to High(SollSortStrings) do
|
1: for i := 0 to High(SollSortStrings) do // Strings only
|
||||||
Myworksheet.WriteUTF8Text(i, col, SollSortStrings[i]);
|
Myworksheet.WriteUTF8Text(i, col, SollSortStrings[i]);
|
||||||
2: begin
|
2: begin // Numbers and strings
|
||||||
for i := 0 to High(SollSortNumbers) do
|
for i := 0 to High(SollSortNumbers) do
|
||||||
MyWorkSheet.WriteNumber(i*2, col, SollSortNumbers[i]);
|
MyWorkSheet.WriteNumber(i*2, col, SollSortNumbers[i]);
|
||||||
for i := 0 to High(SollSortStrings) do
|
for i := 0 to High(SollSortStrings) do
|
||||||
@ -171,6 +180,14 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
// Add comment and hyperlink to cell A1. After sorting it is expected
|
||||||
|
// in cell defined by CommentIsSortedToXXXIndex (XXX = Number/String)
|
||||||
|
|
||||||
|
if AFormat <> sfExcel8 then // Comments not implemented for writing Excel8
|
||||||
|
MyWorksheet.WriteComment(0, 0, 'Test comment');
|
||||||
|
MyWorksheet.WriteHyperlink(0, 0, 'http://www.google.com');
|
||||||
|
|
||||||
MyWorkBook.WriteToFile(TempFile, AFormat, true);
|
MyWorkBook.WriteToFile(TempFile, AFormat, true);
|
||||||
finally
|
finally
|
||||||
MyWorkbook.Free;
|
MyWorkbook.Free;
|
||||||
@ -223,20 +240,41 @@ begin
|
|||||||
end;
|
end;
|
||||||
case AWhat of
|
case AWhat of
|
||||||
0: begin
|
0: begin
|
||||||
actualNumber := MyWorksheet.ReadAsNumber(row, col);
|
cell := MyWorksheet.FindCell(row, col);
|
||||||
|
actualNumber := MyWorksheet.ReadAsNumber(cell);
|
||||||
expectedNumber := i;
|
expectedNumber := i;
|
||||||
CheckEquals(expectednumber, actualnumber,
|
CheckEquals(expectednumber, actualnumber,
|
||||||
'Sorted cell number mismatch, cell '+CellNotation(MyWorksheet, row, col));
|
'Sorted cell number mismatch, cell '+CellNotation(MyWorksheet, row, col));
|
||||||
|
if AFormat <> sfExcel8 then // Comments are not written for sfExcel8 --> ignore
|
||||||
|
CheckEquals(
|
||||||
|
i=CommentIsSortedToNumberIndex,
|
||||||
|
MyWorksheet.HasComment(cell),
|
||||||
|
'Sorted comment position mismatch, cell '+CellNotation(MyWorksheet, row, col));
|
||||||
|
CheckEquals(
|
||||||
|
i = HyperlinkisSortedToNumberIndex,
|
||||||
|
MyWorksheet.HasHyperlink(cell),
|
||||||
|
'Sorted hyperlink position mismatch, cell '+CellNotation(MyWorksheet, row, col));
|
||||||
end;
|
end;
|
||||||
1: begin
|
1: begin
|
||||||
actualString := MyWorksheet.ReadAsUTF8Text(row, col);
|
cell := MyWorksheet.FindCell(row, col);
|
||||||
|
actualString := MyWorksheet.ReadAsUTF8Text(cell);
|
||||||
expectedString := char(ord('A') + i);
|
expectedString := char(ord('A') + i);
|
||||||
CheckEquals(expectedstring, actualstring,
|
CheckEquals(expectedstring, actualstring,
|
||||||
'Sorted cell string mismatch, cell '+CellNotation(MyWorksheet, row, col));
|
'Sorted cell string mismatch, cell '+CellNotation(MyWorksheet, row, col));
|
||||||
|
if AFormat <> sfExcel8 then // Comments are not written for sfExcel8 --> ignore
|
||||||
|
CheckEquals(
|
||||||
|
i=CommentIsSortedToStringIndex,
|
||||||
|
MyWorksheet.HasComment(cell),
|
||||||
|
'Sorted comment position mismatch, cell '+CellNotation(MyWorksheet, row, col));
|
||||||
|
CheckEquals(
|
||||||
|
i = HyperlinkisSortedToStringIndex,
|
||||||
|
MyWorksheet.HasHyperlink(cell),
|
||||||
|
'Sorted hyperlink position mismatch, cell '+CellNotation(MyWorksheet, row, col));
|
||||||
end;
|
end;
|
||||||
2: begin // with increasing i, we see first the numbers, then the strings
|
2: begin // with increasing i, we see first the numbers, then the strings
|
||||||
if i <= High(SollSortNumbers) then begin
|
if i <= High(SollSortNumbers) then begin
|
||||||
actualnumber := MyWorksheet.ReadAsNumber(row, col);
|
cell := MyWorksheet.FindCell(row, col);
|
||||||
|
actualnumber := MyWorksheet.ReadAsNumber(cell);
|
||||||
expectedNumber := i;
|
expectedNumber := i;
|
||||||
CheckEquals(expectednumber, actualnumber,
|
CheckEquals(expectednumber, actualnumber,
|
||||||
'Sorted cell number mismatch, cell '+CellNotation(MyWorksheet, row, col));
|
'Sorted cell number mismatch, cell '+CellNotation(MyWorksheet, row, col));
|
||||||
@ -346,7 +384,7 @@ begin
|
|||||||
MyWorksheet.Sort(sortParams, 0, 0, 1, iLast);
|
MyWorksheet.Sort(sortParams, 0, 0, 1, iLast);
|
||||||
|
|
||||||
// for debugging, to see the sorted data
|
// for debugging, to see the sorted data
|
||||||
MyWorkbook.WriteToFile('sorted.xls', AFormat, true);
|
// MyWorkbook.WriteToFile('sorted.xls', AFormat, true);
|
||||||
|
|
||||||
for i:=0 to iLast do
|
for i:=0 to iLast do
|
||||||
begin
|
begin
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
<PackageName Value="FCL"/>
|
<PackageName Value="FCL"/>
|
||||||
</Item4>
|
</Item4>
|
||||||
</RequiredPackages>
|
</RequiredPackages>
|
||||||
<Units Count="22">
|
<Units Count="23">
|
||||||
<Unit0>
|
<Unit0>
|
||||||
<Filename Value="spreadtestgui.lpr"/>
|
<Filename Value="spreadtestgui.lpr"/>
|
||||||
<IsPartOfProject Value="True"/>
|
<IsPartOfProject Value="True"/>
|
||||||
@ -96,6 +96,7 @@
|
|||||||
<Unit13>
|
<Unit13>
|
||||||
<Filename Value="formulatests.pas"/>
|
<Filename Value="formulatests.pas"/>
|
||||||
<IsPartOfProject Value="True"/>
|
<IsPartOfProject Value="True"/>
|
||||||
|
<UnitName Value="formulatests"/>
|
||||||
</Unit13>
|
</Unit13>
|
||||||
<Unit14>
|
<Unit14>
|
||||||
<Filename Value="emptycelltests.pas"/>
|
<Filename Value="emptycelltests.pas"/>
|
||||||
@ -121,6 +122,7 @@
|
|||||||
<Unit19>
|
<Unit19>
|
||||||
<Filename Value="sortingtests.pas"/>
|
<Filename Value="sortingtests.pas"/>
|
||||||
<IsPartOfProject Value="True"/>
|
<IsPartOfProject Value="True"/>
|
||||||
|
<UnitName Value="sortingtests"/>
|
||||||
</Unit19>
|
</Unit19>
|
||||||
<Unit20>
|
<Unit20>
|
||||||
<Filename Value="copytests.pas"/>
|
<Filename Value="copytests.pas"/>
|
||||||
@ -131,6 +133,11 @@
|
|||||||
<IsPartOfProject Value="True"/>
|
<IsPartOfProject Value="True"/>
|
||||||
<UnitName Value="commenttests"/>
|
<UnitName Value="commenttests"/>
|
||||||
</Unit21>
|
</Unit21>
|
||||||
|
<Unit22>
|
||||||
|
<Filename Value="enumeratortests.pas"/>
|
||||||
|
<IsPartOfProject Value="True"/>
|
||||||
|
<UnitName Value="enumeratortests"/>
|
||||||
|
</Unit22>
|
||||||
</Units>
|
</Units>
|
||||||
</ProjectOptions>
|
</ProjectOptions>
|
||||||
<CompilerOptions>
|
<CompilerOptions>
|
||||||
|
@ -12,7 +12,7 @@ uses
|
|||||||
manualtests, testsutility, internaltests, formattests, colortests, fonttests,
|
manualtests, testsutility, internaltests, formattests, colortests, fonttests,
|
||||||
optiontests, numformatparsertests, formulatests, rpnFormulaUnit,
|
optiontests, numformatparsertests, formulatests, rpnFormulaUnit,
|
||||||
emptycelltests, errortests, virtualmodetests, insertdeletetests,
|
emptycelltests, errortests, virtualmodetests, insertdeletetests,
|
||||||
celltypetests, sortingtests, copytests, commenttests;
|
celltypetests, sortingtests, copytests, commenttests, enumeratortests;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
{$IFDEF HEAPTRC}
|
{$IFDEF HEAPTRC}
|
||||||
|
@ -2314,7 +2314,7 @@ var
|
|||||||
value: Variant;
|
value: Variant;
|
||||||
lCell: TCell;
|
lCell: TCell;
|
||||||
styleCell: PCell;
|
styleCell: PCell;
|
||||||
AVLNode: TAVLTreeNode;
|
cell: PCell;
|
||||||
rh: String;
|
rh: String;
|
||||||
h0: Single;
|
h0: Single;
|
||||||
begin
|
begin
|
||||||
@ -2395,11 +2395,9 @@ begin
|
|||||||
'<row r="%d" spans="%d:%d"%s>', [r+1, c1+1, c2+1, rh]));
|
'<row r="%d" spans="%d:%d"%s>', [r+1, c1+1, c2+1, rh]));
|
||||||
// Write cells belonging to this row.
|
// Write cells belonging to this row.
|
||||||
for c := c1 to c2 do begin
|
for c := c1 to c2 do begin
|
||||||
lCell.Row := r;
|
cell := AWorksheet.FindCell(r, c);
|
||||||
lCell.Col := c;
|
if Assigned(cell) then begin
|
||||||
AVLNode := AWorksheet.Cells.Find(@lCell);
|
WriteCellCallback(cell, AStream);
|
||||||
if Assigned(AVLNode) then begin
|
|
||||||
WriteCellCallback(PCell(AVLNode.Data), AStream);
|
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
AppendToStream(AStream,
|
AppendToStream(AStream,
|
||||||
|
Reference in New Issue
Block a user