Rev 49 | Rev 83 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
13 | daniel-mar | 1 | unit FindReplace; |
2 | |||
24 | daniel-mar | 3 | (* |
4 | TSynSearchOption = (ssoMatchCase, ssoWholeWord, ssoBackwards, |
||
5 | ssoEntireScope, ssoSelectedOnly, ssoReplace, ssoReplaceAll, ssoPrompt); |
||
13 | daniel-mar | 6 | |
24 | daniel-mar | 7 | frDisableMatchCase |
8 | Disables (grays) the Match Case check box in a find dialog. |
||
9 | frDisableUpDown |
||
10 | Disables (grays) the Up and Down buttons, which determine the direction of the search. |
||
11 | frDisableWholeWord |
||
12 | Disables (grays) the Match Whole Word check box of find dialog. |
||
13 | frDown = not ssoBackwards |
||
14 | Selects the Down button by default when the dialog opens. If the frDown flags is off, Up is selected when the dialog opens. (By default, frDown is on.) |
||
15 | frFindNext |
||
16 | This flag is turned on when the user clicks the Find Next button and turned off when the dialog closes. |
||
17 | frHideMatchCase |
||
18 | Removes the Match Case check box from the dialog. |
||
19 | frHideWholeWord |
||
20 | Removes the Match Whole Word check box from the dialog. |
||
21 | frHideUpDown |
||
22 | Removes the Up and Down buttons from the dialog. |
||
23 | frMatchCase = ssoMatchCase |
||
24 | This flag is turned on (off) when the user selects (deselects) the Match Case check box. To select the check box by default when the dialog opens, set frMatchCase at design time. |
||
25 | frReplace = ssoReplace |
||
26 | Applies to TReplaceDialog only. This flag is set by the system to indicate that the application should replace the current occurrence (and only the current occurrence) of the FindText string with the ReplaceText string. Not used in search routines. |
||
27 | frReplaceAll = ssoReplaceAll |
||
28 | Applies to TReplaceDialog only. This flag is set by the system to indicate that the application should replace all occurrences of the FindText string with the ReplaceText string. |
||
29 | frShowHelp |
||
30 | Displays a Help button in the dialog. |
||
31 | frWholeWord = ssoWholeWord |
||
32 | This flag is turned on (off) when the user selects (deselects) the Match Whole Word check box. To select the check box by default when the dialog opens, set frWholeWord at design time. |
||
33 | *) |
||
34 | |||
13 | daniel-mar | 35 | interface |
36 | |||
37 | uses |
||
38 | Windows, Messages, SysUtils, Classes, Dialogs, SynEdit; |
||
39 | |||
40 | type |
||
24 | daniel-mar | 41 | TSynEditFindReplace = class(TComponent) |
13 | daniel-mar | 42 | private |
24 | daniel-mar | 43 | fEditor: TSynEdit; |
44 | fReplaceDialog: TReplaceDialog; |
||
45 | fFindDialog: TFindDialog; |
||
25 | daniel-mar | 46 | fAutofocus: boolean; |
13 | daniel-mar | 47 | protected |
22 | daniel-mar | 48 | type |
49 | TFindDirection = (sdDefault, sdForwards, sdBackwards); |
||
50 | |||
24 | daniel-mar | 51 | procedure OnFind(Sender: TObject); virtual; |
52 | procedure OnReplace(Sender: TObject); virtual; |
||
13 | daniel-mar | 53 | |
67 | daniel-mar | 54 | procedure DoFind(dialog: TFindDialog; direction: TFindDirection); overload; |
24 | daniel-mar | 55 | procedure DoReplace(dialog: TReplaceDialog; direction: TFindDirection); |
13 | daniel-mar | 56 | |
24 | daniel-mar | 57 | function GetDirection(dialog: TFindDialog): TFindDirection; |
13 | daniel-mar | 58 | |
59 | public |
||
24 | daniel-mar | 60 | constructor Create(AOwner: TComponent); override; |
13 | daniel-mar | 61 | |
22 | daniel-mar | 62 | property FindDialog: TFindDialog read fFindDialog; |
63 | property ReplaceDialog: TReplaceDialog read fReplaceDialog; |
||
13 | daniel-mar | 64 | |
22 | daniel-mar | 65 | procedure CloseDialogs; |
66 | |||
13 | daniel-mar | 67 | procedure FindExecute; |
68 | procedure ReplaceExecute; |
||
69 | |||
22 | daniel-mar | 70 | procedure FindContinue; |
71 | procedure FindNext; |
||
72 | procedure FindPrev; |
||
73 | |||
24 | daniel-mar | 74 | procedure GoToLine(LineNumber: integer); |
13 | daniel-mar | 75 | |
76 | published |
||
22 | daniel-mar | 77 | property Editor: TSynEdit read fEditor write fEditor; |
25 | daniel-mar | 78 | property Autofocus: boolean read fAutofocus write fAutofocus; |
13 | daniel-mar | 79 | end; |
80 | |||
81 | implementation |
||
82 | |||
24 | daniel-mar | 83 | uses |
84 | SynEditTypes; |
||
13 | daniel-mar | 85 | |
24 | daniel-mar | 86 | constructor TSynEditFindReplace.Create(AOwner: TComponent); |
13 | daniel-mar | 87 | begin |
24 | daniel-mar | 88 | inherited Create(AOwner); |
13 | daniel-mar | 89 | |
24 | daniel-mar | 90 | fFindDialog := TFindDialog.Create(Self); |
13 | daniel-mar | 91 | fFindDialog.OnFind := OnFind; |
92 | |||
24 | daniel-mar | 93 | fReplaceDialog := TReplaceDialog.Create(Self); |
13 | daniel-mar | 94 | fReplaceDialog.OnReplace := OnReplace; |
95 | fReplaceDialog.OnFind := OnFind; |
||
23 | daniel-mar | 96 | fReplaceDialog.Options := fReplaceDialog.Options + [frHideWholeWord]; // TODO: currently not supported (see below) |
13 | daniel-mar | 97 | end; |
98 | |||
24 | daniel-mar | 99 | function TSynEditFindReplace.GetDirection(dialog: TFindDialog): TFindDirection; |
13 | daniel-mar | 100 | begin |
24 | daniel-mar | 101 | if frDown in dialog.Options then |
102 | result := sdForwards |
||
103 | else |
||
104 | result := sdBackwards; |
||
13 | daniel-mar | 105 | end; |
106 | |||
24 | daniel-mar | 107 | procedure TSynEditFindReplace.DoFind(dialog: TFindDialog; direction: TFindDirection); |
13 | daniel-mar | 108 | var |
24 | daniel-mar | 109 | opt: TSynSearchOptions; |
110 | found: boolean; |
||
13 | daniel-mar | 111 | begin |
24 | daniel-mar | 112 | if direction = sdDefault then direction := GetDirection(dialog); |
13 | daniel-mar | 113 | |
24 | daniel-mar | 114 | if fEditor.SelAvail then |
22 | daniel-mar | 115 | begin |
24 | daniel-mar | 116 | if direction = sdForwards then |
117 | begin |
||
118 | fEditor.SelStart := fEditor.SelStart + 1; |
||
119 | fEditor.SelLength := 0; |
||
120 | end |
||
22 | daniel-mar | 121 | else |
24 | daniel-mar | 122 | begin |
123 | // Links von Selektion springen |
||
124 | fEditor.SelLength := 0; |
||
125 | end; |
||
22 | daniel-mar | 126 | end; |
13 | daniel-mar | 127 | |
24 | daniel-mar | 128 | opt := []; |
129 | if frMatchCase in dialog.Options then Include(opt, ssoMatchCase); |
||
130 | if frWholeWord in dialog.Options then Include(opt, ssoWholeWord); |
||
131 | //if frReplace in dialog.Options then Include(opt, ssoReplace); |
||
132 | //if frReplaceAll in dialog.Options then Include(opt, ssoReplaceAll); |
||
133 | if direction = sdBackwards then Include(opt, ssoBackwards); |
||
134 | //Include(opt, ssoPrompt); // TODO: test. geht nicht? |
||
135 | //if fEditor.SelAvail then Include(opt, ssoSelectedOnly); // TODO: geht nicht, weil er bei einer suche ja dann etwas selektirert und dann nicht weitergeht |
||
136 | Exclude(opt, ssoEntireScope); // TODO: ok? |
||
13 | daniel-mar | 137 | |
24 | daniel-mar | 138 | found := fEditor.SearchReplace(dialog.FindText, '', opt) > 0; |
13 | daniel-mar | 139 | |
24 | daniel-mar | 140 | if not found then |
13 | daniel-mar | 141 | begin |
67 | daniel-mar | 142 | // TODO: If single replace was chosen, behave like Notepad and select the last replaced word |
24 | daniel-mar | 143 | if direction = sdForwards then |
49 | daniel-mar | 144 | MessageDlg('End of document reached.', mtInformation, [mbOk], 0) |
22 | daniel-mar | 145 | else |
49 | daniel-mar | 146 | MessageDlg('Begin of document reached.', mtInformation, [mbOk], 0); |
13 | daniel-mar | 147 | end; |
25 | daniel-mar | 148 | |
149 | if fAutofocus and fEditor.CanFocus then fEditor.SetFocus; |
||
22 | daniel-mar | 150 | end; |
13 | daniel-mar | 151 | |
24 | daniel-mar | 152 | procedure TSynEditFindReplace.DoReplace(dialog: TReplaceDialog; direction: TFindDirection); |
22 | daniel-mar | 153 | var |
24 | daniel-mar | 154 | opt: TSynSearchOptions; |
155 | numReplacements: integer; |
||
22 | daniel-mar | 156 | begin |
67 | daniel-mar | 157 | try |
158 | if direction = sdDefault then direction := GetDirection(dialog); |
||
13 | daniel-mar | 159 | |
67 | daniel-mar | 160 | opt := []; |
161 | if frMatchCase in dialog.Options then Include(opt, ssoMatchCase); |
||
162 | if frWholeWord in dialog.Options then Include(opt, ssoWholeWord); |
||
163 | if frReplace in dialog.Options then Include(opt, ssoReplace); |
||
164 | if frReplaceAll in dialog.Options then Include(opt, ssoReplaceAll); |
||
165 | if direction = sdBackwards then Include(opt, ssoBackwards); |
||
166 | Include(opt, ssoPrompt); // TODO: test. geht nicht? |
||
167 | if fEditor.SelAvail then Include(opt, ssoSelectedOnly); |
||
168 | Exclude(opt, ssoEntireScope); // TODO: ok? |
||
13 | daniel-mar | 169 | |
67 | daniel-mar | 170 | if not (ssoReplaceAll in opt) then |
171 | begin |
||
172 | if fEditor.SelLength = 0 then |
||
173 | begin |
||
174 | DoFind(dialog, sdForwards); |
||
175 | exit; |
||
176 | end; |
||
177 | end; |
||
178 | |||
179 | fEditor.BeginUpdate; // TODO: geht nicht? |
||
180 | //fEditor.BeginUndoBlock; |
||
181 | try |
||
182 | numReplacements := fEditor.SearchReplace(dialog.FindText, dialog.ReplaceText, opt); |
||
183 | finally |
||
184 | //fEditor.EndUndoBlock; |
||
185 | fEditor.EndUpdate; |
||
186 | end; |
||
187 | |||
188 | if not (ssoReplaceAll in opt) then |
||
189 | begin |
||
190 | DoFind(dialog, sdForwards); |
||
191 | end |
||
192 | else |
||
193 | begin |
||
194 | ShowMessageFmt('%d replaced.', [numReplacements]); |
||
195 | end; |
||
23 | daniel-mar | 196 | finally |
67 | daniel-mar | 197 | if fAutofocus and fEditor.CanFocus then fEditor.SetFocus; |
13 | daniel-mar | 198 | end; |
199 | end; |
||
200 | |||
24 | daniel-mar | 201 | procedure TSynEditFindReplace.OnFind(Sender: TObject); |
202 | begin |
||
203 | DoFind(Sender as TFindDialog, sdDefault); |
||
204 | end; |
||
13 | daniel-mar | 205 | |
24 | daniel-mar | 206 | procedure TSynEditFindReplace.OnReplace(Sender: TObject); |
13 | daniel-mar | 207 | begin |
24 | daniel-mar | 208 | DoReplace(Sender as TReplaceDialog, sdDefault); |
13 | daniel-mar | 209 | end; |
210 | |||
24 | daniel-mar | 211 | procedure TSynEditFindReplace.FindExecute; |
13 | daniel-mar | 212 | begin |
213 | fFindDialog.Execute; |
||
214 | end; |
||
215 | |||
24 | daniel-mar | 216 | procedure TSynEditFindReplace.ReplaceExecute; |
13 | daniel-mar | 217 | begin |
218 | fReplaceDialog.Execute; |
||
219 | end; |
||
220 | |||
24 | daniel-mar | 221 | procedure TSynEditFindReplace.FindContinue; |
13 | daniel-mar | 222 | begin |
22 | daniel-mar | 223 | if fFindDialog.FindText = '' then |
224 | begin |
||
225 | fFindDialog.Options := fFindDialog.Options + [frDown]; // Default direction: down |
||
226 | FindExecute; |
||
227 | end |
||
228 | else |
||
229 | DoFind(fFindDialog, sdDefault); |
||
230 | end; |
||
231 | |||
24 | daniel-mar | 232 | procedure TSynEditFindReplace.FindNext; |
13 | daniel-mar | 233 | begin |
22 | daniel-mar | 234 | if fFindDialog.FindText = '' then |
235 | begin |
||
236 | fFindDialog.Options := fFindDialog.Options + [frDown]; |
||
237 | FindExecute; |
||
238 | end |
||
239 | else |
||
240 | DoFind(fFindDialog, sdForwards); |
||
13 | daniel-mar | 241 | end; |
242 | |||
24 | daniel-mar | 243 | procedure TSynEditFindReplace.FindPrev; |
13 | daniel-mar | 244 | begin |
245 | if fFindDialog.FindText = '' then |
||
246 | begin |
||
22 | daniel-mar | 247 | fFindDialog.Options := fFindDialog.Options - [frDown]; |
248 | FindExecute; |
||
249 | end |
||
250 | else |
||
251 | DoFind(fFindDialog, sdBackwards); |
||
13 | daniel-mar | 252 | end; |
253 | |||
24 | daniel-mar | 254 | procedure TSynEditFindReplace.GoToLine(LineNumber: integer); |
13 | daniel-mar | 255 | var |
256 | currentLine: integer; |
||
257 | i: integer; |
||
258 | begin |
||
259 | currentLine := 1; |
||
260 | |||
261 | for i := 1 to fEditor.GetTextLen do |
||
262 | begin |
||
263 | if currentLine = LineNumber then |
||
264 | begin |
||
265 | fEditor.selStart := i; |
||
266 | fEditor.SetFocus; |
||
267 | Exit; |
||
268 | end |
||
269 | else if fEditor.Text = #$D then |
||
24 | daniel-mar | 270 | inc(currentLine); |
13 | daniel-mar | 271 | end; |
272 | end; |
||
273 | |||
24 | daniel-mar | 274 | procedure TSynEditFindReplace.CloseDialogs; |
22 | daniel-mar | 275 | begin |
276 | fFindDialog.CloseDialog; |
||
277 | fReplaceDialog.CloseDialog; |
||
278 | end; |
||
279 | |||
13 | daniel-mar | 280 | end. |