fpspreadsheet: Add "replace" to search engine.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@4316 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz 2015-09-08 21:43:02 +00:00
parent 50f0b2fbe6
commit a5cbacff27
6 changed files with 583 additions and 209 deletions

View File

@ -500,6 +500,7 @@ begin
SearchForm.OnFound := @SearchFound; SearchForm.OnFound := @SearchFound;
SearchForm.OnClose := @SearchClose; SearchForm.OnClose := @SearchClose;
SearchForm.SearchParams := DefaultSearchParams; SearchForm.SearchParams := DefaultSearchParams;
SearchForm.ReplaceParams := DefaultReplaceParams;
SearchForm.Execute(WorkbookSource.Workbook); SearchForm.Execute(WorkbookSource.Workbook);
end; end;
@ -609,6 +610,7 @@ procedure TMainForm.SearchClose(Sender: TObject; var CloseAction: TCloseAction);
begin begin
Unused(CloseAction); Unused(CloseAction);
DefaultSearchParams := TSearchForm(Sender).SearchParams; DefaultSearchParams := TSearchForm(Sender).SearchParams;
DefaultReplaceParams := TSearchForm(Sender).ReplaceParams;
end; end;
procedure TMainForm.SearchFound(Sender: TObject; AFound: Boolean; procedure TMainForm.SearchFound(Sender: TObject; AFound: Boolean;

View File

@ -1,112 +1,39 @@
object SearchForm: TSearchForm object SearchForm: TSearchForm
Left = 238 Left = 238
Height = 272 Height = 341
Top = 157 Top = 157
Width = 483 Width = 487
BorderStyle = bsDialog BorderStyle = bsDialog
Caption = 'Search' Caption = 'Search'
ClientHeight = 272 ClientHeight = 341
ClientWidth = 483 ClientWidth = 487
FormStyle = fsStayOnTop FormStyle = fsStayOnTop
OnClose = FormClose OnClose = FormClose
OnCreate = FormCreate OnCreate = FormCreate
OnShow = FormShow OnShow = FormShow
LCLVersion = '1.5' 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 = 374
Anchors = [akTop, akLeft, akRight]
ItemHeight = 15
TabOrder = 0
end
object CgSearchOptions: TCheckGroup
Left = 16
Height = 163
Top = 53
Width = 192
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 = 188
Items.Strings = (
'Compare entire cell '
'Match case'
'Regular expression'
'Search along rows'
'Continue at start/end'
)
TabOrder = 1
Data = {
050000000202020202
}
end
object RgSearchWithin: TRadioGroup
Left = 232
Height = 67
Top = 53
Width = 232
AutoFill = True
Caption = 'Search within'
ChildSizing.LeftRightSpacing = 6
ChildSizing.EnlargeHorizontal = crsHomogenousChildResize
ChildSizing.EnlargeVertical = crsHomogenousChildResize
ChildSizing.ShrinkHorizontal = crsScaleChilds
ChildSizing.ShrinkVertical = crsScaleChilds
ChildSizing.Layout = cclTopToBottomThenLeftToRight
ChildSizing.ControlsPerLine = 2
ClientHeight = 47
ClientWidth = 228
ColumnLayout = clVerticalThenHorizontal
Columns = 2
ItemIndex = 0
Items.Strings = (
'workbook'
'worksheet'
'column'
'row'
)
TabOrder = 2
end
object ButtonPanel: TPanel object ButtonPanel: TPanel
Left = 0 Left = 0
Height = 38 Height = 38
Top = 234 Top = 303
Width = 483 Width = 487
Align = alBottom Align = alBottom
BevelOuter = bvNone BevelOuter = bvNone
ClientHeight = 38 ClientHeight = 38
ClientWidth = 483 ClientWidth = 487
TabOrder = 3 TabOrder = 0
object Bevel1: TBevel object Bevel1: TBevel
Left = 6 Left = 6
Height = 3 Height = 3
Top = 0 Top = 0
Width = 471 Width = 475
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 = 240 Left = 244
Height = 25 Height = 25
Top = 7 Top = 7
Width = 75 Width = 75
@ -148,12 +75,12 @@ object SearchForm: TSearchForm
0000000000000000000000000000000000000000000054545411555555405555 0000000000000000000000000000000000000000000054545411555555405555
555A555555655555555A55555540545454110000000000000000 555A555555655555555A55555540545454110000000000000000
} }
OnClick = SearchButtonClick OnClick = ExecuteClick
TabOrder = 0 TabOrder = 0
Visible = False Visible = False
end end
object BtnClose: TBitBtn object BtnClose: TBitBtn
Left = 400 Left = 404
Height = 25 Height = 25
Top = 7 Top = 7
Width = 75 Width = 75
@ -165,7 +92,7 @@ object SearchForm: TSearchForm
TabOrder = 1 TabOrder = 1
end end
object BtnSearch: TBitBtn object BtnSearch: TBitBtn
Left = 320 Left = 324
Height = 25 Height = 25
Top = 7 Top = 7
Width = 75 Width = 75
@ -208,32 +135,178 @@ object SearchForm: TSearchForm
0000000000000000000000000000000000000000000054545411555555405555 0000000000000000000000000000000000000000000054545411555555405555
555A555555655555555A55555540545454110000000000000000 555A555555655555555A55555540545454110000000000000000
} }
OnClick = SearchButtonClick OnClick = ExecuteClick
TabOrder = 2 TabOrder = 2
end end
end end
object RgSearchStart: TRadioGroup object TabControl: TTabControl
Left = 232 Left = 8
Height = 56 Height = 287
Top = 160 Top = 8
Width = 232 Width = 471
AutoFill = True OnChange = TabControlChange
Caption = 'Start search at' OnChanging = TabControlChanging
ChildSizing.LeftRightSpacing = 6 TabIndex = 0
ChildSizing.EnlargeHorizontal = crsHomogenousChildResize Tabs.Strings = (
ChildSizing.EnlargeVertical = crsHomogenousChildResize 'Search'
ChildSizing.ShrinkHorizontal = crsScaleChilds 'Replace'
ChildSizing.ShrinkVertical = crsScaleChilds
ChildSizing.Layout = cclLeftToRightThenTopToBottom
ChildSizing.ControlsPerLine = 2
ClientHeight = 36
ClientWidth = 228
Columns = 2
ItemIndex = 0
Items.Strings = (
'active cell'
'beginning/end'
) )
TabOrder = 4 Align = alClient
BorderSpacing.Around = 8
TabOrder = 1
object SearchTextPanel: TPanel
Left = 2
Height = 33
Top = 23
Width = 467
Align = alTop
BevelOuter = bvNone
ClientHeight = 33
ClientWidth = 467
Color = clNone
ParentColor = False
TabOrder = 1
object LblSearchText: TLabel
Left = 14
Height = 15
Top = 12
Width = 53
Caption = 'Search for'
ParentColor = False
end
object CbSearchText: TComboBox
Left = 104
Height = 23
Top = 8
Width = 351
Anchors = [akTop, akLeft, akRight]
ItemHeight = 15
TabOrder = 0
end
end
object ReplaceTextPanel: TPanel
Left = 2
Height = 33
Top = 56
Width = 467
Align = alTop
BevelOuter = bvNone
ClientHeight = 33
ClientWidth = 467
Color = clNone
ParentColor = False
TabOrder = 2
Visible = False
object LblSearchText1: TLabel
Left = 14
Height = 15
Top = 12
Width = 67
Caption = 'Replace with'
ParentColor = False
end
object CbReplaceText: TComboBox
Left = 104
Height = 23
Top = 8
Width = 351
Anchors = [akTop, akLeft, akRight]
ItemHeight = 15
TabOrder = 0
end
end
object SearchParamsPanel: TPanel
Left = 2
Height = 196
Top = 89
Width = 467
Align = alClient
BevelOuter = bvNone
ClientHeight = 196
ClientWidth = 467
Color = clNone
ParentColor = False
TabOrder = 3
object CgOptions: TCheckGroup
Left = 16
Height = 163
Top = 16
Width = 192
AutoFill = True
Caption = '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 = 188
Items.Strings = (
'Compare entire cell '
'Match case'
'Regular expression'
'Search along rows'
'Continue at start/end'
)
TabOrder = 0
Data = {
050000000202020202
}
end
object RgSearchWithin: TRadioGroup
Left = 232
Height = 67
Top = 16
Width = 223
AutoFill = True
Caption = 'Search within'
ChildSizing.LeftRightSpacing = 6
ChildSizing.EnlargeHorizontal = crsHomogenousChildResize
ChildSizing.EnlargeVertical = crsHomogenousChildResize
ChildSizing.ShrinkHorizontal = crsScaleChilds
ChildSizing.ShrinkVertical = crsScaleChilds
ChildSizing.Layout = cclTopToBottomThenLeftToRight
ChildSizing.ControlsPerLine = 2
ClientHeight = 47
ClientWidth = 219
ColumnLayout = clVerticalThenHorizontal
Columns = 2
ItemIndex = 0
Items.Strings = (
'workbook'
'worksheet'
'column'
'row'
)
TabOrder = 1
end
object RgSearchStart: TRadioGroup
Left = 232
Height = 56
Top = 123
Width = 223
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 = 2
ClientHeight = 36
ClientWidth = 219
Columns = 2
ItemIndex = 0
Items.Strings = (
'active cell'
'beginning/end'
)
TabOrder = 2
end
end
end end
end end

