Subversion Repositories fastphp

Rev

Rev 67 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. unit FindReplace;
  2.  
  3.   (*
  4.   TSynSearchOption = (ssoMatchCase, ssoWholeWord, ssoBackwards,
  5.     ssoEntireScope, ssoSelectedOnly, ssoReplace, ssoReplaceAll, ssoPrompt);
  6.  
  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.  
  35. interface
  36.  
  37. uses
  38.   Windows, Messages, SysUtils, Classes, Dialogs, SynEdit, System.UITypes;
  39.  
  40. type
  41.   TSynEditFindReplace = class(TComponent)
  42.   private
  43.     fEditor: TSynEdit;
  44.     fReplaceDialog: TReplaceDialog;
  45.     fFindDialog: TFindDialog;
  46.     fAutofocus: boolean;
  47.   protected
  48.     type
  49.       TFindDirection = (sdDefault, sdForwards, sdBackwards);
  50.  
  51.     procedure OnFind(Sender: TObject); virtual;
  52.     procedure OnReplace(Sender: TObject); virtual;
  53.  
  54.     procedure DoFind(dialog: TFindDialog; direction: TFindDirection); overload;
  55.     procedure DoReplace(dialog: TReplaceDialog; direction: TFindDirection);
  56.  
  57.     function GetDirection(dialog: TFindDialog): TFindDirection;
  58.  
  59.   public
  60.     constructor Create(AOwner: TComponent); override;
  61.  
  62.     property FindDialog: TFindDialog read fFindDialog;
  63.     property ReplaceDialog: TReplaceDialog read fReplaceDialog;
  64.  
  65.     procedure CloseDialogs;
  66.  
  67.     procedure FindExecute;
  68.     procedure ReplaceExecute;
  69.  
  70.     procedure FindContinue;
  71.     procedure FindNext;
  72.     procedure FindPrev;
  73.  
  74.     procedure GoToLine(LineNumber: integer);
  75.  
  76.   published
  77.     property Editor: TSynEdit read fEditor write fEditor;
  78.     property Autofocus: boolean read fAutofocus write fAutofocus;
  79.   end;
  80.  
  81. implementation
  82.  
  83. uses
  84.   SynEditTypes;
  85.  
  86. constructor TSynEditFindReplace.Create(AOwner: TComponent);
  87. begin
  88.   inherited Create(AOwner);
  89.  
  90.   fFindDialog := TFindDialog.Create(Self);
  91.   fFindDialog.OnFind := OnFind;
  92.  
  93.   fReplaceDialog := TReplaceDialog.Create(Self);
  94.   fReplaceDialog.OnReplace := OnReplace;
  95.   fReplaceDialog.OnFind := OnFind;
  96.   fReplaceDialog.Options := fReplaceDialog.Options + [frHideWholeWord]; // TODO: currently not supported (see below)
  97. end;
  98.  
  99. function TSynEditFindReplace.GetDirection(dialog: TFindDialog): TFindDirection;
  100. begin
  101.   if frDown in dialog.Options then
  102.     result := sdForwards
  103.   else
  104.     result := sdBackwards;
  105. end;
  106.  
  107. procedure TSynEditFindReplace.DoFind(dialog: TFindDialog; direction: TFindDirection);
  108. var
  109.   opt: TSynSearchOptions;
  110.   found: boolean;
  111. begin
  112.   if direction = sdDefault then direction := GetDirection(dialog);
  113.  
  114.   if fEditor.SelAvail then
  115.   begin
  116.     if direction = sdForwards then
  117.     begin
  118.       fEditor.SelStart := fEditor.SelStart + 1;
  119.       fEditor.SelLength := 0;
  120.     end
  121.     else
  122.     begin
  123.       // Links von Selektion springen
  124.       fEditor.SelLength := 0;
  125.     end;
  126.   end;
  127.  
  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?
  137.  
  138.   found := fEditor.SearchReplace(dialog.FindText, '', opt) > 0;
  139.  
  140.   if not found then
  141.   begin
  142.     // TODO: If single replace was chosen, behave like Notepad and select the last replaced word
  143.     if direction = sdForwards then
  144.       MessageDlg('End of document reached.', mtInformation, [mbOk], 0)
  145.     else
  146.       MessageDlg('Begin of document reached.', mtInformation, [mbOk], 0);
  147.   end;
  148.  
  149.   if fAutofocus and fEditor.CanFocus then fEditor.SetFocus;
  150. end;
  151.  
  152. procedure TSynEditFindReplace.DoReplace(dialog: TReplaceDialog; direction: TFindDirection);
  153. var
  154.   opt: TSynSearchOptions;
  155.   numReplacements: integer;
  156. begin
  157.   try
  158.     if direction = sdDefault then direction := GetDirection(dialog);
  159.  
  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?
  169.  
  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;
  196.   finally
  197.     if fAutofocus and fEditor.CanFocus then fEditor.SetFocus;
  198.   end;
  199. end;
  200.  
  201. procedure TSynEditFindReplace.OnFind(Sender: TObject);
  202. begin
  203.   DoFind(Sender as TFindDialog, sdDefault);
  204. end;
  205.  
  206. procedure TSynEditFindReplace.OnReplace(Sender: TObject);
  207. begin
  208.   DoReplace(Sender as TReplaceDialog, sdDefault);
  209. end;
  210.  
  211. procedure TSynEditFindReplace.FindExecute;
  212. begin
  213.   fFindDialog.Execute;
  214. end;
  215.  
  216. procedure TSynEditFindReplace.ReplaceExecute;
  217. begin
  218.   fReplaceDialog.Execute;
  219. end;
  220.  
  221. procedure TSynEditFindReplace.FindContinue;
  222. begin
  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.  
  232. procedure TSynEditFindReplace.FindNext;
  233. begin
  234.   if fFindDialog.FindText = '' then
  235.   begin
  236.     fFindDialog.Options := fFindDialog.Options + [frDown];
  237.     FindExecute;
  238.   end
  239.   else
  240.     DoFind(fFindDialog, sdForwards);
  241. end;
  242.  
  243. procedure TSynEditFindReplace.FindPrev;
  244. begin
  245.   if fFindDialog.FindText = '' then
  246.   begin
  247.     fFindDialog.Options := fFindDialog.Options - [frDown];
  248.     FindExecute;
  249.   end
  250.   else
  251.     DoFind(fFindDialog, sdBackwards);
  252. end;
  253.  
  254. procedure TSynEditFindReplace.GoToLine(LineNumber: integer);
  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
  270.       inc(currentLine);
  271.   end;
  272. end;
  273.  
  274. procedure TSynEditFindReplace.CloseDialogs;
  275. begin
  276.   fFindDialog.CloseDialog;
  277.   fReplaceDialog.CloseDialog;
  278. end;
  279.  
  280. end.
  281.