Rev 22 | Rev 24 | 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 | |||
22 | daniel-mar | 3 | // FindReplace.pas |
13 | daniel-mar | 4 | // Source: http://www.tek-tips.com/viewthread.cfm?qid=160357 |
22 | daniel-mar | 5 | // 18 Nov 2001 "bearsite4" |
6 | // Changes by Daniel Marschall, especially to make it compatible with TSynEdit |
||
13 | daniel-mar | 7 | |
8 | interface |
||
9 | |||
10 | uses |
||
11 | Windows, Messages, SysUtils, Classes, Dialogs, SynEdit; |
||
12 | |||
13 | type |
||
14 | FindReplaceCommunication = ( frcAlertUser, frcAlertReplace, frcEndReached ); |
||
15 | {allows the replace functions to use the find function avoiding alot |
||
16 | of code duplication. frcAlertuser means that when the find function |
||
17 | has reached the end of the text while searching for a word it will pop |
||
18 | up a message saying the word can't be found. frcAlertReplace |
||
19 | tells the find function not to display a message to the user saying that |
||
20 | the word can't be found but instead to set the state to frcEndReached to |
||
21 | let the replace function know it's reached the end of the text} |
||
22 | |||
22 | daniel-mar | 23 | TReplaceFunc = function ( const S1, S2: string ): Integer; |
24 | |||
13 | daniel-mar | 25 | TFindReplace = class(TComponent) |
26 | private |
||
27 | fEditor: TSynEdit; {the richedit or memo component to hook it up to} |
||
28 | fReplaceDialog: TReplaceDialog; {the replace dialog} |
||
29 | fFindDialog: TFindDialog; {the find dialog} |
||
30 | |||
31 | FindActionOnEnd: FindReplaceCommunication; {the action the find function |
||
32 | should take when it reaches the end of the text while searching for the |
||
33 | word} |
||
34 | |||
35 | function TestWholeWord( Sender: TFindDialog; TestString: string ): boolean; |
||
36 | {returns a true or false depending on whether the user chose the whole word |
||
37 | only option and whether or not the word is a whole word. Actually, it can |
||
38 | test multiple words in a single string as well.} |
||
39 | |||
40 | protected |
||
22 | daniel-mar | 41 | type |
42 | TFindDirection = (sdDefault, sdForwards, sdBackwards); |
||
43 | |||
13 | daniel-mar | 44 | procedure FindForwards( Sender: TFindDialog; start, finish: integer ); |
45 | {search through the editor in a forwards direction} |
||
22 | daniel-mar | 46 | procedure FindBackwards( Sender: TFindDialog; start, finish: integer ); |
13 | daniel-mar | 47 | {search through the editor in a backwards direction} |
48 | |||
49 | {defined event handlers} |
||
50 | procedure OnFind( Sender: TObject ); virtual; |
||
51 | procedure OnReplace( Sender: TObject ); virtual; |
||
52 | |||
53 | {the centralised find/replace functions} |
||
54 | function TryAndMatch( Sender: TFindDialog; index, finish: integer ): boolean; virtual; |
||
22 | daniel-mar | 55 | function TryAndReplace(dialog: TReplaceDialog): boolean; virtual; |
13 | daniel-mar | 56 | |
22 | daniel-mar | 57 | procedure DoReplace(dialog: TReplaceDialog); virtual; |
13 | daniel-mar | 58 | {the replace function that coordinates all the work} |
22 | daniel-mar | 59 | procedure DoReplaceAll(dialog: TReplaceDialog); virtual; |
13 | daniel-mar | 60 | {the replace all function that coordinates all the work} |
61 | |||
22 | daniel-mar | 62 | procedure DoFind(dialog: TFindDialog; direction: TFindDirection); |
63 | |||
13 | daniel-mar | 64 | public |
65 | constructor Create( AOwner: TComponent); override; |
||
66 | |||
22 | daniel-mar | 67 | property FindDialog: TFindDialog read fFindDialog; |
68 | property ReplaceDialog: TReplaceDialog read fReplaceDialog; |
||
13 | daniel-mar | 69 | |
22 | daniel-mar | 70 | procedure CloseDialogs; |
71 | |||
13 | daniel-mar | 72 | procedure FindExecute; |
73 | {opens the find dialog} |
||
74 | procedure ReplaceExecute; |
||
75 | {opens the replace dialog} |
||
76 | |||
22 | daniel-mar | 77 | procedure FindContinue; |
78 | procedure FindNext; |
||
79 | procedure FindPrev; |
||
80 | |||
13 | daniel-mar | 81 | procedure GoToLine( LineNumber: integer ); |
82 | |||
83 | published |
||
22 | daniel-mar | 84 | property Editor: TSynEdit read fEditor write fEditor; |
13 | daniel-mar | 85 | end; |
86 | |||
87 | (* |
||
88 | procedure Register; |
||
89 | *) |
||
90 | |||
91 | implementation |
||
92 | |||
93 | (* |
||
94 | {$R findrep.dcr} |
||
95 | *) |
||
96 | |||
97 | constructor TFindReplace.Create( AOwner: TComponent ); |
||
98 | begin |
||
99 | inherited; |
||
100 | |||
101 | {create the find dialog} |
||
102 | fFindDialog := TFindDialog.Create( Self ); |
||
103 | {set up the event handlers} |
||
104 | fFindDialog.OnFind := OnFind; |
||
105 | |||
106 | {create the replace dialog} |
||
107 | fReplaceDialog := TReplaceDialog.Create( Self ); |
||
108 | {set up the event handlers} |
||
109 | fReplaceDialog.OnReplace := OnReplace; |
||
110 | fReplaceDialog.OnFind := OnFind; |
||
23 | daniel-mar | 111 | fReplaceDialog.Options := fReplaceDialog.Options + [frHideWholeWord]; // TODO: currently not supported (see below) |
13 | daniel-mar | 112 | |
113 | {set find's default action on end of text to alert the user. |
||
114 | If a replace function changes this it is it's responsibility |
||
115 | to change it back} |
||
116 | FindActionOnEnd := frcAlertUser; |
||
117 | end; |
||
118 | |||
119 | procedure TFindReplace.FindForwards( Sender: TFindDialog; start, finish: integer ); |
||
120 | var |
||
121 | i: integer; |
||
122 | |||
123 | begin |
||
124 | |||
125 | {to find the word we go through the text on a character by character |
||
126 | basis} |
||
127 | for i := start to finish do |
||
128 | if TryAndMatch( Sender, i, finish ) then |
||
129 | {if we've got a match then stop} |
||
130 | Exit; |
||
131 | |||
132 | end; |
||
133 | |||
22 | daniel-mar | 134 | procedure TFindReplace.FindBackwards( Sender: TFindDialog; start, finish: Integer ); |
13 | daniel-mar | 135 | {since only find has a (search) up option and replace doesn't |
136 | we don't have to worry about sender since only the onFind will |
||
22 | daniel-mar | 137 | be calling this function} |
13 | daniel-mar | 138 | |
139 | var |
||
140 | i: integer; |
||
141 | |||
142 | begin |
||
143 | {See comments for findforward} |
||
144 | |||
145 | {to find the word we go through the text on a character by character |
||
146 | basis but working backwards} |
||
147 | for i := finish downto start do |
||
22 | daniel-mar | 148 | if TryAndMatch( Sender, i, start ) then |
13 | daniel-mar | 149 | Exit; |
150 | |||
151 | end; |
||
152 | |||
153 | function TFindReplace.TryAndMatch( Sender: TFindDialog; index, finish: integer ): boolean; |
||
154 | {returns true if there was a match and false otherwise} |
||
155 | var |
||
156 | StringToTest: string; |
||
157 | |||
22 | daniel-mar | 158 | StringComparison: TReplaceFunc; |
159 | {the function to use to compare 2 strings. Should be assigned |
||
160 | different values according to the search criteria} |
||
161 | |||
162 | FindTextLength: integer; |
||
163 | |||
164 | resourcestring |
||
165 | S_CANT_BE_FOUND = '%s could not be found'; |
||
13 | daniel-mar | 166 | begin |
22 | daniel-mar | 167 | FindTextLength := Length( Sender.FindText ); |
168 | |||
13 | daniel-mar | 169 | {create a new string to test against} |
170 | StringToTest := copy( fEditor.Text, index+1, FindTextLength ); |
||
171 | |||
22 | daniel-mar | 172 | {assign a case sensitive or case insensitive string |
173 | comparison function to StringComparison depending |
||
174 | on the whether or not the user chose to match case. |
||
175 | The functions assigned are normal VCL functions.} |
||
176 | if frMatchCase in Sender.Options then |
||
177 | StringComparison := CompareStr |
||
178 | else |
||
179 | StringComparison := CompareText; |
||
180 | |||
181 | if (StringComparison( StringToTest, Sender.FindText ) = 0) and |
||
13 | daniel-mar | 182 | TestWholeWord( Sender, copy( fEditor.Text, index, FindTextLength+2 ) ) then |
183 | {with TestWholeWord we pass the value index not index+1 so that it will also |
||
184 | get the previous character. We pass the value FindTextLenght+2 so it |
||
185 | will copy the next character after the test string aswell} |
||
186 | begin {if all true then we've found the text} |
||
187 | {highlight the word} |
||
188 | fEditor.SetFocus; |
||
189 | fEditor.SelStart := index; |
||
190 | fEditor.SelLength := FindTextLength; |
||
191 | |||
192 | {quit the function} |
||
193 | Result := true; {because we've found the word} |
||
194 | Exit; |
||
195 | end |
||
196 | {if we've tried the last character and we can't find it then |
||
197 | display a message saying so.} |
||
198 | else if (index = finish) and (FindActionOnEnd = frcAlertUser) then |
||
22 | daniel-mar | 199 | ShowMessageFmt(S_CANT_BE_FOUND, [Sender.FindText]) |
13 | daniel-mar | 200 | {otherwise if the replace function requested us to keep quiet |
201 | about it then don't display the message to the user} |
||
202 | else if (index = finish) and (FindActionOnEnd = frcAlertReplace) then |
||
203 | FindActionOnEnd := frcEndReached; |
||
204 | |||
205 | Result := false; {didn't find it} |
||
206 | end; |
||
207 | |||
22 | daniel-mar | 208 | procedure TFindReplace.DoFind(dialog: TFindDialog; direction: TFindDirection); |
13 | daniel-mar | 209 | var |
210 | // highlightedText: pChar; |
||
211 | highlightedText: string; |
||
212 | |||
213 | begin |
||
22 | daniel-mar | 214 | if direction = sdDefault then |
215 | begin |
||
216 | if frDown in dialog.Options then |
||
217 | direction := sdForwards |
||
218 | else |
||
219 | direction := sdBackwards; |
||
220 | end; |
||
13 | daniel-mar | 221 | |
222 | {check if there is already some highlighted text. If there is and |
||
223 | this text is the text to search for then it's probably been highlighted |
||
224 | by the previous find operation. In this case, move selStart to |
||
225 | the position after the final character so the find operation won't find |
||
226 | the same word again. If the user chose to search up then move selStart |
||
227 | to the character before the highlighted word} |
||
228 | if fEditor.SelLength > 0 then |
||
229 | begin |
||
230 | (* |
||
231 | GetMem( highlightedText, fEditor.SelLength + 1 ); |
||
232 | fEditor.GetSelTextBuf( highlightedText, fEditor.SelLength+1 ); |
||
233 | *) |
||
234 | highlightedText := fEditor.SelText; |
||
235 | |||
236 | {compare the two strings} |
||
22 | daniel-mar | 237 | if StrIComp( PChar(highlightedText), pChar( dialog.FindText ) ) = 0 then |
13 | daniel-mar | 238 | begin |
22 | daniel-mar | 239 | if direction = sdForwards then |
13 | daniel-mar | 240 | fEditor.selStart := fEditor.SelStart + fEditor.SelLength |
22 | daniel-mar | 241 | else |
242 | fEditor.selStart := fEditor.SelStart - 1; |
||
13 | daniel-mar | 243 | end; |
244 | |||
245 | (* |
||
246 | FreeMem( highlightedText, fEditor.SelLength + 1 ); |
||
247 | *) |
||
248 | end; |
||
249 | |||
250 | {begin the search} |
||
22 | daniel-mar | 251 | if direction = sdForwards then {the user choose to search down} |
13 | daniel-mar | 252 | begin |
253 | {if the user has highlighted a block of text only search |
||
254 | within that block} |
||
255 | if fEditor.SelLength > 0 then |
||
22 | daniel-mar | 256 | FindForwards( dialog, fEditor.selStart, fEditor.selStart + fEditor.selLength ) |
13 | daniel-mar | 257 | {otherwise search the whole of the text} |
22 | daniel-mar | 258 | else |
259 | FindForwards( dialog, fEditor.selStart, fEditor.GetTextLen ); |
||
13 | daniel-mar | 260 | end |
261 | else {the user chose to search up} |
||
262 | begin |
||
263 | {if the user has highlighted a block of text only search |
||
264 | within that block} |
||
265 | if fEditor.SelLength > 0 then |
||
22 | daniel-mar | 266 | FindBackwards( dialog, fEditor.selStart, fEditor.selStart + fEditor.selLength ) |
13 | daniel-mar | 267 | {otherwise search the whole of the text} |
22 | daniel-mar | 268 | else |
269 | FindBackwards( dialog, 0, fEditor.selStart ); |
||
13 | daniel-mar | 270 | end; |
22 | daniel-mar | 271 | end; |
13 | daniel-mar | 272 | |
22 | daniel-mar | 273 | procedure TFindReplace.OnFind(Sender: TObject); |
274 | var |
||
275 | FindDialog: TFindDialog; |
||
276 | begin |
||
277 | FindDialog := Sender as TFindDialog; |
||
278 | DoFind(FindDialog, sdDefault); |
||
13 | daniel-mar | 279 | end; |
280 | |||
22 | daniel-mar | 281 | procedure TFindReplace.OnReplace( Sender: TObject ); |
282 | var |
||
283 | ReplaceDialog: TReplaceDialog; |
||
13 | daniel-mar | 284 | begin |
22 | daniel-mar | 285 | ReplaceDialog := Sender as TReplaceDialog; |
13 | daniel-mar | 286 | |
287 | {set the action on end to alert the function not the user} |
||
288 | FindActionOnEnd := frcAlertReplace; |
||
289 | |||
23 | daniel-mar | 290 | // TODO: UnDo does not work |
291 | |||
13 | daniel-mar | 292 | {now replace the word} |
22 | daniel-mar | 293 | if frReplace in ReplaceDialog.Options then |
294 | DoReplace(ReplaceDialog) |
||
295 | else |
||
296 | DoReplaceAll(ReplaceDialog); |
||
13 | daniel-mar | 297 | |
298 | {reset the action on end to alert the user} |
||
299 | FindActionOnEnd := frcAlertUser; |
||
300 | end; |
||
301 | |||
22 | daniel-mar | 302 | procedure TFindReplace.DoReplace(dialog: TReplaceDialog); |
13 | daniel-mar | 303 | begin |
23 | daniel-mar | 304 | FindForwards( dialog, fEditor.selStart, fEditor.GetTextLen ); |
305 | TryAndReplace(dialog); |
||
306 | FindForwards( dialog, fEditor.selStart, fEditor.GetTextLen ); // Jump to the next occurrence |
||
13 | daniel-mar | 307 | end; |
308 | |||
22 | daniel-mar | 309 | procedure TFindReplace.DoReplaceAll(dialog: TReplaceDialog); |
13 | daniel-mar | 310 | begin |
311 | {see comments for DoReplace} |
||
312 | |||
23 | daniel-mar | 313 | fEditor.BeginUpdate; |
314 | fEditor.BeginUndoBlock; |
||
315 | try |
||
316 | {if the user has highlighted a block of text only replace |
||
317 | within that block} |
||
318 | if fEditor.SelLength > 0 then |
||
13 | daniel-mar | 319 | begin |
23 | daniel-mar | 320 | // TODO: test this functionality |
321 | FindForwards( dialog, fEditor.selStart, fEditor.selStart + fEditor.selLength ); |
||
322 | {keep replacing until we reach the end of the text} |
||
323 | while FindActionOnEnd <> frcEndReached do |
||
324 | begin |
||
325 | {we enclose the TryAndReplace in a loop because there might be more |
||
326 | than one occurence of the word in the line} |
||
327 | while TryAndReplace(dialog) do |
||
328 | FindForwards( dialog, fEditor.selStart, fEditor.selStart + fEditor.selLength ); |
||
329 | |||
22 | daniel-mar | 330 | FindForwards( dialog, fEditor.selStart, fEditor.selStart + fEditor.selLength ); |
23 | daniel-mar | 331 | end; |
332 | end |
||
333 | else {otherwise replace within the whole of the text} |
||
334 | begin |
||
335 | FindForwards( dialog, fEditor.selStart, fEditor.GetTextLen ); |
||
336 | while FindActionOnEnd <> frcEndReached do |
||
337 | begin |
||
338 | while TryAndReplace(dialog) do |
||
339 | FindForwards( dialog, fEditor.selStart, fEditor.GetTextLen ); |
||
13 | daniel-mar | 340 | |
22 | daniel-mar | 341 | FindForwards( dialog, fEditor.selStart, fEditor.GetTextLen ); |
23 | daniel-mar | 342 | end; |
13 | daniel-mar | 343 | end; |
23 | daniel-mar | 344 | finally |
345 | fEditor.EndUpdate; |
||
346 | fEditor.EndUndoBlock; |
||
13 | daniel-mar | 347 | end; |
348 | end; |
||
349 | |||
22 | daniel-mar | 350 | function TFindReplace.TryAndReplace(dialog: TReplaceDialog): boolean; |
13 | daniel-mar | 351 | {returns true if a replacement was made and false otherwise. This is |
352 | so a function can keep calling TryAndReplace until it returns false |
||
353 | since there might be more than one occurence of the word to replace |
||
354 | in the line} |
||
355 | |||
356 | var |
||
357 | LineNumber, ColumnNumber: integer; |
||
358 | |||
23 | daniel-mar | 359 | OldSelStart: integer; {the position of the cursor prior to the text being replaced} |
13 | daniel-mar | 360 | |
361 | |||
362 | begin |
||
363 | {assume no replacement was made} |
||
364 | Result := false; |
||
365 | |||
366 | {check to see if the word was found otherwise we don't add the |
||
367 | replaceText to the editor. That is, only delete the selected text |
||
368 | and insert the replacement text if the end was not reached} |
||
369 | if not (FindActionOnEnd = frcEndReached) then |
||
370 | begin |
||
371 | {get the line number and column number of the cursor which |
||
372 | is needed for string manipulations later. We should do this |
||
373 | before the call to clear selection} |
||
23 | daniel-mar | 374 | |
375 | // TODO: only replace beginning at the selected section / caret, not from beginning of the line!! |
||
376 | LineNumber := fEditor.CaretY-1; |
||
377 | ColumnNumber := fEditor.CaretX-1; |
||
378 | |||
13 | daniel-mar | 379 | {get the position of the cursor prior to the replace operation |
380 | so we cab restore it later} |
||
381 | OldSelStart := fEditor.SelStart; |
||
382 | |||
23 | daniel-mar | 383 | // Note: "fEditor.ClearSelection" can be used to delete the selected text |
13 | daniel-mar | 384 | |
23 | daniel-mar | 385 | // TODO: only replace beginning at the selected section / caret, not from beginning of the line |
386 | // TODO: support "whole word" ? |
||
387 | if frMatchCase in dialog.Options then |
||
388 | fEditor.Lines[LineNumber] := StringReplace(fEditor.Lines[LineNumber], dialog.FindText, dialog.ReplaceText, []) |
||
389 | else |
||
390 | fEditor.Lines[LineNumber] := StringReplace(fEditor.Lines[LineNumber], dialog.FindText, dialog.ReplaceText, [rfIgnoreCase]); |
||
13 | daniel-mar | 391 | |
392 | {set the result to true since we have made a replacement} |
||
393 | Result := true; |
||
394 | |||
395 | {reposition the cursor to the character after the last chracter in |
||
396 | the newly replacing text. This is mainly so we can locate multiple |
||
397 | occurences of the to-be-replaced text in the same line} |
||
22 | daniel-mar | 398 | fEditor.SelStart := oldSelStart + length( dialog.ReplaceText ); |
13 | daniel-mar | 399 | end |
400 | end; |
||
401 | |||
402 | procedure TFindReplace.FindExecute; |
||
403 | begin |
||
404 | fFindDialog.Execute; |
||
405 | end; |
||
406 | |||
407 | procedure TFindReplace.ReplaceExecute; |
||
408 | begin |
||
409 | fReplaceDialog.Execute; |
||
410 | end; |
||
411 | |||
412 | function TFindReplace.TestWholeWord( Sender: TFindDialog; TestString: string ): boolean; |
||
22 | daniel-mar | 413 | var |
414 | FindTextLength: integer; |
||
13 | daniel-mar | 415 | begin |
416 | {assume it's not a whole word} |
||
417 | Result := false; |
||
418 | |||
22 | daniel-mar | 419 | FindTextLength := Length( Sender.FindText ); |
420 | |||
13 | daniel-mar | 421 | {if the user didn't choose whole words only then basically |
422 | we don't care about it so return true} |
||
423 | if not (frWholeWord in Sender.Options) then |
||
424 | begin |
||
425 | Result := true; |
||
426 | Exit; |
||
427 | end; |
||
428 | |||
429 | {Test if the word is a whole word} |
||
430 | {Basically there are 4 cases: ( _ denotes whitespace ) |
||
431 | 1. _word_ |
||
432 | 2. \nword_ |
||
433 | 3. _word\n |
||
434 | 4.\nword\n} |
||
435 | {case 1, note: #9 tab, #$A newline} |
||
436 | if (CharInSet(TestString[1], [' ', #9 ])) and (CharInSet(TestString[FindTextLength + 2], [' ', #9 ])) then |
||
437 | Result := true |
||
438 | {case 2} |
||
439 | else if(TestString[1] = #$A) and (CharInSet(TestString[FindTextLength + 2], [' ', #9 ])) then |
||
440 | Result := true |
||
441 | {case 3, note: #$D end of line} |
||
442 | else if(CharInSet(TestString[1], [' ', #9 ])) and (TestString[FindTextLength + 2] = #$D) then |
||
443 | Result := true |
||
444 | else if (TestString[1] = #$A) and (TestString[FindTextLength + 2] = #$D) then |
||
445 | Result := true |
||
446 | |||
447 | end; |
||
448 | |||
22 | daniel-mar | 449 | procedure TFindReplace.FindContinue; |
450 | begin |
||
451 | if fFindDialog.FindText = '' then |
||
452 | begin |
||
453 | fFindDialog.Options := fFindDialog.Options + [frDown]; // Default direction: down |
||
454 | FindExecute; |
||
455 | end |
||
456 | else |
||
457 | DoFind(fFindDialog, sdDefault); |
||
458 | end; |
||
459 | |||
13 | daniel-mar | 460 | procedure TFindReplace.FindNext; |
461 | begin |
||
22 | daniel-mar | 462 | if fFindDialog.FindText = '' then |
463 | begin |
||
464 | fFindDialog.Options := fFindDialog.Options + [frDown]; |
||
465 | FindExecute; |
||
466 | end |
||
467 | else |
||
468 | DoFind(fFindDialog, sdForwards); |
||
13 | daniel-mar | 469 | end; |
470 | |||
22 | daniel-mar | 471 | procedure TFindReplace.FindPrev; |
13 | daniel-mar | 472 | begin |
473 | if fFindDialog.FindText = '' then |
||
474 | begin |
||
22 | daniel-mar | 475 | fFindDialog.Options := fFindDialog.Options - [frDown]; |
476 | FindExecute; |
||
477 | end |
||
478 | else |
||
479 | DoFind(fFindDialog, sdBackwards); |
||
13 | daniel-mar | 480 | end; |
481 | |||
482 | procedure TFindReplace.GoToLine( LineNumber: integer ); |
||
483 | var |
||
484 | currentLine: integer; |
||
485 | i: integer; |
||
486 | |||
487 | begin |
||
488 | {set the current line to 1} |
||
489 | currentLine := 1; |
||
490 | |||
491 | {go through the whole text looking for the line} |
||
492 | for i := 1 to fEditor.GetTextLen do |
||
493 | begin |
||
494 | if currentLine = LineNumber then |
||
495 | begin |
||
496 | {goto the position corresponding to the line} |
||
497 | fEditor.selStart := i; |
||
498 | fEditor.SetFocus; |
||
499 | {quit the function} |
||
500 | Exit; |
||
501 | end |
||
502 | else if fEditor.Text = #$D then |
||
503 | inc( currentLine ); |
||
504 | end; |
||
505 | |||
506 | end; |
||
507 | |||
22 | daniel-mar | 508 | procedure TFindReplace.CloseDialogs; |
509 | begin |
||
510 | fFindDialog.CloseDialog; |
||
511 | fReplaceDialog.CloseDialog; |
||
512 | end; |
||
513 | |||
13 | daniel-mar | 514 | (* |
515 | procedure Register; |
||
516 | begin |
||
517 | RegisterComponents('Tek-tips', [TFindReplace]); |
||
518 | end; |
||
519 | *) |
||
520 | |||
521 | end. |