KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > texteditor > FindReplaceDialog


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.ui.texteditor;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.HashSet JavaDoc;
15 import java.util.List JavaDoc;
16 import java.util.Set JavaDoc;
17 import java.util.regex.PatternSyntaxException JavaDoc;
18
19 import org.eclipse.swt.SWT;
20 import org.eclipse.swt.custom.BusyIndicator;
21 import org.eclipse.swt.events.ModifyEvent;
22 import org.eclipse.swt.events.ModifyListener;
23 import org.eclipse.swt.events.SelectionAdapter;
24 import org.eclipse.swt.events.SelectionEvent;
25 import org.eclipse.swt.events.SelectionListener;
26 import org.eclipse.swt.events.ShellAdapter;
27 import org.eclipse.swt.events.ShellEvent;
28 import org.eclipse.swt.graphics.Point;
29 import org.eclipse.swt.graphics.Rectangle;
30 import org.eclipse.swt.layout.GridData;
31 import org.eclipse.swt.layout.GridLayout;
32 import org.eclipse.swt.widgets.Button;
33 import org.eclipse.swt.widgets.Combo;
34 import org.eclipse.swt.widgets.Composite;
35 import org.eclipse.swt.widgets.Control;
36 import org.eclipse.swt.widgets.Group;
37 import org.eclipse.swt.widgets.Label;
38 import org.eclipse.swt.widgets.Shell;
39
40 import org.eclipse.jface.dialogs.Dialog;
41 import org.eclipse.jface.dialogs.IDialogSettings;
42 import org.eclipse.jface.fieldassist.ComboContentAdapter;
43 import org.eclipse.jface.fieldassist.FieldDecoration;
44 import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
45 import org.eclipse.jface.resource.JFaceColors;
46
47 import org.eclipse.jface.text.IFindReplaceTarget;
48 import org.eclipse.jface.text.IFindReplaceTargetExtension;
49 import org.eclipse.jface.text.IFindReplaceTargetExtension3;
50 import org.eclipse.jface.text.IRegion;
51 import org.eclipse.jface.text.Region;
52 import org.eclipse.jface.text.TextUtilities;
53
54 import org.eclipse.ui.IEditorPart;
55 import org.eclipse.ui.IWorkbenchPage;
56 import org.eclipse.ui.IWorkbenchWindow;
57 import org.eclipse.ui.PlatformUI;
58 import org.eclipse.ui.fieldassist.ContentAssistCommandAdapter;
59 import org.eclipse.ui.internal.texteditor.NLSUtility;
60 import org.eclipse.ui.internal.texteditor.SWTUtil;
61 import org.eclipse.ui.internal.texteditor.TextEditorPlugin;
62
63
64 /**
65  * Find/Replace dialog. The dialog is opened on a particular
66  * target but can be re-targeted. Internally used by the <code>FindReplaceAction</code>
67  */

