fpspreadsheet: Add search form for visual demo.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@4215 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2015-07-27 23:19:18 +00:00
parent ef69632cea
commit 745ac96e84
5 changed files with 614 additions and 0 deletions

View File

@ -0,0 +1,233 @@
object SearchForm: TSearchForm
Left = 238
Height = 271
Top = 157
Width = 392
BorderStyle = bsDialog
Caption = 'Search'
ClientHeight = 271
ClientWidth = 392
FormStyle = fsStayOnTop
OnClose = FormClose
OnCreate = FormCreate
OnShow = FormShow
LCLVersion = '1.5'
object LblSearchText: TLabel
Left = 14
Height = 15
Top = 18
Width = 53
Caption = 'Search for'
ParentColor = False
end
object CbSearchText: TComboBox
Left = 93
Height = 23
Top = 14
Width = 283
Anchors = [akTop, akLeft, akRight]
ItemHeight = 15
TabOrder = 0
end
object CgSearchOptions: TCheckGroup
Left = 19
Height = 163
Top = 53
Width = 189
AutoFill = True
Caption = 'Search options'
ChildSizing.LeftRightSpacing = 6
ChildSizing.TopBottomSpacing = 6
ChildSizing.EnlargeHorizontal = crsHomogenousChildResize
ChildSizing.EnlargeVertical = crsHomogenousChildResize
ChildSizing.ShrinkHorizontal = crsScaleChilds
ChildSizing.ShrinkVertical = crsScaleChilds
ChildSizing.Layout = cclLeftToRightThenTopToBottom
ChildSizing.ControlsPerLine = 1
ClientHeight = 143
ClientWidth = 185
Items.Strings = (
'Compare full cell '
'Ignore case'
'Regular expression'
'Backwards'
'Search along rows'
)
TabOrder = 1
Data = {
050000000202020202
}
end
object RgSearchSource: TRadioGroup
Left = 237
Height = 75
Top = 53
Width = 139
AutoFill = True
Caption = 'Search within'
ChildSizing.LeftRightSpacing = 6
ChildSizing.EnlargeHorizontal = crsHomogenousChildResize
ChildSizing.EnlargeVertical = crsHomogenousChildResize
ChildSizing.ShrinkHorizontal = crsScaleChilds
ChildSizing.ShrinkVertical = crsScaleChilds
ChildSizing.Layout = cclLeftToRightThenTopToBottom
ChildSizing.ControlsPerLine = 1
ClientHeight = 55
ClientWidth = 135
ItemIndex = 0
Items.Strings = (
'worksheet'
'workbook'
)
TabOrder = 2
end
object ButtonPanel: TPanel
Left = 0
Height = 38
Top = 233
Width = 392
Align = alBottom
BevelOuter = bvNone
ClientHeight = 38
ClientWidth = 392
TabOrder = 3
object Bevel1: TBevel
Left = 6
Height = 3
Top = 0
Width = 380
Align = alTop
BorderSpacing.Left = 6
BorderSpacing.Right = 6
Shape = bsTopLine
end
object BtnSearchBack: TBitBtn
Left = 149
Height = 25
Top = 7
Width = 75
Anchors = [akTop, akRight]
Caption = 'Previous'
Glyph.Data = {
36040000424D3604000000000000360000002800000010000000100000000100
2000000000000004000064000000640000000000000000000000000000000000
000000000000000000000000000000000000994E035C994E0399000000000000
0000000000000000000000000000000000000000000000000000000000002E2E
2E2A141414840505055C000000009E53075C9D5206CC9D5206CC000000000000
0000000000000000000000000000000000000000000000000000000000003737
3774EADADAFF433F3F9E713E0987A3580BCCFFBA16FFA3580BCC000000000000
0000000000000000000000000000000000000000000000000000000000003E3E
3E4B64606090CAA88BFF9A5813EAF7BA30FFF6B11DFFAA5F10CC000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000915B2180A6631CE7ECB952FFE09E29FFE5A83AFFB16616CC000000000000
000000000000000000000000000000000000000000000000000000000000BA6F
1D5CB96E1CCCE9BD6EFFCF9240FFCF9240FFD9A352FFB26A1BD4040404560404
047904040487040404790404045604040416000000000000000000000000C277
22CCFAD589FFE9AD61FFDFA357FFD5994DFFDCA95DFFB06D22E79D9791A5EEE8
E3C4F9F3EDD6EFEAE5C5A3A09EA92928287D1111112A0000000000000000C97E
275CCA7F28CCFBD88CFFEEB266FFEEB266FFF4C276FFCD8B40F2F3E6D9CBF6ED
E4CEF6EDE4CEF6EDE4CEF7EFE6D1DFD9D3B83D3C3B7426262614000000000000
0000D1862D5CD2872ECCFDDD91FFF2B96DFFF7CA7EFFD59345F3F5E9DFCBF6ED
E4CEF6EDE4CEF6EDE4CEF6EDE4CEF6ECE2CEADA69E9D31313149000000000000
000000000000D88D335CD98E33CCFEE195FFFBD488FFDB9848F2F6EDE4CEF6ED
E4CEF6EDE4CEF6EDE4CEF6EDE4CEF6EDE4CEE7D8CAB838383865000000000000
00000000000000000000DF94385CD08C38E2FFE498FFE19E4CF2E8D2BBC0F6ED
E4CEF6EDE4CEF6EDE4CEF6EDE4CEF6EDE4CEEDDBC8C53E3E3E6F000000000000
0000000000000000000000000000A4773E99E4A14DEEE5A24FF2E8D2BBC0E8D2
BBC0E8D2BBC0E8D2BBC0E8D2BBC0E8D2BBC0E4D3C1B243434360000000000000
000000000000000000000000000049494943CB9E68B7E8AF69E6F1E3D5C8F6ED
E4CEF6EDE4CEF6EDE4CEF6EDE4CEF2E4D6C8B0A4979149494943000000000000
00000000000000000000000000004D4D4D115F5D5A64D5C1AEA1EBD8C4C2F6EC
E2CDF6EDE4CEF6EDE4CEF6ECE2CDD9C8B8A4605D5B644D4D4D11000000000000
0000000000000000000000000000000000005151512163605E62B1A3948BE6D5
C5AFF4EADFC7EDE3D9B5B6ACA28E63605E625151512100000000000000000000
0000000000000000000000000000000000000000000054545411555555405555
555A555555655555555A55555540545454110000000000000000
}
OnClick = SearchButtonClick
TabOrder = 0
Visible = False
end
object BtnClose: TBitBtn
Left = 309
Height = 25
Top = 7
Width = 75
Anchors = [akTop, akRight]
DefaultCaption = True
Kind = bkClose
ModalResult = 11
TabOrder = 1
end
object BtnSearch: TBitBtn
Left = 229
Height = 25
Top = 7
Width = 75
Anchors = [akTop, akRight]
Caption = 'Search'
Default = True
Glyph.Data = {
36040000424D3604000000000000360000002800000010000000100000000100
2000000000000004000064000000640000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000994E0399994E
035C000000000000000000000000000000000000000000000000000000002E2E
2E2A141414840505055C000000000000000000000000000000009D5206CC9D52
06CC9E53075C0000000000000000000000000000000000000000000000003737
3774EADADAFF433F3F9E05050544000000000000000000000000A3580BCCFFBF
25FFA3580BCCA4590C5C00000000000000000000000000000000000000003E3E
3E4B64606090DDD1D1FF302E2E96040404330000000000000000AA5F10CCFBB8
21FFFBBF34FFAA5F10CCAB60115C000000000000000000000000000000000000
00003D3D3D3853515186CCC4C4FF2221218C0404042500000000B16616CCEFB3
39FFEAA41DFFF2BD4AFFB16616CCB267175C0000000000000000000000000000
0000000000003C3C3C2A4746467CBCB8B8FF161515830404042AAB651ADDE4AE
50FFD99934FFD99934FFEABB60FFB56B1BD0BA6F1D5C00000000000000000000
000000000000000000003B3B3B1F3C3C3C73AFADADFF2B292887BC7B31EDE5B4
66FFCE9244FFCD9143FFCD9143FFE7BC6FFFBB7321D400000000000000000000
0000000000000000000000000000373737244746447BDED1C4BED09045F5F5C6
7AFFE9AD61FFDFA357FFF1CC80FFCD8C42F18A602FA626262614000000000000
000000000000000000000000000031313149A89D9397EAD5BFC3D7974BF5F7CB
7FFFF1B66AFFFDDC90FFD8984CF5E6C297E0ADA69E9D31313149000000000000
000000000000000000000000000038383865E1CFBCB1E8D2BBC0DD9D50F5FBD4
88FFFFE397FFDD9D50F5E9C59BE0F6EDE4CEE7D8CAB838383865000000000000
00000000000000000000000000003E3E3E6FE9D4BEBEE8D2BBC0E19E4CF2FFE5
99FFE3A354F5ECC89DE0F6EDE4CEF6EDE4CEEDDBC8C53E3E3E6F000000000000
000000000000000000000000000043434360E0CBB6ACE8D2BBC0E5A24FF2E5A2
4FF2E6BA84D7E8D2BBC0E8D2BBC0E8D2BBC0E4D3C1B243434360000000000000
000000000000000000000000000049494943AD9F918EE8D2BBC0EBB573E9F0CC
A0E0F6EDE4CEF6EDE4CEF6EDE4CEF2E4D6C8B0A4979149494943000000000000
00000000000000000000000000004D4D4D115F5D5A64D5C1AEA1EBD8C4C2F6EC
E2CDF6EDE4CEF6EDE4CEF6ECE2CDD9C8B8A4605D5B644D4D4D11000000000000
0000000000000000000000000000000000005151512163605E62B1A3948BE6D5
C5AFF4EADFC7EDE3D9B5B6ACA28E63605E625151512100000000000000000000
0000000000000000000000000000000000000000000054545411555555405555
555A555555655555555A55555540545454110000000000000000
}
OnClick = SearchButtonClick
TabOrder = 2
end
end
object RgSearchStart: TRadioGroup
Left = 237
Height = 75
Top = 141
Width = 139
AutoFill = True
Caption = 'Start search at'
ChildSizing.LeftRightSpacing = 6
ChildSizing.EnlargeHorizontal = crsHomogenousChildResize
ChildSizing.EnlargeVertical = crsHomogenousChildResize
ChildSizing.ShrinkHorizontal = crsScaleChilds
ChildSizing.ShrinkVertical = crsScaleChilds
ChildSizing.Layout = cclLeftToRightThenTopToBottom
ChildSizing.ControlsPerLine = 1
ClientHeight = 55
ClientWidth = 135
ItemIndex = 0
Items.Strings = (
'beginning/end'
'active cell'
)
TabOrder = 4
end
end

