You've already forked lazarus-ccr
fpspreadsheet: Redo searching (better OO code), some identifiers renamed with respect to initial commit.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@4313 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -355,7 +355,9 @@ type
|
|||||||
const AHyperlink: TsHyperlink);
|
const AHyperlink: TsHyperlink);
|
||||||
private
|
private
|
||||||
{ private declarations }
|
{ private declarations }
|
||||||
procedure SearchFound(Sender: TObject; ACell: PCell);
|
procedure SearchClose(Sender: TObject; var CloseAction: TCloseAction);
|
||||||
|
procedure SearchFound(Sender: TObject; AFound: Boolean;
|
||||||
|
AWorksheet: TsWorksheet; ARow, ACol: Cardinal);
|
||||||
procedure UpdateCaption;
|
procedure UpdateCaption;
|
||||||
protected
|
protected
|
||||||
procedure ReadFromIni;
|
procedure ReadFromIni;
|
||||||
@ -496,7 +498,9 @@ begin
|
|||||||
if SearchForm = nil then
|
if SearchForm = nil then
|
||||||
SearchForm := TSearchForm.Create(self);
|
SearchForm := TSearchForm.Create(self);
|
||||||
SearchForm.OnFound := @SearchFound;
|
SearchForm.OnFound := @SearchFound;
|
||||||
SearchForm.Execute(WorkbookSource.Workbook, DefaultSearchParams);
|
SearchForm.OnClose := @SearchClose;
|
||||||
|
SearchForm.SearchParams := DefaultSearchParams;
|
||||||
|
SearchForm.Execute(WorkbookSource.Workbook);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TMainForm.AcSettingsCSVParamsExecute(Sender: TObject);
|
procedure TMainForm.AcSettingsCSVParamsExecute(Sender: TObject);
|
||||||
@ -601,9 +605,30 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TMainForm.SearchFound(Sender: TObject; ACell: PCell);
|
procedure TMainForm.SearchClose(Sender: TObject; var CloseAction: TCloseAction);
|
||||||
begin
|
begin
|
||||||
// There could be status message "search string found", here
|
Unused(CloseAction);
|
||||||
|
DefaultSearchParams := TSearchForm(Sender).SearchParams;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TMainForm.SearchFound(Sender: TObject; AFound: Boolean;
|
||||||
|
AWorksheet: TsWorksheet; ARow, ACol: Cardinal);
|
||||||
|
begin
|
||||||
|
Unused(AWorksheet, ARow, ACol);
|
||||||
|
|
||||||
|
if AFound then
|
||||||
|
begin
|
||||||
|
//
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
DefaultSearchParams := TSearchForm(Sender).SearchParams;
|
||||||
|
MessageDlg(
|
||||||
|
Format('The search text "%s" could not be found.', [DefaultSearchParams.SearchText]),
|
||||||
|
mtInformation,
|
||||||
|
[mbOK], 0
|
||||||
|
);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TMainForm.UpdateCaption;
|
procedure TMainForm.UpdateCaption;
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
object SearchForm: TSearchForm
|
object SearchForm: TSearchForm
|
||||||
Left = 238
|
Left = 238
|
||||||
Height = 271
|
Height = 272
|
||||||
Top = 157
|
Top = 157
|
||||||
Width = 392
|
Width = 483
|
||||||
BorderStyle = bsDialog
|
BorderStyle = bsDialog
|
||||||
Caption = 'Search'
|
Caption = 'Search'
|
||||||
ClientHeight = 271
|
ClientHeight = 272
|
||||||
ClientWidth = 392
|
ClientWidth = 483
|
||||||
FormStyle = fsStayOnTop
|
FormStyle = fsStayOnTop
|
||||||
OnClose = FormClose
|
OnClose = FormClose
|
||||||
OnCreate = FormCreate
|
OnCreate = FormCreate
|
||||||
@ -24,16 +24,16 @@ object SearchForm: TSearchForm
|
|||||||
Left = 93
|
Left = 93
|
||||||
Height = 23
|
Height = 23
|
||||||
Top = 14
|
Top = 14
|
||||||
Width = 283
|
Width = 374
|
||||||
Anchors = [akTop, akLeft, akRight]
|
Anchors = [akTop, akLeft, akRight]
|
||||||
ItemHeight = 15
|
ItemHeight = 15
|
||||||
TabOrder = 0
|
TabOrder = 0
|
||||||
end
|
end
|
||||||
object CgSearchOptions: TCheckGroup
|
object CgSearchOptions: TCheckGroup
|
||||||
Left = 19
|
Left = 16
|
||||||
Height = 163
|
Height = 163
|
||||||
Top = 53
|
Top = 53
|
||||||
Width = 189
|
Width = 192
|
||||||
AutoFill = True
|
AutoFill = True
|
||||||
Caption = 'Search options'
|
Caption = 'Search options'
|
||||||
ChildSizing.LeftRightSpacing = 6
|
ChildSizing.LeftRightSpacing = 6
|
||||||
@ -45,24 +45,24 @@ object SearchForm: TSearchForm
|
|||||||
ChildSizing.Layout = cclLeftToRightThenTopToBottom
|
ChildSizing.Layout = cclLeftToRightThenTopToBottom
|
||||||
ChildSizing.ControlsPerLine = 1
|
ChildSizing.ControlsPerLine = 1
|
||||||
ClientHeight = 143
|
ClientHeight = 143
|
||||||
ClientWidth = 185
|
ClientWidth = 188
|
||||||
Items.Strings = (
|
Items.Strings = (
|
||||||
'Compare full cell '
|
'Compare entire cell '
|
||||||
'Ignore case'
|
'Match case'
|
||||||
'Regular expression'
|
'Regular expression'
|
||||||
'Backwards'
|
|
||||||
'Search along rows'
|
'Search along rows'
|
||||||
|
'Continue at start/end'
|
||||||
)
|
)
|
||||||
TabOrder = 1
|
TabOrder = 1
|
||||||
Data = {
|
Data = {
|
||||||
050000000202020202
|
050000000202020202
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
object RgSearchSource: TRadioGroup
|
object RgSearchWithin: TRadioGroup
|
||||||
Left = 237
|
Left = 232
|
||||||
Height = 75
|
Height = 67
|
||||||
Top = 53
|
Top = 53
|
||||||
Width = 139
|
Width = 232
|
||||||
AutoFill = True
|
AutoFill = True
|
||||||
Caption = 'Search within'
|
Caption = 'Search within'
|
||||||
ChildSizing.LeftRightSpacing = 6
|
ChildSizing.LeftRightSpacing = 6
|
||||||
@ -70,39 +70,43 @@ object SearchForm: TSearchForm
|
|||||||
ChildSizing.EnlargeVertical = crsHomogenousChildResize
|
ChildSizing.EnlargeVertical = crsHomogenousChildResize
|
||||||
ChildSizing.ShrinkHorizontal = crsScaleChilds
|
ChildSizing.ShrinkHorizontal = crsScaleChilds
|
||||||
ChildSizing.ShrinkVertical = crsScaleChilds
|
ChildSizing.ShrinkVertical = crsScaleChilds
|
||||||
ChildSizing.Layout = cclLeftToRightThenTopToBottom
|
ChildSizing.Layout = cclTopToBottomThenLeftToRight
|
||||||
ChildSizing.ControlsPerLine = 1
|
ChildSizing.ControlsPerLine = 2
|
||||||
ClientHeight = 55
|
ClientHeight = 47
|
||||||
ClientWidth = 135
|
ClientWidth = 228
|
||||||
|
ColumnLayout = clVerticalThenHorizontal
|
||||||
|
Columns = 2
|
||||||
ItemIndex = 0
|
ItemIndex = 0
|
||||||
Items.Strings = (
|
Items.Strings = (
|
||||||
'worksheet'
|
|
||||||
'workbook'
|
'workbook'
|
||||||
|
'worksheet'
|
||||||
|
'column'
|
||||||
|
'row'
|
||||||
)
|
)
|
||||||
TabOrder = 2
|
TabOrder = 2
|
||||||
end
|
end
|
||||||
object ButtonPanel: TPanel
|
object ButtonPanel: TPanel
|
||||||
Left = 0
|
Left = 0
|
||||||
Height = 38
|
Height = 38
|
||||||
Top = 233
|
Top = 234
|
||||||
Width = 392
|
Width = 483
|
||||||
Align = alBottom
|
Align = alBottom
|
||||||
BevelOuter = bvNone
|
BevelOuter = bvNone
|
||||||
ClientHeight = 38
|
ClientHeight = 38
|
||||||
ClientWidth = 392
|
ClientWidth = 483
|
||||||
TabOrder = 3
|
TabOrder = 3
|
||||||
object Bevel1: TBevel
|
object Bevel1: TBevel
|
||||||
Left = 6
|
Left = 6
|
||||||
Height = 3
|
Height = 3
|
||||||
Top = 0
|
Top = 0
|
||||||
Width = 380
|
Width = 471
|
||||||
Align = alTop
|
Align = alTop
|
||||||
BorderSpacing.Left = 6
|
BorderSpacing.Left = 6
|
||||||
BorderSpacing.Right = 6
|
BorderSpacing.Right = 6
|
||||||
Shape = bsTopLine
|
Shape = bsTopLine
|
||||||
end
|
end
|
||||||
object BtnSearchBack: TBitBtn
|
object BtnSearchBack: TBitBtn
|
||||||
Left = 149
|
Left = 240
|
||||||
Height = 25
|
Height = 25
|
||||||
Top = 7
|
Top = 7
|
||||||
Width = 75
|
Width = 75
|
||||||
@ -149,18 +153,19 @@ object SearchForm: TSearchForm
|
|||||||
Visible = False
|
Visible = False
|
||||||
end
|
end
|
||||||
object BtnClose: TBitBtn
|
object BtnClose: TBitBtn
|
||||||
Left = 309
|
Left = 400
|
||||||
Height = 25
|
Height = 25
|
||||||
Top = 7
|
Top = 7
|
||||||
Width = 75
|
Width = 75
|
||||||
Anchors = [akTop, akRight]
|
Anchors = [akTop, akRight]
|
||||||
|
Cancel = True
|
||||||
DefaultCaption = True
|
DefaultCaption = True
|
||||||
Kind = bkClose
|
Kind = bkClose
|
||||||
ModalResult = 11
|
ModalResult = 11
|
||||||
TabOrder = 1
|
TabOrder = 1
|
||||||
end
|
end
|
||||||
object BtnSearch: TBitBtn
|
object BtnSearch: TBitBtn
|
||||||
Left = 229
|
Left = 320
|
||||||
Height = 25
|
Height = 25
|
||||||
Top = 7
|
Top = 7
|
||||||
Width = 75
|
Width = 75
|
||||||
@ -208,10 +213,10 @@ object SearchForm: TSearchForm
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
object RgSearchStart: TRadioGroup
|
object RgSearchStart: TRadioGroup
|
||||||
Left = 237
|
Left = 232
|
||||||
Height = 75
|
Height = 56
|
||||||
Top = 141
|
Top = 160
|
||||||
Width = 139
|
Width = 232
|
||||||
AutoFill = True
|
AutoFill = True
|
||||||
Caption = 'Start search at'
|
Caption = 'Start search at'
|
||||||
ChildSizing.LeftRightSpacing = 6
|
ChildSizing.LeftRightSpacing = 6
|
||||||
@ -220,13 +225,14 @@ object SearchForm: TSearchForm
|
|||||||
ChildSizing.ShrinkHorizontal = crsScaleChilds
|
ChildSizing.ShrinkHorizontal = crsScaleChilds
|
||||||
ChildSizing.ShrinkVertical = crsScaleChilds
|
ChildSizing.ShrinkVertical = crsScaleChilds
|
||||||
ChildSizing.Layout = cclLeftToRightThenTopToBottom
|
ChildSizing.Layout = cclLeftToRightThenTopToBottom
|
||||||
ChildSizing.ControlsPerLine = 1
|
ChildSizing.ControlsPerLine = 2
|
||||||
ClientHeight = 55
|
ClientHeight = 36
|
||||||
ClientWidth = 135
|
ClientWidth = 228
|
||||||
|
Columns = 2
|
||||||
ItemIndex = 0
|
ItemIndex = 0
|
||||||
Items.Strings = (
|
Items.Strings = (
|
||||||
'beginning/end'
|
|
||||||
'active cell'
|
'active cell'
|
||||||
|
'beginning/end'
|
||||||
)
|
)
|
||||||
TabOrder = 4
|
TabOrder = 4
|
||||||
end
|
end
|
||||||
|
@ -5,25 +5,12 @@ unit sSearchForm;
|
|||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ButtonPanel,
|
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
|
||||||
StdCtrls, ExtCtrls, Buttons, fpsTypes, fpspreadsheet;
|
StdCtrls, ExtCtrls, Buttons, fpsTypes, fpspreadsheet, fpsSearch;
|
||||||
|
|
||||||
type
|
type
|
||||||
|
TsSearchEvent = procedure (Sender: TObject; AFound: Boolean;
|
||||||
{ TSearchParams }
|
AWorksheet: TsWorksheet; ARow, ACol: Cardinal) of object;
|
||||||
|
|
||||||
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 }
|
||||||
|
|
||||||
@ -37,24 +24,25 @@ type
|
|||||||
LblSearchText: TLabel;
|
LblSearchText: TLabel;
|
||||||
ButtonPanel: TPanel;
|
ButtonPanel: TPanel;
|
||||||
RgSearchStart: TRadioGroup;
|
RgSearchStart: TRadioGroup;
|
||||||
RgSearchSource: TRadioGroup;
|
RgSearchWithin: TRadioGroup;
|
||||||
procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
|
procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
|
||||||
procedure FormCreate(Sender: TObject);
|
procedure FormCreate(Sender: TObject);
|
||||||
procedure FormShow(Sender: TObject);
|
procedure FormShow(Sender: TObject);
|
||||||
procedure SearchButtonClick(Sender: TObject);
|
procedure SearchButtonClick(Sender: TObject);
|
||||||
private
|
private
|
||||||
{ private declarations }
|
{ private declarations }
|
||||||
|
FSearchEngine: TsSearchEngine;
|
||||||
FWorkbook: TsWorkbook;
|
FWorkbook: TsWorkbook;
|
||||||
FFoundCell: PCell;
|
FFoundWorksheet: TsWorksheet;
|
||||||
|
FFoundRow, FFoundCol: Cardinal;
|
||||||
FOnFound: TsSearchEvent;
|
FOnFound: TsSearchEvent;
|
||||||
procedure CtrlsToParams(var ASearchParams: TsSearchParams);
|
function GetParams: TsSearchParams;
|
||||||
function FindStartCell(AParams: TsSearchParams; var AWorksheet: TsWorksheet;
|
procedure SetParams(const AValue: TsSearchParams);
|
||||||
var AStartRow, AStartCol: Cardinal): Boolean;
|
|
||||||
procedure ParamsToCtrls(const ASearchParams: TsSearchParams);
|
|
||||||
public
|
public
|
||||||
{ public declarations }
|
{ public declarations }
|
||||||
procedure Execute(AWorkbook: TsWorkbook; var ASearchParams: TsSearchParams);
|
procedure Execute(AWorkbook: TsWorkbook);
|
||||||
property Workbook: TsWorkbook read FWorkbook;
|
property Workbook: TsWorkbook read FWorkbook;
|
||||||
|
property SearchParams: TsSearchParams read GetParams write SetParams;
|
||||||
property OnFound: TsSearchEvent read FOnFound write FOnFound;
|
property OnFound: TsSearchEvent read FOnFound write FOnFound;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -63,9 +51,8 @@ var
|
|||||||
|
|
||||||
DefaultSearchParams: TsSearchParams = (
|
DefaultSearchParams: TsSearchParams = (
|
||||||
SearchText: '';
|
SearchText: '';
|
||||||
Options: [soIgnoreCase];
|
Options: [];
|
||||||
Source: spsWorksheet;
|
Within: swWorksheet
|
||||||
Start: spsActiveCell;
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
@ -73,26 +60,33 @@ implementation
|
|||||||
|
|
||||||
{$R *.lfm}
|
{$R *.lfm}
|
||||||
|
|
||||||
const
|
uses
|
||||||
MAX_SEARCH_ITEMS = 10;
|
fpsUtils;
|
||||||
|
|
||||||
procedure TSearchForm.CtrlsToParams(var ASearchParams: TsSearchParams);
|
const
|
||||||
var
|
MAX_SEARCH_ITEMS = 10;
|
||||||
i: Integer;
|
|
||||||
|
COMPARE_ENTIRE_CELL = 0;
|
||||||
|
MATCH_CASE = 1;
|
||||||
|
REGULAR_EXPRESSION = 2;
|
||||||
|
SEARCH_ALONG_ROWS = 3;
|
||||||
|
CONTINUE_AT_START_END = 4;
|
||||||
|
|
||||||
|
|
||||||
|
{ TSearchForms }
|
||||||
|
|
||||||
|
procedure TSearchForm.Execute(AWorkbook: TsWorkbook);
|
||||||
begin
|
begin
|
||||||
ASearchParams.SearchText := CbSearchText.Text;
|
FWorkbook := AWorkbook;
|
||||||
ASearchParams.Options := [];
|
Show;
|
||||||
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;
|
end;
|
||||||
|
|
||||||
procedure TSearchForm.FormClose(Sender: TObject; var CloseAction: TCloseAction);
|
procedure TSearchForm.FormClose(Sender: TObject; var CloseAction: TCloseAction);
|
||||||
var
|
var
|
||||||
P: TPoint;
|
P: TPoint;
|
||||||
begin
|
begin
|
||||||
|
Unused(CloseAction);
|
||||||
|
FreeAndNil(FSearchEngine);
|
||||||
P.X := Left;
|
P.X := Left;
|
||||||
P.Y := Top;
|
P.Y := Top;
|
||||||
Position := poDesigned;
|
Position := poDesigned;
|
||||||
@ -109,203 +103,37 @@ procedure TSearchForm.FormShow(Sender: TObject);
|
|||||||
begin
|
begin
|
||||||
BtnSearch.Caption := 'Search';
|
BtnSearch.Caption := 'Search';
|
||||||
BtnSearchBack.Visible := false;
|
BtnSearchBack.Visible := false;
|
||||||
FFoundCell := nil;
|
|
||||||
|
FFoundCol := UNASSIGNED_ROW_COL_INDEX;
|
||||||
|
FFoundRow := UNASSIGNED_ROW_COL_INDEX;
|
||||||
|
FFoundWorksheet := nil;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TSearchForm.Execute(AWorkbook: TsWorkbook;
|
function TSearchForm.GetParams: TsSearchParams;
|
||||||
var ASearchParams: TsSearchParams);
|
|
||||||
begin
|
begin
|
||||||
FWorkbook := AWorkbook;
|
Result.SearchText := CbSearchText.Text;
|
||||||
ParamsToCtrls(ASearchParams);
|
Result.Options := [];
|
||||||
Show;
|
if CgSearchOptions.Checked[COMPARE_ENTIRE_CELL] then
|
||||||
CtrlsToParams(ASearchParams);
|
Include(Result.Options, soCompareEntireCell);
|
||||||
end;
|
if CgSearchOptions.Checked[MATCH_CASE] then
|
||||||
|
Include(Result.Options, soMatchCase);
|
||||||
function TSearchForm.FindStartCell(AParams: TsSearchParams;
|
if CgSearchOptions.Checked[REGULAR_EXPRESSION] then
|
||||||
var AWorksheet: TsWorksheet; var AStartRow, AStartCol: Cardinal): Boolean;
|
Include(Result.Options, soRegularExpr);
|
||||||
var
|
if CgSearchOptions.Checked[SEARCH_ALONG_ROWS] then
|
||||||
sheetIndex: integer;
|
Include(Result.Options, soAlongRows);
|
||||||
cell: PCell;
|
if CgSearchOptions.Checked[CONTINUE_AT_START_END] then
|
||||||
begin
|
Include(Result.Options, soWrapDocument);
|
||||||
Result := false;
|
if RgSearchStart.ItemIndex = 1 then
|
||||||
cell := nil;
|
Include(Result.Options, soEntireDocument);
|
||||||
|
Result.Within := TsSearchWithin(RgSearchWithin.ItemIndex);
|
||||||
// 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;
|
end;
|
||||||
|
|
||||||
procedure TSearchForm.SearchButtonClick(Sender: TObject);
|
procedure TSearchForm.SearchButtonClick(Sender: TObject);
|
||||||
var
|
var
|
||||||
startsheet: TsWorksheet;
|
|
||||||
sheetIdx: Integer;
|
|
||||||
r,c: Cardinal;
|
|
||||||
backward: Boolean;
|
|
||||||
params: TsSearchParams;
|
params: TsSearchParams;
|
||||||
cell: PCell;
|
found: Boolean;
|
||||||
begin
|
begin
|
||||||
CtrlsToParams(params);
|
params := GetParams;
|
||||||
if params.SearchText = '' then
|
if params.SearchText = '' then
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
@ -316,66 +144,43 @@ begin
|
|||||||
CbSearchText.Items.Delete(CbSearchText.Items.Count-1);
|
CbSearchText.Items.Delete(CbSearchText.Items.Count-1);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if FFoundcell = nil then
|
if FSearchEngine = 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
|
begin
|
||||||
startSheet := FWorkbook.ActiveWorksheet;
|
FSearchEngine := TsSearchEngine.Create(FWorkbook);
|
||||||
FFoundCell := startSheet.FindCell(startSheet.ActiveCellRow, startSheet.ActiveCellCol);
|
if (soBackward in params.Options) then
|
||||||
|
Include(params.Options, soBackward) else
|
||||||
|
Exclude(params.Options, soBackward);
|
||||||
|
found := FSearchEngine.FindFirst(params.SearchText, params, FFoundWorksheet, FFoundRow, FFoundCol);
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
if (Sender = BtnSearchBack) then
|
||||||
|
Include(params.Options, soBackward) else
|
||||||
|
Exclude(params.Options, soBackward);
|
||||||
|
// User may select a different worksheet/different cell to continue search!
|
||||||
|
FFoundWorksheet := FWorkbook.ActiveWorksheet;
|
||||||
|
FFoundRow := FFoundWorksheet.ActiveCellRow;
|
||||||
|
FFoundCol := FFoundWorksheet.ActiveCellCol;
|
||||||
|
found := FSearchEngine.FindNext(params.SearchText, params, FFoundWorksheet, FFoundRow, FFoundCol);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if FFoundCell <> nil then
|
if Assigned(FOnFound) then
|
||||||
begin
|
FOnFound(self, found, FFoundWorksheet, FFoundRow, FFoundCol);
|
||||||
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;
|
BtnSearchBack.Visible := true;
|
||||||
BtnSearch.Caption := 'Next';
|
BtnSearch.Caption := 'Next';
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TSearchForm.SetParams(const AValue: TsSearchParams);
|
||||||
|
begin
|
||||||
|
CbSearchText.Text := Avalue.SearchText;
|
||||||
|
CgSearchOptions.Checked[COMPARE_ENTIRE_CELL] := (soCompareEntireCell in AValue.Options);
|
||||||
|
CgSearchOptions.Checked[MATCH_CASE] := (soMatchCase in AValue.Options);
|
||||||
|
CgSearchOptions.Checked[REGULAR_EXPRESSION] := (soRegularExpr in Avalue.Options);
|
||||||
|
CgSearchOptions.Checked[SEARCH_ALONG_ROWS] := (soAlongRows in AValue.Options);
|
||||||
|
CgSearchOptions.Checked[CONTINUE_AT_START_END] := (soWrapDocument in Avalue.Options);
|
||||||
|
RgSearchWithin.ItemIndex := ord(AValue.Within);
|
||||||
|
RgSearchStart.ItemIndex := ord(soEntireDocument in AValue.Options);
|
||||||
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -450,11 +450,6 @@ type
|
|||||||
function GetSelectionCount: Integer;
|
function GetSelectionCount: Integer;
|
||||||
procedure SetSelection(const ASelection: TsCellRangeArray);
|
procedure SetSelection(const ASelection: TsCellRangeArray);
|
||||||
|
|
||||||
// Searching
|
|
||||||
function Search(ASearchText: String; AOptions: TsSearchOptions;
|
|
||||||
AStartRow: Cardinal = UNASSIGNED_ROW_COL_INDEX;
|
|
||||||
AStartCol: Cardinal = UNASSIGNED_ROW_COL_INDEX): PCell;
|
|
||||||
|
|
||||||
// Comments
|
// Comments
|
||||||
function FindComment(ACell: PCell): PsComment;
|
function FindComment(ACell: PCell): PsComment;
|
||||||
function HasComment(ACell: PCell): Boolean;
|
function HasComment(ACell: PCell): Boolean;
|
||||||
@ -617,6 +612,7 @@ type
|
|||||||
FFileName: String;
|
FFileName: String;
|
||||||
FLockCount: Integer;
|
FLockCount: Integer;
|
||||||
FLog: TStringList;
|
FLog: TStringList;
|
||||||
|
FSearchEngine: TObject;
|
||||||
|
|
||||||
{ Setter/Getter }
|
{ Setter/Getter }
|
||||||
function GetErrorMsg: String;
|
function GetErrorMsg: String;
|
||||||
@ -733,12 +729,13 @@ type
|
|||||||
ABigEndian: Boolean = false);
|
ABigEndian: Boolean = false);
|
||||||
function UsesColor(AColorIndex: TsColor): Boolean;
|
function UsesColor(AColorIndex: TsColor): Boolean;
|
||||||
*)
|
*)
|
||||||
|
(*
|
||||||
{ Searching }
|
{ Searching }
|
||||||
function Search(ASearchText: String; AOptions: TsSearchOptions;
|
function SearchFirst(ASearchText: String; AParams: TsSearchParams;
|
||||||
AStartSheet: TsWorksheet = nil; AStartRow: Cardinal = UNASSIGNED_ROW_COL_INDEX;
|
out AWorksheet: TsWorksheet; out ARow, ACol: Cardinal): Boolean;
|
||||||
AStartCol: Cardinal = UNASSIGNED_ROW_COL_INDEX): PCell;
|
function SearchNext(out AWorksheet: TsWorksheet;
|
||||||
|
out ARow, ACol: Cardinal): Boolean;
|
||||||
|
*)
|
||||||
{ Utilities }
|
{ Utilities }
|
||||||
procedure UpdateCaches;
|
procedure UpdateCaches;
|
||||||
|
|
||||||
@ -834,7 +831,7 @@ procedure CopyCellFormat(AFromCell, AToCell: PCell);
|
|||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
Math, StrUtils, DateUtils, TypInfo, lazutf8, lazFileUtils, URIParser, RegExpr,
|
Math, StrUtils, DateUtils, TypInfo, lazutf8, lazFileUtils, URIParser,
|
||||||
fpsStrings, uvirtuallayer_ole,
|
fpsStrings, uvirtuallayer_ole,
|
||||||
fpsUtils, fpsHTMLUtils, fpsreaderwriter, fpsCurrency, fpsExprParser,
|
fpsUtils, fpsHTMLUtils, fpsreaderwriter, fpsCurrency, fpsExprParser,
|
||||||
fpsNumFormatParser;
|
fpsNumFormatParser;
|
||||||
@ -3594,186 +3591,6 @@ begin
|
|||||||
FSelection[i] := ASelection[i];
|
FSelection[i] := ASelection[i];
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
|
||||||
Searches the cell containing a specified text. The search begins with the
|
|
||||||
cell "AStartCell". A set of options is respected. Returns a pointer to the
|
|
||||||
first cell meeting the criteria.
|
|
||||||
-------------------------------------------------------------------------------}
|
|
||||||
function TsWorksheet.Search(ASearchText: String; AOptions: TsSearchOptions;
|
|
||||||
AStartRow: Cardinal = UNASSIGNED_ROW_COL_INDEX;
|
|
||||||
AStartCol: Cardinal = UNASSIGNED_ROW_COL_INDEX): PCell;
|
|
||||||
var
|
|
||||||
regex: TRegExpr;
|
|
||||||
cell, startCell: PCell;
|
|
||||||
r, c: Cardinal;
|
|
||||||
firstR, firstC, lastR, lastC: Cardinal;
|
|
||||||
|
|
||||||
function CellMatches(ACell: PCell): boolean;
|
|
||||||
var
|
|
||||||
txt: String;
|
|
||||||
begin
|
|
||||||
txt := ReadAsText(ACell);
|
|
||||||
if (soRegularExpr in AOptions) then
|
|
||||||
Result := regex.Exec(txt)
|
|
||||||
else
|
|
||||||
if (soIgnoreCase in AOptions) then
|
|
||||||
txt := UTF8Lowercase(txt);
|
|
||||||
if (soCompareFullCell in AOptions) then
|
|
||||||
exit(txt = ASearchText);
|
|
||||||
if UTF8Pos(ASearchText, txt) > 0 then
|
|
||||||
exit(true);
|
|
||||||
Result := false;
|
|
||||||
end;
|
|
||||||
|
|
||||||
begin
|
|
||||||
Result := nil;
|
|
||||||
regex := nil;
|
|
||||||
firstR := 0;
|
|
||||||
firstC := 0;
|
|
||||||
lastR := GetLastRowIndex;
|
|
||||||
lastC := GetLastColIndex;
|
|
||||||
|
|
||||||
// Find first occupied cell to start with
|
|
||||||
if (soBackward in AOptions) then
|
|
||||||
begin
|
|
||||||
if AStartRow = UNASSIGNED_ROW_COL_INDEX then AStartRow := lastR;
|
|
||||||
if AStartCol = UNASSIGNED_ROW_COL_INDEX then AStartCol := lastC;
|
|
||||||
end else
|
|
||||||
begin
|
|
||||||
if AStartRow = UNASSIGNED_ROW_COL_INDEX then AStartRow := firstR;
|
|
||||||
if AStartCol = UNASSIGNED_ROW_COL_INDEX then AStartCol := firstC;
|
|
||||||
end;
|
|
||||||
startcell := FindCell(AStartRow, AStartCol);
|
|
||||||
if startcell = nil then
|
|
||||||
// Backward search along rows
|
|
||||||
if (AOptions * [soBackward, soAlongRows] = [soBackward, soAlongRows]) then
|
|
||||||
begin
|
|
||||||
startcell := FindPrevCellInRow(AStartRow, AStartCol);
|
|
||||||
// Not found in this row? Go to previous row
|
|
||||||
while (startcell = nil) and (AStartRow > 0) do begin
|
|
||||||
AStartCol := lastC;
|
|
||||||
dec(AStartRow);
|
|
||||||
startcell := FindPrevCellInRow(AStartRow, AStartCol);
|
|
||||||
end;
|
|
||||||
end
|
|
||||||
else
|
|
||||||
// Backward search along columns
|
|
||||||
if (AOptions * [soBackward, soAlongRows] = [soBackward]) then
|
|
||||||
begin
|
|
||||||
startcell := FindPrevCellInCol(AStartRow, AStartCol);
|
|
||||||
// not found in this column? Go to previous column.
|
|
||||||
while (startcell = nil) and (AStartcol > 0) do begin
|
|
||||||
AStartRow := lastR;
|
|
||||||
dec(AStartCol);
|
|
||||||
startcell := FindPrevCellInCol(AStartRow, AStartCol);
|
|
||||||
end;
|
|
||||||
end
|
|
||||||
else
|
|
||||||
// Forward search along rows
|
|
||||||
if (AOptions * [soBackward, soAlongRows] = [soAlongRows]) then
|
|
||||||
begin
|
|
||||||
startcell := FindNextCellInRow(AStartRow, AStartCol);
|
|
||||||
// Not found in this row? Proceed to next row
|
|
||||||
while (startcell = nil) and (AStartRow <= lastR) do begin
|
|
||||||
AStartCol := firstC;
|
|
||||||
inc(AStartRow);
|
|
||||||
startcell := FindNextCellInRow(AStartRow, AStartCol);
|
|
||||||
end;
|
|
||||||
end
|
|
||||||
else
|
|
||||||
// Forward search along columns
|
|
||||||
if (AOptions * [soBackward, soAlongRows] = []) then
|
|
||||||
begin
|
|
||||||
startCell := FindNextCellInCol(AStartRow, AStartCol);
|
|
||||||
// Not found in this column? Proceed to next column
|
|
||||||
while (startcell = nil) and (AStartCol <= lastC) do begin
|
|
||||||
AStartRow := firstR;
|
|
||||||
inc(AStartCol);
|
|
||||||
startcell := FindNextCellinCol(AStartRow, AStartCol);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
// Still no occupied cell found for starting? Nothing to do...
|
|
||||||
if startcell = nil then
|
|
||||||
exit;
|
|
||||||
|
|
||||||
// Iterate through cells in order defined by the search options
|
|
||||||
try
|
|
||||||
if soRegularExpr in AOptions then
|
|
||||||
begin
|
|
||||||
regex := TRegExpr.Create;
|
|
||||||
regex.Expression := ASearchText
|
|
||||||
end else
|
|
||||||
if soIgnoreCase in AOptions then
|
|
||||||
ASearchText := UTF8Lowercase(ASearchText);
|
|
||||||
|
|
||||||
// Perform backward search along rows
|
|
||||||
if (AOptions * [soBackward, soAlongRows] = [soBackward, soAlongRows]) then
|
|
||||||
begin
|
|
||||||
r := startCell^.Row;
|
|
||||||
for cell in Cells.GetReverseRowEnumerator(r, startCell^.Col) do
|
|
||||||
if CellMatches(cell) then exit(cell);
|
|
||||||
if r = 0 then
|
|
||||||
exit;
|
|
||||||
while r > 0 do begin
|
|
||||||
dec(r);
|
|
||||||
for cell in Cells.GetReverseRowEnumerator(r) do
|
|
||||||
if CellMatches(cell) then exit(cell);
|
|
||||||
end;
|
|
||||||
end
|
|
||||||
else
|
|
||||||
// Perform forward search along rows
|
|
||||||
if (AOptions * [soBackward, soAlongRows] = [soAlongRows]) then
|
|
||||||
begin
|
|
||||||
r := startCell^.Row;
|
|
||||||
for cell in Cells.GetRowEnumerator(r, startCell^.Col) do
|
|
||||||
if CellMatches(cell) then exit(cell);
|
|
||||||
if r = lastR then
|
|
||||||
exit;
|
|
||||||
while (r < lastR) do
|
|
||||||
begin
|
|
||||||
inc(r);
|
|
||||||
for cell in Cells.GetRowEnumerator(r) do
|
|
||||||
if CellMatches(cell) then exit(cell);
|
|
||||||
end;
|
|
||||||
end
|
|
||||||
else
|
|
||||||
// Perform backward search along columns
|
|
||||||
if (AOptions * [soBackward, soAlongRows] = [soBackward]) then
|
|
||||||
begin
|
|
||||||
c := startCell^.Col;
|
|
||||||
for cell in Cells.GetReverseColEnumerator(c, 0, startCell^.Row) do
|
|
||||||
if CellMatches(cell) then exit(cell);
|
|
||||||
if c = 0 then
|
|
||||||
exit;
|
|
||||||
while (c > 0) do
|
|
||||||
begin
|
|
||||||
dec(c);
|
|
||||||
for cell in Cells.GetReverseColEnumerator(c) do
|
|
||||||
if CellMatches(cell) then exit(cell);
|
|
||||||
end;
|
|
||||||
end
|
|
||||||
else
|
|
||||||
// Perform forward search along columns
|
|
||||||
if (AOptions * [soBackward, soAlongRows] = []) then
|
|
||||||
begin
|
|
||||||
c := startCell^.Col;
|
|
||||||
for cell in Cells.GetColEnumerator(c, startCell^.Row) do
|
|
||||||
if CellMatches(cell) then exit(cell);
|
|
||||||
if c = lastC then
|
|
||||||
exit;
|
|
||||||
while (c < lastC) do
|
|
||||||
begin
|
|
||||||
inc(c);
|
|
||||||
for cell in Cells.GetColEnumerator(c) do
|
|
||||||
if CellMatches(cell) then exit(cell);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
finally
|
|
||||||
if regex <> nil then regex.Free;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Helper method to update internal caching variables
|
Helper method to update internal caching variables
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
@ -6513,66 +6330,37 @@ begin
|
|||||||
Unused(arg);
|
Unused(arg);
|
||||||
TsWorksheet(data).Free;
|
TsWorksheet(data).Free;
|
||||||
end;
|
end;
|
||||||
|
(*
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Searches the entire workbook for the first cell (after AStartCell) containing
|
Searches the first cell matching the ASearchText according to the
|
||||||
a specified text.
|
specified AParams.
|
||||||
|
Use SearchNext for subsequent calls for the next occurances.
|
||||||
|
The function result is TRUE if the search text has been found. In this case
|
||||||
|
AWorksheet, ARow and ACol specify the cell containing the search text.
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
function TsWorkbook.Search(ASearchText: String; AOptions: TsSearchOptions;
|
function TsWorkbook.SearchFirst(ASearchText: String; AParams: TsSearchParams;
|
||||||
AStartSheet: TsWorksheet = nil; AStartRow: Cardinal = UNASSIGNED_ROW_COL_INDEX;
|
out AWorksheet: TsWorksheet; out ARow, ACol: Cardinal): Boolean;
|
||||||
AStartCol: Cardinal = UNASSIGNED_ROW_COL_INDEX): PCell;
|
|
||||||
var
|
|
||||||
i, idxSheet: Integer;
|
|
||||||
sheet: TsWorksheet;
|
|
||||||
begin
|
begin
|
||||||
// Setup missing default parameters
|
FreeAndNil(FSearchEngine);
|
||||||
if soBackward in AOptions then
|
FSearchEngine := TsSearchEngine.Create(self);
|
||||||
begin
|
with (FSearchEngine as TsSearchEngine) do
|
||||||
if (AStartRow = UNASSIGNED_ROW_COL_INDEX) and (AStartCol = UNASSIGNED_ROW_COL_INDEX) and (AStartSheet = nil)
|
Result := FindFirst(ASearchText, AParams, AWorksheet, ARow, ACol);
|
||||||
then AStartsheet := GetWorksheetByIndex(GetWorksheetCount-1);
|
|
||||||
if AStartRow = UNASSIGNED_ROW_COL_INDEX then
|
|
||||||
AStartRow := AStartsheet.GetLastRowIndex;
|
|
||||||
if AStartCol = UNASSIGNED_ROW_COL_INDEX then
|
|
||||||
AStartCol := AStartsheet.GetLastColIndex;
|
|
||||||
end else
|
|
||||||
begin
|
|
||||||
if (AStartRow = UNASSIGNED_ROW_COL_INDEX) and (AStartCol = UNASSIGNED_ROW_COL_INDEX) and (AStartSheet = nil)
|
|
||||||
then AStartsheet := GetWorksheetByIndex(0);
|
|
||||||
if (AStartRow = UNASSIGNED_ROW_COL_INDEX) then
|
|
||||||
AStartRow := AStartsheet.GetFirstRowIndex;
|
|
||||||
if (AStartCol = UNASSIGNED_ROW_COL_INDEX) then
|
|
||||||
AStartCol := AStartsheet.GetFirstColIndex;
|
|
||||||
end;
|
|
||||||
if AStartSheet = nil then
|
|
||||||
AStartSheet := ActiveWorksheet;
|
|
||||||
|
|
||||||
// Search this worksheet
|
|
||||||
Result := AStartSheet.Search(ASearchText, AOptions, AStartRow, AStartCol);
|
|
||||||
if Result <> nil then
|
|
||||||
exit;
|
|
||||||
|
|
||||||
// If not found continue with other sheets in requested order...
|
|
||||||
idxSheet := GetWorksheetIndex(AStartSheet);
|
|
||||||
if (soBackward in AOptions) then
|
|
||||||
// ... backward
|
|
||||||
for i := idxSheet - 1 downto 0 do
|
|
||||||
begin
|
|
||||||
sheet := GetWorksheetByIndex(i);
|
|
||||||
Result := sheet.Search(ASearchText, AOptions);
|
|
||||||
if Result <> nil then
|
|
||||||
exit;
|
|
||||||
end
|
|
||||||
else
|
|
||||||
// ... forward
|
|
||||||
for i := idxSheet + 1 to GetWorksheetCount-1 do
|
|
||||||
begin
|
|
||||||
sheet := GetWorksheetByIndex(i);
|
|
||||||
Result := sheet.Search(ASearchText, AOptions);
|
|
||||||
if Result <> nil then
|
|
||||||
exit;
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Searches the next cell matching the text and params specified a the preceding
|
||||||
|
call to SearchFirst.
|
||||||
|
The function result is TRUE if the search text has been found. In this case
|
||||||
|
AWorksheet, ARow and ACol specify the cell containing the search text.
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
function TsWorkbook.SearchNext(out AWorksheet: TsWorksheet;
|
||||||
|
out ARow, ACol: Cardinal): Boolean;
|
||||||
|
begin
|
||||||
|
if FSearchEngine = nil then
|
||||||
|
Result := false else
|
||||||
|
Result := (FSearchEngine as TsSearchEngine).FindNext(AWorksheet, ARow, ACol);
|
||||||
|
end;
|
||||||
|
*)
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Helper method to update internal caching variables
|
Helper method to update internal caching variables
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
@ -6628,6 +6416,8 @@ begin
|
|||||||
FFontList.Free;
|
FFontList.Free;
|
||||||
|
|
||||||
FLog.Free;
|
FLog.Free;
|
||||||
|
FreeAndNil(FSearchEngine);
|
||||||
|
|
||||||
inherited Destroy;
|
inherited Destroy;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
435
components/fpspreadsheet/fpssearch.pas
Normal file
435
components/fpspreadsheet/fpssearch.pas
Normal file
@ -0,0 +1,435 @@
|
|||||||
|
unit fpsSearch;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes, SysUtils, RegExpr, fpstypes, fpspreadsheet;
|
||||||
|
|
||||||
|
type
|
||||||
|
TsSearchEngine = class
|
||||||
|
private
|
||||||
|
FWorkbook: TsWorkbook;
|
||||||
|
FSearchText: String;
|
||||||
|
FParams: TsSearchParams;
|
||||||
|
FCurrSel: Integer;
|
||||||
|
FRegEx: TRegExpr;
|
||||||
|
protected
|
||||||
|
function ExecSearch(var AWorksheet: TsWorksheet;
|
||||||
|
var ARow, ACol: Cardinal): Boolean;
|
||||||
|
procedure GotoFirst(out AWorksheet: TsWorksheet; out ARow, ACol: Cardinal);
|
||||||
|
procedure GotoLast(out AWorksheet: TsWorksheet; out ARow, ACol: Cardinal);
|
||||||
|
function GotoNext(var AWorksheet: TsWorksheet;
|
||||||
|
var ARow, ACol: Cardinal): Boolean;
|
||||||
|
function GotoNextInWorksheet(AWorksheet: TsWorksheet;
|
||||||
|
var ARow, ACol: Cardinal): Boolean;
|
||||||
|
function GotoPrev(var AWorksheet: TsWorksheet;
|
||||||
|
var ARow, ACol: Cardinal): Boolean;
|
||||||
|
function GotoPrevInWorksheet(AWorksheet: TsWorksheet;
|
||||||
|
var ARow, ACol: Cardinal): Boolean;
|
||||||
|
function Matches(AWorksheet: TsWorksheet; ARow, ACol: Cardinal): Boolean;
|
||||||
|
procedure PrepareSearchText(const ASearchText: String);
|
||||||
|
|
||||||
|
public
|
||||||
|
constructor Create(AWorkbook: TsWorkbook);
|
||||||
|
destructor Destroy; override;
|
||||||
|
function FindFirst(const ASearchText: String; const AParams: TsSearchParams;
|
||||||
|
out AWorksheet: TsWorksheet; out ARow, ACol: Cardinal): Boolean;
|
||||||
|
function FindNext(const ASearchText: String; const AParams: TsSearchParams;
|
||||||
|
var AWorksheet: TsWorksheet; var ARow, ACol: Cardinal): Boolean;
|
||||||
|
end;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
uses
|
||||||
|
lazutf8;
|
||||||
|
|
||||||
|
constructor TsSearchEngine.Create(AWorkbook: TsWorkbook);
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
FWorkbook := AWorkbook;
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TsSearchEngine.Destroy;
|
||||||
|
begin
|
||||||
|
FreeAndNil(FRegEx);
|
||||||
|
inherited Destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsSearchEngine.ExecSearch(var AWorksheet: TsWorksheet;
|
||||||
|
var ARow, ACol: Cardinal): Boolean;
|
||||||
|
var
|
||||||
|
complete: boolean;
|
||||||
|
r, c: LongInt;
|
||||||
|
sheet: TsWorksheet;
|
||||||
|
begin
|
||||||
|
sheet := AWorksheet;
|
||||||
|
r := ARow;
|
||||||
|
c := ACol;
|
||||||
|
complete := false;
|
||||||
|
while (not complete) and (not Matches(AWorksheet, ARow, ACol)) do
|
||||||
|
begin
|
||||||
|
if soBackward in FParams.Options then
|
||||||
|
complete := not GotoPrev(AWorkSheet, ARow, ACol) else
|
||||||
|
complete := not GotoNext(AWorkSheet, ARow, ACol);
|
||||||
|
// Avoid infinite loop if search phrase does not exist in document.
|
||||||
|
if (AWorksheet = sheet) and (ARow = r) and (ACol = c) then
|
||||||
|
complete := true;
|
||||||
|
end;
|
||||||
|
Result := not complete;
|
||||||
|
if Result then
|
||||||
|
begin
|
||||||
|
FWorkbook.SelectWorksheet(AWorksheet);
|
||||||
|
AWorksheet.SelectCell(ARow, ACol);
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
AWorksheet := nil;
|
||||||
|
ARow := UNASSIGNED_ROW_COL_INDEX;
|
||||||
|
ACol := UNASSIGNED_ROW_COL_INDEX;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsSearchEngine.FindFirst(const ASearchText: String;
|
||||||
|
const AParams: TsSearchParams; out AWorksheet: TsWorksheet;
|
||||||
|
out ARow, ACol: Cardinal): Boolean;
|
||||||
|
begin
|
||||||
|
FParams := AParams;
|
||||||
|
PrepareSearchText(ASearchText);
|
||||||
|
|
||||||
|
if soBackward in FParams.Options then
|
||||||
|
GotoLast(AWorksheet, ARow, ACol) else
|
||||||
|
GotoFirst(AWorksheet, ARow, ACol);
|
||||||
|
|
||||||
|
Result := ExecSearch(AWorksheet, ARow, ACol);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsSearchEngine.FindNext(const ASearchText: String;
|
||||||
|
const AParams: TsSearchParams; var AWorksheet: TsWorksheet;
|
||||||
|
var ARow, ACol: Cardinal): Boolean;
|
||||||
|
begin
|
||||||
|
FParams := AParams;
|
||||||
|
PrepareSearchText(ASearchText);
|
||||||
|
|
||||||
|
if soBackward in FParams.Options then
|
||||||
|
GotoPrev(AWorksheet, ARow, ACol) else
|
||||||
|
GotoNext(AWorksheet, ARow, ACol);
|
||||||
|
|
||||||
|
Result := ExecSearch(AWorksheet, ARow, ACol);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TsSearchEngine.GotoFirst(out AWorksheet: TsWorksheet;
|
||||||
|
out ARow, ACol: Cardinal);
|
||||||
|
begin
|
||||||
|
if soEntireDocument in FParams.Options then
|
||||||
|
// Search entire document forward from start
|
||||||
|
case FParams.Within of
|
||||||
|
swWorkbook :
|
||||||
|
begin
|
||||||
|
AWorksheet := FWorkbook.GetWorksheetByIndex(0);
|
||||||
|
ARow := 0;
|
||||||
|
ACol := 0;
|
||||||
|
end;
|
||||||
|
swWorksheet:
|
||||||
|
begin
|
||||||
|
AWorksheet := FWorkbook.ActiveWorksheet;
|
||||||
|
ARow := 0;
|
||||||
|
ACol := 0;
|
||||||
|
end;
|
||||||
|
swColumn:
|
||||||
|
begin
|
||||||
|
AWorksheet := FWorkbook.ActiveWorksheet;
|
||||||
|
ARow := 0;
|
||||||
|
ACol := AWorksheet.ActiveCellCol;
|
||||||
|
end;
|
||||||
|
swRow:
|
||||||
|
begin
|
||||||
|
AWorksheet := FWorkbook.ActiveWorksheet;
|
||||||
|
ARow := AWorksheet.ActiveCellRow;
|
||||||
|
ACol := 0;
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
// Search starts at active cell
|
||||||
|
AWorksheet := FWorkbook.ActiveWorksheet;
|
||||||
|
ARow := AWorksheet.ActiveCellRow;
|
||||||
|
ACol := AWorksheet.ActiveCellCol;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TsSearchEngine.GotoLast(out AWorksheet: TsWorksheet;
|
||||||
|
out ARow, ACol: Cardinal);
|
||||||
|
var
|
||||||
|
cell: PCell;
|
||||||
|
sel: TsCellRangeArray;
|
||||||
|
begin
|
||||||
|
if soEntireDocument in FParams.Options then
|
||||||
|
// Search entire document backward from end
|
||||||
|
case FParams.Within of
|
||||||
|
swWorkbook :
|
||||||
|
begin
|
||||||
|
AWorksheet := FWorkbook.GetWorksheetByIndex(FWorkbook.GetWorksheetCount-1);
|
||||||
|
ARow := AWorksheet.GetLastRowIndex;
|
||||||
|
ACol := AWorksheet.GetLastColIndex;
|
||||||
|
end;
|
||||||
|
swWorksheet:
|
||||||
|
begin
|
||||||
|
AWorksheet := FWorkbook.ActiveWorksheet;
|
||||||
|
ARow := AWorksheet.GetLastRowIndex;
|
||||||
|
ACol := AWorksheet.GetLastColIndex;
|
||||||
|
end;
|
||||||
|
swColumn:
|
||||||
|
begin
|
||||||
|
AWorksheet := FWorkbook.ActiveWorksheet;
|
||||||
|
ARow := AWorksheet.GetLastRowIndex;
|
||||||
|
ACol := AWorksheet.ActiveCellCol;
|
||||||
|
end;
|
||||||
|
swRow:
|
||||||
|
begin
|
||||||
|
AWorksheet := FWorkbook.ActiveWorksheet;
|
||||||
|
ARow := AWorksheet.ActiveCellRow;
|
||||||
|
ACol := AWorksheet.GetLastColIndex;
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
// Search starts at active cell
|
||||||
|
AWorksheet := FWorkbook.ActiveWorksheet;
|
||||||
|
ARow := AWorksheet.ActiveCellRow;
|
||||||
|
ACol := AWorksheet.ActiveCellCol;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsSearchEngine.GotoNext(var AWorksheet: TsWorksheet;
|
||||||
|
var ARow, ACol: Cardinal): Boolean;
|
||||||
|
var
|
||||||
|
idx: Integer;
|
||||||
|
sel: TsCellRangeArray;
|
||||||
|
begin
|
||||||
|
Result := true;
|
||||||
|
|
||||||
|
if GotoNextInWorksheet(AWorksheet, ARow, ACol) then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
case FParams.Within of
|
||||||
|
swWorkbook:
|
||||||
|
begin
|
||||||
|
// Need to go to next sheet
|
||||||
|
idx := FWorkbook.GetWorksheetIndex(AWorksheet) + 1;
|
||||||
|
if idx < FWorkbook.GetWorksheetCount then
|
||||||
|
begin
|
||||||
|
AWorksheet := FWorkbook.GetWorksheetByIndex(idx);
|
||||||
|
ARow := 0;
|
||||||
|
ACol := 0;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
// Continue search with first worksheet
|
||||||
|
if (soWrapDocument in FParams.Options) then
|
||||||
|
begin
|
||||||
|
AWorksheet := FWorkbook.GetWorksheetByIndex(0);
|
||||||
|
ARow := 0;
|
||||||
|
ACol := 0;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
swWorksheet:
|
||||||
|
if soWrapDocument in FParams.Options then begin
|
||||||
|
ARow := 0;
|
||||||
|
ACol := 0;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
swColumn:
|
||||||
|
if soWrapDocument in FParams.Options then begin
|
||||||
|
ARow := 0;
|
||||||
|
ACol := AWorksheet.ActiveCellCol;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
swRow:
|
||||||
|
if soWrapDocument in FParams.Options then begin
|
||||||
|
ARow := AWorksheet.ActiveCellRow;
|
||||||
|
ACol := 0;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end; // case
|
||||||
|
|
||||||
|
Result := false;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TsSearchEngine.GotoNextInWorksheet(AWorksheet: TsWorksheet;
|
||||||
|
var ARow, ACol: Cardinal): Boolean;
|
||||||
|
begin
|
||||||
|
Result := true;
|
||||||
|
if (soAlongRows in FParams.Options) or (FParams.Within = swRow) then
|
||||||
|
begin
|
||||||
|
inc(ACol);
|
||||||
|
if ACol <= AWorksheet.GetLastColIndex then
|
||||||
|
exit;
|
||||||
|
if (FParams.Within <> swRow) then
|
||||||
|
begin
|
||||||
|
ACol := 0;
|
||||||
|
inc(ARow);
|
||||||
|
if ARow <= AWorksheet.GetLastRowIndex then
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end else
|
||||||
|
if not (soAlongRows in FParams.Options) or (FParams.Within = swColumn) then
|
||||||
|
begin
|
||||||
|
inc(ARow);
|
||||||
|
if ARow <= AWorksheet.GetLastRowIndex then
|
||||||
|
exit;
|
||||||
|
if (FParams.Within <> swColumn) then
|
||||||
|
begin
|
||||||
|
ARow := 0;
|
||||||
|
inc(ACol);
|
||||||
|
if (ACol <= AWorksheet.GetLastColIndex) then
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
// We reached the last cell, there is no "next" cell in this sheet
|
||||||
|
Result := false;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsSearchEngine.GotoPrev(var AWorksheet: TsWorksheet;
|
||||||
|
var ARow, ACol: Cardinal): Boolean;
|
||||||
|
var
|
||||||
|
idx: Integer;
|
||||||
|
sel: TsCellRangeArray;
|
||||||
|
begin
|
||||||
|
Result := true;
|
||||||
|
|
||||||
|
if GotoPrevInWorksheet(AWorksheet, ARow, ACol) then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
case FParams.Within of
|
||||||
|
swWorkbook:
|
||||||
|
begin
|
||||||
|
// Need to go to previous sheet
|
||||||
|
idx := FWorkbook.GetWorksheetIndex(AWorksheet) - 1;
|
||||||
|
if idx >= 0 then
|
||||||
|
begin
|
||||||
|
AWorksheet := FWorkbook.GetWorksheetByIndex(idx);
|
||||||
|
ARow := AWorksheet.GetLastRowIndex;
|
||||||
|
ACol := AWorksheet.GetlastColIndex;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
if (soWrapDocument in FParams.Options) then
|
||||||
|
begin
|
||||||
|
AWorksheet := FWorkbook.GetWorksheetByIndex(FWorkbook.GetWorksheetCount-1);
|
||||||
|
ARow := AWorksheet.GetLastRowIndex;
|
||||||
|
ACol := AWorksheet.GetLastColIndex;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
swWorksheet:
|
||||||
|
if soWrapDocument in FParams.Options then
|
||||||
|
begin
|
||||||
|
ARow := AWorksheet.GetLastRowIndex;
|
||||||
|
ACol := AWorksheet.GetLastColIndex;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
swColumn:
|
||||||
|
if soWrapDocument in FParams.Options then
|
||||||
|
begin
|
||||||
|
ARow := AWorksheet.GetLastRowIndex;
|
||||||
|
ACol := AWorksheet.ActiveCellCol;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
swRow:
|
||||||
|
if soWrapDocument in FParams.Options then
|
||||||
|
begin
|
||||||
|
ARow := AWorksheet.ActiveCellRow;
|
||||||
|
ACol := AWorksheet.GetLastColIndex;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end; // case
|
||||||
|
|
||||||
|
Result := false;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsSearchEngine.GotoPrevInWorksheet(AWorksheet: TsWorksheet;
|
||||||
|
var ARow, ACol: Cardinal): Boolean;
|
||||||
|
begin
|
||||||
|
Result := true;
|
||||||
|
if (soAlongRows in FParams.Options) or (FParams.Within = swRow) then
|
||||||
|
begin
|
||||||
|
if ACol > 0 then begin
|
||||||
|
dec(ACol);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
if (FParams.Within <> swRow) then
|
||||||
|
begin
|
||||||
|
ACol := AWorksheet.GetLastColIndex;
|
||||||
|
if ARow > 0 then
|
||||||
|
begin
|
||||||
|
dec(ARow);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end else
|
||||||
|
if not (soAlongRows in FParams.Options) or (FParams.Within = swColumn) then
|
||||||
|
begin
|
||||||
|
if ARow > 0 then begin
|
||||||
|
dec(ARow);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
if (FParams.Within <> swColumn) then
|
||||||
|
begin
|
||||||
|
ARow := AWorksheet.GetlastRowIndex;
|
||||||
|
if ACol > 0 then
|
||||||
|
begin
|
||||||
|
dec(ACol);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
// We reached the first cell, there is no "previous" cell
|
||||||
|
Result := false;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsSearchEngine.Matches(AWorksheet: TsWorksheet; ARow, ACol: Cardinal): Boolean;
|
||||||
|
var
|
||||||
|
cell: PCell;
|
||||||
|
celltxt: String;
|
||||||
|
begin
|
||||||
|
cell := AWorksheet.FindCell(ARow, ACol);
|
||||||
|
if cell <> nil then
|
||||||
|
celltxt := AWorksheet.ReadAsText(cell) else
|
||||||
|
celltxt := '';
|
||||||
|
|
||||||
|
if soRegularExpr in FParams.Options then
|
||||||
|
Result := FRegEx.Exec(celltxt)
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
if not (soMatchCase in FParams.Options) then
|
||||||
|
celltxt := UTF8Lowercase(celltxt);
|
||||||
|
if soCompareEntireCell in FParams.Options then
|
||||||
|
exit(celltxt = FSearchText);
|
||||||
|
if UTF8Pos(FSearchText, celltxt) > 0 then
|
||||||
|
exit(true);
|
||||||
|
Result := false;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TsSearchEngine.PrepareSearchText(const ASearchText: String);
|
||||||
|
begin
|
||||||
|
if soRegularExpr in FParams.Options then
|
||||||
|
begin
|
||||||
|
FreeAndNil(FRegEx);
|
||||||
|
FRegEx := TRegExpr.Create;
|
||||||
|
FRegEx.Expression := ASearchText
|
||||||
|
end else
|
||||||
|
if (soMatchCase in FParams.Options) then
|
||||||
|
FSearchText := ASearchText else
|
||||||
|
FSearchText := UTF8Lowercase(ASearchText);
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
@ -698,12 +698,6 @@ type
|
|||||||
{@@ Pointer to a page layout record }
|
{@@ Pointer to a page layout record }
|
||||||
PsPageLayout = ^TsPageLayout;
|
PsPageLayout = ^TsPageLayout;
|
||||||
|
|
||||||
{@@ Search option }
|
|
||||||
TsSearchOption = (soCompareFullCell, soIgnoreCase, soRegularExpr,
|
|
||||||
soBackward, soAlongRows);
|
|
||||||
TsSearchOptions = set of TsSearchOption;
|
|
||||||
|
|
||||||
|
|
||||||
const
|
const
|
||||||
{@@ Indexes to be used for the various headers and footers }
|
{@@ Indexes to be used for the various headers and footers }
|
||||||
HEADER_FOOTER_INDEX_FIRST = 0;
|
HEADER_FOOTER_INDEX_FIRST = 0;
|
||||||
@ -712,6 +706,25 @@ const
|
|||||||
HEADER_FOOTER_INDEX_ALL = 1;
|
HEADER_FOOTER_INDEX_ALL = 1;
|
||||||
|
|
||||||
|
|
||||||
|
type
|
||||||
|
{@@ Search option }
|
||||||
|
TsSearchOption = (soCompareEntireCell, soMatchCase, soRegularExpr, soAlongRows,
|
||||||
|
soBackward, soWrapDocument, soEntireDocument);
|
||||||
|
|
||||||
|
{@@ A set of search options }
|
||||||
|
TsSearchOptions = set of TsSearchOption;
|
||||||
|
|
||||||
|
{@@ Defines which part of document is scanned }
|
||||||
|
TsSearchWithin = (swWorkbook, swWorksheet, swColumn, swRow);
|
||||||
|
|
||||||
|
{@@ Search parameters }
|
||||||
|
TsSearchParams = record
|
||||||
|
SearchText: String;
|
||||||
|
Options: TsSearchOptions;
|
||||||
|
Within: TsSearchWithin;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
constructor TsFont.Create(AFontName: String; ASize: Single; AStyle: TsFontStyles;
|
constructor TsFont.Create(AFontName: String; ASize: Single; AStyle: TsFontStyles;
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
This package is all you need if you don't want graphical components (like grids and charts)."/>
|
This package is all you need if you don't want graphical components (like grids and charts)."/>
|
||||||
<License Value="LGPL with static linking exception. This is the same license as is used in the LCL (Lazarus Component Library)."/>
|
<License Value="LGPL with static linking exception. This is the same license as is used in the LCL (Lazarus Component Library)."/>
|
||||||
<Version Major="1" Minor="7"/>
|
<Version Major="1" Minor="7"/>
|
||||||
<Files Count="38">
|
<Files Count="39">
|
||||||
<Item1>
|
<Item1>
|
||||||
<Filename Value="fpolestorage.pas"/>
|
<Filename Value="fpolestorage.pas"/>
|
||||||
<UnitName Value="fpolestorage"/>
|
<UnitName Value="fpolestorage"/>
|
||||||
@ -183,6 +183,10 @@ This package is all you need if you don't want graphical components (like grids
|
|||||||
<Filename Value="fpscell.pas"/>
|
<Filename Value="fpscell.pas"/>
|
||||||
<UnitName Value="fpsCell"/>
|
<UnitName Value="fpsCell"/>
|
||||||
</Item38>
|
</Item38>
|
||||||
|
<Item39>
|
||||||
|
<Filename Value="fpssearch.pas"/>
|
||||||
|
<UnitName Value="fpsSearch"/>
|
||||||
|
</Item39>
|
||||||
</Files>
|
</Files>
|
||||||
<RequiredPkgs Count="2">
|
<RequiredPkgs Count="2">
|
||||||
<Item1>
|
<Item1>
|
||||||
|
@ -14,7 +14,7 @@ uses
|
|||||||
fpolebasic, wikitable, fpsNumFormatParser, fpsfunc, fpsRPN, fpsStrings,
|
fpolebasic, wikitable, fpsNumFormatParser, fpsfunc, fpsRPN, fpsStrings,
|
||||||
fpscsv, fpsCsvDocument, fpspatches, fpsTypes, xlsEscher, fpsReaderWriter,
|
fpscsv, fpsCsvDocument, fpspatches, fpsTypes, xlsEscher, fpsReaderWriter,
|
||||||
fpsNumFormat, fpsclasses, fpsHeaderFooterParser, fpsPalette, fpsHTML,
|
fpsNumFormat, fpsclasses, fpsHeaderFooterParser, fpsPalette, fpsHTML,
|
||||||
fpsHTMLUtils, fpsCell;
|
fpsHTMLUtils, fpsCell, fpsSearch;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user