68 class FindReplaceDialog extends Dialog {
69
70     /**
71      * Updates the find replace dialog on activation changes.
72      */

73     class ActivationListener extends ShellAdapter {
74         /*
75          * @see ShellListener#shellActivated(ShellEvent)
76          */

77         public void shellActivated(ShellEvent e) {
78             fActiveShell= (Shell)e.widget;
79             updateButtonState();
80
81             if (fGiveFocusToFindField && getShell() == fActiveShell && okToUse(fFindField))
82                 fFindField.setFocus();
83
84         }
85
86         /*
87          * @see ShellListener#shellDeactivated(ShellEvent)
88          */

89         public void shellDeactivated(ShellEvent e) {
90             fGiveFocusToFindField= false;
91
92             storeSettings();
93
94             fGlobalRadioButton.setSelection(true);
95             fSelectedRangeRadioButton.setSelection(false);
96             fUseSelectedLines= false;
97
98             if (fTarget != null && (fTarget instanceof IFindReplaceTargetExtension))
99                 ((IFindReplaceTargetExtension) fTarget).setScope(null);
100
101             fOldScope= null;
102
103             fActiveShell= null;
104             updateButtonState();
105         }
106     }
107
108     /**
109      * Modify listener to update the search result in case of incremental search.
110      * @since 2.0
111      */

112     private class FindModifyListener implements ModifyListener {
113
114         /*
115          * @see ModifyListener#modifyText(ModifyEvent)
116          */

117         public void modifyText(ModifyEvent e) {
118             if (isIncrementalSearch() && !isRegExSearchAvailableAndChecked()) {
119                 if (fFindField.getText().equals("") && fTarget != null) { //$NON-NLS-1$
120
// empty selection at base location
121
int offset= fIncrementalBaseLocation.x;
122
123                     if (isForwardSearch() && !fNeedsInitialFindBeforeReplace || !isForwardSearch() && fNeedsInitialFindBeforeReplace)
124                         offset= offset + fIncrementalBaseLocation.y;
125
126                     fNeedsInitialFindBeforeReplace= false;
127                     findAndSelect(offset, "", isForwardSearch(), isCaseSensitiveSearch(), isWholeWordSearch(), isRegExSearchAvailableAndChecked()); //$NON-NLS-1$
128
} else {
129                     performSearch(false);
130                 }
131             }
132
133             updateButtonState(!isIncrementalSearch());
134         }
135     }
136
137     /** The size of the dialogs search history. */
138     private static final int HISTORY_SIZE= 5;
139
140     private Point fIncrementalBaseLocation;
141     private boolean fWrapInit, fCaseInit, fWholeWordInit, fForwardInit, fGlobalInit, fIncrementalInit;
142     /**
143      * Tells whether an initial find operation is needed
144      * before the replace operation.
145      * @since 3.0
146      */

147     private boolean fNeedsInitialFindBeforeReplace;
148     /**
149      * Initial value for telling whether the search string is a regular expression.
150      * @since 3.0
151      */

152     boolean fIsRegExInit;
153
154     private List JavaDoc fFindHistory;
155     private List JavaDoc fReplaceHistory;
156     private IRegion fOldScope;
157
158     private boolean fIsTargetEditable;
159     private IFindReplaceTarget fTarget;
160     private Shell fParentShell;
161     private Shell fActiveShell;
162
163     private final ActivationListener fActivationListener= new ActivationListener();
164     private final ModifyListener fFindModifyListener= new FindModifyListener();
165
166     private Label fReplaceLabel, fStatusLabel;
167     private Button fForwardRadioButton, fGlobalRadioButton, fSelectedRangeRadioButton;
168     private Button fCaseCheckBox, fWrapCheckBox, fWholeWordCheckBox, fIncrementalCheckBox;
169
170     /**
171      * Checkbox for selecting whether the search string is a regular expression.
172      * @since 3.0
173      */

174     private Button fIsRegExCheckBox;
175
176     private Button fReplaceSelectionButton, fReplaceFindButton, fFindNextButton, fReplaceAllButton;
177     private Combo fFindField, fReplaceField;
178     
179     /**
180      * Find and replace command adapters.
181      * @since 3.3
182      */

183     private ContentAssistCommandAdapter fContentAssistFindField, fContentAssistReplaceField;
184
185     private Rectangle fDialogPositionInit;
186
187     private IDialogSettings fDialogSettings;
188     /**
189      * Tells whether the target supports regular expressions.
190      * <code>true</code> if the target supports regular expressions
191      * @since 3.0
192      */

193     private boolean fIsTargetSupportingRegEx;
194     /**
195      * Tells whether fUseSelectedLines radio is checked.
196      * @since 3.0
197      */

198     private boolean fUseSelectedLines;
199     /**
200      * <code>true</code> if the find field should receive focus the next time
201      * the dialog is activated, <code>false</code> otherwise.
202      * @since 3.0
203      */

204     private boolean fGiveFocusToFindField= true;
205
206
207     /**
208      * Creates a new dialog with the given shell as parent.
209      * @param parentShell the parent shell
210      */

211     public FindReplaceDialog(Shell parentShell) {
212         super(parentShell);
213
214         fParentShell= null;
215         fTarget= null;
216
217         fDialogPositionInit= null;
218         fFindHistory= new ArrayList JavaDoc(HISTORY_SIZE - 1);
219         fReplaceHistory= new ArrayList JavaDoc(HISTORY_SIZE - 1);
220
221         fWrapInit= false;
222         fCaseInit= false;
223         fIsRegExInit= false;
224         fWholeWordInit= false;
225         fIncrementalInit= false;
226         fGlobalInit= true;
227         fForwardInit= true;
228
229         readConfiguration();
230
231         setShellStyle(SWT.CLOSE | SWT.MODELESS | SWT.BORDER | SWT.TITLE | SWT.RESIZE);
232         setBlockOnOpen(false);
233     }
234
235     /**
236      * Returns this dialog's parent shell.
237      * @return the dialog's parent shell
238      */

239     public Shell getParentShell() {
240         return super.getParentShell();
241     }
242
243
244     /**
245      * Returns <code>true</code> if control can be used.
246      *
247      * @param control the control to be checked
248      * @return <code>true</code> if control can be used
249      */

250     private boolean okToUse(Control control) {
251         return control != null && !control.isDisposed();
252     }
253
254     /*
255      * @see org.eclipse.jface.window.Window#create()
256      */

257     public void create() {
258
259         super.create();
260
261         Shell shell= getShell();
262         shell.addShellListener(fActivationListener);
263
264         // set help context
265
PlatformUI.getWorkbench().getHelpSystem().setHelp(shell, IAbstractTextEditorHelpContextIds.FIND_REPLACE_DIALOG);
266
267         // fill in combo contents
268
fFindField.removeModifyListener(fFindModifyListener);
269         updateCombo(fFindField, fFindHistory);
270         fFindField.addModifyListener(fFindModifyListener);
271         updateCombo(fReplaceField, fReplaceHistory);
272
273         // get find string
274
initFindStringFromSelection();
275
276         // set dialog position
277
if (fDialogPositionInit != null)
278             shell.setBounds(fDialogPositionInit);
279
280         shell.setText(EditorMessages.FindReplace_title);
281         // shell.setImage(null);
282
}
283     
284     /**
285      * Create the button section of the find/replace dialog.
286      *
287      * @param parent the parent composite
288      * @return the button section
289      */

290     private Composite createButtonSection(Composite parent) {
291
292         Composite panel= new Composite(parent, SWT.NONE);
293         GridLayout layout= new GridLayout();
294         layout.numColumns= -2; // this is intended
295
panel.setLayout(layout);
296
297         fFindNextButton= makeButton(panel, EditorMessages.FindReplace_FindNextButton_label, 102, true, new SelectionAdapter() {
298             public void widgetSelected(SelectionEvent e) {
299                 if (isIncrementalSearch() && !isRegExSearchAvailableAndChecked())
300                     initIncrementalBaseLocation();
301
302                 fNeedsInitialFindBeforeReplace= false;
303                 performSearch();
304                 updateFindHistory();
305                 fFindNextButton.setFocus();
306             }
307         });
308         setGridData(fFindNextButton, SWT.FILL, true, SWT.FILL, false);
309
310         fReplaceFindButton= makeButton(panel, EditorMessages.FindReplace_ReplaceFindButton_label, 103, false, new SelectionAdapter() {
311             public void widgetSelected(SelectionEvent e) {
312                 if (fNeedsInitialFindBeforeReplace)
313                     performSearch();
314                 if (performReplaceSelection())
315                     performSearch();
316                 updateFindAndReplaceHistory();
317                 fReplaceFindButton.setFocus();
318             }
319         });
320         setGridData(fReplaceFindButton, SWT.FILL, false, SWT.FILL, false);
321
322         fReplaceSelectionButton= makeButton(panel, EditorMessages.FindReplace_ReplaceSelectionButton_label, 104, false, new SelectionAdapter() {
323             public void widgetSelected(SelectionEvent e) {
324                 if (fNeedsInitialFindBeforeReplace)
325                     performSearch();
326                 performReplaceSelection();
327                 updateFindAndReplaceHistory();
328                 fFindNextButton.setFocus();
329             }
330         });
331         setGridData(fReplaceSelectionButton, SWT.FILL, false, SWT.FILL, false);
332
333         fReplaceAllButton= makeButton(panel, EditorMessages.FindReplace_ReplaceAllButton_label, 105, false, new SelectionAdapter() {
334             public void widgetSelected(SelectionEvent e) {
335                 performReplaceAll();
336                 updateFindAndReplaceHistory();
337                 fFindNextButton.setFocus();
338             }
339         });
340         setGridData(fReplaceAllButton, SWT.FILL, true, SWT.FILL, false);
341
342         // Make the all the buttons the same size as the Remove Selection button.
343
fReplaceAllButton.setEnabled(isEditable());
344
345         return panel;
346     }
347
348     /**
349      * Creates the options configuration section of the find replace dialog.
350      *
351      * @param parent the parent composite
352      * @return the options configuration section
353      */

354     private Composite createConfigPanel(Composite parent) {
355
356         Composite panel= new Composite(parent, SWT.NONE);
357         GridLayout layout= new GridLayout();
358         layout.numColumns= 2;
359         layout.makeColumnsEqualWidth= true;
360         panel.setLayout(layout);
361
362         Composite directionGroup= createDirectionGroup(panel);
363         setGridData(directionGroup, SWT.FILL, true, SWT.FILL, false);
364         
365         Composite scopeGroup= createScopeGroup(panel);
366         setGridData(scopeGroup, SWT.FILL, true, SWT.FILL, false);
367
368         Composite optionsGroup= createOptionsGroup(panel);
369         setGridData(optionsGroup, SWT.FILL, true, SWT.FILL, true);
370         ((GridData)optionsGroup.getLayoutData()).horizontalSpan= 2;
371
372         return panel;
373     }
374
375     /*
376      * @see org.eclipse.jface.window.Window#createContents(org.eclipse.swt.widgets.Composite)
377      */

378     protected Control createContents(Composite parent) {
379
380         Composite panel= new Composite(parent, SWT.NULL);
381         GridLayout layout= new GridLayout();
382         layout.numColumns= 1;
383         layout.makeColumnsEqualWidth= true;
384         panel.setLayout(layout);
385         panel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
386
387         Composite inputPanel= createInputPanel(panel);
388         setGridData(inputPanel, SWT.FILL, true, SWT.TOP, false);
389
390         Composite configPanel= createConfigPanel(panel);
391         setGridData(configPanel, SWT.FILL, true, SWT.TOP, true);
392
393         Composite buttonPanelB= createButtonSection(panel);
394         setGridData(buttonPanelB, SWT.RIGHT, true, SWT.BOTTOM, false);
395
396         Composite statusBar= createStatusAndCloseButton(panel);
397         setGridData(statusBar, SWT.FILL, true, SWT.BOTTOM, false);
398
399         updateButtonState();
400
401         applyDialogFont(panel);
402
403         return panel;
404     }
405
406     private void setContentAssistsEnablement(boolean enable) {
407         fContentAssistFindField.setEnabled(enable);
408         fContentAssistReplaceField.setEnabled(enable);
409     }
410
411     /**
412      * Creates the direction defining part of the options defining section
413      * of the find replace dialog.
414      *
415      * @param parent the parent composite
416      * @return the direction defining part
417      */

418     private Composite createDirectionGroup(Composite parent) {
419
420         Composite panel= new Composite(parent, SWT.NONE);
421         GridLayout layout= new GridLayout();
422         layout.marginWidth= 0;
423         layout.marginHeight= 0;
424         panel.setLayout(layout);
425
426         Group group= new Group(panel, SWT.SHADOW_ETCHED_IN);
427         group.setText(EditorMessages.FindReplace_Direction);
428         GridLayout groupLayout= new GridLayout();
429         group.setLayout(groupLayout);
430         group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
431
432         SelectionListener selectionListener= new SelectionListener() {
433             public void widgetSelected(SelectionEvent e) {
434                 if (isIncrementalSearch() && !isRegExSearchAvailableAndChecked())
435                     initIncrementalBaseLocation();
436             }
437
438             public void widgetDefaultSelected(SelectionEvent e) {
439             }
440         };
441
442         fForwardRadioButton= new Button(group, SWT.RADIO | SWT.LEFT);
443         fForwardRadioButton.setText(EditorMessages.FindReplace_ForwardRadioButton_label);
444         setGridData(fForwardRadioButton, SWT.LEFT, false, SWT.CENTER, false);
445         fForwardRadioButton.addSelectionListener(selectionListener);
446
447         Button backwardRadioButton= new Button(group, SWT.RADIO | SWT.LEFT);
448         backwardRadioButton.setText(EditorMessages.FindReplace_BackwardRadioButton_label);
449         setGridData(backwardRadioButton, SWT.LEFT, false, SWT.CENTER, false);
450         backwardRadioButton.addSelectionListener(selectionListener);
451
452         backwardRadioButton.setSelection(!fForwardInit);
453         fForwardRadioButton.setSelection(fForwardInit);
454
455         return panel;
456     }
457
458     /**
459      * Creates the scope defining part of the find replace dialog.
460      *
461      * @param parent the parent composite
462      * @return the scope defining part
463      * @since 2.0
464      */

465     private Composite createScopeGroup(Composite parent) {
466
467         Composite panel= new Composite(parent, SWT.NONE);
468         GridLayout layout= new GridLayout();
469         layout.marginWidth= 0;
470         layout.marginHeight= 0;
471         panel.setLayout(layout);
472
473         Group group= new Group(panel, SWT.SHADOW_ETCHED_IN);
474         group.setText(EditorMessages.FindReplace_Scope);
475         GridLayout groupLayout= new GridLayout();
476         group.setLayout(groupLayout);
477         group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
478
479         fGlobalRadioButton= new Button(group, SWT.RADIO | SWT.LEFT);
480         fGlobalRadioButton.setText(EditorMessages.FindReplace_GlobalRadioButton_label);
481         setGridData(fGlobalRadioButton, SWT.LEFT, false, SWT.CENTER, false);
482         fGlobalRadioButton.setSelection(fGlobalInit);
483         fGlobalRadioButton.addSelectionListener(new SelectionListener() {
484             public void widgetSelected(SelectionEvent e) {
485                 if (!fGlobalRadioButton.getSelection() || !fUseSelectedLines)
486                     return;
487                 fUseSelectedLines= false;
488                 useSelectedLines(false);
489             }
490
491             public void widgetDefaultSelected(SelectionEvent e) {
492             }
493         });
494
495         fSelectedRangeRadioButton= new Button(group, SWT.RADIO | SWT.LEFT);
496         fSelectedRangeRadioButton.setText(EditorMessages.FindReplace_SelectedRangeRadioButton_label);
497         setGridData(fSelectedRangeRadioButton, SWT.LEFT, false, SWT.CENTER, false);
498         fSelectedRangeRadioButton.setSelection(!fGlobalInit);
499         fUseSelectedLines= !fGlobalInit;
500         fSelectedRangeRadioButton.addSelectionListener(new SelectionListener() {
501             public void widgetSelected(SelectionEvent e) {
502                 if (!fSelectedRangeRadioButton.getSelection() || fUseSelectedLines)
503                     return;
504                 fUseSelectedLines= true;
505                 useSelectedLines(true);
506             }
507
508             public void widgetDefaultSelected(SelectionEvent e) {
509             }
510         });
511
512         return panel;
513     }
514
515     /**
516      * Tells the dialog to perform searches only in the scope given by the actually selected lines.
517      * @param selectedLines <code>true</code> if selected lines should be used
518      * @since 2.0
519      */

520     private void useSelectedLines(boolean selectedLines) {
521         if (isIncrementalSearch() && !isRegExSearchAvailableAndChecked())
522             initIncrementalBaseLocation();
523
524         if (fTarget == null || !(fTarget instanceof IFindReplaceTargetExtension))
525             return;
526
527         IFindReplaceTargetExtension extensionTarget= (IFindReplaceTargetExtension) fTarget;
528
529         if (selectedLines) {
530
531             IRegion scope;
532             if (fOldScope == null) {
533                 Point lineSelection= extensionTarget.getLineSelection();
534                 scope= new Region(lineSelection.x, lineSelection.y);
535             } else {
536                 scope= fOldScope;
537                 fOldScope= null;
538             }
539
540             int offset= isForwardSearch()
541                 ? scope.getOffset()
542                 : scope.getOffset() + scope.getLength();
543
544             extensionTarget.setSelection(offset, 0);
545             extensionTarget.setScope(scope);
546         } else {
547             fOldScope= extensionTarget.getScope();
548             extensionTarget.setScope(null);
549         }
550     }
551
552     /**
553      * Creates the panel where the user specifies the text to search
554      * for and the optional replacement text.
555      *
556      * @param parent the parent composite
557      * @return the input panel
558      */

559     private Composite createInputPanel(Composite parent) {
560
561         ModifyListener listener= new ModifyListener() {
562             public void modifyText(ModifyEvent e) {
563                 updateButtonState();
564             }
565         };
566
567         Composite panel= new Composite(parent, SWT.NULL);
568         GridLayout layout= new GridLayout();
569         layout.numColumns= 2;
570         panel.setLayout(layout);
571
572         Label findLabel= new Label(panel, SWT.LEFT);
573         findLabel.setText(EditorMessages.FindReplace_Find_label);
574         setGridData(findLabel, SWT.LEFT, false, SWT.CENTER, false);
575         
576         // Create the find content assist field
577
ComboContentAdapter contentAdapter= new ComboContentAdapter();
578         RegExContentProposalProvider findProposer= new RegExContentProposalProvider(true);
579         fFindField= new Combo(panel, SWT.DROP_DOWN | SWT.BORDER);
580         fContentAssistFindField= new ContentAssistCommandAdapter(
581                 fFindField,
582                 contentAdapter,
583                 findProposer,
584                 ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS,
585                 new char[] {'\\', '[', '('},
586                 true);
587         setGridData(fFindField, SWT.FILL, true, SWT.CENTER, false);
588         addDecorationMargin(fFindField);
589         fFindField.addModifyListener(fFindModifyListener);
590
591         fReplaceLabel= new Label(panel, SWT.LEFT);
592         fReplaceLabel.setText(EditorMessages.FindReplace_Replace_label);
593         setGridData(fReplaceLabel, SWT.LEFT, false, SWT.CENTER, false);
594
595         // Create the replace content assist field
596
RegExContentProposalProvider replaceProposer= new RegExContentProposalProvider(false);
597         fReplaceField= new Combo(panel, SWT.DROP_DOWN | SWT.BORDER);
598         fContentAssistReplaceField= new ContentAssistCommandAdapter(
599                 fReplaceField,
600                 contentAdapter, replaceProposer,
601                 ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS,
602                 new char[] {'$'},
603                 true);
604         setGridData(fReplaceField, SWT.FILL, true, SWT.CENTER, false);
605         addDecorationMargin(fReplaceField);
606         fReplaceField.addModifyListener(listener);
607
608         return panel;
609     }
610
611     /**
612      * Creates the functional options part of the options defining
613      * section of the find replace dialog.
614      *
615      * @param parent the parent composite
616      * @return the options group
617      */

618     private Composite createOptionsGroup(Composite parent) {
619
620         Composite panel= new Composite(parent, SWT.NONE);
621         GridLayout layout= new GridLayout();
622         layout.marginWidth= 0;
623         layout.marginHeight= 0;
624         panel.setLayout(layout);
625
626         Group group= new Group(panel, SWT.SHADOW_NONE);
627         group.setText(EditorMessages.FindReplace_Options);
628         GridLayout groupLayout= new GridLayout();
629         groupLayout.numColumns= 2;
630         groupLayout.makeColumnsEqualWidth= true;
631         group.setLayout(groupLayout);
632         group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
633
634         SelectionListener selectionListener= new SelectionListener() {
635             public void widgetSelected(SelectionEvent e) {
636                 storeSettings();
637             }
638
639             public void widgetDefaultSelected(SelectionEvent e) {
640             }
641         };
642
643         fCaseCheckBox= new Button(group, SWT.CHECK | SWT.LEFT);
644         fCaseCheckBox.setText(EditorMessages.FindReplace_CaseCheckBox_label);
645         setGridData(fCaseCheckBox, SWT.LEFT, false, SWT.CENTER, false);
646         fCaseCheckBox.setSelection(fCaseInit);
647         fCaseCheckBox.addSelectionListener(selectionListener);
648
649         fWrapCheckBox= new Button(group, SWT.CHECK | SWT.LEFT);
650         fWrapCheckBox.setText(EditorMessages.FindReplace_WrapCheckBox_label);
651         setGridData(fWrapCheckBox, SWT.LEFT, false, SWT.CENTER, false);
652         fWrapCheckBox.setSelection(fWrapInit);
653         fWrapCheckBox.addSelectionListener(selectionListener);
654
655         fWholeWordCheckBox= new Button(group, SWT.CHECK | SWT.LEFT);
656         fWholeWordCheckBox.setText(EditorMessages.FindReplace_WholeWordCheckBox_label);
657         setGridData(fWholeWordCheckBox, SWT.LEFT, false, SWT.CENTER, false);
658         fWholeWordCheckBox.setSelection(fWholeWordInit);
659         fWholeWordCheckBox.addSelectionListener(selectionListener);
660
661         fIncrementalCheckBox= new Button(group, SWT.CHECK | SWT.LEFT);
662         fIncrementalCheckBox.setText(EditorMessages.FindReplace_IncrementalCheckBox_label);
663         setGridData(fIncrementalCheckBox, SWT.LEFT, false, SWT.CENTER, false);
664         fIncrementalCheckBox.setSelection(fIncrementalInit);
665         fIncrementalCheckBox.addSelectionListener(new SelectionListener() {
666             public void widgetSelected(SelectionEvent e) {
667                 if (isIncrementalSearch() && !isRegExSearch())
668                     initIncrementalBaseLocation();
669
670                 storeSettings();
671             }
672
673             public void widgetDefaultSelected(SelectionEvent e) {
674             }
675         });
676
677         fIsRegExCheckBox= new Button(group, SWT.CHECK | SWT.LEFT);
678         fIsRegExCheckBox.setText(EditorMessages.FindReplace_RegExCheckbox_label);
679         setGridData(fIsRegExCheckBox, SWT.LEFT, false, SWT.CENTER, false);
680         ((GridData)fIsRegExCheckBox.getLayoutData()).horizontalSpan= 2;
681         fIsRegExCheckBox.setSelection(fIsRegExInit);
682         fIsRegExCheckBox.addSelectionListener(new SelectionAdapter() {
683             /*
684              * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
685              */

686             public void widgetSelected(SelectionEvent e) {
687                 boolean newState= fIsRegExCheckBox.getSelection();
688                 fIncrementalCheckBox.setEnabled(!newState);
689                 updateButtonState();
690                 storeSettings();
691                 setContentAssistsEnablement(newState);
692             }
693         });
694         fWholeWordCheckBox.setEnabled(!isRegExSearchAvailableAndChecked());
695         fWholeWordCheckBox.addSelectionListener(new SelectionAdapter() {
696             /*
697              * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
698              */

699             public void widgetSelected(SelectionEvent e) {
700                 updateButtonState();
701             }
702         });
703         fIncrementalCheckBox.setEnabled(!isRegExSearchAvailableAndChecked());
704         return panel;
705     }
706
707     /**
708      * Creates the status and close section of the dialog.
709      *
710      * @param parent the parent composite
711      * @return the status and close button
712      */

713     private Composite createStatusAndCloseButton(Composite parent) {
714
715         Composite panel= new Composite(parent, SWT.NULL);
716         GridLayout layout= new GridLayout();
717         layout.numColumns= 2;
718         layout.marginWidth= 0;
719         layout.marginHeight= 0;
720         panel.setLayout(layout);
721
722         fStatusLabel= new Label(panel, SWT.LEFT);
723         setGridData(fStatusLabel, SWT.FILL, true, SWT.CENTER, false);
724
725         String JavaDoc label= EditorMessages.FindReplace_CloseButton_label;
726         Button closeButton= createButton(panel, 101, label, false);
727         setGridData(closeButton, SWT.RIGHT, false, SWT.BOTTOM, false);
728
729         return panel;
730     }
731
732     /*
733      * @see Dialog#buttonPressed
734      */

735     protected void buttonPressed(int buttonID) {
736         if (buttonID == 101)
737             close();
738     }
739
740
741
742     // ------- action invocation ---------------------------------------
743

744     /**
745      * Returns the position of the specified search string, or <code>-1</code> if the string can
746      * not be found when searching using the given options.
747      *
748      * @param findString the string to search for
749      * @param startPosition the position at which to start the search
750      * @param forwardSearch the direction of the search
751      * @param caseSensitive should the search be case sensitive
752      * @param wrapSearch should the search wrap to the start/end if arrived at the end/start
753      * @param wholeWord does the search string represent a complete word
754      * @param regExSearch if <code>true</code> findString represents a regular expression
755      * @return the occurrence of the find string following the options or <code>-1</code> if nothing found
756      * @since 3.0
757      */

758     private int findIndex(String JavaDoc findString, int startPosition, boolean forwardSearch, boolean caseSensitive, boolean wrapSearch, boolean wholeWord, boolean regExSearch) {
759
760         if (forwardSearch) {
761             if (wrapSearch) {
762                 int index= findAndSelect(startPosition, findString, true, caseSensitive, wholeWord, regExSearch);
763                 if (index == -1) {
764                     if (okToUse(getShell()) && !isIncrementalSearch())
765                         getShell().getDisplay().beep();
766                     index= findAndSelect(-1, findString, true, caseSensitive, wholeWord, regExSearch);
767                 }
768                 return index;
769             }
770             return findAndSelect(startPosition, findString, true, caseSensitive, wholeWord, regExSearch);
771         }
772
773         // backward
774
if (wrapSearch) {
775             int index= findAndSelect(startPosition - 1, findString, false, caseSensitive, wholeWord, regExSearch);
776             if (index == -1) {
777                 if (okToUse(getShell()) && !isIncrementalSearch())
778                     getShell().getDisplay().beep();
779                 index= findAndSelect(-1, findString, false, caseSensitive, wholeWord, regExSearch);
780             }
781             return index;
782         }
783         return findAndSelect(startPosition - 1, findString, false, caseSensitive, wholeWord, regExSearch);
784     }
785
786     /**
787      * Searches for a string starting at the given offset and using the specified search
788      * directives. If a string has been found it is selected and its start offset is
789      * returned.
790      *
791      * @param offset the offset at which searching starts
792      * @param findString the string which should be found
793      * @param forwardSearch the direction of the search
794      * @param caseSensitive <code>true</code> performs a case sensitive search, <code>false</code> an insensitive search
795      * @param wholeWord if <code>true</code> only occurrences are reported in which the findString stands as a word by itself
796      * @param regExSearch if <code>true</code> findString represents a regular expression
797      * @return the position of the specified string, or -1 if the string has not been found
798      * @since 3.0
799      */

800     private int findAndSelect(int offset, String JavaDoc findString, boolean forwardSearch, boolean caseSensitive, boolean wholeWord, boolean regExSearch) {
801         if (fTarget instanceof IFindReplaceTargetExtension3)
802             return ((IFindReplaceTargetExtension3)fTarget).findAndSelect(offset, findString, forwardSearch, caseSensitive, wholeWord, regExSearch);
803         return fTarget.findAndSelect(offset, findString, forwardSearch, caseSensitive, wholeWord);
804     }
805
806     /**
807      * Replaces the selection with <code>replaceString</code>. If
808      * <code>regExReplace</code> is <code>true</code>,
809      * <code>replaceString</code> is a regex replace pattern which will get
810      * expanded if the underlying target supports it. Returns the region of the
811      * inserted text; note that the returned selection covers the expanded
812      * pattern in case of regex replace.
813      *
814      * @param replaceString the replace string (or a regex pattern)
815      * @param regExReplace <code>true</code> if <code>replaceString</code>
816      * is a pattern
817      * @return the selection after replacing, i.e. the inserted text
818      * @since 3.0
819      */

820     Point replaceSelection(String JavaDoc replaceString, boolean regExReplace) {
821         if (fTarget instanceof IFindReplaceTargetExtension3)
822             ((IFindReplaceTargetExtension3)fTarget).replaceSelection(replaceString, regExReplace);
823         else
824             fTarget.replaceSelection(replaceString);
825
826         return fTarget.getSelection();
827     }
828
829     /**
830      * Returns whether the specified search string can be found using the given options.
831      *
832      * @param findString the string to search for
833      * @param forwardSearch the direction of the search
834      * @param caseSensitive should the search be case sensitive
835      * @param wrapSearch should the search wrap to the start/end if arrived at the end/start
836      * @param wholeWord does the search string represent a complete word
837      * @param incremental is this an incremental search
838      * @param regExSearch if <code>true</code> findString represents a regular expression
839      * @return <code>true</code> if the search string can be found using the given options
840      *
841      * @since 3.0
842      */

843     private boolean findNext(String JavaDoc findString, boolean forwardSearch, boolean caseSensitive, boolean wrapSearch, boolean wholeWord, boolean incremental, boolean regExSearch) {
844
845         if (fTarget == null)
846             return false;
847
848         Point r= null;
849         if (incremental)
850             r= fIncrementalBaseLocation;
851         else
852             r= fTarget.getSelection();
853
854         int findReplacePosition= r.x;
855         if (forwardSearch && !fNeedsInitialFindBeforeReplace || !forwardSearch && fNeedsInitialFindBeforeReplace)
856             findReplacePosition += r.y;
857
858         fNeedsInitialFindBeforeReplace= false;
859
860         int index= findIndex(findString, findReplacePosition, forwardSearch, caseSensitive, wrapSearch, wholeWord, regExSearch);
861
862         if (index != -1)
863             return true;
864
865         return false;
866     }
867
868     /**
869      * Returns the dialog's boundaries.
870      * @return the dialog's boundaries
871      */

872     private Rectangle getDialogBoundaries() {
873         if (okToUse(getShell()))
874             return getShell().getBounds();
875         return fDialogPositionInit;
876     }
877
878     /**
879      * Returns the dialog's history.
880      * @return the dialog's history
881      */

882     private List JavaDoc getFindHistory() {
883         return fFindHistory;
884     }
885
886     // ------- accessors ---------------------------------------
887

888     /**
889      * Retrieves the string to search for from the appropriate text input field and returns it.
890      * @return the search string
891      */

892     private String JavaDoc getFindString() {
893         if (okToUse(fFindField)) {
894             return fFindField.getText();
895         }
896         return ""; //$NON-NLS-1$
897
}
898
899     /**
900      * Returns the dialog's replace history.
901      * @return the dialog's replace history
902      */

903     private List JavaDoc getReplaceHistory() {
904         return fReplaceHistory;
905     }
906
907     /**
908      * Retrieves the replacement string from the appropriate text input field and returns it.
909      * @return the replacement string
910      */

911     private String JavaDoc getReplaceString() {
912         if (okToUse(fReplaceField)) {
913             return fReplaceField.getText();
914         }
915         return ""; //$NON-NLS-1$
916
}
917
918     // ------- init / close ---------------------------------------
919

920     /**
921      * Returns the actual selection of the find replace target.
922      * @return the selection of the target
923      */

924     private String JavaDoc getSelectionString() {
925         String JavaDoc selection= fTarget.getSelectionText();
926         if (selection != null && selection.length() > 0) {
927             int[] info= TextUtilities.indexOf(TextUtilities.DELIMITERS, selection, 0);
928             if (info[0] > 0)
929                 return selection.substring(0, info[0]);
930             else if (info[0] == -1)
931                 return selection;
932         }
933         return null;
934     }
935
936     /**
937      * @see org.eclipse.jface.window.Window#close()
938      */

939     public boolean close() {
940         handleDialogClose();
941         return super.close();
942     }
943
944     /**
945      * Removes focus changed listener from browser and stores settings for re-open.
946      */

947     private void handleDialogClose() {
948
949         // remove listeners
950
if (okToUse(fFindField)) {
951             fFindField.removeModifyListener(fFindModifyListener);
952         }
953
954         if (fParentShell != null) {
955             fParentShell.removeShellListener(fActivationListener);
956             fParentShell= null;
957         }
958
959         getShell().removeShellListener(fActivationListener);
960
961         // store current settings in case of re-open
962
storeSettings();
963
964         if (fTarget != null && fTarget instanceof IFindReplaceTargetExtension)
965             ((IFindReplaceTargetExtension) fTarget).endSession();
966
967         // prevent leaks
968
fActiveShell= null;
969         fTarget= null;
970
971     }
972
973     /**
974      * Writes the current selection to the dialog settings.
975      * @since 3.0
976      */

977     private void writeSelection() {
978         if (fTarget == null)
979             return;
980         String JavaDoc selection= fTarget.getSelectionText();
981         if (selection == null)
982             selection= ""; //$NON-NLS-1$
983

984         IDialogSettings s= getDialogSettings();
985         s.put("selection", selection); //$NON-NLS-1$
986
}
987
988     /**
989      * Stores the current state in the dialog settings.
990      * @since 2.0
991      */

992     private void storeSettings() {
993         fDialogPositionInit= getDialogBoundaries();
994         fWrapInit= isWrapSearch();
995         fWholeWordInit= isWholeWordSetting();
996         fCaseInit= isCaseSensitiveSearch();
997         fIsRegExInit= isRegExSearch();
998         fIncrementalInit= isIncrementalSearch();
999         fForwardInit= isForwardSearch();
1000
1001        writeConfiguration();
1002    }
1003
1004    /**
1005     * Initializes the string to search for and the appropriate
1006     * text in the Find field based on the selection found in the
1007     * action's target.
1008     */

1009    private void initFindStringFromSelection() {
1010        if (fTarget != null && okToUse(fFindField)) {
1011            String JavaDoc selection= getSelectionString();
1012            fFindField.removeModifyListener(fFindModifyListener);
1013            if (selection != null) {
1014                fFindField.setText(selection);
1015                if (!selection.equals(fTarget.getSelectionText())) {
1016                    useSelectedLines(true);
1017                    fGlobalRadioButton.setSelection(false);
1018                    fSelectedRangeRadioButton.setSelection(true);
1019                    fUseSelectedLines= true;
1020                }
1021            } else {
1022                if ("".equals(fFindField.getText())) { //$NON-NLS-1$
1023
if (fFindHistory.size() > 0)
1024                        fFindField.setText((String JavaDoc) fFindHistory.get(0));
1025                    else
1026                        fFindField.setText(""); //$NON-NLS-1$
1027
}
1028            }
1029            fFindField.setSelection(new Point(0, fFindField.getText().length()));
1030            fFindField.addModifyListener(fFindModifyListener);
1031        }
1032    }
1033
1034    /**
1035     * Initializes the anchor used as starting point for incremental searching.
1036     * @since 2.0
1037     */

1038    private void initIncrementalBaseLocation() {
1039        if (fTarget != null && isIncrementalSearch() && !isRegExSearchAvailableAndChecked()) {
1040            fIncrementalBaseLocation= fTarget.getSelection();
1041        } else {
1042            fIncrementalBaseLocation= new Point(0, 0);
1043        }
1044    }
1045
1046    // ------- history ---------------------------------------
1047

1048    /**
1049     * Retrieves and returns the option case sensitivity from the appropriate check box.
1050     * @return <code>true</code> if case sensitive
1051     */

1052    private boolean isCaseSensitiveSearch() {
1053        if (okToUse(fCaseCheckBox)) {
1054            return fCaseCheckBox.getSelection();
1055        }
1056        return fCaseInit;
1057    }
1058
1059    /**
1060     * Retrieves and returns the regEx option from the appropriate check box.
1061     *
1062     * @return <code>true</code> if case sensitive
1063     * @since 3.0
1064     */

1065    private boolean isRegExSearch() {
1066        if (okToUse(fIsRegExCheckBox)) {
1067            return fIsRegExCheckBox.getSelection();
1068        }
1069        return fIsRegExInit;
1070    }
1071
1072    /**
1073     * If the target supports regular expressions search retrieves and returns
1074     * regEx option from appropriate check box.
1075     *
1076     * @return <code>true</code> if regEx is available and checked
1077     * @since 3.0
1078     */

1079    private boolean isRegExSearchAvailableAndChecked() {
1080        if (okToUse(fIsRegExCheckBox)) {
1081            return fIsTargetSupportingRegEx && fIsRegExCheckBox.getSelection();
1082        }
1083        return fIsRegExInit;
1084    }
1085
1086    /**
1087     * Retrieves and returns the option search direction from the appropriate check box.
1088     * @return <code>true</code> if searching forward
1089     */

1090    private boolean isForwardSearch() {
1091        if (okToUse(fForwardRadioButton)) {
1092            return fForwardRadioButton.getSelection();
1093        }
1094        return fForwardInit;
1095    }
1096
1097    /**
1098     * Retrieves and returns the option search whole words from the appropriate check box.
1099     * @return <code>true</code> if searching for whole words
1100     */

1101    private boolean isWholeWordSetting() {
1102        if (okToUse(fWholeWordCheckBox)) {
1103            return fWholeWordCheckBox.getSelection();
1104        }
1105        return fWholeWordInit;
1106    }
1107
1108    /**
1109     * Returns <code>true</code> if searching should be restricted to entire
1110     * words, <code>false</code> if not. This is the case if the respective
1111     * checkbox is turned on, regex is off, and the checkbox is enabled, i.e.
1112     * the current find string is an entire word.
1113     *
1114     * @return <code>true</code> if the search is restricted to whole words
1115     */

1116    private boolean isWholeWordSearch() {
1117        return isWholeWordSetting() && !isRegExSearchAvailableAndChecked() && (okToUse(fWholeWordCheckBox) ? fWholeWordCheckBox.isEnabled() : true);
1118    }
1119
1120    /**
1121     * Retrieves and returns the option wrap search from the appropriate check box.
1122     * @return <code>true</code> if wrapping while searching
1123     */

1124    private boolean isWrapSearch() {
1125        if (okToUse(fWrapCheckBox)) {
1126            return fWrapCheckBox.getSelection();
1127        }
1128        return fWrapInit;
1129    }
1130
1131    /**
1132     * Retrieves and returns the option incremental search from the appropriate check box.
1133     * @return <code>true</code> if incremental search
1134     * @since 2.0
1135     */

1136    private boolean isIncrementalSearch() {
1137        if (okToUse(fIncrementalCheckBox)) {
1138            return fIncrementalCheckBox.getSelection();
1139        }
1140        return fIncrementalInit;
1141    }
1142
1143    /**
1144     * Creates a button.
1145     * @param parent the parent control
1146     * @param label the button label
1147     * @param id the button id
1148     * @param dfltButton is this button the default button
1149     * @param listener a button pressed listener
1150     * @return the new button
1151     */

1152    private Button makeButton(Composite parent, String JavaDoc label, int id, boolean dfltButton, SelectionListener listener) {
1153        Button b= createButton(parent, id, label, dfltButton);
1154        b.addSelectionListener(listener);
1155        return b;
1156    }
1157
1158    /**
1159     * Returns the status line manager of the active editor or <code>null</code> if there is no such editor.
1160     * @return the status line manager of the active editor
1161     */

1162    private IEditorStatusLine getStatusLineManager() {
1163        IWorkbenchWindow window= PlatformUI.getWorkbench().getActiveWorkbenchWindow();
1164        if (window == null)
1165            return null;
1166
1167        IWorkbenchPage page= window.getActivePage();
1168        if (page == null)
1169            return null;
1170
1171        IEditorPart editor= page.getActiveEditor();
1172        if (editor == null)
1173            return null;
1174
1175        return (IEditorStatusLine) editor.getAdapter(IEditorStatusLine.class);
1176    }
1177
1178    /**
1179     * Sets the given status message in the status line.
1180     *
1181     * @param error <code>true</code> if it is an error
1182     * @param message the error message
1183     */

1184    private void statusMessage(boolean error, String JavaDoc message) {
1185        fStatusLabel.setText(message);
1186
1187        if (error)
1188            fStatusLabel.setForeground(JFaceColors.getErrorText(fStatusLabel.getDisplay()));
1189        else
1190            fStatusLabel.setForeground(null);
1191
1192        IEditorStatusLine statusLine= getStatusLineManager();
1193        if (statusLine != null)
1194            statusLine.setMessage(error, message, null);
1195
1196        if (error)
1197            getShell().getDisplay().beep();
1198    }
1199
1200    /**
1201     * Sets the given error message in the status line.
1202     * @param message the message
1203     */

1204    private void statusError(String JavaDoc message) {
1205        statusMessage(true, message);
1206    }
1207
1208    /**
1209     * Sets the given message in the status line.
1210     * @param message the message
1211     */

1212    private void statusMessage(String JavaDoc message) {
1213        statusMessage(false, message);
1214    }
1215
1216    /**
1217     * Replaces all occurrences of the user's findString with
1218     * the replace string. Indicate to the user the number of replacements
1219     * that occur.
1220     */

1221    private void performReplaceAll() {
1222
1223        int replaceCount= 0;
1224        final String JavaDoc replaceString= getReplaceString();
1225        final String JavaDoc findString= getFindString();
1226
1227        if (findString != null && findString.length() > 0) {
1228
1229            class ReplaceAllRunnable implements Runnable JavaDoc {
1230                public int numberOfOccurrences;
1231                public void run() {
1232                    numberOfOccurrences= replaceAll(findString, replaceString == null ? "" : replaceString, isForwardSearch(), isCaseSensitiveSearch(), isWrapSearch(), isWholeWordSearch(), isRegExSearchAvailableAndChecked()); //$NON-NLS-1$
1233
}
1234            }
1235
1236            try {
1237                ReplaceAllRunnable runnable= new ReplaceAllRunnable();
1238                BusyIndicator.showWhile(fActiveShell.getDisplay(), runnable);
1239                replaceCount= runnable.numberOfOccurrences;
1240
1241                if (replaceCount != 0) {
1242                    if (replaceCount == 1) { // not plural
1243
statusMessage(EditorMessages.FindReplace_Status_replacement_label);
1244                    } else {
1245                        String JavaDoc msg= EditorMessages.FindReplace_Status_replacements_label;
1246                        msg= NLSUtility.format(msg, String.valueOf(replaceCount));
1247                        statusMessage(msg);
1248                    }
1249                } else {
1250                    statusMessage(EditorMessages.FindReplace_Status_noMatch_label);
1251                }
1252            } catch (PatternSyntaxException JavaDoc ex) {
1253                statusError(ex.getLocalizedMessage());
1254            } catch (IllegalStateException JavaDoc ex) {
1255                // we don't keep state in this dialog
1256
}
1257        }
1258        writeSelection();
1259        updateButtonState();
1260    }
1261
1262    /**
1263     * Validates the state of the find/replace target.
1264     * @return <code>true</code> if target can be changed, <code>false</code> otherwise
1265     * @since 2.1
1266     */

1267    private boolean validateTargetState() {
1268
1269        if (fTarget instanceof IFindReplaceTargetExtension2) {
1270            IFindReplaceTargetExtension2 extension= (IFindReplaceTargetExtension2) fTarget;
1271            if (!extension.validateTargetState()) {
1272                statusError(EditorMessages.FindReplaceDialog_read_only);
1273                updateButtonState();
1274                return false;
1275            }
1276        }
1277        return isEditable();
1278    }
1279
1280    /**
1281     * Replaces the current selection of the target with the user's
1282     * replace string.
1283     *
1284     * @return <code>true</code> if the operation was successful
1285     */

1286    private boolean performReplaceSelection() {
1287
1288        if (!validateTargetState())
1289            return false;
1290
1291        String JavaDoc replaceString= getReplaceString();
1292        if (replaceString == null)
1293            replaceString= ""; //$NON-NLS-1$
1294

1295        boolean replaced;
1296        try {
1297            replaceSelection(replaceString, isRegExSearchAvailableAndChecked());
1298            replaced= true;
1299            writeSelection();
1300        } catch (PatternSyntaxException JavaDoc ex) {
1301            statusError(ex.getLocalizedMessage());
1302            replaced= false;
1303        } catch (IllegalStateException JavaDoc ex) {
1304            replaced= false;
1305        }
1306
1307        updateButtonState();
1308        return replaced;
1309    }
1310
1311    /**
1312     * Locates the user's findString in the text of the target.
1313     */

1314    private void performSearch() {
1315        performSearch(isIncrementalSearch() && !isRegExSearchAvailableAndChecked());
1316    }
1317
1318    /**
1319     * Locates the user's findString in the text of the target.
1320     *
1321     * @param mustInitIncrementalBaseLocation <code>true</code> if base location must be initialized
1322     * @since 3.0
1323     */

1324    private void performSearch(boolean mustInitIncrementalBaseLocation) {
1325
1326        if (mustInitIncrementalBaseLocation)
1327            initIncrementalBaseLocation();
1328
1329        String JavaDoc findString= getFindString();
1330        boolean somethingFound= false;
1331
1332        if (findString != null && findString.length() > 0) {
1333
1334            try {
1335                somethingFound= findNext(findString, isForwardSearch(), isCaseSensitiveSearch(), isWrapSearch(), isWholeWordSearch(), isIncrementalSearch() && !isRegExSearchAvailableAndChecked(), isRegExSearchAvailableAndChecked());
1336                if (somethingFound) {
1337                    statusMessage(""); //$NON-NLS-1$
1338
} else {
1339                    statusMessage(EditorMessages.FindReplace_Status_noMatch_label);
1340                }
1341            } catch (PatternSyntaxException JavaDoc ex) {
1342                statusError(ex.getLocalizedMessage());
1343            } catch (IllegalStateException JavaDoc ex) {
1344                // we don't keep state in this dialog
1345
}
1346        }
1347        writeSelection();
1348        updateButtonState(!somethingFound);
1349    }
1350
1351    /**
1352     * Replaces all occurrences of the user's findString with
1353     * the replace string. Returns the number of replacements
1354     * that occur.
1355     *
1356     * @param findString the string to search for
1357     * @param replaceString the replacement string
1358     * @param forwardSearch the search direction
1359     * @param caseSensitive should the search be case sensitive
1360     * @param wrapSearch should search wrap to start/end if end/start is reached
1361     * @param wholeWord does the search string represent a complete word
1362     * @param regExSearch if <code>true</code> findString represents a regular expression
1363     * @return the number of occurrences
1364     *
1365     * @since 3.0
1366     */

1367    private int replaceAll(String JavaDoc findString, String JavaDoc replaceString, boolean forwardSearch, boolean caseSensitive, boolean wrapSearch, boolean wholeWord, boolean regExSearch) {
1368
1369        int replaceCount= 0;
1370        int findReplacePosition= 0;
1371
1372        if (wrapSearch) { // search the whole text
1373
findReplacePosition= 0;
1374            forwardSearch= true;
1375        } else if (fTarget.getSelectionText() != null) {
1376            // the cursor is set to the end or beginning of the selected text
1377
Point selection= fTarget.getSelection();
1378            findReplacePosition= selection.x;
1379        }
1380
1381        if (!validateTargetState())
1382            return replaceCount;
1383
1384        if (fTarget instanceof IFindReplaceTargetExtension)
1385            ((IFindReplaceTargetExtension) fTarget).setReplaceAllMode(true);
1386
1387        try {
1388            int index= 0;
1389            while (index != -1) {
1390                index= findAndSelect(findReplacePosition, findString, forwardSearch, caseSensitive, wholeWord, regExSearch);
1391                if (index != -1) { // substring not contained from current position
1392
Point selection= replaceSelection(replaceString, regExSearch);
1393                    replaceCount++;
1394
1395                    if (forwardSearch)
1396                        findReplacePosition= selection.x + selection.y;
1397                    else {
1398                        findReplacePosition= selection.x - 1;
1399                        if (findReplacePosition == -1)
1400                            break;
1401                    }
1402                }
1403            }
1404        } finally {
1405            if (fTarget instanceof IFindReplaceTargetExtension)
1406                ((IFindReplaceTargetExtension) fTarget).setReplaceAllMode(false);
1407        }
1408
1409        return replaceCount;
1410    }
1411
1412    // ------- UI creation ---------------------------------------
1413

1414    /**
1415     * Attaches the given layout specification to the <code>component</code>.
1416     *
1417     * @param component the component
1418     * @param horizontalAlignment horizontal alignment
1419     * @param grabExcessHorizontalSpace grab excess horizontal space
1420     * @param verticalAlignment vertical alignment
1421     * @param grabExcessVerticalSpace grab excess vertical space
1422     */

1423    private void setGridData(Control component, int horizontalAlignment, boolean grabExcessHorizontalSpace, int verticalAlignment, boolean grabExcessVerticalSpace) {
1424        GridData gd;
1425        if (component instanceof Button && (((Button)component).getStyle() & SWT.PUSH) != 0) {
1426            SWTUtil.setButtonDimensionHint((Button)component);
1427            gd= (GridData)component.getLayoutData();
1428        } else {
1429            gd= new GridData();
1430            component.setLayoutData(gd);
1431            gd.horizontalAlignment= horizontalAlignment;
1432            gd.grabExcessHorizontalSpace= grabExcessHorizontalSpace;
1433        }
1434        gd.verticalAlignment= verticalAlignment;
1435        gd.grabExcessVerticalSpace= grabExcessVerticalSpace;
1436    }
1437    
1438    /**
1439     * Adds enough space in the control's layout data margin for the content assist
1440     * decoration.
1441     * @param control the control that needs a margin
1442     * @since 3.3
1443     */

1444    private void addDecorationMargin(Control control) {
1445        Object JavaDoc layoutData= control.getLayoutData();
1446        if (!(layoutData instanceof GridData))
1447            return;
1448        GridData gd= (GridData)layoutData;
1449        FieldDecoration dec= FieldDecorationRegistry.getDefault().getFieldDecoration(FieldDecorationRegistry.DEC_CONTENT_PROPOSAL);
1450        gd.horizontalIndent= dec.getImage().getBounds().width;
1451    }
1452
1453    /**
1454     * Updates the enabled state of the buttons.
1455     */

1456    private void updateButtonState() {
1457        updateButtonState(false);
1458    }
1459
1460    /**
1461     * Updates the enabled state of the buttons.
1462     *
1463     * @param disableReplace <code>true</code> if replace button must be disabled
1464     * @since 3.0
1465     */

1466    private void updateButtonState(boolean disableReplace) {
1467        if (okToUse(getShell()) && okToUse(fFindNextButton)) {
1468
1469            boolean selection= false;
1470            if (fTarget != null) {
1471                String JavaDoc selectedText= fTarget.getSelectionText();
1472                selection= (selectedText != null && selectedText.length() > 0);
1473            }
1474            boolean enable= fTarget != null && (fActiveShell == fParentShell || fActiveShell == getShell());
1475            String JavaDoc str= getFindString();
1476            boolean findString= str != null && str.length() > 0;
1477
1478            fWholeWordCheckBox.setEnabled(isWord(str) && !isRegExSearchAvailableAndChecked());
1479
1480            fFindNextButton.setEnabled(enable && findString);
1481            fReplaceSelectionButton.setEnabled(!disableReplace && enable && isEditable() && selection && (!fNeedsInitialFindBeforeReplace || !isRegExSearchAvailableAndChecked()));
1482            fReplaceFindButton.setEnabled(!disableReplace && enable && isEditable() && findString && selection && (!fNeedsInitialFindBeforeReplace || !isRegExSearchAvailableAndChecked()));
1483            fReplaceAllButton.setEnabled(enable && isEditable() && findString);
1484        }
1485    }
1486
1487    /**
1488     * Tests whether each character in the given
1489     * string is a letter.
1490     *
1491     * @param str
1492     * @return <code>true</code> if the given string is a word
1493     * @since 3.0
1494     */

1495    private boolean isWord(String JavaDoc str) {
1496        if (str == null || str.length() == 0)
1497            return false;
1498
1499        for (int i= 0; i < str.length(); i++) {
1500            if (!Character.isJavaIdentifierPart(str.charAt(i)))
1501                return false;
1502        }
1503        return true;
1504    }
1505
1506    /**
1507     * Updates the given combo with the given content.
1508     * @param combo combo to be updated
1509     * @param content to be put into the combo
1510     */

1511    private void updateCombo(Combo combo, List JavaDoc content) {
1512        combo.removeAll();
1513        for (int i= 0; i < content.size(); i++) {
1514            combo.add(content.get(i).toString());
1515        }
1516    }
1517
1518    // ------- open / reopen ---------------------------------------
1519

1520    /**
1521     * Called after executed find/replace action to update the history.
1522     */

1523    private void updateFindAndReplaceHistory() {
1524        updateFindHistory();
1525        if (okToUse(fReplaceField)) {
1526            updateHistory(fReplaceField, fReplaceHistory);
1527        }
1528
1529    }
1530
1531    /**
1532     * Called after executed find action to update the history.
1533     */

1534    private void updateFindHistory() {
1535        if (okToUse(fFindField)) {
1536            fFindField.removeModifyListener(fFindModifyListener);
1537            updateHistory(fFindField, fFindHistory);
1538            fFindField.addModifyListener(fFindModifyListener);
1539        }
1540    }
1541
1542    /**
1543     * Updates the combo with the history.
1544     * @param combo to be updated
1545     * @param history to be put into the combo
1546     */

1547    private void updateHistory(Combo combo, List JavaDoc history) {
1548        String JavaDoc findString= combo.getText();
1549        int index= history.indexOf(findString);
1550        if (index != 0) {
1551            if (index != -1) {
1552                history.remove(index);
1553            }
1554            history.add(0, findString);
1555            updateCombo(combo, history);
1556            combo.setText(findString);
1557        }
1558    }
1559
1560    /**
1561     * Returns whether the target is editable.
1562     * @return <code>true</code> if target is editable
1563     */

1564    private boolean isEditable() {
1565        boolean isEditable= (fTarget == null ? false : fTarget.isEditable());
1566        return fIsTargetEditable && isEditable;
1567    }
1568
1569    /**
1570     * Updates this dialog because of a different target.
1571     * @param target the new target
1572     * @param isTargetEditable <code>true</code> if the new target can be modified
1573     * @param initializeFindString <code>true</code> if the find string of this dialog should be initialized based on the viewer's selection
1574     * @since 2.0
1575     */

1576    public void updateTarget(IFindReplaceTarget target, boolean isTargetEditable, boolean initializeFindString) {
1577
1578        fIsTargetEditable= isTargetEditable;
1579        fNeedsInitialFindBeforeReplace= true;
1580
1581        if (target != fTarget) {
1582            if (fTarget != null && fTarget instanceof IFindReplaceTargetExtension)
1583                ((IFindReplaceTargetExtension) fTarget).endSession();
1584
1585            fTarget= target;
1586            if (fTarget != null)
1587                fIsTargetSupportingRegEx= fTarget instanceof IFindReplaceTargetExtension3;
1588
1589            if (fTarget instanceof IFindReplaceTargetExtension) {
1590                ((IFindReplaceTargetExtension) fTarget).beginSession();
1591
1592                fGlobalInit= true;
1593                fGlobalRadioButton.setSelection(fGlobalInit);
1594                fSelectedRangeRadioButton.setSelection(!fGlobalInit);
1595                fUseSelectedLines= !fGlobalInit;
1596            }
1597        }
1598
1599        if (okToUse(fIsRegExCheckBox))
1600            fIsRegExCheckBox.setEnabled(fIsTargetSupportingRegEx);
1601
1602        if (okToUse(fWholeWordCheckBox))
1603            fWholeWordCheckBox.setEnabled(!isRegExSearchAvailableAndChecked());
1604
1605        if (okToUse(fIncrementalCheckBox))
1606            fIncrementalCheckBox.setEnabled(!isRegExSearchAvailableAndChecked());
1607
1608        if (okToUse(fReplaceLabel)) {
1609            fReplaceLabel.setEnabled(isEditable());
1610            fReplaceField.setEnabled(isEditable());
1611            if (initializeFindString) {
1612                initFindStringFromSelection();
1613                fGiveFocusToFindField= true;
1614            }
1615            initIncrementalBaseLocation();
1616            updateButtonState();
1617        }
1618
1619        setContentAssistsEnablement(isRegExSearchAvailableAndChecked());
1620    }
1621
1622    /**
1623     * Sets the parent shell of this dialog to be the given shell.
1624     *
1625     * @param shell the new parent shell
1626     */

1627    public void setParentShell(Shell shell) {
1628        if (shell != fParentShell) {
1629
1630            if (fParentShell != null)
1631                fParentShell.removeShellListener(fActivationListener);
1632
1633            fParentShell= shell;
1634            fParentShell.addShellListener(fActivationListener);
1635        }
1636
1637        fActiveShell= shell;
1638    }
1639
1640
1641    //--------------- configuration handling --------------
1642

1643    /**
1644     * Returns the dialog settings object used to share state
1645     * between several find/replace dialogs.
1646     *
1647     * @return the dialog settings to be used
1648     */

1649    private IDialogSettings getDialogSettings() {
1650        IDialogSettings settings= TextEditorPlugin.getDefault().getDialogSettings();
1651        fDialogSettings= settings.getSection(getClass().getName());
1652        if (fDialogSettings == null)
1653            fDialogSettings= settings.addNewSection(getClass().getName());
1654        return fDialogSettings;
1655    }
1656    
1657    /*
1658     * @see org.eclipse.jface.dialogs.Dialog#getDialogBoundsSettings()
1659     * @since 3.2
1660     */

1661    protected IDialogSettings getDialogBoundsSettings() {
1662        String JavaDoc sectionName= getClass().getName() + "_dialogBounds"; //$NON-NLS-1$
1663
IDialogSettings settings= TextEditorPlugin.getDefault().getDialogSettings();
1664        IDialogSettings section= settings.getSection(sectionName);
1665        if (section == null)
1666            section= settings.addNewSection(sectionName);
1667        return section;
1668    }
1669    
1670    /*
1671     * @see org.eclipse.jface.dialogs.Dialog#getDialogBoundsStrategy()
1672     * @since 3.2
1673     */

1674    protected int getDialogBoundsStrategy() {
1675        return DIALOG_PERSISTLOCATION | DIALOG_PERSISTSIZE;
1676    }
1677
1678    /**
1679     * Initializes itself from the dialog settings with the same state
1680     * as at the previous invocation.
1681     */

1682    private void readConfiguration() {
1683        IDialogSettings s= getDialogSettings();
1684
1685        fWrapInit= s.getBoolean("wrap"); //$NON-NLS-1$
1686
fCaseInit= s.getBoolean("casesensitive"); //$NON-NLS-1$
1687
fWholeWordInit= s.getBoolean("wholeword"); //$NON-NLS-1$
1688
fIncrementalInit= s.getBoolean("incremental"); //$NON-NLS-1$
1689
fIsRegExInit= s.getBoolean("isRegEx"); //$NON-NLS-1$
1690

1691        String JavaDoc[] findHistory= s.getArray("findhistory"); //$NON-NLS-1$
1692
if (findHistory != null) {
1693            List JavaDoc history= getFindHistory();
1694            history.clear();
1695            for (int i= 0; i < findHistory.length; i++)
1696                history.add(findHistory[i]);
1697        }
1698
1699        String JavaDoc[] replaceHistory= s.getArray("replacehistory"); //$NON-NLS-1$
1700
if (replaceHistory != null) {
1701            List JavaDoc history= getReplaceHistory();
1702            history.clear();
1703            for (int i= 0; i < replaceHistory.length; i++)
1704                history.add(replaceHistory[i]);
1705        }
1706    }
1707
1708    /**
1709     * Stores its current configuration in the dialog store.
1710     */

1711    private void writeConfiguration() {
1712        IDialogSettings s= getDialogSettings();
1713
1714        s.put("wrap", fWrapInit); //$NON-NLS-1$
1715
s.put("casesensitive", fCaseInit); //$NON-NLS-1$
1716
s.put("wholeword", fWholeWordInit); //$NON-NLS-1$
1717
s.put("incremental", fIncrementalInit); //$NON-NLS-1$
1718
s.put("isRegEx", fIsRegExInit); //$NON-NLS-1$
1719

1720        List JavaDoc history= getFindHistory();
1721        String JavaDoc findString= getFindString();
1722        if (findString.length() > 0)
1723            history.add(0, findString);
1724        writeHistory(history, s, "findhistory"); //$NON-NLS-1$
1725

1726        history= getReplaceHistory();
1727        String JavaDoc replaceString= getReplaceString();
1728        if (replaceString.length() > 0)
1729            history.add(0, replaceString);
1730        writeHistory(history, s, "replacehistory"); //$NON-NLS-1$
1731
}
1732    
1733    /**
1734     * Writes the given history into the given dialog store.
1735     *
1736     * @param history the history
1737     * @param settings the dialog settings
1738     * @param sectionName the section name
1739     * @since 3.2
1740     */

1741    private void writeHistory(List JavaDoc history, IDialogSettings settings, String JavaDoc sectionName) {
1742        int itemCount= history.size();
1743        Set JavaDoc distinctItems= new HashSet JavaDoc(itemCount);
1744        for (int i= 0; i < itemCount; i++) {
1745            String JavaDoc item= (String JavaDoc)history.get(i);
1746            if (distinctItems.contains(item)) {
1747                history.remove(i--);
1748                itemCount--;
1749            } else {
1750                distinctItems.add(item);
1751            }
1752        }
1753        
1754        while (history.size() > 8)
1755            history.remove(8);
1756        
1757        String JavaDoc[] names= new String JavaDoc[history.size()];
1758        history.toArray(names);
1759        settings.put(sectionName, names);
1760        
1761    }
1762}
1763
Popular Tags