View File

@ -0,0 +1,381 @@
unit sSearchForm;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ButtonPanel,
StdCtrls, ExtCtrls, Buttons, fpsTypes, fpspreadsheet;
type
{ TSearchParams }
TsSearchSource = (spsWorksheet, spsWorkbook);
TsSearchStart = (spsBeginningEnd, spsActiveCell);
TsSearchParams = record
SearchText: String;
Options: TsSearchOptions;
Source: TsSearchSource;
Start: TsSearchStart;
end;
TsSearchEvent = procedure (Sender: TObject; ACell: PCell) of object;
{ TSearchForm }
TSearchForm = class(TForm)
Bevel1: TBevel;
BtnSearchBack: TBitBtn;
BtnClose: TBitBtn;
BtnSearch: TBitBtn;
CbSearchText: TComboBox;
CgSearchOptions: TCheckGroup;
LblSearchText: TLabel;
ButtonPanel: TPanel;
RgSearchStart: TRadioGroup;
RgSearchSource: TRadioGroup;
procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
procedure FormCreate(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure SearchButtonClick(Sender: TObject);
private
{ private declarations }
FWorkbook: TsWorkbook;
FFoundCell: PCell;
FOnFound: TsSearchEvent;
procedure CtrlsToParams(var ASearchParams: TsSearchParams);
function FindStartCell(AParams: TsSearchParams; var AWorksheet: TsWorksheet;
var AStartRow, AStartCol: Cardinal): Boolean;
procedure ParamsToCtrls(const ASearchParams: TsSearchParams);
public
{ public declarations }
procedure Execute(AWorkbook: TsWorkbook; var ASearchParams: TsSearchParams);
property Workbook: TsWorkbook read FWorkbook;
property OnFound: TsSearchEvent read FOnFound write FOnFound;
end;
var
SearchForm: TSearchForm;
DefaultSearchParams: TsSearchParams = (
SearchText: '';
Options: [soIgnoreCase];
Source: spsWorksheet;
Start: spsActiveCell;
);
implementation
{$R *.lfm}
const
MAX_SEARCH_ITEMS = 10;
procedure TSearchForm.CtrlsToParams(var ASearchParams: TsSearchParams);
var
i: Integer;
begin
ASearchParams.SearchText := CbSearchText.Text;
ASearchParams.Options := [];
for i:=0 to CgSearchOptions.Items.Count-1 do
if CgSearchOptions.Checked[i] then
Include(ASearchparams.Options, TsSearchOption(i));
ASearchParams.Source := TsSearchSource(RgSearchSource.ItemIndex);
ASearchParams.Start := TsSearchStart(RgSearchStart.ItemIndex);
end;
procedure TSearchForm.FormClose(Sender: TObject; var CloseAction: TCloseAction);
var
P: TPoint;
begin
P.X := Left;
P.Y := Top;
Position := poDesigned;
Left := P.X;
Top := P.Y;
end;
procedure TSearchForm.FormCreate(Sender: TObject);
begin
Position := poMainFormCenter;
end;
procedure TSearchForm.FormShow(Sender: TObject);
begin
BtnSearch.Caption := 'Search';
BtnSearchBack.Visible := false;
FFoundCell := nil;
end;
procedure TSearchForm.Execute(AWorkbook: TsWorkbook;
var ASearchParams: TsSearchParams);
begin
FWorkbook := AWorkbook;
ParamsToCtrls(ASearchParams);
Show;
CtrlsToParams(ASearchParams);
end;
function TSearchForm.FindStartCell(AParams: TsSearchParams;
var AWorksheet: TsWorksheet; var AStartRow, AStartCol: Cardinal): Boolean;
var
sheetIndex: integer;
cell: PCell;
begin
Result := false;
cell := nil;
// Case (1): Search not executed before
if FFoundCell = nil then
begin
case AParams.Start of
spsActiveCell:
begin
AWorksheet := FWorkbook.ActiveWorksheet;
AStartRow := AWorksheet.ActiveCellRow;
AStartCol := AWorksheet.ActiveCellCol;
end;
spsBeginningEnd:
if (soBackward in AParams.Options) then
begin
AWorksheet := FWorkbook.GetWorksheetByIndex(FWorkbook.GetWorksheetCount-1);
AStartCol := AWorksheet.GetLastColIndex;
AStartRow := AWorksheet.GetlastRowIndex;
end else
begin
AWorksheet := FWorkbook.GetWorksheetByIndex(0);
AStartCol := AWorksheet.GetFirstColIndex;
AStartRow := AWorksheet.GetFirstRowIndex;
end;
end;
end else
// Case (2):
// Repeated execution of search to start at cell adjacent to the one found in
// previous call.
begin
//AWorksheet := TsWorksheet(FFoundCell^.Worksheet);
// FoundCell is the cell found in the previous call.
//AStartRow := FFoundCell^.Row;
//AStartCol := FFoundCell^.Col;
sheetIndex := FWorkbook.GetWorksheetIndex(AWorksheet);
// Case (1): Find prior occupied cell along row
if (AParams.Options * [soAlongRows, soBackward] = [soAlongRows, soBackward]) then
begin
cell := AWorksheet.FindPrevCellInRow(AStartRow, AStartCol);
// No "prior" cell found in this row --> Proceed with previous row
while (cell = nil) and (AStartRow > 0) do
begin
dec(AStartRow);
AStartCol := AWorksheet.GetLastColIndex;
cell := AWorksheet.FindCell(AStartRow, AStartCol);
if (cell = nil) then
cell := AWorksheet.FindPrevCellInRow(AStartRow, AStartCol);
// No "prior" cell found in this sheet --> Proceed with previous sheet
if (cell = nil) and (AStartRow = 0) then
begin
if sheetIndex = 0 then
exit;
dec(sheetIndex);
AWorksheet := FWorkbook.GetWorksheetByIndex(sheetIndex);
AStartCol := AWorksheet.GetLastColIndex;
AStartRow := AWorksheet.GetLastRowIndex;
cell := AWorksheet.FindCell(AStartRow, AStartCol);
if (cell = nil) then
cell := AWorksheet.FindPrevCellInRow(AStartRow, AStartCol);
end;
end;
end
else
// Case (2): Find prior occupied cell along columns
if (AParams.Options * [soAlongRows, soBackward] = [soBackward]) then
begin
cell := AWorksheet.FindPrevCellInCol(AStartRow, AStartCol);
// No "preior" cell found in this column --> Proceed with previous column
while (cell = nil) and (AStartCol > 0) do
begin
dec(AStartCol);
AStartRow := AWorksheet.GetLastRowIndex;
cell := AWorksheet.FindCell(AStartRow, AStartCol);
if (cell = nil) then
cell := AWorksheet.FindPrevCellInCol(AStartRow, AStartCol);
// No "prior" cell found in this sheet --> Proceed with previous sheet
if (cell = nil) and (AStartCol = 0) then
begin
if sheetIndex = 0 then
exit;
dec(sheetIndex);
AWorksheet := FWorkbook.GetWorksheetByIndex(sheetIndex);
AStartCol := AWorksheet.GetLastColIndex;
AStartRow := AWorksheet.GetLastRowIndex;
cell := AWorksheet.FindCell(AStartRow, AStartCol);
if (cell = nil) then
cell := AWorksheet.FindPrevCellinCol(AStartRow, AStartCol);
end;
end;
end
else
// Case (3): Find next occupied cell along row
if (AParams.Options * [soAlongRows, soBackward] = [soAlongRows]) then
begin
cell := AWorksheet.FindNextCellInRow(AStartRow, AStartCol);
// No cell found in this row --> Proceed with next row
while (cell = nil) and (AStartRow < AWorksheet.GetLastRowIndex) do
begin
inc(AStartRow);
AStartCol := AWorksheet.GetFirstColIndex;
cell := AWorksheet.FindCell(AStartRow, AStartCol);
if (cell = nil) then
cell := AWorksheet.FindNextCellInRow(AStartRow, AStartCol);
// No "next" cell found in this sheet --> Proceed with next sheet
if (cell = nil) and (AStartRow = AWorksheet.GetLastRowIndex) then
begin
if sheetIndex = 0 then
exit;
inc(sheetIndex);
AWorksheet := FWorkbook.GetWorksheetByIndex(sheetIndex);
AStartCol := AWorksheet.GetLastColIndex;
AStartRow := AWorksheet.GetLastRowIndex;
cell := AWorksheet.FindCell(AStartRow, AStartCol);
if (cell = nil) then
cell := AWorksheet.FindNextCellInRow(AStartRow, AStartCol);
end;
end;
end
else
// Case (4): Find next occupied cell along column
if (AParams.Options * [soAlongRows, soBackward] = []) then
begin
cell := AWorksheet.FindNextCellInCol(AStartRow, AStartCol);
// No "next" occupied cell found in this column --> Proceed with next column
while (cell = nil) and (AStartCol < AWorksheet.GetLastColIndex) do
begin
inc(AStartCol);
AStartRow := AWorksheet.GetFirstRowIndex;
cell := AWorksheet.FindCell(AStartRow, AStartCol);
if (cell = nil) then
cell := AWorksheet.FindNextCellInCol(AStartRow, AStartCol);
// No "next" cell found in this sheet --> Proceed with next sheet
if (cell = nil) and (AStartCol = 0) then
begin
if sheetIndex = 0 then
exit;
inc(sheetIndex);
AWorksheet := FWorkbook.GetWorksheetByIndex(sheetIndex);
AStartCol := AWorksheet.GetLastColIndex;
AStartRow := AWorksheet.GetLastRowIndex;
cell := AWorksheet.FindCell(AStartRow, AStartCol);
if (cell = nil) then
cell := AWorksheet.FindNextCellInCol(AStartRow, AStartCol);
end;
end;
end;
end;
if cell <> nil then
begin
AStartRow := cell^.Row;
AStartCol := cell^.Col;
end;
Result := true;
end;
procedure TSearchForm.ParamsToCtrls(const ASearchParams: TsSearchParams);
var
i: Integer;
o: TsSearchOption;
begin
CbSearchText.Text := ASearchParams.SearchText;
for o in TsSearchOption do
if ord(o) < CgSearchOptions.Items.Count then
CgSearchOptions.Checked[ord(o)] := (o in ASearchParams.Options);
RgSearchSource.ItemIndex := ord(ASearchParams.Source);
RgSearchStart.ItemIndex := ord(ASearchParams.Start);
end;
procedure TSearchForm.SearchButtonClick(Sender: TObject);
var
startsheet: TsWorksheet;
sheetIdx: Integer;
r,c: Cardinal;
backward: Boolean;
params: TsSearchParams;
cell: PCell;
begin
CtrlsToParams(params);
if params.SearchText = '' then
exit;
if CbSearchText.Items.IndexOf(params.SearchText) = -1 then
begin
CbSearchText.Items.Insert(0, params.SearchText);
while CbSearchText.Items.Count > MAX_SEARCH_ITEMS do
CbSearchText.Items.Delete(CbSearchText.Items.Count-1);
end;
if FFoundcell = nil then
backward := (soBackward in params.Options) // 1st call: use value from Options
else
backward := (Sender = BtnSearchBack); // subseq call: follow button
if backward then Include(params.Options, soBackward) else
Exclude(params.Options, soBackward);
if params.Start = spsActiveCell then
begin
startSheet := FWorkbook.ActiveWorksheet;
FFoundCell := startSheet.FindCell(startSheet.ActiveCellRow, startSheet.ActiveCellCol);
end;
if FFoundCell <> nil then
begin
startsheet := TsWorksheet(FFoundCell^.Worksheet);
r := FFoundCell^.Row;
c := FFoundCell^.Col;
end;
cell := nil;
while FindStartCell(params, startsheet, r, c) and (cell = nil) do
begin
cell := startsheet.Search(params.SearchText, params.Options, r, c);
if (cell <> nil) then
begin
FWorkbook.SelectWorksheet(startsheet);
startsheet.SelectCell(cell^.Row, cell^.Col);
if Assigned(FOnFound) then FOnFound(Self, cell);
FFoundCell := cell;
break;
end;
// not found --> go to next sheet
case params.Source of
spsWorksheet:
break;
spsWorkbook:
begin
sheetIdx := FWorkbook.GetWorksheetIndex(startsheet);
if backward then
begin
if (sheetIdx = 0) then exit;
startsheet := FWorkbook.GetWorksheetByIndex(sheetIdx-1);
r := startsheet.GetLastRowIndex;
c := startsheet.GetLastColIndex;
end else
begin
if (sheetIdx = FWorkbook.GetWorksheetCount-1) then exit;
startsheet := FWorkbook.GetWorksheetByIndex(sheetIdx+1);
r := 0;
c := 0;
end;
end;
end;
end;
BtnSearchBack.Visible := true;
BtnSearch.Caption := 'Next';
end;
end.

Binary file not shown.

After

Width:  |  Height:  |  Size: 808 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 754 B

Binary file not shown.