View File

@ -6,7 +6,7 @@ interface
uses uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
StdCtrls, ExtCtrls, Buttons, fpsTypes, fpspreadsheet, fpsSearch; StdCtrls, ExtCtrls, Buttons, ComCtrls, fpsTypes, fpspreadsheet, fpsSearch;
type type
TsSearchEvent = procedure (Sender: TObject; AFound: Boolean; TsSearchEvent = procedure (Sender: TObject; AFound: Boolean;
@ -20,29 +20,46 @@ type
BtnClose: TBitBtn; BtnClose: TBitBtn;
BtnSearch: TBitBtn; BtnSearch: TBitBtn;
CbSearchText: TComboBox; CbSearchText: TComboBox;
CgSearchOptions: TCheckGroup; CbReplaceText: TComboBox;
CgOptions: TCheckGroup;
LblSearchText: TLabel; LblSearchText: TLabel;
ButtonPanel: TPanel; ButtonPanel: TPanel;
LblSearchText1: TLabel;
SearchParamsPanel: TPanel;
SearchTextPanel: TPanel;
RgSearchStart: TRadioGroup; RgSearchStart: TRadioGroup;
RgSearchWithin: TRadioGroup; RgSearchWithin: TRadioGroup;
ReplaceTextPanel: TPanel;
TabControl: TTabControl;
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 ExecuteClick(Sender: TObject);
procedure TabControlChange(Sender: TObject);
procedure TabControlChanging(Sender: TObject; var AllowChange: Boolean);
private private
{ private declarations } { private declarations }
FSearchEngine: TsSearchEngine; FSearchEngine: TsSearchEngine;
FWorkbook: TsWorkbook; FWorkbook: TsWorkbook;
FFoundWorksheet: TsWorksheet; FFoundWorksheet: TsWorksheet;
FFoundRow, FFoundCol: Cardinal; FFoundRow, FFoundCol: Cardinal;
FSearchParams: TsSearchParams;
FReplaceParams: TsReplaceParams;
FOnFound: TsSearchEvent; FOnFound: TsSearchEvent;
function GetParams: TsSearchParams; function GetReplaceParams: TsReplaceParams;
procedure SetParams(const AValue: TsSearchParams); function GetSearchParams: TsSearchParams;
procedure SetReplaceParams(const AValue: TsReplaceParams);
procedure SetSearchParams(const AValue: TsSearchParams);
protected
procedure ConfirmReplacementHandler(Sender: TObject; AWorksheet: TsWorksheet;
ARow, ACol: Cardinal; const ASearchText, AReplaceText: String; var Allow: Boolean);
procedure PopulateOptions;
public public
{ public declarations } { public declarations }
procedure Execute(AWorkbook: TsWorkbook); procedure Execute(AWorkbook: TsWorkbook);
property Workbook: TsWorkbook read FWorkbook; property Workbook: TsWorkbook read FWorkbook;
property SearchParams: TsSearchParams read GetParams write SetParams; property SearchParams: TsSearchParams read GetSearchParams write SetSearchParams;
property ReplaceParams: TsReplaceParams read GetReplaceParams write SetReplaceParams;
property OnFound: TsSearchEvent read FOnFound write FOnFound; property OnFound: TsSearchEvent read FOnFound write FOnFound;
end; end;
@ -54,6 +71,10 @@ var
Options: []; Options: [];
Within: swWorksheet Within: swWorksheet
); );
DefaultReplaceParams: TsReplaceParams = (
ReplaceText: '';
Options: [roConfirm]
);
implementation implementation
@ -66,21 +87,108 @@ uses
const const
MAX_SEARCH_ITEMS = 10; MAX_SEARCH_ITEMS = 10;
// Search & replace
COMPARE_ENTIRE_CELL = 0; COMPARE_ENTIRE_CELL = 0;
MATCH_CASE = 1; MATCH_CASE = 1;
REGULAR_EXPRESSION = 2; REGULAR_EXPRESSION = 2;
SEARCH_ALONG_ROWS = 3; SEARCH_ALONG_ROWS = 3;
CONTINUE_AT_START_END = 4; CONTINUE_AT_START_END = 4;
// Replace only
REPLACE_ENTIRE_CELL = 5;
REPLACE_ALL = 6;
CONFIRM_REPLACEMENT = 7;
BASE_HEIGHT = 340; // Design height of SearchForm
SEARCH_TAB = 0;
REPLACE_TAB = 1;
{ TSearchForms } { TSearchForms }
procedure TSearchForm.ConfirmReplacementHandler(Sender: TObject;
AWorksheet: TsWorksheet; ARow, ACol: Cardinal;
const ASearchText, AReplaceText: String; var Allow: Boolean);
begin
Unused(AWorksheet, ARow, ACol);
Unused(ASearchText, AReplaceText);
Allow := MessageDlg('Replace?', mtConfirmation, [mbYes, mbNo], 0) = mrYes;
end;
procedure TSearchForm.Execute(AWorkbook: TsWorkbook); procedure TSearchForm.Execute(AWorkbook: TsWorkbook);
begin begin
FWorkbook := AWorkbook; FWorkbook := AWorkbook;
Show; Show;
end; end;
procedure TSearchForm.ExecuteClick(Sender: TObject);
var
sp: TsSearchParams;
rp: TsReplaceParams;
found: Boolean;
crs: TCursor;
begin
sp := GetSearchParams;
if sp.SearchText = '' then
exit;
if TabControl.TabIndex = REPLACE_TAB then
rp := GetReplaceParams;
if CbSearchText.Items.IndexOf(sp.SearchText) = -1 then
begin
CbSearchText.Items.Insert(0, sp.SearchText);
while CbSearchText.Items.Count > MAX_SEARCH_ITEMS do
CbSearchText.Items.Delete(CbSearchText.Items.Count-1);
end;
if (TabControl.TabIndex = REPLACE_TAB) and
(CbReplaceText.Items.IndexOf(rp.ReplaceText) = -1) then
begin
CbReplaceText.items.Insert(0, rp.ReplaceText);
while CbReplaceText.Items.Count > MAX_SEARCH_ITEMS do
CbReplaceText.Items.Delete(CbReplaceText.Items.Count-1);
end;
crs := Screen.Cursor;
try
Screen.Cursor := crHourglass;
if FSearchEngine = nil then
begin
FSearchEngine := TsSearchEngine.Create(FWorkbook);
FSearchEngine.OnConfirmReplacement := @ConfirmReplacementHandler;
if (soBackward in sp.Options) then
Include(sp.Options, soBackward) else
Exclude(sp.Options, soBackward);
case Tabcontrol.TabIndex of
0: found := FSearchEngine.FindFirst(sp, FFoundWorksheet, FFoundRow, FFoundCol);
1: found := FSearchEngine.ReplaceFirst(sp, rp, FFoundWorksheet, FFoundRow, FFoundCol);
end;
end else
begin
if (Sender = BtnSearchBack) then
Include(sp.Options, soBackward) else
Exclude(sp.Options, soBackward);
// User may select a different worksheet/different cell to continue search!
FFoundWorksheet := FWorkbook.ActiveWorksheet;
FFoundRow := FFoundWorksheet.ActiveCellRow;
FFoundCol := FFoundWorksheet.ActiveCellCol;
case TabControl.TabIndex of
0: found := FSearchEngine.FindNext(sp, FFoundWorksheet, FFoundRow, FFoundCol);
1: found := FSearchEngine.ReplaceNext(sp, rp, FFoundWorksheet, FFoundRow, FFoundCol);
end;
end;
finally
Screen.Cursor := crs;
end;
if Assigned(FOnFound) then
FOnFound(self, found, FFoundWorksheet, FFoundRow, FFoundCol);
BtnSearchBack.Visible := true;
BtnSearch.Caption := 'Next';
end;
procedure TSearchForm.FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure TSearchForm.FormClose(Sender: TObject; var CloseAction: TCloseAction);
var var
P: TPoint; P: TPoint;
@ -97,6 +205,7 @@ end;
procedure TSearchForm.FormCreate(Sender: TObject); procedure TSearchForm.FormCreate(Sender: TObject);
begin begin
Position := poMainFormCenter; Position := poMainFormCenter;
PopulateOptions;
end; end;
procedure TSearchForm.FormShow(Sender: TObject); procedure TSearchForm.FormShow(Sender: TObject);
@ -109,78 +218,115 @@ begin
FFoundWorksheet := nil; FFoundWorksheet := nil;
end; end;
function TSearchForm.GetParams: TsSearchParams; function TSearchForm.GetReplaceParams: TsReplaceParams;
begin
if TabControl.TabIndex = 0 then
Result := FReplaceParams
else
begin
Result.ReplaceText := CbReplaceText.Text;
Result.Options := [];
if CgOptions.Checked[REPLACE_ENTIRE_CELL] then
Include(Result.Options, roReplaceEntireCell);
if CgOptions.Checked[REPLACE_ALL] then
Include(Result.Options, roReplaceAll);
if CgOptions.Checked[CONFIRM_REPLACEMENT] then
Include(Result.Options, roConfirm);
FReplaceParams := Result;
end;
end;
function TSearchForm.GetSearchParams: TsSearchParams;
begin begin
Result.SearchText := CbSearchText.Text; Result.SearchText := CbSearchText.Text;
Result.Options := []; Result.Options := [];
if CgSearchOptions.Checked[COMPARE_ENTIRE_CELL] then if CgOptions.Checked[COMPARE_ENTIRE_CELL] then
Include(Result.Options, soCompareEntireCell); Include(Result.Options, soCompareEntireCell);
if CgSearchOptions.Checked[MATCH_CASE] then if CgOptions.Checked[MATCH_CASE] then
Include(Result.Options, soMatchCase); Include(Result.Options, soMatchCase);
if CgSearchOptions.Checked[REGULAR_EXPRESSION] then if CgOptions.Checked[REGULAR_EXPRESSION] then
Include(Result.Options, soRegularExpr); Include(Result.Options, soRegularExpr);
if CgSearchOptions.Checked[SEARCH_ALONG_ROWS] then if CgOptions.Checked[SEARCH_ALONG_ROWS] then
Include(Result.Options, soAlongRows); Include(Result.Options, soAlongRows);
if CgSearchOptions.Checked[CONTINUE_AT_START_END] then if CgOptions.Checked[CONTINUE_AT_START_END] then
Include(Result.Options, soWrapDocument); Include(Result.Options, soWrapDocument);
if RgSearchStart.ItemIndex = 1 then if RgSearchStart.ItemIndex = 1 then
Include(Result.Options, soEntireDocument); Include(Result.Options, soEntireDocument);
Result.Within := TsSearchWithin(RgSearchWithin.ItemIndex); Result.Within := TsSearchWithin(RgSearchWithin.ItemIndex);
end; end;
procedure TSearchForm.SearchButtonClick(Sender: TObject); procedure TSearchForm.PopulateOptions;
var
params: TsSearchParams;
found: Boolean;
begin begin
params := GetParams; with CgOptions.Items do
if params.SearchText = '' then
exit;
if CbSearchText.Items.IndexOf(params.SearchText) = -1 then
begin begin
CbSearchText.Items.Insert(0, params.SearchText); Clear;
while CbSearchText.Items.Count > MAX_SEARCH_ITEMS do Add('Compare entire cell');
CbSearchText.Items.Delete(CbSearchText.Items.Count-1); Add('Match case');
Add('Regular expression');
Add('Search along rows');
Add('Continue at start/end');
if TabControl.TabIndex = REPLACE_TAB then
begin
Add('Replace entire cell');
Add('Replace all');
Add('Confirm replacement');
end;
end; end;
if FSearchEngine = nil then
begin
FSearchEngine := TsSearchEngine.Create(FWorkbook);
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;
if Assigned(FOnFound) then
FOnFound(self, found, FFoundWorksheet, FFoundRow, FFoundCol);
BtnSearchBack.Visible := true;
BtnSearch.Caption := 'Next';
end; end;
procedure TSearchForm.SetParams(const AValue: TsSearchParams); procedure TSearchForm.SetSearchParams(const AValue: TsSearchParams);
begin begin
CbSearchText.Text := Avalue.SearchText; CbSearchText.Text := Avalue.SearchText;
CgSearchOptions.Checked[COMPARE_ENTIRE_CELL] := (soCompareEntireCell in AValue.Options); CgOptions.Checked[COMPARE_ENTIRE_CELL] := (soCompareEntireCell in AValue.Options);
CgSearchOptions.Checked[MATCH_CASE] := (soMatchCase in AValue.Options); CgOptions.Checked[MATCH_CASE] := (soMatchCase in AValue.Options);
CgSearchOptions.Checked[REGULAR_EXPRESSION] := (soRegularExpr in Avalue.Options); CgOptions.Checked[REGULAR_EXPRESSION] := (soRegularExpr in Avalue.Options);
CgSearchOptions.Checked[SEARCH_ALONG_ROWS] := (soAlongRows in AValue.Options); CgOptions.Checked[SEARCH_ALONG_ROWS] := (soAlongRows in AValue.Options);
CgSearchOptions.Checked[CONTINUE_AT_START_END] := (soWrapDocument in Avalue.Options); CgOptions.Checked[CONTINUE_AT_START_END] := (soWrapDocument in Avalue.Options);
RgSearchWithin.ItemIndex := ord(AValue.Within); RgSearchWithin.ItemIndex := ord(AValue.Within);
RgSearchStart.ItemIndex := ord(soEntireDocument in AValue.Options); RgSearchStart.ItemIndex := ord(soEntireDocument in AValue.Options);
end; end;
procedure TSearchForm.SetReplaceParams(const AValue: TsReplaceParams);
begin
FReplaceParams := AValue;
if TabControl.TabIndex = REPLACE_TAB then
begin
CbReplaceText.Text := AValue.ReplaceText;
CgOptions.Checked[REPLACE_ENTIRE_CELL] := (roReplaceEntireCell in AValue.Options);
CgOptions.Checked[REPLACE_ALL] := (roReplaceAll in AValue.Options);
CgOptions.Checked[CONFIRM_REPLACEMENT] := (roConfirm in AValue.Options);
end;
end;
procedure TSearchForm.TabControlChange(Sender: TObject);
var
h, d: Integer;
begin
ReplaceTextPanel.Visible := (TabControl.TabIndex = REPLACE_TAB);
PopulateOptions;
SetSearchParams(FSearchParams);
SetReplaceParams(FReplaceParams);
h := RgSearchStart.Top + RgSearchStart.Height - CgOptions.Top;
if TabControl.TabIndex = 0 then
begin
CgOptions.Height := h;
Height := BASE_HEIGHT - ReplaceTextPanel.Height;
end else
begin
d := 3 * 16;
CgOptions.Height := h + d;
Height := BASE_HEIGHT + d;
end;
end;
procedure TSearchForm.TabControlChanging(Sender: TObject;
var AllowChange: Boolean);
begin
AllowChange := true;
FSearchParams := GetSearchParams;
FReplaceParams := GetReplaceParams;
end;
end. end.

