Subversion Repositories fastphp

Rev

Rev 83 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 83 Rev 88
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, System.UITypes;
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
  bakSelLenght: Integer;
-
 
157
  stmp: string;
-
 
158
  bakSelStart: Integer;
156
begin
159
begin
157
  try
160
  try
158
    if direction = sdDefault then direction := GetDirection(dialog);
161
    if direction = sdDefault then direction := GetDirection(dialog);
159
 
162
 
160
    opt := [];
163
    opt := [];
161
    if frMatchCase in dialog.Options then Include(opt, ssoMatchCase);
164
    if frMatchCase in dialog.Options then Include(opt, ssoMatchCase);
162
    if frWholeWord in dialog.Options then Include(opt, ssoWholeWord);
165
    if frWholeWord in dialog.Options then Include(opt, ssoWholeWord);
163
    if frReplace in dialog.Options then Include(opt, ssoReplace);
166
    if frReplace in dialog.Options then Include(opt, ssoReplace);
164
    if frReplaceAll in dialog.Options then Include(opt, ssoReplaceAll);
167
    if frReplaceAll in dialog.Options then Include(opt, ssoReplaceAll);
165
    if direction = sdBackwards then Include(opt, ssoBackwards);
168
    if direction = sdBackwards then Include(opt, ssoBackwards);
166
    Include(opt, ssoPrompt); // TODO: test. geht nicht?
169
    Include(opt, ssoPrompt); // TODO: test. geht nicht?
167
    if fEditor.SelAvail then Include(opt, ssoSelectedOnly);
170
    if fEditor.SelAvail then Include(opt, ssoSelectedOnly);
168
    Exclude(opt, ssoEntireScope); // TODO: ok?
171
    Exclude(opt, ssoEntireScope); // TODO: ok?
169
 
172
 
170
    if not (ssoReplaceAll in opt) then
173
    if not (ssoReplaceAll in opt) then
171
    begin
174
    begin
172
      if fEditor.SelLength = 0 then
175
      if fEditor.SelLength = 0 then
173
      begin
176
      begin
174
        DoFind(dialog, sdForwards);
177
        DoFind(dialog, sdForwards);
175
        exit;
178
        exit;
176
      end;
179
      end;
177
    end;
180
    end;
178
 
181
 
179
    fEditor.BeginUpdate; // TODO: geht nicht?
182
    fEditor.BeginUpdate; // TODO: geht nicht?
180
    //fEditor.BeginUndoBlock;
183
    //fEditor.BeginUndoBlock;
181
    try
184
    try
-
 
185
      bakSelLenght := 0; // avoid compiler warning
-
 
186
      if ssoReplaceAll in opt then
-
 
187
      begin
-
 
188
        // Remember the selection length
-
 
189
        bakSelLenght := fEditor.SelLength;
-
 
190
        //bakSelStart := fEditor.SelStart;
-
 
191
 
-
 
192
        // Remember the selection start (we don't backup fEditor.SelStart, since the replacement might change the location)!
-
 
193
        // We assume that character #1 will not be in a text file!
-
 
194
        stmp := fEditor.Text;
-
 
195
        Insert(chr(1), stmp, fEditor.SelStart+1);
-
 
196
        //showmessage(inttostr(ord(stmp[fEditor.SelStart-1])));
-
 
197
        //showmessage(inttostr(ord(stmp[fEditor.SelStart])));
-
 
198
        //showmessage(inttostr(ord(stmp[fEditor.SelStart+1])));
-
 
199
        fEditor.Text := stmp;
-
 
200
 
-
 
201
        // When the user presses "Replace all", then we want to replace from the very beginning!
-
 
202
        fEditor.SelStart := 0;
-
 
203
        fEditor.SelLength := 0;
-
 
204
      end;
-
 
205
 
182
      numReplacements := fEditor.SearchReplace(dialog.FindText, dialog.ReplaceText, opt);
206
      numReplacements := fEditor.SearchReplace(dialog.FindText, dialog.ReplaceText, opt);
-
 
207
 
-
 
208
      if ssoReplaceAll in opt then
-
 
209
      begin
-
 
210
        stmp := fEditor.Text;
-
 
211
        bakSelStart := AnsiPos(chr(1), stmp)-1;
-
 
212
        Delete(stmp, bakSelStart+1, 1);
-
 
213
        fEditor.Text := stmp;
-
 
214
 
-
 
215
        fEditor.SelStart := bakSelStart;
-
 
216
        fEditor.SelLength := bakSelLenght;
-
 
217
 
-
 
218
        // TODO: The SelStart and SelLength were kept, but the scrollposition did not. What can we do?
-
 
219
      end;
183
    finally
220
    finally
184
      //fEditor.EndUndoBlock;
221
      //fEditor.EndUndoBlock;
185
      fEditor.EndUpdate;
222
      fEditor.EndUpdate;
186
    end;
223
    end;
187
 
224
 
188
    if not (ssoReplaceAll in opt) then
225
    if not (ssoReplaceAll in opt) then
189
    begin
226
    begin
190
      DoFind(dialog, sdForwards);
227
      DoFind(dialog, sdForwards);
191
    end
228
    end
192
    else
229
    else
193
    begin
230
    begin
