Subversion Repositories fastphp

Rev

Rev 67 | 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
83 daniel-mar 38
  Windows, Messages, SysUtils, Classes, Dialogs, SynEdit, System.UITypes;
13 daniel-mar 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.