View File

@ -737,6 +737,9 @@ type
out ARow, ACol: Cardinal): Boolean; out ARow, ACol: Cardinal): Boolean;
*) *)
{ Utilities } { Utilities }
procedure DisableNotifications;
procedure EnableNotifications;
function NotificationsEnabled: Boolean;
procedure UpdateCaches; procedure UpdateCaches;
{ Error messages } { Error messages }
@ -1530,7 +1533,7 @@ begin
CalcFormulas; CalcFormulas;
end; end;
if Assigned(FOnChangeCell) then if FWorkbook.NotificationsEnabled and Assigned(FOnChangeCell) then
FOnChangeCell(Self, ARow, ACol); FOnChangeCell(Self, ARow, ACol);
end; end;
@ -1543,7 +1546,7 @@ end;
-------------------------------------------------------------------------------} -------------------------------------------------------------------------------}
procedure TsWorksheet.ChangedFont(ARow, ACol: Cardinal); procedure TsWorksheet.ChangedFont(ARow, ACol: Cardinal);
begin begin
if FWorkbook.FReadWriteFlag = rwfRead then if (FWorkbook.FReadWriteFlag = rwfRead) or not FWorkbook.NotificationsEnabled then
exit; exit;
if Assigned(FOnChangeFont) then if Assigned(FOnChangeFont) then
FOnChangeFont(Self, ARow, ACol); FOnChangeFont(Self, ARow, ACol);
@ -3521,6 +3524,9 @@ end;
-------------------------------------------------------------------------------} -------------------------------------------------------------------------------}
procedure TsWorksheet.SelectCell(ARow, ACol: Cardinal); procedure TsWorksheet.SelectCell(ARow, ACol: Cardinal);
begin begin
if not FWorkbook.NotificationsEnabled then
exit;
FActiveCellRow := ARow; FActiveCellRow := ARow;
FActiveCellCol := ACol; FActiveCellCol := ACol;
if Assigned(FOnSelectCell) then if Assigned(FOnSelectCell) then
@ -6361,6 +6367,31 @@ begin
Result := (FSearchEngine as TsSearchEngine).FindNext(AWorksheet, ARow, ACol); Result := (FSearchEngine as TsSearchEngine).FindNext(AWorksheet, ARow, ACol);
end; end;
*) *)
{@@ ----------------------------------------------------------------------------
Helper method to disable notification of visual controls
-------------------------------------------------------------------------------}
procedure TsWorkbook.DisableNotifications;
begin
inc(FLockCount);
end;
{@@ ----------------------------------------------------------------------------
Helper method to enable notification of visual controls
-------------------------------------------------------------------------------}
procedure TsWorkbook.EnableNotifications;
begin
dec(FLockCount);
end;
{@@ ----------------------------------------------------------------------------
Helper method to determine whether visual controls are notified of changes
-------------------------------------------------------------------------------}
function TsWorkbook.NotificationsEnabled: Boolean;
begin
Result := (FLockCount = 0);
end;
{@@ ---------------------------------------------------------------------------- {@@ ----------------------------------------------------------------------------
Helper method to update internal caching variables Helper method to update internal caching variables
-------------------------------------------------------------------------------} -------------------------------------------------------------------------------}