194
      ShowMessageFmt('%d replaced.', [numReplacements]);
231
      ShowMessageFmt('%d replaced.', [numReplacements]);
195
    end;
232
    end;
196
  finally
233
  finally
197
    if fAutofocus and fEditor.CanFocus then fEditor.SetFocus;
234
    if fAutofocus and fEditor.CanFocus then fEditor.SetFocus;
198
  end;
235
  end;
199
end;
236
end;
200
 
237
 
201
procedure TSynEditFindReplace.OnFind(Sender: TObject);
238
procedure TSynEditFindReplace.OnFind(Sender: TObject);
202
begin
239
begin
203
  DoFind(Sender as TFindDialog, sdDefault);
240
  DoFind(Sender as TFindDialog, sdDefault);
204
end;
241
end;
205
 
242
 
206
procedure TSynEditFindReplace.OnReplace(Sender: TObject);
243
procedure TSynEditFindReplace.OnReplace(Sender: TObject);
207
begin
244
begin
208
  DoReplace(Sender as TReplaceDialog, sdDefault);
245
  DoReplace(Sender as TReplaceDialog, sdDefault);
209
end;
246
end;
210
 
247
 
211
procedure TSynEditFindReplace.FindExecute;
248
procedure TSynEditFindReplace.FindExecute;
212
begin
249
begin
213
  fFindDialog.Execute;
250
  fFindDialog.Execute;
214
end;
251
end;
215
 
252
 
216
procedure TSynEditFindReplace.ReplaceExecute;
253
procedure TSynEditFindReplace.ReplaceExecute;
217
begin
254
begin
218
  fReplaceDialog.Execute;
255
  fReplaceDialog.Execute;
219
end;
256
end;
220
 
257
 
221
procedure TSynEditFindReplace.FindContinue;
258
procedure TSynEditFindReplace.FindContinue;
222
begin
259
begin
223
  if fFindDialog.FindText = '' then
260
  if fFindDialog.FindText = '' then
224
  begin
261
  begin
225
    fFindDialog.Options := fFindDialog.Options + [frDown]; // Default direction: down
262
    fFindDialog.Options := fFindDialog.Options + [frDown]; // Default direction: down
226
    FindExecute;
263
    FindExecute;
227
  end
264
  end
228
  else
265
  else
229
    DoFind(fFindDialog, sdDefault);
266
    DoFind(fFindDialog, sdDefault);
230
end;
267
end;
231
 
268
 
232
procedure TSynEditFindReplace.FindNext;
269
procedure TSynEditFindReplace.FindNext;
233
begin
270
begin
234
  if fFindDialog.FindText = '' then
271
  if fFindDialog.FindText = '' then
235
  begin
272
  begin
236
    fFindDialog.Options := fFindDialog.Options + [frDown];
273
    fFindDialog.Options := fFindDialog.Options + [frDown];
237
    FindExecute;
274
    FindExecute;
238
  end
275
  end
239
  else
276
  else
240
    DoFind(fFindDialog, sdForwards);
277
    DoFind(fFindDialog, sdForwards);
241
end;
278
end;
242
 
279
 
243
procedure TSynEditFindReplace.FindPrev;
280
procedure TSynEditFindReplace.FindPrev;
244
begin
281
begin
245
  if fFindDialog.FindText = '' then
282
  if fFindDialog.FindText = '' then
246
  begin
283
  begin
247
    fFindDialog.Options := fFindDialog.Options - [frDown];
284
    fFindDialog.Options := fFindDialog.Options - [frDown];
248
    FindExecute;
285
    FindExecute;
249
  end
286
  end
250
  else
287
  else
251
    DoFind(fFindDialog, sdBackwards);
288
    DoFind(fFindDialog, sdBackwards);
252
end;
289
end;
253
 
290
 
254
procedure TSynEditFindReplace.GoToLine(LineNumber: integer);
291
procedure TSynEditFindReplace.GoToLine(LineNumber: integer);
255
var
292
var
256
  currentLine: integer;
293
  currentLine: integer;
257
  i: integer;
294
  i: integer;
258
begin
295
begin
259
  currentLine := 1;
296
  currentLine := 1;
260
 
297
 
261
  for i := 1 to fEditor.GetTextLen do
298
  for i := 1 to fEditor.GetTextLen do
262
  begin
299
  begin
263
    if currentLine = LineNumber then
300
    if currentLine = LineNumber then
264
    begin
301
    begin
265
      fEditor.selStart := i;
302
      fEditor.selStart := i;
266
      fEditor.SetFocus;
303
      fEditor.SetFocus;
267
      Exit;
304
      Exit;
268
    end
305
    end
269
    else if fEditor.Text = #$D then
306
    else if fEditor.Text = #$D then
270
      inc(currentLine);
307
      inc(currentLine);
271
  end;
308
  end;
272
end;
309
end;
273
 
310
 
274
procedure TSynEditFindReplace.CloseDialogs;
311
procedure TSynEditFindReplace.CloseDialogs;
275
begin
312
begin
276
  fFindDialog.CloseDialog;
313
  fFindDialog.CloseDialog;
277
  fReplaceDialog.CloseDialog;
314
  fReplaceDialog.CloseDialog;
278
end;
315
end;
279
 
316
 
280
end.
317
end.
281
 
318