mirror of
https://github.com/HeidiSQL/HeidiSQL.git
synced 2025-08-06 18:24:26 +08:00
Implement a home brown find + replace dialog, supporting regular expressions, and using all stuff SynEdit gives us. Add main menu item "Search" next to "Edit". Fixes issue #1069.
This commit is contained in:
@ -35,7 +35,8 @@ uses
|
||||
table_editor in '..\..\source\table_editor.pas' {frmTableEditor},
|
||||
mysql_api in '..\..\source\mysql_api.pas',
|
||||
mysql_connection in '..\..\source\mysql_connection.pas',
|
||||
trigger_editor in '..\..\source\trigger_editor.pas' {frmTriggerEditor: TFrame};
|
||||
trigger_editor in '..\..\source\trigger_editor.pas' {frmTriggerEditor: TFrame},
|
||||
searchreplace in '..\..\source\searchreplace.pas' {frmSearchReplace};
|
||||
|
||||
{$R ..\..\res\icon.RES}
|
||||
{$R ..\..\res\version.RES}
|
||||
|
@ -195,6 +195,9 @@
|
||||
<Form>frmTriggerEditor</Form>
|
||||
<DesignClass>TFrame</DesignClass>
|
||||
</DCCReference>
|
||||
<DCCReference Include="..\..\source\searchreplace.pas">
|
||||
<Form>frmSearchReplace</Form>
|
||||
</DCCReference>
|
||||
<RcCompile Include="..\..\res\icon.rc">
|
||||
<Form>icon.res</Form>
|
||||
</RcCompile>
|
||||
|
BIN
res/icons/find_again.png
Normal file
BIN
res/icons/find_again.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 755 B |
@ -190,6 +190,8 @@ const
|
||||
DEFAULT_FILTERACTIVE = False;
|
||||
REGNAME_MULTI_INSTANCES = 'AllowMultipleInstances';
|
||||
DEFAULT_MULTI_INSTANCES = True;
|
||||
REGNAME_SEARCHTEXT = 'FindDialogSearchHistory';
|
||||
REGNAME_REPLACETEXT = 'FindDialogReplaceHistory';
|
||||
|
||||
REGNAME_FIELDCOLOR_NUMERIC = 'FieldColor_Numeric';
|
||||
REGNAME_FIELDCOLOR_TEXT = 'FieldColor_Text';
|
||||
|
@ -1263,6 +1263,7 @@ object MainForm: TMainForm
|
||||
Top = 0
|
||||
Width = 411
|
||||
Height = 96
|
||||
OnSearchNotFound = SynMemoQuerySearchNotFound
|
||||
SingleLineMode = False
|
||||
Align = alClient
|
||||
ActiveLineColor = clWindow
|
||||
@ -1292,6 +1293,7 @@ object MainForm: TMainForm
|
||||
TabWidth = 3
|
||||
WantTabs = True
|
||||
OnDropFiles = SynMemoQueryDropFiles
|
||||
OnReplaceText = SynMemoQueryReplaceText
|
||||
OnStatusChange = SynMemoQueryStatusChange
|
||||
RemovedKeystrokes = <
|
||||
item
|
||||
@ -1498,6 +1500,18 @@ object MainForm: TMainForm
|
||||
Action = actReformatSQL
|
||||
end
|
||||
end
|
||||
object Search1: TMenuItem
|
||||
Caption = 'Search'
|
||||
object Findtext1: TMenuItem
|
||||
Action = actQueryFind
|
||||
end
|
||||
object actQueryFindAgain1: TMenuItem
|
||||
Action = actQueryFindAgain
|
||||
end
|
||||
object Replacetext1: TMenuItem
|
||||
Action = actQueryReplace
|
||||
end
|
||||
end
|
||||
object Extra1: TMenuItem
|
||||
Tag = 19
|
||||
Caption = '&Tools'
|
||||
@ -2146,7 +2160,7 @@ object MainForm: TMainForm
|
||||
Hint = 'Find text ...'
|
||||
ImageIndex = 30
|
||||
ShortCut = 16454
|
||||
OnExecute = actQueryFindExecute
|
||||
OnExecute = actQueryFindReplaceExecute
|
||||
end
|
||||
object actQueryReplace: TAction
|
||||
Category = 'SQL'
|
||||
@ -2155,7 +2169,14 @@ object MainForm: TMainForm
|
||||
Hint = 'Replace text ...'
|
||||
ImageIndex = 59
|
||||
ShortCut = 16466
|
||||
OnExecute = actQueryReplaceExecute
|
||||
OnExecute = actQueryFindReplaceExecute
|
||||
end
|
||||
object actQueryFindAgain: TAction
|
||||
Category = 'SQL'
|
||||
Caption = 'Find or replace again'
|
||||
ImageIndex = 142
|
||||
ShortCut = 114
|
||||
OnExecute = actQueryFindAgainExecute
|
||||
end
|
||||
object actSetDelimiter: TAction
|
||||
Category = 'SQL'
|
||||
@ -6231,23 +6252,42 @@ object MainForm: TMainForm
|
||||
43F83D4D2738195C82C5B763381B5E31A3DD0479CBAF6D7E05EBBBC0DC883A01
|
||||
4C91E3672618257B704396A99BE46D97C9623AF93A3F9224CD92FC8501FA8D75
|
||||
FE4FCCAC61ACF6D72F62B02F294EFE3B9F0000000049454E44AE426082}
|
||||
end
|
||||
item
|
||||
Background = clWindow
|
||||
Name = 'find_again'
|
||||
PngImage.Data = {
|
||||
89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF
|
||||
610000001974455874536F667477617265005061696E742E4E45542076332E35
|
||||
2E32D7EE6943000002C24944415478DAAD934B48547114C6BF3BB719535354A6
|
||||
4143255F93AF468D5132CD3470229D5AD4226813650FA3400B1795B98841DB55
|
||||
D426B0D08A30717415F9487BA838D6989A9889927847677CA6F3721EF7D99D11
|
||||
DA45481D38FC17E7FFFDCEE17C1C02FF18C47F07E8EE3F31C5C5ED8EA1280AD5
|
||||
1565C4A3C636C16E5BC7E8D0E074CB8B7AE55F013774F74C39D9D9314D2F9F43
|
||||
1410E5D76F0BCA94746C389DE69A6BE7A3FF083877A54A484ECF84C36E436060
|
||||
10DA9A1A3064E8250A355A2155B50F325900FADF77FADE5796B9D90B36BBD5B5
|
||||
BEBAC2138DFACEED635F870BC3C2E5ED2429C1EAF212BE8F8F826568F88036EB
|
||||
1A18991C494989703BD6306EEC455FF79B6A8665EED25EAF403C78DAB24D8C1F
|
||||
A121C1B1C64F83FE69427725234A11069AE31887C32B655DEB98999D07EB5A83
|
||||
529988BAEA0A8A63D904F12B47D43D6C900A024F8747C8F16D6C181CC789DD19
|
||||
B85D1B301A7A119F948CC43DA9605916C16A03ECDE35D49F1D11447180980C71
|
||||
B1F2A674D13CE75C5EB4C822E40A2C2D98E171BB60B7592D6E97B3542A0BA815
|
||||
BB95040505437B27123BC36230611E4673F924290278FF12B5274EF71D282CCE
|
||||
5767ED85D5E604356F41F3B3C7CD795785531058D0BC982C87A8F004A8A2F3F1
|
||||
79F61DC6CD4674545A083F40A33DC9A6A46792A5A547A16F6D85D7E3C1887160
|
||||
E26025528BD3CE801378703C071E02166DF3080F56C030D38D91B9FE4D1B8B8E
|
||||
1C13545939F0015AF47A4824243E76BDA6F3AA24B2125519A89FD360C429589E
|
||||
01C331625D06454834FA673A370179451A213BF7100A0A0AD0D5D5099224D1DB
|
||||
D30ED565078E675C12859C3F7D932CD84C88D81129761FC0DBC98E493F409D5B
|
||||
20F836CF88DED3B4D7EF82E831726E11BCDBE395D03C0D0F4B2351918EFDF11A
|
||||
0C9906D033D53546E990B1A5634AD3112BEAD8C3F20F533D5FA85AA8B77C8D71
|
||||
3558E178526EAAE57EEB7E01DE445494B226E2DE0000000049454E44AE426082}
|
||||
end>
|
||||
PngOptions = [pngBlendOnDisabled, pngGrayscaleOnDisabled]
|
||||
Left = 104
|
||||
Top = 232
|
||||
Bitmap = {}
|
||||
end
|
||||
object FindDialogQuery: TFindDialog
|
||||
OnFind = FindDialogQueryFind
|
||||
Left = 104
|
||||
Top = 200
|
||||
end
|
||||
object ReplaceDialogQuery: TReplaceDialog
|
||||
OnFind = ReplaceDialogQueryFind
|
||||
OnReplace = ReplaceDialogQueryReplace
|
||||
Left = 136
|
||||
Top = 200
|
||||
end
|
||||
object PopupQueryLoad: TPopupMenu
|
||||
Left = 104
|
||||
Top = 64
|
||||
@ -6968,4 +7008,8 @@ object MainForm: TMainForm
|
||||
Left = 40
|
||||
Top = 269
|
||||
end
|
||||
object SynEditRegexSearch1: TSynEditRegexSearch
|
||||
Left = 104
|
||||
Top = 304
|
||||
end
|
||||
end
|
||||
|
180
source/main.pas
180
source/main.pas
@ -13,12 +13,12 @@ uses
|
||||
Windows, SysUtils, Classes, Graphics, GraphUtil, Forms, Controls, Menus, StdCtrls, Dialogs, Buttons,
|
||||
Messages, ExtCtrls, ComCtrls, StdActns, ActnList, ImgList, ToolWin, Clipbrd, SynMemo,
|
||||
SynEdit, SynEditTypes, SynEditKeyCmds, VirtualTrees, DateUtils, PngImageList,
|
||||
ShlObj, SynEditMiscClasses, SynEditSearch, SynCompletionProposal, SynEditHighlighter,
|
||||
ShlObj, SynEditMiscClasses, SynEditSearch, SynEditRegexSearch, SynCompletionProposal, SynEditHighlighter,
|
||||
SynHighlighterSQL, Tabs, SynUnicode, SynRegExpr, WideStrUtils, ExtActns,
|
||||
CommCtrl, Contnrs, PngSpeedButton, Generics.Collections,
|
||||
routine_editor, trigger_editor, options, EditVar, helpers, createdatabase, table_editor,
|
||||
TableTools, View, Usermanager, SelectDBObject, connections, sqlhelp, mysql_connection,
|
||||
mysql_api, insertfiles;
|
||||
mysql_api, insertfiles, searchreplace;
|
||||
|
||||
|
||||
type
|
||||
@ -182,8 +182,6 @@ type
|
||||
actQueryWordWrap: TAction;
|
||||
actQueryFind: TAction;
|
||||
actQueryReplace: TAction;
|
||||
FindDialogQuery: TFindDialog;
|
||||
ReplaceDialogQuery: TReplaceDialog;
|
||||
ToolBarQuery: TToolBar;
|
||||
btnExecuteQuery: TToolButton;
|
||||
btnLoadSQL: TToolButton;
|
||||
@ -300,6 +298,7 @@ type
|
||||
OpenDialogSQLFile: TOpenDialog;
|
||||
SaveDialogSQLFile: TSaveDialog;
|
||||
SynEditSearch1: TSynEditSearch;
|
||||
SynEditRegexSearch1: TSynEditRegexSearch;
|
||||
tabCommandStats: TTabSheet;
|
||||
ListCommandStats: TVirtualStringTree;
|
||||
QF13: TMenuItem;
|
||||
@ -454,6 +453,11 @@ type
|
||||
menuFilterInsertFunction: TMenuItem;
|
||||
actBlobAsText: TAction;
|
||||
btnBlobAsText: TToolButton;
|
||||
actQueryFindAgain: TAction;
|
||||
Search1: TMenuItem;
|
||||
Findtext1: TMenuItem;
|
||||
actQueryFindAgain1: TMenuItem;
|
||||
Replacetext1: TMenuItem;
|
||||
procedure refreshMonitorConfig;
|
||||
procedure loadWindowConfig;
|
||||
procedure saveWindowConfig;
|
||||
@ -504,8 +508,7 @@ type
|
||||
procedure actNewWindowExecute(Sender: TObject);
|
||||
procedure actSessionManagerExecute(Sender: TObject);
|
||||
procedure actPreferencesExecute(Sender: TObject);
|
||||
procedure actQueryFindExecute(Sender: TObject);
|
||||
procedure actQueryReplaceExecute(Sender: TObject);
|
||||
procedure actQueryFindReplaceExecute(Sender: TObject);
|
||||
procedure actQueryStopOnErrorsExecute(Sender: TObject);
|
||||
procedure actQueryWordWrapExecute(Sender: TObject);
|
||||
procedure actReadmeExecute(Sender: TObject);
|
||||
@ -518,9 +521,6 @@ type
|
||||
procedure actSQLhelpExecute(Sender: TObject);
|
||||
procedure actUpdateCheckExecute(Sender: TObject);
|
||||
procedure actWebbrowse(Sender: TObject);
|
||||
procedure FindDialogQueryFind(Sender: TObject);
|
||||
procedure ReplaceDialogQueryFind(Sender: TObject);
|
||||
procedure ReplaceDialogQueryReplace(Sender: TObject);
|
||||
procedure actCopyAsSQLExecute(Sender: TObject);
|
||||
procedure actSelectTreeBackgroundExecute(Sender: TObject);
|
||||
procedure popupQueryPopup(Sender: TObject);
|
||||
@ -722,6 +722,10 @@ type
|
||||
NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex;
|
||||
var Allowed: Boolean);
|
||||
procedure actBlobAsTextExecute(Sender: TObject);
|
||||
procedure SynMemoQuerySearchNotFound(Sender: TObject; FindText: string);
|
||||
procedure SynMemoQueryReplaceText(Sender: TObject; const ASearch,
|
||||
AReplace: string; Line, Column: Integer; var Action: TSynReplaceAction);
|
||||
procedure actQueryFindAgainExecute(Sender: TObject);
|
||||
private
|
||||
ReachedEOT: Boolean;
|
||||
FDelimiter: String;
|
||||
@ -742,6 +746,7 @@ type
|
||||
FCmdlineFilenames: TStringlist;
|
||||
FCmdlineConnectionParams: TConnectionParameters;
|
||||
FCmdlineSessionName: String;
|
||||
FSearchReplaceExecuted: Boolean;
|
||||
procedure ParseCommandLineParameters(Parameters: TStringlist);
|
||||
procedure SetDelimiter(Value: String);
|
||||
procedure DisplayRowCountStats(MatchingRows: Int64 = -1);
|
||||
@ -782,6 +787,7 @@ type
|
||||
TableEditor: TfrmTableEditor;
|
||||
InsertFiles: TfrmInsertFiles;
|
||||
EditVariableForm: TfrmEditVariable;
|
||||
SearchReplaceDialog: TfrmSearchReplace;
|
||||
|
||||
// Virtual Tree data arrays
|
||||
VTRowDataListVariables,
|
||||
@ -1091,6 +1097,7 @@ begin
|
||||
FreeAndNil(TableEditor);
|
||||
FreeAndNil(TriggerEditor);
|
||||
FreeAndNil(CreateDatabaseForm);
|
||||
FreeAndNil(SearchReplaceDialog);
|
||||
|
||||
// Close database connection
|
||||
DoDisconnect;
|
||||
@ -2553,25 +2560,78 @@ begin
|
||||
end;
|
||||
|
||||
|
||||
procedure TMainForm.actQueryFindExecute(Sender: TObject);
|
||||
procedure TMainForm.actQueryFindReplaceExecute(Sender: TObject);
|
||||
var
|
||||
DlgResult: TModalResult;
|
||||
Occurences: Integer;
|
||||
begin
|
||||
// if something is selected search for that text
|
||||
if ActiveQueryMemo.SelAvail then
|
||||
FindDialogQuery.FindText := ActiveQueryMemo.SelText
|
||||
// Display search + replace dialog
|
||||
if not Assigned(SearchReplaceDialog) then
|
||||
SearchReplaceDialog := TfrmSearchReplace.Create(Self);
|
||||
SearchReplaceDialog.Editor := ActiveQueryMemo;
|
||||
SearchReplaceDialog.chkReplace.Checked := Sender = actQueryReplace;
|
||||
DlgResult := SearchReplaceDialog.ShowModal;
|
||||
if SearchReplaceDialog.chkRegularExpression.Checked then
|
||||
SearchReplaceDialog.Editor.SearchEngine := SynEditRegexSearch1
|
||||
else
|
||||
FindDialogQuery.FindText := ActiveQueryMemo.WordAtCursor;
|
||||
FindDialogQuery.Execute;
|
||||
SearchReplaceDialog.Editor.SearchEngine := SynEditSearch1;
|
||||
ShowStatus('Searching ...');
|
||||
case DlgResult of
|
||||
mrOK, mrAll: begin
|
||||
Occurences := SearchReplaceDialog.Editor.SearchReplace(
|
||||
SearchReplaceDialog.comboSearch.Text,
|
||||
SearchReplaceDialog.comboReplace.Text,
|
||||
SearchReplaceDialog.Options
|
||||
);
|
||||
FSearchReplaceExecuted := True; // Helper for later F3 hits
|
||||
if DlgResult = mrAll then
|
||||
ShowStatus('Text "'+SearchReplaceDialog.comboSearch.Text+'" '+FormatNumber(Occurences)+' times replaced.', 0);
|
||||
end;
|
||||
mrCancel: Exit;
|
||||
end;
|
||||
ShowStatus(STATUS_MSG_READY);
|
||||
end;
|
||||
|
||||
|
||||
procedure TMainForm.actQueryReplaceExecute(Sender: TObject);
|
||||
procedure TMainForm.actQueryFindAgainExecute(Sender: TObject);
|
||||
begin
|
||||
// if something is selected search for that text
|
||||
if ActiveQueryMemo.SelAvail then
|
||||
ReplaceDialogQuery.FindText := ActiveQueryMemo.SelText
|
||||
// F3 - search or replace again, using previous settings
|
||||
if not FSearchReplaceExecuted then begin
|
||||
// Display dialog if not done yet
|
||||
actQueryFindReplaceExecute(Sender)
|
||||
end else begin
|
||||
SearchReplaceDialog.Editor := ActiveQueryMemo;
|
||||
if SearchReplaceDialog.chkRegularExpression.Checked then
|
||||
SearchReplaceDialog.Editor.SearchEngine := SynEditRegexSearch1
|
||||
else
|
||||
ReplaceDialogQuery.FindText := ActiveQueryMemo.WordAtCursor;
|
||||
ReplaceDialogQuery.Execute;
|
||||
SearchReplaceDialog.Editor.SearchEngine := SynEditSearch1;
|
||||
SearchReplaceDialog.Editor.SearchReplace(
|
||||
SearchReplaceDialog.comboSearch.Text,
|
||||
SearchReplaceDialog.comboReplace.Text,
|
||||
SearchReplaceDialog.Options
|
||||
);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure TMainForm.SynMemoQuerySearchNotFound(Sender: TObject; FindText: string);
|
||||
begin
|
||||
// No text found
|
||||
ShowStatus('Text "'+sstr(FindText,50)+'" not found.', 0);
|
||||
MessageBeep(MB_ICONASTERISK);
|
||||
end;
|
||||
|
||||
|
||||
procedure TMainForm.SynMemoQueryReplaceText(Sender: TObject; const ASearch,
|
||||
AReplace: string; Line, Column: Integer; var Action: TSynReplaceAction);
|
||||
begin
|
||||
// Fires when "Replace all" in search dialog was pressed with activated "Prompt on replace"
|
||||
case MessageDlg('Replace this occurrence of "'+sstr(ASearch, 100)+'"?', mtConfirmation, [mbYes, mbYesToAll, mbNo, mbCancel], 0) of
|
||||
mrYes: Action := raReplace;
|
||||
mrYesToAll: Action := raReplaceAll;
|
||||
mrNo: Action := raSkip;
|
||||
mrCancel: Action := raCancel;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
@ -2792,68 +2852,6 @@ begin
|
||||
end;
|
||||
|
||||
|
||||
procedure TMainForm.FindDialogQueryFind(Sender: TObject);
|
||||
var
|
||||
Options: TSynSearchOptions;
|
||||
Search: String;
|
||||
begin
|
||||
Search := FindDialogQuery.FindText;
|
||||
Options := [];
|
||||
if Sender is TReplaceDialog then
|
||||
Include(Options, ssoEntireScope);
|
||||
if not (frDown in FindDialogQuery.Options) then
|
||||
Include(Options, ssoBackwards);
|
||||
if frMatchCase in FindDialogQuery.Options then
|
||||
Include(Options, ssoMatchCase);
|
||||
if frWholeWord in FindDialogQuery.Options then
|
||||
Include(Options, ssoWholeWord);
|
||||
if ActiveQueryMemo.SearchReplace(Search, '', Options) = 0 then
|
||||
begin
|
||||
MessageBeep(MB_ICONASTERISK);
|
||||
ShowStatus( 'SearchText ''' + Search + ''' not found!', 0);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure TMainForm.ReplaceDialogQueryFind(Sender: TObject);
|
||||
begin
|
||||
FindDialogQuery.FindText := ReplaceDialogQuery.FindText;
|
||||
FindDialogQueryFind( ReplaceDialogQuery );
|
||||
end;
|
||||
|
||||
|
||||
procedure TMainForm.ReplaceDialogQueryReplace(Sender: TObject);
|
||||
var
|
||||
Options: TSynSearchOptions;
|
||||
Search: String;
|
||||
begin
|
||||
Search := ReplaceDialogQuery.FindText;
|
||||
Options := [ssoEntireScope]; // Do replaces always on entire scope, because the standard-dialog lacks of a down/up-option
|
||||
if frReplaceAll in ReplaceDialogQuery.Options then
|
||||
Include( Options, ssoReplaceAll );
|
||||
if not (frDown in ReplaceDialogQuery.Options) then
|
||||
Include(Options, ssoBackwards);
|
||||
if frMatchCase in ReplaceDialogQuery.Options then
|
||||
Include(Options, ssoMatchCase);
|
||||
if frWholeWord in ReplaceDialogQuery.Options then
|
||||
Include(Options, ssoWholeWord);
|
||||
if frReplace in ReplaceDialogQuery.Options then // Replace instead of ReplaceAll is pressed
|
||||
Include(Options, ssoReplace)
|
||||
else
|
||||
Include(Options, ssoReplaceAll);
|
||||
if ActiveQueryMemo.SearchReplace( Search, ReplaceDialogQuery.ReplaceText, Options) = 0 then
|
||||
begin
|
||||
MessageBeep(MB_ICONASTERISK);
|
||||
ShowStatus( 'SearchText ''' + Search + ''' not found!', 0);
|
||||
if ssoBackwards in Options then
|
||||
ActiveQueryMemo.BlockEnd := ActiveQueryMemo.BlockBegin
|
||||
else
|
||||
ActiveQueryMemo.BlockBegin := ActiveQueryMemo.BlockEnd;
|
||||
ActiveQueryMemo.CaretXY := ActiveQueryMemo.BlockBegin;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure TMainform.FillPopupQueryLoad;
|
||||
var
|
||||
i, j: Integer;
|
||||
@ -3774,8 +3772,9 @@ begin
|
||||
actSaveSQLselection.Enabled := InQueryTab and HasSelection;
|
||||
actSaveSQLSnippet.Enabled := InQueryTab and NotEmpty;
|
||||
actSaveSQLSelectionSnippet.Enabled := InQueryTab and HasSelection;
|
||||
actQueryFind.Enabled := InQueryTab and NotEmpty;
|
||||
actQueryReplace.Enabled := InQueryTab and NotEmpty;
|
||||
actQueryFind.Enabled := InQueryTab;
|
||||
actQueryReplace.Enabled := InQueryTab;
|
||||
actQueryFindAgain.Enabled := InQueryTab;
|
||||
// We need a pressed button which somehow does not work in conjunction with Enabled=False
|
||||
// actQueryStopOnErrors.Enabled := QueryTabActive;
|
||||
actQueryWordWrap.Enabled := InQueryTab;
|
||||
@ -7873,8 +7872,6 @@ begin
|
||||
// Copy text from a focused control to clipboard
|
||||
Success := False;
|
||||
Control := Screen.ActiveControl;
|
||||
// Do not handle Search/replace dialog
|
||||
if not Control.Focused then Exit;
|
||||
DoCut := Sender = actCut;
|
||||
if Control is TCustomEdit then begin
|
||||
Edit := TCustomEdit(Control);
|
||||
@ -7925,8 +7922,6 @@ begin
|
||||
// Paste text into the focused control
|
||||
Success := False;
|
||||
Control := Screen.ActiveControl;
|
||||
// Do not handle Search/replace dialog
|
||||
if not Control.Focused then Exit;
|
||||
if not Clipboard.HasFormat(CF_TEXT) then begin
|
||||
// Do nothing, we cannot paste a picture or so
|
||||
end else if Control is TCustomEdit then begin
|
||||
@ -7969,8 +7964,6 @@ begin
|
||||
// Select all items, text or whatever
|
||||
Success := False;
|
||||
Control := Screen.ActiveControl;
|
||||
// Do not handle Search/replace dialog
|
||||
if not Control.Focused then Exit;
|
||||
if Control is TCustomEdit then begin
|
||||
TCustomEdit(Control).SelectAll;
|
||||
Success := True;
|
||||
@ -8006,8 +7999,6 @@ begin
|
||||
// Invert selection in grids or listboxes
|
||||
Success := False;
|
||||
Control := Screen.ActiveControl;
|
||||
// Do not handle Search/replace dialog
|
||||
if not Control.Focused then Exit;
|
||||
if Control is TVirtualStringTree then begin
|
||||
Grid := TVirtualStringTree(Control);
|
||||
if toMultiSelect in Grid.TreeOptions.SelectionOptions then begin
|
||||
@ -8316,13 +8307,14 @@ begin
|
||||
QueryTab.Memo.RightEdge := SynMemoQuery.RightEdge;
|
||||
QueryTab.Memo.WantTabs := SynMemoQuery.WantTabs;
|
||||
QueryTab.Memo.Highlighter := SynMemoQuery.Highlighter;
|
||||
QueryTab.Memo.SearchEngine := SynMemoQuery.SearchEngine;
|
||||
QueryTab.Memo.Gutter.Assign(SynMemoQuery.Gutter);
|
||||
QueryTab.Memo.Font.Assign(SynMemoQuery.Font);
|
||||
QueryTab.Memo.ActiveLineColor := SynMemoQuery.ActiveLineColor;
|
||||
QueryTab.Memo.OnDragDrop := SynMemoQuery.OnDragDrop;
|
||||
QueryTab.Memo.OnDragOver := SynMemoQuery.OnDragOver;
|
||||
QueryTab.Memo.OnDropFiles := SynMemoQuery.OnDropFiles;
|
||||
QueryTab.Memo.OnSearchNotFound := SynMemoQuery.OnSearchNotFound;
|
||||
QueryTab.Memo.OnReplaceText := SynMemoQuery.OnReplaceText;
|
||||
QueryTab.Memo.OnStatusChange := SynMemoQuery.OnStatusChange;
|
||||
SynCompletionProposal.AddEditor(QueryTab.Memo);
|
||||
|
||||
|
180
source/searchreplace.dfm
Normal file
180
source/searchreplace.dfm
Normal file
@ -0,0 +1,180 @@
|
||||
object frmSearchReplace: TfrmSearchReplace
|
||||
Left = 0
|
||||
Top = 0
|
||||
BorderStyle = bsDialog
|
||||
Caption = 'Search and replace text'
|
||||
ClientHeight = 236
|
||||
ClientWidth = 388
|
||||
Color = clBtnFace
|
||||
Font.Charset = DEFAULT_CHARSET
|
||||
Font.Color = clWindowText
|
||||
Font.Height = -11
|
||||
Font.Name = 'Tahoma'
|
||||
Font.Style = []
|
||||
OldCreateOrder = False
|
||||
Position = poOwnerFormCenter
|
||||
OnClose = FormClose
|
||||
OnCreate = FormCreate
|
||||
OnDestroy = FormDestroy
|
||||
OnShow = FormShow
|
||||
DesignSize = (
|
||||
388
|
||||
236)
|
||||
PixelsPerInch = 96
|
||||
TextHeight = 13
|
||||
object lblSearch: TLabel
|
||||
Left = 8
|
||||
Top = 11
|
||||
Width = 60
|
||||
Height = 13
|
||||
Caption = '&Text to find:'
|
||||
FocusControl = comboSearch
|
||||
end
|
||||
object btnCancel: TButton
|
||||
Left = 305
|
||||
Top = 203
|
||||
Width = 75
|
||||
Height = 25
|
||||
Anchors = [akRight, akBottom]
|
||||
Cancel = True
|
||||
Caption = 'Cancel'
|
||||
ModalResult = 2
|
||||
TabOrder = 9
|
||||
end
|
||||
object btnReplaceAll: TButton
|
||||
Left = 224
|
||||
Top = 203
|
||||
Width = 75
|
||||
Height = 25
|
||||
Anchors = [akRight, akBottom]
|
||||
Caption = 'Replace all'
|
||||
ModalResult = 8
|
||||
TabOrder = 8
|
||||
end
|
||||
object chkReplace: TCheckBox
|
||||
Left = 8
|
||||
Top = 35
|
||||
Width = 73
|
||||
Height = 17
|
||||
Caption = 'Replace:'
|
||||
TabOrder = 1
|
||||
OnClick = chkReplaceClick
|
||||
end
|
||||
object comboSearch: TComboBox
|
||||
Left = 90
|
||||
Top = 8
|
||||
Width = 290
|
||||
Height = 21
|
||||
Anchors = [akLeft, akTop, akRight]
|
||||
TabOrder = 0
|
||||
Text = 'comboSearch'
|
||||
TextHint = 'Enter text to find ...'
|
||||
OnExit = comboSearchReplaceExit
|
||||
end
|
||||
object comboReplace: TComboBox
|
||||
Left = 90
|
||||
Top = 33
|
||||
Width = 290
|
||||
Height = 21
|
||||
Anchors = [akLeft, akTop, akRight]
|
||||
Enabled = False
|
||||
TabOrder = 2
|
||||
Text = 'comboReplace'
|
||||
TextHint = 'Enter replacement pattern ...'
|
||||
OnExit = comboSearchReplaceExit
|
||||
end
|
||||
object grpOptions: TGroupBox
|
||||
Left = 8
|
||||
Top = 60
|
||||
Width = 372
|
||||
Height = 69
|
||||
Anchors = [akLeft, akTop, akRight]
|
||||
Caption = 'Options'
|
||||
TabOrder = 3
|
||||
object chkCaseSensitive: TCheckBox
|
||||
Left = 12
|
||||
Top = 18
|
||||
Width = 130
|
||||
Height = 17
|
||||
Caption = 'Case sensitive'
|
||||
TabOrder = 0
|
||||
end
|
||||
object chkWholeWords: TCheckBox
|
||||
Left = 12
|
||||
Top = 41
|
||||
Width = 130
|
||||
Height = 17
|
||||
Caption = 'Whole words'
|
||||
TabOrder = 1
|
||||
end
|
||||
object chkRegularExpression: TCheckBox
|
||||
Left = 156
|
||||
Top = 18
|
||||
Width = 130
|
||||
Height = 17
|
||||
Caption = 'Regular expression'
|
||||
ParentShowHint = False
|
||||
ShowHint = True
|
||||
TabOrder = 2
|
||||
OnClick = ValidateControls
|
||||
end
|
||||
object chkPromptOnReplace: TCheckBox
|
||||
Left = 156
|
||||
Top = 41
|
||||
Width = 130
|
||||
Height = 17
|
||||
Caption = 'Prompt on replace'
|
||||
TabOrder = 3
|
||||
end
|
||||
end
|
||||
object grpDirection: TRadioGroup
|
||||
Left = 8
|
||||
Top = 135
|
||||
Width = 120
|
||||
Height = 62
|
||||
Anchors = [akLeft, akTop, akBottom]
|
||||
Caption = 'Direction'
|
||||
ItemIndex = 0
|
||||
Items.Strings = (
|
||||
'&Forward'
|
||||
'&Backward')
|
||||
TabOrder = 4
|
||||
end
|
||||
object grpOrigin: TRadioGroup
|
||||
Left = 134
|
||||
Top = 135
|
||||
Width = 120
|
||||
Height = 62
|
||||
Anchors = [akLeft, akTop, akBottom]
|
||||
Caption = 'Origin'
|
||||
ItemIndex = 0
|
||||
Items.Strings = (
|
||||
'From cursor'
|
||||
'Entire scope')
|
||||
TabOrder = 5
|
||||
end
|
||||
object grpScope: TRadioGroup
|
||||
Left = 260
|
||||
Top = 135
|
||||
Width = 120
|
||||
Height = 62
|
||||
Anchors = [akLeft, akTop, akRight, akBottom]
|
||||
Caption = 'Scope'
|
||||
ItemIndex = 0
|
||||
Items.Strings = (
|
||||
'Global'
|
||||
'Selected text')
|
||||
TabOrder = 6
|
||||
end
|
||||
object btnOK: TButton
|
||||
Left = 143
|
||||
Top = 203
|
||||
Width = 75
|
||||
Height = 25
|
||||
Anchors = [akRight, akBottom]
|
||||
Caption = 'OK'
|
||||
Default = True
|
||||
ModalResult = 1
|
||||
TabOrder = 7
|
||||
end
|
||||
end
|
150
source/searchreplace.pas
Normal file
150
source/searchreplace.pas
Normal file
@ -0,0 +1,150 @@
|
||||
unit searchreplace;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Windows, Messages, SysUtils, Classes, Controls, Forms, Dialogs, StdCtrls,
|
||||
ExtCtrls, SynMemo, SynEditSearch, SynEditTypes, SynEditMiscClasses;
|
||||
|
||||
type
|
||||
TfrmSearchReplace = class(TForm)
|
||||
btnCancel: TButton;
|
||||
btnReplaceAll: TButton;
|
||||
lblSearch: TLabel;
|
||||
chkReplace: TCheckBox;
|
||||
comboSearch: TComboBox;
|
||||
comboReplace: TComboBox;
|
||||
grpOptions: TGroupBox;
|
||||
chkCaseSensitive: TCheckBox;
|
||||
chkWholeWords: TCheckBox;
|
||||
chkRegularExpression: TCheckBox;
|
||||
chkPromptOnReplace: TCheckBox;
|
||||
grpDirection: TRadioGroup;
|
||||
grpOrigin: TRadioGroup;
|
||||
grpScope: TRadioGroup;
|
||||
btnOK: TButton;
|
||||
procedure ValidateControls(Sender: TObject);
|
||||
procedure chkReplaceClick(Sender: TObject);
|
||||
procedure FormShow(Sender: TObject);
|
||||
procedure FormClose(Sender: TObject; var Action: TCloseAction);
|
||||
procedure comboSearchReplaceExit(Sender: TObject);
|
||||
procedure FormCreate(Sender: TObject);
|
||||
procedure FormDestroy(Sender: TObject);
|
||||
private
|
||||
{ Private declarations }
|
||||
public
|
||||
{ Public declarations }
|
||||
Editor: TSynMemo;
|
||||
Options: TSynSearchOptions;
|
||||
end;
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
{$R *.dfm}
|
||||
|
||||
uses main, helpers;
|
||||
|
||||
|
||||
procedure TfrmSearchReplace.FormCreate(Sender: TObject);
|
||||
begin
|
||||
comboSearch.Items.Text := GetRegValue(REGNAME_SEARCHTEXT, '');
|
||||
comboReplace.Items.Text := GetRegValue(REGNAME_REPLACETEXT, '');
|
||||
comboSearch.Text := '';
|
||||
comboReplace.Text := '';
|
||||
if comboSearch.Items.Count > 0 then comboSearch.Text := comboSearch.Items[0];
|
||||
if comboReplace.Items.Count > 0 then comboReplace.Text := comboReplace.Items[0];
|
||||
|
||||
chkRegularExpression.Hint := 'Search patterns:'+CRLF+
|
||||
' ^ Start of line'+CRLF+
|
||||
' $ End of line'+CRLF+
|
||||
' \w Any word character'+CRLF+
|
||||
' \d Digit (0-9)'+CRLF+
|
||||
' \s Whitespace'+CRLF+
|
||||
'Replacement patterns:'+CRLF+
|
||||
' $0 .. $n Callback parentheses'
|
||||
;
|
||||
end;
|
||||
|
||||
|
||||
procedure TfrmSearchReplace.FormShow(Sender: TObject);
|
||||
var
|
||||
SearchText: String;
|
||||
begin
|
||||
// Prefill search editor with selected text
|
||||
if Editor.SelAvail then
|
||||
SearchText := Editor.SelText
|
||||
else
|
||||
SearchText := Editor.WordAtCursor;
|
||||
if SearchText <> '' then
|
||||
comboSearch.Text := SearchText;
|
||||
ValidateControls(Sender);
|
||||
comboSearch.SetFocus;
|
||||
end;
|
||||
|
||||
|
||||
procedure TfrmSearchReplace.FormClose(Sender: TObject; var Action: TCloseAction);
|
||||
begin
|
||||
// Set SynEditSearch options, which the caller can use in Editor.SearchReplace()
|
||||
Options := [];
|
||||
if chkReplace.Checked then Include(Options, ssoReplace);
|
||||
if chkCaseSensitive.Checked then Include(Options, ssoMatchCase);
|
||||
if chkWholeWords.Checked then Include(Options, ssoWholeWord);
|
||||
if chkPromptOnReplace.Checked and chkPromptOnReplace.Enabled then Include(Options, ssoPrompt);
|
||||
if grpDirection.ItemIndex = 1 then Include(Options, ssoBackwards);
|
||||
if grpOrigin.ItemIndex = 1 then Include(Options, ssoEntireScope);
|
||||
if grpScope.ItemIndex = 1 then Include(Options, ssoSelectedOnly);
|
||||
if ModalResult = mrAll then Include(Options, ssoReplaceAll);
|
||||
|
||||
end;
|
||||
|
||||
|
||||
procedure TfrmSearchReplace.FormDestroy(Sender: TObject);
|
||||
begin
|
||||
OpenRegistry;
|
||||
Mainreg.WriteString(REGNAME_SEARCHTEXT, comboSearch.Items.Text);
|
||||
Mainreg.WriteString(REGNAME_REPLACETEXT, comboReplace.Items.Text);
|
||||
end;
|
||||
|
||||
|
||||
procedure TfrmSearchReplace.chkReplaceClick(Sender: TObject);
|
||||
begin
|
||||
// Jump to replace editor
|
||||
ValidateControls(Sender);
|
||||
if comboReplace.Enabled then
|
||||
ActiveControl := comboReplace;
|
||||
end;
|
||||
|
||||
|
||||
procedure TfrmSearchReplace.ValidateControls(Sender: TObject);
|
||||
begin
|
||||
// Enable or disable various controls
|
||||
comboReplace.Enabled := chkReplace.Checked;
|
||||
chkPromptOnReplace.Enabled := chkReplace.Checked;
|
||||
btnReplaceAll.Enabled := chkReplace.Checked;
|
||||
if chkReplace.Checked then
|
||||
btnOK.Caption := 'Replace'
|
||||
else
|
||||
btnOK.Caption := 'Find';
|
||||
end;
|
||||
|
||||
|
||||
procedure TfrmSearchReplace.comboSearchReplaceExit(Sender: TObject);
|
||||
var
|
||||
Combo: TComboBox;
|
||||
idx: Integer;
|
||||
begin
|
||||
// Store search or replace text history
|
||||
Combo := Sender as TComboBox;
|
||||
if Combo.Text = '' then
|
||||
Exit;
|
||||
idx := Combo.Items.IndexOf(Combo.Text);
|
||||
if idx > -1 then
|
||||
Combo.Items.Move(idx, 0)
|
||||
else
|
||||
Combo.Items.Insert(0, Combo.Text);
|
||||
Combo.Text := Combo.Items[0];
|
||||
end;
|
||||
|
||||
|
||||
end.
|
Reference in New Issue
Block a user