You've already forked lazarus-ccr
382 lines
12 KiB
ObjectPascal
382 lines
12 KiB
ObjectPascal
![]() |
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.
|
||
|
|