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