Subversion Repositories fastphp

Rev

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