View File

@ -8,14 +8,21 @@ uses
Classes, SysUtils, RegExpr, fpstypes, fpspreadsheet; Classes, SysUtils, RegExpr, fpstypes, fpspreadsheet;
type type
TsConfirmReplacementEvent = procedure (Sender: TObject; AWorksheet: TsWorksheet;
ARow, ACol: Cardinal; const ASearchText, AReplaceText: String;
var Allow: Boolean) of object;
TsSearchEngine = class TsSearchEngine = class
private private
FWorkbook: TsWorkbook; FWorkbook: TsWorkbook;
FSearchText: String; FSearchText: String;
FParams: TsSearchParams; FSearchParams: TsSearchParams;
FReplaceParams: TsReplaceParams;
FCurrSel: Integer; FCurrSel: Integer;
FRegEx: TRegExpr; FRegEx: TRegExpr;
FOnConfirmReplacement: TsConfirmReplacementEvent;
protected protected
function ExecReplace(AWorksheet: TsWorksheet; ARow, ACol: Cardinal): boolean;
function ExecSearch(var AWorksheet: TsWorksheet; function ExecSearch(var AWorksheet: TsWorksheet;
var ARow, ACol: Cardinal): Boolean; var ARow, ACol: Cardinal): Boolean;
procedure GotoFirst(out AWorksheet: TsWorksheet; out ARow, ACol: Cardinal); procedure GotoFirst(out AWorksheet: TsWorksheet; out ARow, ACol: Cardinal);
@ -34,10 +41,19 @@ type
public public
constructor Create(AWorkbook: TsWorkbook); constructor Create(AWorkbook: TsWorkbook);
destructor Destroy; override; destructor Destroy; override;
function FindFirst(const ASearchText: String; const AParams: TsSearchParams; function FindFirst(const ASearchParams: TsSearchParams;
out AWorksheet: TsWorksheet; out ARow, ACol: Cardinal): Boolean; out AWorksheet: TsWorksheet; out ARow, ACol: Cardinal): Boolean;
function FindNext(const ASearchText: String; const AParams: TsSearchParams; function FindNext(const ASearchParams: TsSearchParams;
var AWorksheet: TsWorksheet; var ARow, ACol: Cardinal): Boolean; var AWorksheet: TsWorksheet; var ARow, ACol: Cardinal): Boolean;
function ReplaceFirst(const ASearchParams: TsSearchParams;
const AReplaceParams: TsReplaceParams;
out AWorksheet: TsWorksheet; out ARow, ACol: Cardinal): Boolean;
function ReplaceNext(const ASearchParams: TsSearchParams;
const AReplaceParams: TsReplaceParams;
var AWorksheet: TsWorksheet; var ARow, ACol: Cardinal): Boolean;
property OnConfirmReplacement: TsConfirmReplacementEvent
read FOnConfirmReplacement write FOnConfirmReplacement;
end; end;
implementation implementation
@ -57,6 +73,44 @@ begin
inherited Destroy; inherited Destroy;
end; end;
function TsSearchEngine.ExecReplace(AWorksheet: TsWorksheet; ARow, ACol: Cardinal) : Boolean;
var
res: Integer;
s: String;
allow: Boolean;
flags: TReplaceFlags;
begin
if roConfirm in FReplaceParams.Options then
begin
allow := false;
if Assigned(FOnConfirmReplacement) then
begin
FOnConfirmReplacement(self, AWorksheet, ARow, ACol,
FSearchParams.SearchText, FReplaceParams.ReplaceText, allow);
if not allow then
exit(false);
end else
raise Exception.Create('[TsSearchEngine.ExecReplace] OnConfirmReplacement handler needed.');
end;
if roReplaceEntireCell in FReplaceParams.Options then
AWorksheet.WriteCellValueAsString(ARow, ACol, FReplaceParams.ReplaceText)
else begin
s := AWorksheet.ReadAsText(ARow, ACol);
if soCompareEntireCell in FSearchParams.Options then
AWorksheet.WriteCellValueAsString(ARow, ACol, FReplaceParams.ReplaceText)
else
begin
flags := [];
if not (soMatchCase in FSearchParams.Options) then
Include(flags, rfIgnoreCase);
s := UTF8StringReplace(s, FSearchparams.SearchText, FReplaceParams.ReplaceText, flags);
AWorksheet.WritecellValueAsString(ARow, ACol, s);
// to do: RegEx to be added
end;
end;
end;
function TsSearchEngine.ExecSearch(var AWorksheet: TsWorksheet; function TsSearchEngine.ExecSearch(var AWorksheet: TsWorksheet;
var ARow, ACol: Cardinal): Boolean; var ARow, ACol: Cardinal): Boolean;
var var
@ -70,7 +124,7 @@ begin
complete := false; complete := false;
while (not complete) and (not Matches(AWorksheet, ARow, ACol)) do while (not complete) and (not Matches(AWorksheet, ARow, ACol)) do
begin begin
if soBackward in FParams.Options then if soBackward in FSearchParams.Options then
complete := not GotoPrev(AWorkSheet, ARow, ACol) else complete := not GotoPrev(AWorkSheet, ARow, ACol) else
complete := not GotoNext(AWorkSheet, ARow, ACol); complete := not GotoNext(AWorkSheet, ARow, ACol);
// Avoid infinite loop if search phrase does not exist in document. // Avoid infinite loop if search phrase does not exist in document.
@ -90,28 +144,26 @@ begin
end; end;
end; end;
function TsSearchEngine.FindFirst(const ASearchText: String; function TsSearchEngine.FindFirst(const ASearchParams: TsSearchParams;
const AParams: TsSearchParams; out AWorksheet: TsWorksheet; out AWorksheet: TsWorksheet; out ARow, ACol: Cardinal): Boolean;
out ARow, ACol: Cardinal): Boolean;
begin begin
FParams := AParams; FSearchParams := ASearchParams;
PrepareSearchText(ASearchText); PrepareSearchText(FSearchParams.SearchText);
if soBackward in FParams.Options then if soBackward in FSearchParams.Options then
GotoLast(AWorksheet, ARow, ACol) else GotoLast(AWorksheet, ARow, ACol) else
GotoFirst(AWorksheet, ARow, ACol); GotoFirst(AWorksheet, ARow, ACol);
Result := ExecSearch(AWorksheet, ARow, ACol); Result := ExecSearch(AWorksheet, ARow, ACol);
end; end;
function TsSearchEngine.FindNext(const ASearchText: String; function TsSearchEngine.FindNext(const ASearchParams: TsSearchParams;
const AParams: TsSearchParams; var AWorksheet: TsWorksheet; var AWorksheet: TsWorksheet; var ARow, ACol: Cardinal): Boolean;
var ARow, ACol: Cardinal): Boolean;
begin begin
FParams := AParams; FSearchParams := ASearchParams;
PrepareSearchText(ASearchText); PrepareSearchText(FSearchParams.SearchText);
if soBackward in FParams.Options then if soBackward in FSearchParams.Options then
GotoPrev(AWorksheet, ARow, ACol) else GotoPrev(AWorksheet, ARow, ACol) else
GotoNext(AWorksheet, ARow, ACol); GotoNext(AWorksheet, ARow, ACol);
@ -121,9 +173,9 @@ end;
procedure TsSearchEngine.GotoFirst(out AWorksheet: TsWorksheet; procedure TsSearchEngine.GotoFirst(out AWorksheet: TsWorksheet;
out ARow, ACol: Cardinal); out ARow, ACol: Cardinal);
begin begin
if soEntireDocument in FParams.Options then if soEntireDocument in FSearchParams.Options then
// Search entire document forward from start // Search entire document forward from start
case FParams.Within of case FSearchParams.Within of
swWorkbook : swWorkbook :
begin begin
AWorksheet := FWorkbook.GetWorksheetByIndex(0); AWorksheet := FWorkbook.GetWorksheetByIndex(0);
@ -153,6 +205,7 @@ begin
begin begin
// Search starts at active cell // Search starts at active cell
AWorksheet := FWorkbook.ActiveWorksheet; AWorksheet := FWorkbook.ActiveWorksheet;
if AWorksheet = nil then AWorksheet := FWorkbook.GetFirstWorksheet;
ARow := AWorksheet.ActiveCellRow; ARow := AWorksheet.ActiveCellRow;
ACol := AWorksheet.ActiveCellCol; ACol := AWorksheet.ActiveCellCol;
end; end;
@ -164,9 +217,9 @@ var
cell: PCell; cell: PCell;
sel: TsCellRangeArray; sel: TsCellRangeArray;
begin begin
if soEntireDocument in FParams.Options then if soEntireDocument in FSearchParams.Options then
// Search entire document backward from end // Search entire document backward from end
case FParams.Within of case FSearchParams.Within of
swWorkbook : swWorkbook :
begin begin
AWorksheet := FWorkbook.GetWorksheetByIndex(FWorkbook.GetWorksheetCount-1); AWorksheet := FWorkbook.GetWorksheetByIndex(FWorkbook.GetWorksheetCount-1);
@ -212,7 +265,7 @@ begin
if GotoNextInWorksheet(AWorksheet, ARow, ACol) then if GotoNextInWorksheet(AWorksheet, ARow, ACol) then
exit; exit;
case FParams.Within of case FSearchParams.Within of
swWorkbook: swWorkbook:
begin begin
// Need to go to next sheet // Need to go to next sheet
@ -225,7 +278,7 @@ begin
exit; exit;
end; end;
// Continue search with first worksheet // Continue search with first worksheet
if (soWrapDocument in FParams.Options) then if (soWrapDocument in FSearchParams.Options) then
begin begin
AWorksheet := FWorkbook.GetWorksheetByIndex(0); AWorksheet := FWorkbook.GetWorksheetByIndex(0);
ARow := 0; ARow := 0;
@ -235,21 +288,21 @@ begin
end; end;
swWorksheet: swWorksheet:
if soWrapDocument in FParams.Options then begin if soWrapDocument in FSearchParams.Options then begin
ARow := 0; ARow := 0;
ACol := 0; ACol := 0;
exit; exit;
end; end;
swColumn: swColumn:
if soWrapDocument in FParams.Options then begin if soWrapDocument in FSearchParams.Options then begin
ARow := 0; ARow := 0;
ACol := AWorksheet.ActiveCellCol; ACol := AWorksheet.ActiveCellCol;
exit; exit;
end; end;
swRow: swRow:
if soWrapDocument in FParams.Options then begin if soWrapDocument in FSearchParams.Options then begin
ARow := AWorksheet.ActiveCellRow; ARow := AWorksheet.ActiveCellRow;
ACol := 0; ACol := 0;
exit; exit;
@ -264,12 +317,12 @@ function TsSearchEngine.GotoNextInWorksheet(AWorksheet: TsWorksheet;
var ARow, ACol: Cardinal): Boolean; var ARow, ACol: Cardinal): Boolean;
begin begin
Result := true; Result := true;
if (soAlongRows in FParams.Options) or (FParams.Within = swRow) then if (soAlongRows in FSearchParams.Options) or (FSearchParams.Within = swRow) then
begin begin
inc(ACol); inc(ACol);
if ACol <= AWorksheet.GetLastColIndex then if ACol <= AWorksheet.GetLastColIndex then
exit; exit;
if (FParams.Within <> swRow) then if (FSearchParams.Within <> swRow) then
begin begin
ACol := 0; ACol := 0;
inc(ARow); inc(ARow);
@ -277,12 +330,12 @@ begin
exit; exit;
end; end;
end else end else
if not (soAlongRows in FParams.Options) or (FParams.Within = swColumn) then if not (soAlongRows in FSearchParams.Options) or (FSearchParams.Within = swColumn) then
begin begin
inc(ARow); inc(ARow);
if ARow <= AWorksheet.GetLastRowIndex then if ARow <= AWorksheet.GetLastRowIndex then
exit; exit;
if (FParams.Within <> swColumn) then if (FSearchParams.Within <> swColumn) then
begin begin
ARow := 0; ARow := 0;
inc(ACol); inc(ACol);
@ -305,7 +358,7 @@ begin
if GotoPrevInWorksheet(AWorksheet, ARow, ACol) then if GotoPrevInWorksheet(AWorksheet, ARow, ACol) then
exit; exit;
case FParams.Within of case FSearchParams.Within of
swWorkbook: swWorkbook:
begin begin
// Need to go to previous sheet // Need to go to previous sheet
@ -317,7 +370,7 @@ begin
ACol := AWorksheet.GetlastColIndex; ACol := AWorksheet.GetlastColIndex;
exit; exit;
end; end;
if (soWrapDocument in FParams.Options) then if (soWrapDocument in FSearchParams.Options) then
begin begin
AWorksheet := FWorkbook.GetWorksheetByIndex(FWorkbook.GetWorksheetCount-1); AWorksheet := FWorkbook.GetWorksheetByIndex(FWorkbook.GetWorksheetCount-1);
ARow := AWorksheet.GetLastRowIndex; ARow := AWorksheet.GetLastRowIndex;
@ -327,7 +380,7 @@ begin
end; end;
swWorksheet: swWorksheet:
if soWrapDocument in FParams.Options then if soWrapDocument in FSearchParams.Options then
begin begin
ARow := AWorksheet.GetLastRowIndex; ARow := AWorksheet.GetLastRowIndex;
ACol := AWorksheet.GetLastColIndex; ACol := AWorksheet.GetLastColIndex;
@ -335,7 +388,7 @@ begin
end; end;
swColumn: swColumn:
if soWrapDocument in FParams.Options then if soWrapDocument in FSearchParams.Options then
begin begin
ARow := AWorksheet.GetLastRowIndex; ARow := AWorksheet.GetLastRowIndex;
ACol := AWorksheet.ActiveCellCol; ACol := AWorksheet.ActiveCellCol;
@ -343,7 +396,7 @@ begin
end; end;
swRow: swRow:
if soWrapDocument in FParams.Options then if soWrapDocument in FSearchParams.Options then
begin begin
ARow := AWorksheet.ActiveCellRow; ARow := AWorksheet.ActiveCellRow;
ACol := AWorksheet.GetLastColIndex; ACol := AWorksheet.GetLastColIndex;
@ -358,13 +411,13 @@ function TsSearchEngine.GotoPrevInWorksheet(AWorksheet: TsWorksheet;
var ARow, ACol: Cardinal): Boolean; var ARow, ACol: Cardinal): Boolean;
begin begin
Result := true; Result := true;
if (soAlongRows in FParams.Options) or (FParams.Within = swRow) then if (soAlongRows in FSearchParams.Options) or (FSearchParams.Within = swRow) then
begin begin
if ACol > 0 then begin if ACol > 0 then begin
dec(ACol); dec(ACol);
exit; exit;
end; end;
if (FParams.Within <> swRow) then if (FSearchParams.Within <> swRow) then
begin begin
ACol := AWorksheet.GetLastColIndex; ACol := AWorksheet.GetLastColIndex;
if ARow > 0 then if ARow > 0 then
@ -374,13 +427,13 @@ begin
end; end;
end; end;
end else end else
if not (soAlongRows in FParams.Options) or (FParams.Within = swColumn) then if not (soAlongRows in FSearchParams.Options) or (FSearchParams.Within = swColumn) then
begin begin
if ARow > 0 then begin if ARow > 0 then begin
dec(ARow); dec(ARow);
exit; exit;
end; end;
if (FParams.Within <> swColumn) then if (FSearchParams.Within <> swColumn) then
begin begin
ARow := AWorksheet.GetlastRowIndex; ARow := AWorksheet.GetlastRowIndex;
if ACol > 0 then if ACol > 0 then
@ -404,13 +457,13 @@ begin
celltxt := AWorksheet.ReadAsText(cell) else celltxt := AWorksheet.ReadAsText(cell) else
celltxt := ''; celltxt := '';
if soRegularExpr in FParams.Options then if soRegularExpr in FSearchParams.Options then
Result := FRegEx.Exec(celltxt) Result := FRegEx.Exec(celltxt)
else else
begin begin
if not (soMatchCase in FParams.Options) then if not (soMatchCase in FSearchParams.Options) then
celltxt := UTF8Lowercase(celltxt); celltxt := UTF8Lowercase(celltxt);
if soCompareEntireCell in FParams.Options then if soCompareEntireCell in FSearchParams.Options then
exit(celltxt = FSearchText); exit(celltxt = FSearchText);
if UTF8Pos(FSearchText, celltxt) > 0 then if UTF8Pos(FSearchText, celltxt) > 0 then
exit(true); exit(true);
@ -420,16 +473,72 @@ end;
procedure TsSearchEngine.PrepareSearchText(const ASearchText: String); procedure TsSearchEngine.PrepareSearchText(const ASearchText: String);
begin begin
if soRegularExpr in FParams.Options then if soRegularExpr in FSearchParams.Options then
begin begin
FreeAndNil(FRegEx); FreeAndNil(FRegEx);
FRegEx := TRegExpr.Create; FRegEx := TRegExpr.Create;
FRegEx.Expression := ASearchText FRegEx.Expression := ASearchText
end else end else
if (soMatchCase in FParams.Options) then if (soMatchCase in FSearchParams.Options) then
FSearchText := ASearchText else FSearchText := ASearchText else
FSearchText := UTF8Lowercase(ASearchText); FSearchText := UTF8Lowercase(ASearchText);
end; end;
function TsSearchEngine.ReplaceFirst(const ASearchParams: TsSearchParams;
const AReplaceParams: TsReplaceParams; out AWorksheet: TsWorksheet;
out ARow, ACol: Cardinal): Boolean;
var
r,c: Cardinal;
sheet: TsWorksheet;
begin
Result := FindFirst(ASearchParams, AWorksheet, ARow, ACol);
if Result then
begin
FReplaceParams := AReplaceParams;
Result := ExecReplace(AWorksheet, ARow, ACol);
if roReplaceAll in FReplaceParams.Options then
begin
FWorkbook.DisableNotifications;
while FindNext(FSearchParams, AWorksheet, ARow, ACol) do
begin
r := ARow;
c := ACol;
sheet := AWorksheet;
ExecReplace(AWorksheet, ARow, ACol);
end;
FWorkbook.EnableNotifications;
sheet.SelectCell(r, c);
end;
end;
end;
function TsSearchEngine.ReplaceNext(const ASearchParams: TsSearchParams;
const AReplaceParams: TsReplaceParams; var AWorksheet: TsWorksheet;
var ARow, ACol: Cardinal): Boolean;
var
r, c: Cardinal;
sheet: TsWorksheet;
begin
Result := FindNext(ASearchParams, AWorksheet, ARow, ACol);
if Result then
begin
FReplaceParams := AReplaceParams;
Result := ExecReplace(AWorksheet, ARow, ACol);
if roReplaceAll in FReplaceParams.Options then
begin
FWorkbook.DisableNotifications;
while FindNext(FSearchParams, AWorksheet, ARow, ACol) do
begin
r := ARow;
c := ACol;
sheet := AWorksheet;
ExecReplace(AWorksheet, ARow, ACol);
end;
FWorkbook.EnableNotifications;
sheet.SelectCell(r, c);
end;
end;
end;
end. end.

View File

@ -724,6 +724,19 @@ type
Within: TsSearchWithin; Within: TsSearchWithin;
end; end;
{@@ Replace option }
TsReplaceOption = (roReplaceEntirecell, roReplaceAll, roConfirm);
{@@ A set of replace options }
TsReplaceOptions = set of TsReplaceOption;
{@@ Replace parameters }
TsReplaceParams = record
ReplaceText: String;
Options: TsReplaceOptions;
end;
implementation implementation