doublecmd/src/frames/fquicksearch.pas

854 lines
23 KiB
ObjectPascal

unit fQuickSearch;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, StdCtrls, LCLType,
ExtCtrls, Buttons;
type
TQuickSearchMode = (qsSearch, qsFilter, qsNone);
TQuickSearchDirection = (qsdNone, qsdFirst, qsdLast, qsdNext, qsdPrevious);
TQuickSearchMatch = (qsmBeginning, qsmEnding);
TQuickSearchCase = (qscSensitive, qscInsensitive);
TQuickSearchItems = (qsiFiles, qsiDirectories, qsiFilesAndDirectories);
TQuickSearchCancelMode = (qscmNode, qscmAtLeastOneThenCancelIfNoFound, qscmCancelIfNoFound);
TQuickSearchOptions = record
Match: set of TQuickSearchMatch;
SearchCase: TQuickSearchCase;
Items: TQuickSearchItems;
Direction: TQuickSearchDirection;
LastSearchMode: TQuickSearchMode;
CancelSearchMode: TQuickSearchCancelMode;
end;
TOnChangeSearch = procedure(Sender: TObject; ASearchText: String; const ASearchOptions: TQuickSearchOptions; InvertSelection: Boolean = False) of Object;
TOnChangeFilter = procedure(Sender: TObject; AFilterText: String; const AFilterOptions: TQuickSearchOptions) of Object;
TOnExecute = procedure(Sender: TObject) of Object;
TOnHide = procedure(Sender: TObject) of Object;
{ TfrmQuickSearch }
TfrmQuickSearch = class(TFrame)
btnCancel: TButton;
edtSearch: TEdit;
pnlOptions: TPanel;
sbMatchBeginning: TSpeedButton;
sbMatchEnding: TSpeedButton;
sbCaseSensitive: TSpeedButton;
sbFiles: TSpeedButton;
sbDirectories: TSpeedButton;
tglFilter: TToggleBox;
procedure btnCancelClick(Sender: TObject);
procedure edtSearchChange(Sender: TObject);
procedure edtSearchKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
procedure FrameExit(Sender: TObject);
procedure sbCaseSensitiveClick(Sender: TObject);
procedure sbFilesAndDirectoriesClick(Sender: TObject);
procedure sbMatchBeginningClick(Sender: TObject);
procedure sbMatchEndingClick(Sender: TObject);
procedure tglFilterChange(Sender: TObject);
procedure btnMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure btnCancelMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
private
Options: TQuickSearchOptions;
Mode: TQuickSearchMode;
Active: Boolean;
FilterOptions: TQuickSearchOptions;
FilterText: String;
Finalizing: Boolean;
FUpdateCount: Integer;
FNeedsChangeSearch: Boolean;
FIntendedLeave: Boolean;
procedure BeginUpdate;
procedure CheckFilesOrDirectoriesDown;
procedure EndUpdate;
procedure DoHide;
procedure DoOnChangeSearch;
{en
Loads control states from options values
}
procedure LoadControlStates;
procedure PushFilter;
procedure PopFilter;
procedure ClearFilter;
procedure CancelFilter;
procedure SetFocus(Data: PtrInt);
procedure RestoreFocus(Data: PtrInt);
procedure ProcessParams(const SearchMode: TQuickSearchMode; const Params: array of String);
public
LimitedAutoHide: Boolean;
OnChangeSearch: TOnChangeSearch;
OnChangeFilter: TOnChangeFilter;
OnExecute: TOnExecute;
OnHide: TOnHide;
constructor Create(TheOwner: TWinControl); reintroduce;
destructor Destroy; override;
procedure CloneTo(AQuickSearch: TfrmQuickSearch);
procedure Execute(SearchMode: TQuickSearchMode; const Params: array of String; Char: TUTF8Char = #0);
procedure Reset;
procedure Finalize;
function CheckSearchOrFilter(var Key: Word): Boolean; overload;
function CheckSearchOrFilter(var UTF8Key: TUTF8Char): Boolean; overload;
end;
{en
Allows to compare TQuickSearchOptions structures
}
operator = (qsOptions1, qsOptions2: TQuickSearchOptions) CompareResult: Boolean;
implementation
uses
LazUTF8,
uKeyboard,
uGlobs,
uFormCommands
{$IF DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)}
, uFileView
{$ENDIF}
;
const
{
Parameters:
"filter" - set filtering (on/off/toggle)
"search" - set searching (on/off/cycle)
"matchbeginning" - set match beginning option (on/off/toggle)
"matchending" - set match ending option (on/off/toggle)
"casesensitive" - set case sensitive searching (on/off/toggle)
"files" - set filtering files (on/off/toggle)
"directories" - set filtering directories (on/off/toggle)
"filesdirectories" - toggle between files, directories and both (no value)
"text"="<...>" - set <...> as new text to search/filter (string)
'toggle' switches between on and off
'cycle' goto to next, next, next and so one
}
// parameters for quick search / filter actions
PARAMETER_FILTER = 'filter';
PARAMETER_SEARCH = 'search';
PARAMETER_DIRECTION = 'direction';
PARAMETER_MATCH_BEGINNING = 'matchbeginning';
PARAMETER_MATCH_ENDING = 'matchending';
PARAMETER_CASE_SENSITIVE = 'casesensitive';
PARAMETER_FILES = 'files';
PARAMETER_DIRECTORIES = 'directories';
PARAMETER_FILES_DIRECTORIES = 'filesdirectories';
PARAMETER_TEXT = 'text';
TOGGLE_VALUE = 'toggle';
CYCLE_VALUE = 'cycle';
FIRST_VALUE = 'first';
LAST_VALUE = 'last';
NEXT_VALUE = 'next';
{$R *.lfm}
operator = (qsOptions1, qsOptions2: TQuickSearchOptions) CompareResult: Boolean;
begin
Result := True;
if qsOptions1.Match <> qsOptions2.Match then
Result := False;
if qsOptions1.Items <> qsOptions2.Items then
Result := False;
if qsOptions1.SearchCase <> qsOptions2.SearchCase then
Result := False;
end;
function GetBoolState(const Value: String; OldState: Boolean): Boolean;
begin
if Value = TOGGLE_VALUE then
Result := not OldState
else if not GetBoolValue(Value, Result) then
Result := OldState;
end;
{ TfrmQuickSearch }
constructor TfrmQuickSearch.Create(TheOwner: TWinControl);
begin
inherited Create(TheOwner);
Self.Parent := TheOwner;
// load default options
Options := gQuickSearchOptions;
Options.LastSearchMode := qsNone;
LoadControlStates;
FilterOptions := gQuickSearchOptions;
FilterText := EmptyStr;
Finalizing := False;
HotMan.Register(Self.edtSearch, 'Quick Search');
end;
destructor TfrmQuickSearch.Destroy;
begin
if Assigned(HotMan) then
HotMan.UnRegister(Self.edtSearch);
inherited Destroy;
end;
procedure TfrmQuickSearch.CloneTo(AQuickSearch: TfrmQuickSearch);
var
TempEvent: TNotifyEvent;
begin
AQuickSearch.Active := Self.Active;
AQuickSearch.Mode := Self.Mode;
AQuickSearch.Options := Self.Options;
AQuickSearch.LoadControlStates;
AQuickSearch.FilterOptions := Self.FilterOptions;
AQuickSearch.FilterText := Self.FilterText;
TempEvent := AQuickSearch.edtSearch.OnChange;
AQuickSearch.edtSearch.OnChange := nil;
AQuickSearch.edtSearch.Text := Self.edtSearch.Text;
AQuickSearch.edtSearch.SelStart := Self.edtSearch.SelStart;
AQuickSearch.edtSearch.SelLength := Self.edtSearch.SelLength;
AQuickSearch.edtSearch.OnChange := TempEvent;
TempEvent := AQuickSearch.tglFilter.OnChange;
AQuickSearch.tglFilter.OnChange := nil;
AQuickSearch.tglFilter.Checked := Self.tglFilter.Checked;
AQuickSearch.tglFilter.OnChange := TempEvent;
AQuickSearch.Visible := Self.Visible;
// Do not clone LimitedAutoHide but honor it instead, because it depends on the parent fileview
if Self.Visible and not Self.edtSearch.Focused and Self.LimitedAutoHide and not AQuickSearch.LimitedAutoHide then
AQuickSearch.FrameExit(nil); // do autohide if needed
end;
procedure TfrmQuickSearch.DoOnChangeSearch;
begin
if FUpdateCount > 0 then
FNeedsChangeSearch := True
else
begin
Options.LastSearchMode:=Self.Mode;
case Self.Mode of
qsSearch:
if Assigned(Self.OnChangeSearch) then
Self.OnChangeSearch(Self, edtSearch.Text, Options);
qsFilter:
if Assigned(Self.OnChangeFilter) then
Self.OnChangeFilter(Self, edtSearch.Text, Options);
end;
FNeedsChangeSearch := False;
end;
end;
procedure TfrmQuickSearch.Execute(SearchMode: TQuickSearchMode; const Params: array of String; Char: TUTF8Char = #0);
begin
Self.Visible := True;
if not edtSearch.Focused then
begin
edtSearch.SetFocus;
edtSearch.SelectAll;
end;
if Char <> #0 then
edtSearch.SelText := Char;
Self.Active := True;
ProcessParams(SearchMode, Params);
end;
procedure TfrmQuickSearch.Reset;
begin
PopFilter;
Options.LastSearchMode := qsNone;
Options.Direction := qsdNone;
Options.CancelSearchMode:=qscmNode;
end;
procedure TfrmQuickSearch.Finalize;
begin
Reset;
Hide;
end;
{ TfrmQuickSearch.ProcessParams }
procedure TfrmQuickSearch.ProcessParams(const SearchMode: TQuickSearchMode; const Params: array of String);
var
Param: String;
Value: String;
bWeGotMainParam: boolean = False;
bLegacyBehavior: boolean = False;
begin
BeginUpdate;
try
Options.Direction:=qsdNone;
for Param in Params do
begin
if (SearchMode=qsFilter) AND (GetParamValue(Param, PARAMETER_FILTER, Value)) then
begin
if (Value <> TOGGLE_VALUE) then
tglFilter.Checked := GetBoolState(Value, tglFilter.Checked)
else
tglFilter.Checked := (not tglFilter.Checked) OR (Options.LastSearchMode<>qsFilter); //With "toggle", if mode was not previously, we activate filter mode.
bWeGotMainParam := True;
end
else if (SearchMode=qsSearch) AND (GetParamValue(Param, PARAMETER_FILTER, Value)) then //Legacy
begin
tglFilter.Checked := GetBoolState(Value, tglFilter.Checked);
bWeGotMainParam := True;
bLegacyBehavior:= True;
end
else if (SearchMode=qsSearch) AND (GetParamValue(Param, PARAMETER_SEARCH, Value)) then
begin
if (Value <> CYCLE_VALUE) then
begin
Options.CancelSearchMode:=qscmNode;
if (Value <> TOGGLE_VALUE) then
tglFilter.Checked := not (GetBoolState(Value, tglFilter.Checked))
else
tglFilter.Checked := not((tglFilter.Checked) OR (Options.LastSearchMode<>qsSearch)); //With "toggle", if mode was not previously, we activate search mode.
end
else
begin
tglFilter.Checked:=FALSE;
if Options.LastSearchMode<>qsSearch then
begin
Options.Direction:=qsdFirst; //With "cycle", if mode was not previously, we activate search mode AND do to first item
Options.CancelSearchMode:=qscmAtLeastOneThenCancelIfNoFound;
end
else
begin
Options.Direction:=qsdNext;
Options.CancelSearchMode:=qscmCancelIfNoFound;
end;
end;
bWeGotMainParam := True;
end
else if (SearchMode=qsSearch) AND GetParamValue(Param, PARAMETER_DIRECTION, Value) then
begin
if Value = FIRST_VALUE then Options.Direction:=qsdFirst;
if Value = LAST_VALUE then Options.Direction:=qsdLast;
if Value = NEXT_VALUE then Options.Direction:=qsdNext;
end
else if GetParamValue(Param, PARAMETER_MATCH_BEGINNING, Value) then
begin
sbMatchBeginning.Down := GetBoolState(Value, sbMatchBeginning.Down);
sbMatchBeginningClick(nil);
end
else if GetParamValue(Param, PARAMETER_MATCH_ENDING, Value) then
begin
sbMatchEnding.Down := GetBoolState(Value, sbMatchEnding.Down);
sbMatchEndingClick(nil);
end
else if GetParamValue(Param, PARAMETER_CASE_SENSITIVE, Value) then
begin
sbCaseSensitive.Down := GetBoolState(Value, sbCaseSensitive.Down);
sbCaseSensitiveClick(nil);
end
else if GetParamValue(Param, PARAMETER_FILES, Value) then
begin
sbFiles.Down := GetBoolState(Value, sbFiles.Down);
sbFilesAndDirectoriesClick(nil);
end
else if GetParamValue(Param, PARAMETER_DIRECTORIES, Value) then
begin
sbDirectories.Down := GetBoolState(Value, sbDirectories.Down);
sbFilesAndDirectoriesClick(nil);
end
else if Param = PARAMETER_FILES_DIRECTORIES then
begin
if sbFiles.Down and sbDirectories.Down then
sbDirectories.Down := False
else if sbFiles.Down then
begin
sbDirectories.Down := True;
sbFiles.Down := False;
end
else if sbDirectories.Down then
sbFiles.Down := True;
sbFilesAndDirectoriesClick(nil);
end
else if GetParamValue(Param, PARAMETER_TEXT, Value) then
begin
edtSearch.Text := Value;
edtSearch.SelectAll;
end;
end;
CheckFilesOrDirectoriesDown;
//If search or filter was called with no parameter...
case SearchMode of
qsSearch: if not bWeGotMainParam then tglFilter.Checked:=False;
qsFilter: if not bWeGotMainParam then tglFilter.Checked:=True;
end;
if not bLegacyBehavior then
begin
case SearchMode of
qsSearch: if tglFilter.Checked then CancelFilter;
qsFilter: if not tglFilter.Checked then CancelFilter;
end;
end;
finally
EndUpdate;
end;
end;
function TfrmQuickSearch.CheckSearchOrFilter(var Key: Word): Boolean;
var
ModifierKeys: TShiftState;
SearchOrFilterModifiers: TShiftState;
SearchMode: TQuickSearchMode;
UTF8Char: TUTF8Char;
KeyTypingModifier: TKeyTypingModifier;
begin
Result := False;
ModifierKeys := GetKeyShiftStateEx;
for KeyTypingModifier in TKeyTypingModifier do
begin
if gKeyTyping[KeyTypingModifier] in [ktaQuickSearch, ktaQuickFilter] then
begin
SearchOrFilterModifiers := TKeyTypingModifierToShift[KeyTypingModifier];
if ((SearchOrFilterModifiers <> []) and
(ModifierKeys * KeyModifiersShortcutNoText = SearchOrFilterModifiers))
{$IFDEF MSWINDOWS}
// Entering international characters with Ctrl+Alt on Windows.
or (HasKeyboardAltGrKey and (SearchOrFilterModifiers = []) and
(ModifierKeys * KeyModifiersShortcutNoText = [ssCtrl, ssAlt]))
{$ENDIF}
then
begin
if (Key <> VK_SPACE) or (edtSearch.Text <> '') then
begin
UTF8Char := VirtualKeyToUTF8Char(Key, ModifierKeys - SearchOrFilterModifiers);
Result := (UTF8Char <> '') and
(not ((Length(UTF8Char) = 1) and (UTF8Char[1] in [#0..#31])));
if Result then
begin
Key := 0;
case gKeyTyping[KeyTypingModifier] of
ktaQuickSearch:
SearchMode := qsSearch;
ktaQuickFilter:
SearchMode := qsFilter;
end;
Self.Execute(SearchMode, [], UTF8Char);
end;
end;
Exit;
end;
end;
end;
end;
function TfrmQuickSearch.CheckSearchOrFilter(var UTF8Key: TUTF8Char): Boolean;
var
ModifierKeys: TShiftState;
SearchMode: TQuickSearchMode;
begin
Result := False;
// Check for certain Ascii keys.
if (Length(UTF8Key) = 1) and (UTF8Key[1] in [#0..#32,'+','-','*']) then
Exit;
ModifierKeys := GetKeyShiftStateEx;
if gKeyTyping[ktmNone] in [ktaQuickSearch, ktaQuickFilter] then
begin
if ModifierKeys * KeyModifiersShortcutNoText = TKeyTypingModifierToShift[ktmNone] then
begin
// Make upper case if either caps-lock is toggled or shift pressed.
if (ssCaps in ModifierKeys) xor (ssShift in ModifierKeys) then
UTF8Key := UTF8UpperCase(UTF8Key)
else
UTF8Key := UTF8LowerCase(UTF8Key);
case gKeyTyping[ktmNone] of
ktaQuickSearch:
SearchMode := qsSearch;
ktaQuickFilter:
SearchMode := qsFilter;
end;
Self.Execute(SearchMode, [], UTF8Key);
UTF8Key := '';
Result := True;
Exit;
end;
end;
end;
procedure TfrmQuickSearch.LoadControlStates;
begin
sbDirectories.Down := (Options.Items = qsiDirectories) or (Options.Items = qsiFilesAndDirectories);
sbFiles.Down := (Options.Items = qsiFiles) or (Options.Items = qsiFilesAndDirectories);
sbCaseSensitive.Down := Options.SearchCase = qscSensitive;
sbMatchBeginning.Down := qsmBeginning in Options.Match;
sbMatchEnding.Down := qsmEnding in Options.Match;
end;
procedure TfrmQuickSearch.PushFilter;
begin
FilterText := edtSearch.Text;
FilterOptions := Options;
end;
procedure TfrmQuickSearch.PopFilter;
begin
edtSearch.Text := FilterText;
// there was no filter saved, do not continue loading
if FilterText = EmptyStr then
Exit;
Options := FilterOptions;
LoadControlStates;
FilterText := EmptyStr;
tglFilter.Checked := True;
end;
procedure TfrmQuickSearch.ClearFilter;
begin
FilterText := EmptyStr;
FilterOptions := Options;
if Assigned(Self.OnChangeFilter) then
Self.OnChangeFilter(Self, EmptyStr, FilterOptions);
end;
procedure TfrmQuickSearch.CancelFilter;
begin
Finalize;
{$IFDEF LCLGTK2}
// On GTK2 OnExit for frame is not called when it is hidden,
// but only when a control from outside of frame gains focus.
FrameExit(nil);
{$ENDIF}
DoHide;
end;
procedure TfrmQuickSearch.SetFocus(Data: PtrInt);
begin
if edtSearch.CanFocus then edtSearch.SetFocus;
end;
procedure TfrmQuickSearch.RestoreFocus(Data: PtrInt);
begin
if Assigned(Screen.ActiveControl) then
begin
// The file panel has lost focus
if Screen.ActiveControl is TCustomForm then
begin
if Parent.CanSetFocus then Parent.SetFocus;
end;
end;
end;
procedure TfrmQuickSearch.CheckFilesOrDirectoriesDown;
begin
if not (sbFiles.Down or sbDirectories.Down) then
begin
// unchecking both should not be possible, so recheck last unchecked
case Options.Items of
qsiFiles:
sbFiles.Down := True;
qsiDirectories:
sbDirectories.Down := True;
end;
end;
end;
procedure TfrmQuickSearch.edtSearchChange(Sender: TObject);
begin
Options.Direction := qsdNone;
DoOnChangeSearch;
end;
procedure TfrmQuickSearch.BeginUpdate;
begin
Inc(FUpdateCount);
end;
procedure TfrmQuickSearch.btnCancelClick(Sender: TObject);
begin
CancelFilter;
end;
procedure TfrmQuickSearch.edtSearchKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if CheckSearchOrFilter(Key) then
Exit;
case Key of
VK_DOWN:
begin
Key := 0;
if Assigned(Self.OnChangeSearch) then
begin
Options.Direction:=qsdNext;
Self.OnChangeSearch(Self, edtSearch.Text, Options, ssShift in Shift);
end;
end;
VK_UP:
begin
Key := 0;
if Assigned(Self.OnChangeSearch) then
begin
Options.Direction:=qsdPrevious;
Self.OnChangeSearch(Self, edtSearch.Text, Options, ssShift in Shift);
end;
end;
// Request to have CTRL pressed at the same time.
// VK_HOME alone reserved to get to start position of edtSearch.
VK_HOME:
begin
if ssCtrl in Shift then
begin
Key := 0;
if Assigned(Self.OnChangeSearch) then
begin
Options.Direction := qsdFirst;
Self.OnChangeSearch(Self, edtSearch.Text, Options, ssShift in Shift);
end;
end;
end;
// Request to have CTRL pressed at the same time.
// VK_END alone reserved to get to end position of edtSearch.
VK_END:
begin
if ssCtrl in Shift then
begin
Key := 0;
if Assigned(Self.OnChangeSearch) then
begin
Options.Direction := qsdLast;
Self.OnChangeSearch(Self, edtSearch.Text, Options, ssShift in Shift);
end;
end;
end;
VK_INSERT:
begin
if Shift = [] then // no modifiers pressed, to not capture Ctrl+Insert and Shift+Insert
begin
Key := 0;
if Assigned(Self.OnChangeSearch) then
begin
Options.Direction := qsdNext;
Self.OnChangeSearch(Self, edtSearch.Text, Options, True);
end;
end;
end;
VK_RETURN, VK_SELECT:
begin
Key := 0;
if Assigned(Self.OnExecute) then
Self.OnExecute(Self);
CancelFilter;
end;
VK_TAB:
begin
Key := 0;
FIntendedLeave := True;
DoHide;
end;
VK_ESCAPE:
begin
Key := 0;
CancelFilter;
end;
end;
end;
procedure TfrmQuickSearch.EndUpdate;
begin
Dec(FUpdateCount);
if FUpdateCount = 0 then
begin
if FNeedsChangeSearch then
DoOnChangeSearch;
end;
end;
procedure TfrmQuickSearch.DoHide;
begin
if Assigned(Self.OnHide) then
Self.OnHide(Self);
end;
procedure TfrmQuickSearch.FrameExit(Sender: TObject);
var
DontHide: Boolean;
begin
{$IF DEFINED(LCLQT) or DEFINED(LCLQT5) or DEFINED(LCLQT6)}
// Workaround: QuickSearch frame lose focus on SpeedButton click
if Screen.ActiveControl is TFileView then
edtSearch.SetFocus
else
{$ENDIF}
if not Finalizing then
begin
Finalizing := True;
Self.Active := False;
if FIntendedLeave then
begin
FIntendedLeave := False;
DontHide := False;
end
else
DontHide := LimitedAutoHide;
if (Mode = qsFilter) and (edtSearch.Text <> EmptyStr) then
Self.Visible := DontHide or not gQuickFilterAutoHide
else begin
if DontHide then Reset else Finalize;
end;
Application.QueueAsyncCall(@RestoreFocus, 0);
Finalizing := False;
end;
end;
procedure TfrmQuickSearch.sbCaseSensitiveClick(Sender: TObject);
begin
if sbCaseSensitive.Down then
Options.SearchCase := qscSensitive
else
Options.SearchCase := qscInsensitive;
if gQuickFilterSaveSessionModifications then gQuickSearchOptions.SearchCase := Options.SearchCase;
Options.Direction := qsdNone;
DoOnChangeSearch;
end;
procedure TfrmQuickSearch.sbFilesAndDirectoriesClick(Sender: TObject);
begin
if sbFiles.Down and sbDirectories.Down then
Options.Items := qsiFilesAndDirectories
else if sbFiles.Down then
Options.Items := qsiFiles
else if sbDirectories.Down then
Options.Items := qsiDirectories
else if FUpdateCount = 0 then
begin
CheckFilesOrDirectoriesDown;
Exit;
end;
if gQuickFilterSaveSessionModifications then gQuickSearchOptions.Items := Options.Items;
Options.Direction := qsdNone;
DoOnChangeSearch;
end;
procedure TfrmQuickSearch.sbMatchBeginningClick(Sender: TObject);
begin
if sbMatchBeginning.Down then
Include(Options.Match, qsmBeginning)
else
Exclude(Options.Match, qsmBeginning);
if gQuickFilterSaveSessionModifications then gQuickSearchOptions.Match := Options.Match;
Options.Direction := qsdNone;
DoOnChangeSearch;
end;
procedure TfrmQuickSearch.sbMatchEndingClick(Sender: TObject);
begin
if sbMatchEnding.Down then
Include(Options.Match, qsmEnding)
else
Exclude(Options.Match, qsmEnding);
if gQuickFilterSaveSessionModifications then gQuickSearchOptions.Match := Options.Match;
Options.Direction := qsdNone;
DoOnChangeSearch;
end;
procedure TfrmQuickSearch.tglFilterChange(Sender: TObject);
begin
Options.LastSearchMode := qsNone;
if tglFilter.Checked then
Mode := qsFilter
else
Mode := qsSearch;
// if a filter was set in background and a search is opened, the filter
// will get pushed staying active. Otherwise the filter will be converted
// in a search
if not Active and (Mode = qsSearch) then
PushFilter
else if Active then
ClearFilter;
Options.Direction := qsdNone;
DoOnChangeSearch;
end;
procedure TfrmQuickSearch.btnMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
Application.QueueAsyncCall(@SetFocus, 0);
end;
procedure TfrmQuickSearch.btnCancelMouseUp(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
if Self.Visible then Application.QueueAsyncCall(@SetFocus, 0);
end;
end.