diff --git a/bundles/org.eclipse.jface.text/META-INF/MANIFEST.MF b/bundles/org.eclipse.jface.text/META-INF/MANIFEST.MF
index a048d96936e..0ce5366cbf8 100644
--- a/bundles/org.eclipse.jface.text/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.jface.text/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.jface.text
-Bundle-Version: 3.24.200.qualifier
+Bundle-Version: 3.25.0.qualifier
Bundle-Vendor: %providerName
Bundle-Localization: plugin
Export-Package:
diff --git a/bundles/org.eclipse.ui.workbench.texteditor/META-INF/MANIFEST.MF b/bundles/org.eclipse.ui.workbench.texteditor/META-INF/MANIFEST.MF
index d11f2afbac8..9349b8fe4f9 100644
--- a/bundles/org.eclipse.ui.workbench.texteditor/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.ui.workbench.texteditor/META-INF/MANIFEST.MF
@@ -2,13 +2,14 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.ui.workbench.texteditor; singleton:=true
-Bundle-Version: 3.17.200.qualifier
+Bundle-Version: 3.18.0.qualifier
Bundle-Activator: org.eclipse.ui.internal.texteditor.TextEditorPlugin
Bundle-ActivationPolicy: lazy
Bundle-Vendor: %providerName
Bundle-Localization: plugin
Export-Package:
org.eclipse.ui.contentassist,
+ org.eclipse.ui.internal.findandreplace;x-friends:="org.eclipse.ui.workbench.texteditor.tests";x-internal:=true,
org.eclipse.ui.internal.texteditor;texteditor=split;mandatory:=texteditor;x-friends:="org.eclipse.ui.editors",
org.eclipse.ui.internal.texteditor.codemining;x-internal:=true,
org.eclipse.ui.internal.texteditor.quickdiff;x-internal:=true,
diff --git a/bundles/org.eclipse.ui.workbench.texteditor/icons/full/dlcl16/select_next.png b/bundles/org.eclipse.ui.workbench.texteditor/icons/full/dlcl16/select_next.png
new file mode 100644
index 00000000000..1a71a7923a9
Binary files /dev/null and b/bundles/org.eclipse.ui.workbench.texteditor/icons/full/dlcl16/select_next.png differ
diff --git a/bundles/org.eclipse.ui.workbench.texteditor/icons/full/dlcl16/select_prev.png b/bundles/org.eclipse.ui.workbench.texteditor/icons/full/dlcl16/select_prev.png
new file mode 100644
index 00000000000..7eaaff97987
Binary files /dev/null and b/bundles/org.eclipse.ui.workbench.texteditor/icons/full/dlcl16/select_prev.png differ
diff --git a/bundles/org.eclipse.ui.workbench.texteditor/icons/full/elcl16/select_next.png b/bundles/org.eclipse.ui.workbench.texteditor/icons/full/elcl16/select_next.png
new file mode 100644
index 00000000000..9fcc646d92b
Binary files /dev/null and b/bundles/org.eclipse.ui.workbench.texteditor/icons/full/elcl16/select_next.png differ
diff --git a/bundles/org.eclipse.ui.workbench.texteditor/icons/full/elcl16/select_prev.png b/bundles/org.eclipse.ui.workbench.texteditor/icons/full/elcl16/select_prev.png
new file mode 100644
index 00000000000..f2e6a039c5d
Binary files /dev/null and b/bundles/org.eclipse.ui.workbench.texteditor/icons/full/elcl16/select_prev.png differ
diff --git a/bundles/org.eclipse.ui.workbench.texteditor/icons/full/obj16/case_sensitive.png b/bundles/org.eclipse.ui.workbench.texteditor/icons/full/obj16/case_sensitive.png
new file mode 100644
index 00000000000..7be33cd83c8
Binary files /dev/null and b/bundles/org.eclipse.ui.workbench.texteditor/icons/full/obj16/case_sensitive.png differ
diff --git a/bundles/org.eclipse.ui.workbench.texteditor/icons/full/obj16/close_replace.png b/bundles/org.eclipse.ui.workbench.texteditor/icons/full/obj16/close_replace.png
new file mode 100644
index 00000000000..018dc33f6fe
Binary files /dev/null and b/bundles/org.eclipse.ui.workbench.texteditor/icons/full/obj16/close_replace.png differ
diff --git a/bundles/org.eclipse.ui.workbench.texteditor/icons/full/obj16/open_replace.png b/bundles/org.eclipse.ui.workbench.texteditor/icons/full/obj16/open_replace.png
new file mode 100644
index 00000000000..c6aeae4d462
Binary files /dev/null and b/bundles/org.eclipse.ui.workbench.texteditor/icons/full/obj16/open_replace.png differ
diff --git a/bundles/org.eclipse.ui.workbench.texteditor/icons/full/obj16/regex_gear.gif b/bundles/org.eclipse.ui.workbench.texteditor/icons/full/obj16/regex_gear.gif
new file mode 100644
index 00000000000..81fb7b4a39d
Binary files /dev/null and b/bundles/org.eclipse.ui.workbench.texteditor/icons/full/obj16/regex_gear.gif differ
diff --git a/bundles/org.eclipse.ui.workbench.texteditor/icons/full/obj16/replace.png b/bundles/org.eclipse.ui.workbench.texteditor/icons/full/obj16/replace.png
new file mode 100644
index 00000000000..d9a07e503ef
Binary files /dev/null and b/bundles/org.eclipse.ui.workbench.texteditor/icons/full/obj16/replace.png differ
diff --git a/bundles/org.eclipse.ui.workbench.texteditor/icons/full/obj16/replace_all.png b/bundles/org.eclipse.ui.workbench.texteditor/icons/full/obj16/replace_all.png
new file mode 100644
index 00000000000..b6af9dbf57b
Binary files /dev/null and b/bundles/org.eclipse.ui.workbench.texteditor/icons/full/obj16/replace_all.png differ
diff --git a/bundles/org.eclipse.ui.workbench.texteditor/icons/full/obj16/search_all.png b/bundles/org.eclipse.ui.workbench.texteditor/icons/full/obj16/search_all.png
new file mode 100644
index 00000000000..997b0545b89
Binary files /dev/null and b/bundles/org.eclipse.ui.workbench.texteditor/icons/full/obj16/search_all.png differ
diff --git a/bundles/org.eclipse.ui.workbench.texteditor/icons/full/obj16/whole_word.png b/bundles/org.eclipse.ui.workbench.texteditor/icons/full/obj16/whole_word.png
new file mode 100644
index 00000000000..bd2eacec42d
Binary files /dev/null and b/bundles/org.eclipse.ui.workbench.texteditor/icons/full/obj16/whole_word.png differ
diff --git a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/FindReplaceLogic.java b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/FindReplaceLogic.java
new file mode 100644
index 00000000000..dd942f3b3d9
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/FindReplaceLogic.java
@@ -0,0 +1,743 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Vector Informatik GmbH and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Vector Informatik GmbH - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.findandreplace;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.PatternSyntaxException;
+
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Display;
+
+import org.eclipse.jface.text.IFindReplaceTarget;
+import org.eclipse.jface.text.IFindReplaceTargetExtension;
+import org.eclipse.jface.text.IFindReplaceTargetExtension3;
+import org.eclipse.jface.text.IFindReplaceTargetExtension4;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.Region;
+
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.texteditor.NLSUtility;
+
+import org.eclipse.ui.texteditor.IEditorStatusLine;
+import org.eclipse.ui.texteditor.IFindReplaceTargetExtension2;
+
+public class FindReplaceLogic implements IFindReplaceLogic {
+ private IFindReplaceLogicStatus status;
+ private IFindReplaceTarget target;
+ private IRegion oldScope;
+ private Point incrementalBaseLocation;
+
+ private boolean isTargetSupportingRegEx;
+ private boolean isTargetEditable;
+ private Set searchOptions = new HashSet<>();
+
+ @Override
+ public void activate(SearchOptions searchOption) {
+ searchOptions.add(searchOption);
+
+ switch (searchOption) {
+ case FORWARD:
+ case INCREMENTAL:
+ if (shouldInitIncrementalBaseLocation()) {
+ initIncrementalBaseLocation();
+ }
+ //$FALL-THROUGH$
+ // $CASES-OMITTED$
+ default:
+ break;
+ }
+ }
+
+ @Override
+ public void deactivate(SearchOptions searchOption) {
+ searchOptions.remove(searchOption);
+
+ if (searchOption == SearchOptions.FORWARD && shouldInitIncrementalBaseLocation()) {
+ initIncrementalBaseLocation();
+ }
+ }
+
+ @Override
+ public boolean isActive(SearchOptions searchOption) {
+ return searchOptions.contains(searchOption);
+ }
+
+ /**
+ * Returns the current status of FindReplaceLogic. Assumes that
+ * resetStatus
was run before the last operation. The Status can
+ * inform about events such as an error happening, a warning happening (e.g.:
+ * the search-string wasn't found) and can including a message that the UI may
+ * choose to print.
+ *
+ * @return FindAndReplaceMessageStatus
+ */
+ @Override
+ public IFindReplaceLogicStatus getStatus() {
+ if (status == null) {
+ return new FindReplaceLogicStatus(FindReplaceLogicStatus.MessageCode.NONE);
+ }
+ return status;
+ }
+
+ /**
+ * Call before running an operation of FindReplaceLogic. Resets the internal
+ * status.
+ */
+ private void resetStatus() {
+ status = null;
+ }
+
+ /**
+ * Returns true
if searching should be restricted to entire words,
+ * false
if not. This is the case if the respective checkbox is
+ * turned on, regex is off, and the checkbox is enabled, i.e. the current find
+ * string is an entire word.
+ *
+ * @return true
if the search is restricted to whole words
+ */
+ private boolean isWholeWordSearchAvailableAndActive() {
+ return isActive(SearchOptions.WHOLE_WORD) && !isRegExSearchAvailableAndActive();
+ }
+
+ @Override
+ public boolean isRegExSearchAvailableAndActive() {
+ return isActive(SearchOptions.REGEX) && isTargetSupportingRegEx;
+ }
+
+
+ /**
+ * Initializes the anchor used as starting point for incremental searching.
+ *
+ */
+ private void initIncrementalBaseLocation() {
+ if (target != null && isActive(SearchOptions.INCREMENTAL) && !isRegExSearchAvailableAndActive()) {
+ incrementalBaseLocation = target.getSelection();
+ } else {
+ incrementalBaseLocation = new Point(0, 0);
+ }
+ }
+
+ public boolean shouldInitIncrementalBaseLocation() {
+ return isActive(SearchOptions.INCREMENTAL) && !isActive(SearchOptions.REGEX);
+ }
+
+ /**
+ * Tells the dialog to perform searches only in the scope given by the actually
+ * selected lines.
+ *
+ * @param selectedLines true
if selected lines should be used
+ */
+ @Override
+ public void useSelectedLines(boolean selectedLines) {
+ if (shouldInitIncrementalBaseLocation()) {
+ initIncrementalBaseLocation();
+ }
+
+ if (target == null || !(target instanceof IFindReplaceTargetExtension)) {
+ return;
+ }
+
+ IFindReplaceTargetExtension extensionTarget = (IFindReplaceTargetExtension) target;
+
+ if (selectedLines) {
+
+ IRegion scope;
+ if (oldScope == null) {
+ Point lineSelection = extensionTarget.getLineSelection();
+ scope = new Region(lineSelection.x, lineSelection.y);
+ } else {
+ scope = oldScope;
+ oldScope = null;
+ }
+
+ int offset = isActive(SearchOptions.FORWARD) ? scope.getOffset() : scope.getOffset() + scope.getLength();
+
+ extensionTarget.setSelection(offset, 0);
+ extensionTarget.setScope(scope);
+ } else {
+ oldScope = extensionTarget.getScope();
+ extensionTarget.setScope(null);
+ }
+ }
+
+ /**
+ * Returns the status line manager of the active editor or null
if
+ * there is no such editor.
+ *
+ * @return the status line manager of the active editor
+ */
+ private IEditorStatusLine getStatusLineManager() {
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ if (window == null) {
+ return null;
+ }
+
+ IWorkbenchPage page = window.getActivePage();
+ if (page == null) {
+ return null;
+ }
+
+ IEditorPart editor = page.getActiveEditor();
+ if (editor == null) {
+ return null;
+ }
+
+ return editor.getAdapter(IEditorStatusLine.class);
+ }
+
+
+ /**
+ * Replaces all occurrences of the user's findString with the replace string.
+ * Indicate to the user the number of replacements that occur.
+ *
+ * status: {@see #getStatus() } message: String telling a user how many
+ * replacements were performed or that the find-String could not be matched at
+ * all
+ *
+ * @param findString The string that will be replaced
+ * @param replaceString The string that will replace the findString
+ * @param display the UI's Display
+ */
+ @Override
+ public void performReplaceAll(String findString, String replaceString, Display display) {
+ resetStatus();
+
+ int replaceCount = 0;
+
+ if (findString != null && !findString.isEmpty()) {
+
+ class ReplaceAllRunnable implements Runnable {
+ public int numberOfOccurrences;
+
+ @Override
+ public void run() {
+ numberOfOccurrences = replaceAll(findString, replaceString == null ? "" : replaceString); //$NON-NLS-1$
+ }
+ }
+
+ try {
+ ReplaceAllRunnable runnable = new ReplaceAllRunnable();
+ BusyIndicator.showWhile(display, runnable);
+ replaceCount = runnable.numberOfOccurrences;
+
+ if (replaceCount != 0) {
+ if (replaceCount == 1) { // not plural
+ statusLineMessage(FindReplaceMessages.FindReplace_Status_replacement_label);
+ } else {
+ String msg = FindReplaceMessages.FindReplace_Status_replacements_label;
+ msg = NLSUtility.format(msg, String.valueOf(replaceCount));
+ statusLineMessage(msg);
+ }
+ status = new FindReplaceLogicReplaceAllStatus(replaceCount);
+ } else {
+ String msg = NLSUtility.format(FindReplaceMessages.FindReplace_Status_noMatchWithValue_label,
+ findString);
+ statusLineMessage(false, msg);
+ status = new FindReplaceLogicStatus(FindReplaceLogicStatus.MessageCode.NO_MATCH);
+ }
+ } catch (PatternSyntaxException ex) {
+ status = new FindReplaceLogicMessage(ex.getLocalizedMessage());
+ } catch (IllegalStateException ex) {
+ // we don't keep state in this dialog
+ }
+ }
+ }
+
+ /**
+ * Selects all occurrences of findString.
+ *
+ * @param findString The String to find and select
+ * @param display The UI's Display The UI's Display
+ */
+ @Override
+ public void performSelectAll(String findString, Display display) {
+ resetStatus();
+
+ int selectCount = 0;
+
+ if (findString != null && !findString.isEmpty()) {
+
+ class SelectAllRunnable implements Runnable {
+ public int numberOfOccurrences;
+
+ @Override
+ public void run() {
+ numberOfOccurrences = selectAll(findString);
+ }
+ }
+
+ try {
+ SelectAllRunnable runnable = new SelectAllRunnable();
+ BusyIndicator.showWhile(display, runnable);
+ selectCount = runnable.numberOfOccurrences;
+
+ if (selectCount != 0) {
+ if (selectCount == 1) { // not plural
+ statusLineMessage(FindReplaceMessages.FindReplace_Status_selection_label);
+ } else {
+ String msg = FindReplaceMessages.FindReplace_Status_selections_label;
+ msg = NLSUtility.format(msg, String.valueOf(selectCount));
+ statusLineMessage(msg);
+ }
+ status = new FindReplaceLogicFindAllStatus(selectCount);
+ } else {
+ String msg = NLSUtility.format(FindReplaceMessages.FindReplace_Status_noMatchWithValue_label,
+ findString);
+ statusLineMessage(false, msg);
+ status = new FindReplaceLogicStatus(FindReplaceLogicStatus.MessageCode.NO_MATCH);
+ }
+ } catch (PatternSyntaxException ex) {
+ status = new FindReplaceLogicMessage(ex.getLocalizedMessage());
+ } catch (IllegalStateException ex) {
+ // we don't keep state
+ }
+ }
+ }
+
+ /**
+ * Validates the state of the find/replace target. Validates the state of this
+ * target. The predominate intent of this method is to take any action probably
+ * necessary to ensure that the target can persistently be changed. Regardless
+ * of whether there is something to do or not, returns whether the target can be
+ * edited.
+ *
+ * @return true
if target can be changed, false
+ * otherwise
+ */
+ private boolean prepareTargetForEditing() {
+ if (target instanceof IFindReplaceTargetExtension2) {
+ IFindReplaceTargetExtension2 extension = (IFindReplaceTargetExtension2) target;
+ if (!extension.validateTargetState()) {
+ status = new FindReplaceLogicStatus(FindReplaceLogicStatus.MessageCode.READONLY);
+ return false;
+ }
+ }
+ return isEditable();
+ }
+
+ /**
+ * Replaces the current selection of the target with the user's replace string.
+ *
+ * @param replaceString the String to replace the selection with
+ *
+ * @return true
if the operation was successful
+ */
+ private boolean replaceSelection(String replaceString) {
+
+ if (!prepareTargetForEditing()) {
+ return false;
+ }
+
+ if (replaceString == null) {
+ replaceString = ""; //$NON-NLS-1$
+ }
+
+ boolean replaced;
+ try {
+ replaceSelection(replaceString, isRegExSearchAvailableAndActive());
+ replaced = true;
+ } catch (PatternSyntaxException ex) {
+ status = new FindReplaceLogicMessage(ex.getLocalizedMessage());
+ replaced = false;
+ } catch (IllegalStateException ex) {
+ replaced = false;
+ }
+
+ return replaced;
+ }
+
+ /**
+ * Locates the user's findString in the target
+ *
+ * @param searchString the String to search for
+ * @return Whether the string was found in the target
+ *
+ */
+ @Override
+ public boolean performSearch(String searchString) {
+ return performSearch(shouldInitIncrementalBaseLocation(), searchString);
+ }
+
+ /**
+ * Locates the user's findString in the text of the target.
+ *
+ * @param mustInitIncrementalBaseLocation true
if base location
+ * must be initialized
+ * @param findString the String to search for
+ * @return Whether the string was found in the target
+ */
+ private boolean performSearch(boolean mustInitIncrementalBaseLocation, String findString) {
+ if (mustInitIncrementalBaseLocation) {
+ initIncrementalBaseLocation();
+ }
+ resetStatus();
+
+ boolean somethingFound = false;
+
+ if (findString != null && !findString.isEmpty()) {
+
+ try {
+ somethingFound = findNext(findString, isActive(SearchOptions.FORWARD));
+ } catch (PatternSyntaxException ex) {
+ status = new FindReplaceLogicMessage(ex.getLocalizedMessage());
+ } catch (IllegalStateException ex) {
+ // we don't keep state in this dialog
+ }
+ }
+ return somethingFound;
+ }
+
+ /**
+ * Replaces all occurrences of the user's findString with the replace string.
+ * Returns the number of replacements that occur.
+ *
+ * @param findString the string to search for
+ * @param replaceString the replacement string
+ * expression
+ * @return the number of occurrences
+ *
+ */
+ private int replaceAll(String findString, String replaceString) {
+
+ int replaceCount = 0;
+ int findReplacePosition = 0;
+
+ findReplacePosition = 0;
+
+ if (!prepareTargetForEditing()) {
+ return replaceCount;
+ }
+
+ if (target instanceof IFindReplaceTargetExtension) {
+ ((IFindReplaceTargetExtension) target).setReplaceAllMode(true);
+ }
+
+ try {
+ int index = 0;
+ while (index != -1) {
+ index = findAndSelect(findReplacePosition, findString);
+ if (index != -1) { // substring not contained from current position
+ Point selection = replaceSelection(replaceString, isRegExSearchAvailableAndActive());
+ replaceCount++;
+ findReplacePosition = selection.x + selection.y;
+ }
+ }
+ } finally {
+ if (target instanceof IFindReplaceTargetExtension)
+ ((IFindReplaceTargetExtension) target).setReplaceAllMode(false);
+ }
+
+ return replaceCount;
+ }
+
+ /**
+ * @param findString the String to select as part of the search
+ * @return The amount of selected Elements
+ */
+ private int selectAll(String findString) {
+
+ int selectCount = 0;
+ int position = 0;
+
+ if (!prepareTargetForEditing()) {
+ return selectCount;
+ }
+
+ List selectedRegions = new ArrayList<>();
+ int index = 0;
+ do {
+ index = findAndSelect(position, findString);
+ if (index != -1) { // substring not contained from current position
+ Point selection = target.getSelection();
+ selectedRegions.add(new Region(selection.x, selection.y));
+ selectCount++;
+ position = selection.x + selection.y;
+ }
+ } while (index != -1);
+ if (target instanceof IFindReplaceTargetExtension4) {
+ ((IFindReplaceTargetExtension4) target).setSelection(selectedRegions.toArray(IRegion[]::new));
+ }
+
+ return selectCount;
+ }
+
+ /**
+ * Returns the position of the specified search string, or -1
if
+ * the string can not be found when searching using the given options.
+ *
+ * @param findString the string to search for
+ * @param startPosition the position at which to start the search
+ * @return the occurrence of the find string following the options or
+ * -1
if nothing found
+ */
+ private int findIndex(String findString, int startPosition) {
+ int index = 0;
+ if (isActive(SearchOptions.FORWARD)) {
+ index = findAndSelect(startPosition, findString);
+ } else {
+ index = startPosition == 0 ? -1
+ : findAndSelect(startPosition - 1, findString);
+ }
+
+ if (index == -1) {
+
+ if (isActive(SearchOptions.WRAP)) {
+ statusLineMessage(FindReplaceMessages.FindReplace_Status_wrapped_label);
+ status = new FindReplaceLogicStatus(FindReplaceLogicStatus.MessageCode.WRAPPED);
+ index = findAndSelect(-1, findString);
+ } else {
+ status = new FindReplaceLogicStatus(FindReplaceLogicStatus.MessageCode.NO_MATCH);
+ }
+ }
+ return index;
+ }
+
+ /**
+ * Searches for a string starting at the given offset and using the specified
+ * search directives. If a string has been found it is selected and its start
+ * offset is returned. * * @param offset the offset at which searching starts
+ *
+ * @param findString the string which should be found
+ * @return the position of the specified string, or -1 if the string has not
+ * been found
+ */
+ @Override
+ public int findAndSelect(int offset, String findString) {
+ if (target instanceof IFindReplaceTargetExtension3)
+ return ((IFindReplaceTargetExtension3) target).findAndSelect(offset, findString,
+ isActive(SearchOptions.FORWARD),
+ isActive(SearchOptions.CASE_SENSITIVE), isWholeWordSearchAvailableAndActive(), isActive(SearchOptions.REGEX));
+ return target.findAndSelect(offset, findString, isActive(SearchOptions.FORWARD),
+ isActive(SearchOptions.CASE_SENSITIVE),
+ isWholeWordSearchAvailableAndActive());
+ }
+
+ /**
+ * Replaces the selection with replaceString
. If
+ * regExReplace
is true
, replaceString
is
+ * a regex replace pattern which will get expanded if the underlying target
+ * supports it. Returns the region of the inserted text; note that the returned
+ * selection covers the expanded pattern in case of regex replace.
+ *
+ * @param replaceString the replace string (or a regex pattern)
+ * @param regExReplace true
if replaceString
is a
+ * pattern
+ * @return the selection after replacing, i.e. the inserted text
+ */
+ private Point replaceSelection(String replaceString, boolean regExReplace) {
+ if (target instanceof IFindReplaceTargetExtension3)
+ ((IFindReplaceTargetExtension3) target).replaceSelection(replaceString, regExReplace);
+ else
+ target.replaceSelection(replaceString);
+
+ return target.getSelection();
+ }
+
+ /**
+ * Returns whether the specified search string can be found using the given
+ * options.
+ *
+ * @param findString the string to search for
+ * @param forwardSearch the direction of the search
+ * @return true
if the search string can be found using the given
+ * options
+ *
+ */
+ private boolean findNext(String findString, boolean forwardSearch) {
+
+ if (target == null) {
+ return false;
+ }
+
+ Point r = null;
+ if (isActive(SearchOptions.INCREMENTAL)) {
+ r = incrementalBaseLocation;
+ } else {
+ r = target.getSelection();
+ }
+
+ int findReplacePosition = r.x;
+ if (forwardSearch // && !nextReplaceOperationNeedsFindOperationFirst
+ ) { // || !forwardSearch && nextReplaceOperationNeedsFindOperationFirst) {
+ findReplacePosition += r.y;
+ }
+
+ // nextReplaceOperationNeedsFindOperationFirst = false;
+
+ int index = findIndex(findString, findReplacePosition);
+
+ if (index == -1) {
+ String msg = NLSUtility.format(FindReplaceMessages.FindReplace_Status_noMatchWithValue_label, findString);
+ statusLineMessage(false, msg);
+ status = new FindReplaceLogicStatus(FindReplaceLogicStatus.MessageCode.NO_MATCH);
+ return false;
+ }
+
+ if (forwardSearch && index >= findReplacePosition || !forwardSearch && index <= findReplacePosition) {
+ statusLineMessage(""); //$NON-NLS-1$
+ }
+
+ return true;
+ }
+
+ /**
+ * Replaces the selection and jumps to the next occurrence of findString
+ * instantly. If another operation annotated that we need to select the
+ * occurrence of findString first before replacing, this method does so. (eg,
+ * after replacing once, we automatically perform findAndSelect
+ * once before being able to replace again).
+ */
+ @Override
+ public boolean performReplaceAndFind(String findString, String replaceString) {
+ resetStatus();
+ if (performSelectAndReplace(findString, replaceString)) {
+ performSearch(findString);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean performSelectAndReplace(String findString, String replaceString) {
+ resetStatus();
+ boolean needToSelectFirst = !getCurrentSelection().equals(findString);
+ if (needToSelectFirst) {
+ performSearch(findString);
+ }
+ return replaceSelection(replaceString);
+ }
+
+ @Override
+ public void updateTarget(IFindReplaceTarget newTarget, boolean canEditTarget) {
+ resetStatus();
+ this.isTargetEditable = canEditTarget;
+ // nextReplaceOperationNeedsFindOperationFirst = true;
+
+ if (this.target != newTarget) {
+ if (newTarget != null && newTarget instanceof IFindReplaceTargetExtension)
+ ((IFindReplaceTargetExtension) newTarget).endSession();
+
+ this.target = newTarget;
+ if (newTarget != null)
+ isTargetSupportingRegEx = newTarget instanceof IFindReplaceTargetExtension3;
+
+ if (newTarget instanceof IFindReplaceTargetExtension) {
+ ((IFindReplaceTargetExtension) newTarget).beginSession();
+
+ activate(SearchOptions.GLOBAL);
+ }
+ }
+
+ initIncrementalBaseLocation();
+ }
+
+ @Override
+ public void dispose() {
+ if (target != null && target instanceof IFindReplaceTargetExtension) {
+ ((IFindReplaceTargetExtension) target).endSession();
+ }
+
+ target = null;
+ }
+
+ private String getCurrentSelection() {
+ if (target == null) {
+ return null;
+ }
+
+ return target.getSelectionText();
+ }
+
+ /**
+ * Returns whether the target is editable.
+ *
+ * @return true
if target is editable
+ */
+ private boolean isEditable() {
+ boolean isEditable = (target == null ? false : target.isEditable());
+ return isTargetEditable && isEditable;
+ }
+
+ /**
+ * Sets the given status message in the status line.
+ *
+ * @param error true
if it is an error
+ * @param editorMessage the message to display in the editor's status line
+ */
+ private void statusLineMessage(boolean error, String editorMessage) {
+ IEditorStatusLine statusLine = getStatusLineManager();
+ if (statusLine != null) {
+ statusLine.setMessage(error, editorMessage, null);
+ }
+ }
+
+ /**
+ * Sets the given message in the status line.
+ *
+ * @param message the message
+ */
+ private void statusLineMessage(String message) {
+ statusLineMessage(false, message);
+ }
+
+ /**
+ * Updates the search result after the Text was Modified. Used in combination
+ * with setIncrementalSearch(true)
. This method specifically allows
+ * for "search-as-you-type"
+ *
+ * "Search-as-you-type" is not compatible with RegEx-search. This will
+ * initialize the base-location for search (if not initialized already) but will
+ * not update it, meaning that incrementally searching the same string twice in
+ * a row will always yield the same result, unless the Base location was
+ * modified (eg., by performing "find next")
+ *
+ * @param searchString the String that is to be searched
+ */
+ @Override
+ public void performIncrementalSearch(String searchString) {
+ resetStatus();
+
+ if (isActive(SearchOptions.INCREMENTAL) && !isRegExSearchAvailableAndActive()) {
+ if (searchString.equals("") && target != null) { //$NON-NLS-1$
+ // empty selection at base location
+ int offset = incrementalBaseLocation.x;
+
+ if (isActive(SearchOptions.FORWARD)) { // && !nextReplaceOperationNeedsFindOperationFirst
+ // || !isActive(SearchOptions.FORWARD) &&
+ // nextReplaceOperationNeedsFindOperationFirst) {
+ offset = offset + incrementalBaseLocation.y;
+ }
+
+ // nextReplaceOperationNeedsFindOperationFirst = false;
+ findAndSelect(offset, ""); //$NON-NLS-1$
+ } else {
+ performSearch(false, searchString);
+ }
+ }
+ }
+
+ @Override
+ public IFindReplaceTarget getTarget() {
+ return target;
+ }
+
+}
diff --git a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/FindReplaceLogicFindAllStatus.java b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/FindReplaceLogicFindAllStatus.java
new file mode 100644
index 00000000000..379d1c6c954
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/FindReplaceLogicFindAllStatus.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Vector Informatik GmbH and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Vector Informatik GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ui.internal.findandreplace;
+
+public class FindReplaceLogicFindAllStatus implements IFindReplaceLogicStatus {
+ private int selectCount;
+
+ public FindReplaceLogicFindAllStatus(int selectCount) {
+ if (selectCount <= 0) {
+ // invalid value - what to do? Throw an exception?! @HeikoKlare
+ }
+ this.selectCount = selectCount;
+ }
+
+ public int getSelectCount() {
+ return selectCount;
+ }
+
+ @Override
+ public T visit(IFindReplaceLogicStatusVisitor visitor) {
+ return visitor.visit(this);
+ }
+
+}
diff --git a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/FindReplaceLogicMessage.java b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/FindReplaceLogicMessage.java
new file mode 100644
index 00000000000..2ad8406eb87
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/FindReplaceLogicMessage.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Vector Informatik GmbH and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Vector Informatik GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ui.internal.findandreplace;
+
+/**
+ * Avoid using this class. It is used as a glue to correctly map to the
+ * error-messages generated by RegEx-Errors which are directly displayed in
+ * plain text.
+ *
+ * Prefer using and extending {@link FindReplaceLogicStatus}
+ */
+public class FindReplaceLogicMessage implements IFindReplaceLogicStatus {
+
+ private String message;
+
+ public FindReplaceLogicMessage(String message) {
+ this.message = message;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ @Override
+ public T visit(IFindReplaceLogicStatusVisitor visitor) {
+ return visitor.visit(this);
+ }
+
+}
diff --git a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/FindReplaceLogicMessageGenerator.java b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/FindReplaceLogicMessageGenerator.java
new file mode 100644
index 00000000000..a0301507ff7
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/FindReplaceLogicMessageGenerator.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Vector Informatik GmbH and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Vector Informatik GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ui.internal.findandreplace;
+
+import org.eclipse.ui.internal.texteditor.NLSUtility;
+
+public class FindReplaceLogicMessageGenerator implements IFindReplaceLogicStatusVisitor {
+
+ @Override
+ public String visit(IFindReplaceLogicStatus status) {
+ return ""; //$NON-NLS-1$
+ }
+
+ @Override
+ public String visit(FindReplaceLogicReplaceAllStatus status) {
+ int replaceCount = status.getReplaceCount();
+ if (replaceCount == 1) {
+ return FindReplaceMessages.FindReplace_Status_replacement_label;
+ }
+ return NLSUtility.format(FindReplaceMessages.FindReplace_Status_replacements_label, replaceCount);
+ }
+
+ @Override
+ public String visit(FindReplaceLogicStatus status) {
+ FindReplaceLogicStatus.MessageCode messageCode = status.getMessageCode();
+ String message;
+ switch (messageCode) {
+ case NO_MATCH:
+ message = FindReplaceMessages.FindReplace_Status_noMatch_label;
+ break;
+ case WRAPPED:
+ message = FindReplaceMessages.FindReplace_Status_wrapped_label;
+ break;
+ case READONLY:
+ message = FindReplaceMessages.FindReplaceDialog_read_only;
+ break;
+ case NONE:
+ default:
+ message = ""; //$NON-NLS-1$
+ }
+
+ return message;
+ }
+
+ @Override
+ public String visit(FindReplaceLogicMessage status) {
+ return status.getMessage();
+ }
+
+ @Override
+ public String visit(FindReplaceLogicFindAllStatus status) {
+ int selectCount = status.getSelectCount();
+ if (selectCount == 1) {
+ return FindReplaceMessages.FindReplace_Status_selection_label;
+ }
+ return NLSUtility.format(FindReplaceMessages.FindReplace_Status_selections_label, selectCount);
+ }
+
+}
diff --git a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/FindReplaceLogicReplaceAllStatus.java b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/FindReplaceLogicReplaceAllStatus.java
new file mode 100644
index 00000000000..7ef140b2b46
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/FindReplaceLogicReplaceAllStatus.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Vector Informatik GmbH and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Vector Informatik GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ui.internal.findandreplace;
+
+public class FindReplaceLogicReplaceAllStatus implements IFindReplaceLogicStatus {
+ private int replaceCount;
+
+ public FindReplaceLogicReplaceAllStatus(int replaceCount) {
+ this.replaceCount = replaceCount;
+ }
+
+ public int getReplaceCount() {
+ return replaceCount;
+ }
+
+ @Override
+ public T visit(IFindReplaceLogicStatusVisitor visitor) {
+ return visitor.visit(this);
+ }
+
+}
diff --git a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/FindReplaceLogicStatus.java b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/FindReplaceLogicStatus.java
new file mode 100644
index 00000000000..0d3bf628bbc
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/FindReplaceLogicStatus.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Vector Informatik GmbH and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Vector Informatik GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ui.internal.findandreplace;
+
+public class FindReplaceLogicStatus implements IFindReplaceLogicStatus {
+
+ public enum MessageCode {
+ NO_MATCH,
+ NONE, WRAPPED, READONLY,
+ }
+
+ private MessageCode messageCode;
+
+ public FindReplaceLogicStatus(MessageCode errorCode) {
+ this.messageCode = errorCode;
+ }
+
+ public MessageCode getMessageCode() {
+ return messageCode;
+ }
+
+ @Override
+ public T visit(IFindReplaceLogicStatusVisitor visitor) {
+ return visitor.visit(this);
+ }
+
+}
diff --git a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/FindReplaceMessages.java b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/FindReplaceMessages.java
new file mode 100644
index 00000000000..e53b4c4e396
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/FindReplaceMessages.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Vector Informatik GmbH and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Vector Informatik GmbH - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.findandreplace;
+
+import org.eclipse.osgi.util.NLS;
+
+final public class FindReplaceMessages extends NLS {
+
+ public static final String BUNDLE_NAME = FindReplaceMessages.class.getName();
+
+ private FindReplaceMessages() {
+ // Do not instantiate
+ }
+
+ static {
+ NLS.initializeMessages(BUNDLE_NAME, FindReplaceMessages.class);
+ }
+
+ public static String FindReplace_Status_replacement_label;
+ public static String FindReplace_Status_replacements_label;
+ public static String FindReplace_Status_noMatchWithValue_label;
+ public static String FindReplace_Status_wrapped_label;
+ public static String FindReplaceDialog_read_only;
+ public static String FindReplace_Status_selections_label;
+ public static String FindReplace_Status_selection_label;
+ public static String FindReplace_Status_noMatch_Label;
+ public static String FindReplace_Status_noMatch_label;
+ public static String FindNext_Status_noMatch_label;
+
+ // The "classic" Find/Replace-Dialog
+ public static String FindReplace_Dialog_Title;
+ public static String FindReplace_Find_label;
+ public static String FindReplace_Replace_label;
+ public static String FindReplace_Direction;
+ public static String FindReplace_ForwardRadioButton_label;
+ public static String FindReplace_BackwardRadioButton_label;
+ public static String FindReplace_Scope;
+ public static String FindReplace_GlobalRadioButton_label;
+ public static String FindReplace_SelectedRangeRadioButton_label;
+ public static String FindReplace_Options;
+ public static String FindReplace_CaseCheckBox_label;
+ public static String FindReplace_WrapCheckBox_label;
+ public static String FindReplace_WholeWordCheckBox_label;
+ public static String FindReplace_IncrementalCheckBox_label;
+ public static String FindReplace_RegExCheckbox_label;
+ public static String FindReplace_FindNextButton_label;
+ public static String FindReplace_ReplaceFindButton_label;
+ public static String FindReplace_ReplaceSelectionButton_label;
+ public static String FindReplace_ReplaceAllButton_label;
+ public static String FindReplace_SelectAllButton_label;
+ public static String FindReplace_CloseButton_label;
+
+
+}
diff --git a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/FindReplaceMessages.properties b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/FindReplaceMessages.properties
new file mode 100644
index 00000000000..8762ce8a59b
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/FindReplaceMessages.properties
@@ -0,0 +1,47 @@
+################################################################################
+# Copyright (c) 2023 Vector Informatik GmbH and others_
+#
+# This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License 2_0
+# which accompanies this distribution, and is available at
+# https://www_eclipse_org/legal/epl-2_0/
+#
+# SPDX-License-Identifier: EPL-2_0
+#
+# Contributors:
+# Vector Informatik GmbH - initial API and implementation
+############################################################################
+
+# FindReplace_Status_noMatch_label=String not found
+FindReplace_Status_noMatchWithValue_label=String {0} not found
+FindReplace_Status_replacement_label=1 match replaced
+FindReplace_Status_replacements_label={0} matches replaced
+FindReplace_Status_selection_label=1 match selected
+FindReplace_Status_selections_label={0} matches selected
+FindReplace_Status_wrapped_label=Wrapped search
+FindReplace_Status_noMatch_label=String not found
+FindNext_Status_noMatch_label=String {0} not found
+FindReplaceDialog_read_only=Cannot replace. File is read-only.
+
+# Messages for the "classic" Find-Replace-Dialog
+FindReplace_Dialog_Title= Find/Replace
+FindReplace_Find_label=&Find:
+FindReplace_Replace_label=R&eplace with:
+FindReplace_Direction=Direction
+FindReplace_ForwardRadioButton_label=F&orward
+FindReplace_BackwardRadioButton_label=&Backward
+FindReplace_Scope=Scope
+FindReplace_GlobalRadioButton_label=A&ll
+FindReplace_SelectedRangeRadioButton_label=Selec&ted lines
+FindReplace_Options=Options
+FindReplace_CaseCheckBox_label=&Case sensitive
+FindReplace_WrapCheckBox_label=Wra&p search
+FindReplace_WholeWordCheckBox_label=&Whole word
+FindReplace_IncrementalCheckBox_label=&Incremental
+FindReplace_RegExCheckbox_label= Regular e&xpressions
+FindReplace_FindNextButton_label=Fi&nd
+FindReplace_ReplaceFindButton_label=Replace/Fin&d
+FindReplace_ReplaceSelectionButton_label=&Replace
+FindReplace_ReplaceAllButton_label=Replace &All
+FindReplace_SelectAllButton_label=&Select All
+FindReplace_CloseButton_label=Close
\ No newline at end of file
diff --git a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/HistoryStore.java b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/HistoryStore.java
new file mode 100644
index 00000000000..c874092c68c
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/HistoryStore.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Vector Informatik GmbH and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Vector Informatik GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ui.internal.findandreplace;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Vector;
+
+import org.eclipse.jface.dialogs.IDialogSettings;
+
+/**
+ * Store for search-histories or replace-histories inside of a dialog.. Stores
+ * the nodes using the DialogSettings-mechanism.
+ */
+public class HistoryStore {
+ IDialogSettings settingsManager;
+ private int historySize;
+ Vector history;
+ String sectionName;
+
+ /**
+ * @param settingsManager
+ * @param sectionName The name of the section in the DialogSettings
+ * containing the history
+ * @param historySize how many entries to keep in the history
+ */
+ public HistoryStore(IDialogSettings settingsManager, String sectionName, int historySize) {
+ this.settingsManager = settingsManager;
+ this.historySize = historySize;
+ loadSection(sectionName);
+ }
+
+ public Vector get() {
+ return history;
+ }
+
+ public String get(int index) {
+ return history.get(index);
+ }
+
+
+ public void add(String historyItem) {
+ if (sectionName == null) {
+ throw new Error("No section loaded"); //$NON-NLS-1$
+ }
+ if (historyItem != null && !historyItem.isEmpty())
+ history.add(0, historyItem);
+
+ writeHistory();
+ }
+
+ public boolean isEmpty() {
+ return history.isEmpty();
+ }
+
+ private void loadSection(String newSectionName) {
+ this.sectionName = newSectionName;
+
+ history = new Vector<>(Arrays.asList(settingsManager.getArray(newSectionName)));
+ }
+
+ /**
+ * Writes the given history into the given dialog store.
+ */
+ private void writeHistory() {
+ int itemCount = history.size();
+ Set distinctItems = new HashSet<>(itemCount);
+ for (int i = 0; i < itemCount; i++) {
+ String item = history.get(i);
+ if (distinctItems.contains(item)) {
+ history.remove(i--);
+ itemCount--;
+ } else {
+ distinctItems.add(item);
+ }
+ }
+
+ while (history.size() > historySize)
+ history.remove(historySize);
+
+ String[] names = new String[history.size()];
+ history.toArray(names);
+ settingsManager.put(sectionName, names);
+ }
+
+}
diff --git a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/IFindReplaceLogic.java b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/IFindReplaceLogic.java
new file mode 100644
index 00000000000..0987569520b
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/IFindReplaceLogic.java
@@ -0,0 +1,148 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Vector Informatik GmbH and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Vector Informatik GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ui.internal.findandreplace;
+
+import org.eclipse.swt.widgets.Display;
+
+import org.eclipse.jface.text.IFindReplaceTarget;
+
+/**
+ * Implements a generalized logic operator for in-file Find/Replace-Operations.
+ * Requires a target that inherits from {@link IFindReplaceTarget} to operate.
+ * Allows enabling or disabling different {@link SearchOptions} which will be
+ * applied to subsequent operations.
+ */
+public interface IFindReplaceLogic {
+
+ /**
+ * Activate a search option
+ *
+ * @param searchOption option
+ */
+ public void activate(SearchOptions searchOption);
+
+ /**
+ * Deactivate a search option
+ *
+ * @param searchOption option
+ */
+ public void deactivate(SearchOptions searchOption);
+
+ /**
+ * @param searchOption option
+ * @return whether the option is active
+ */
+ public boolean isActive(SearchOptions searchOption);
+
+ /**
+ * Returns the current status of FindReplaceLogic. The Status can inform about
+ * events such as an error happening, a warning happening (e.g.: the
+ * search-string wasn't found) and brings a method to retrieve a message that
+ * can directly be displayed to the user.
+ *
+ * @return FindAndReplaceMessageStatus
+ */
+ IFindReplaceLogicStatus getStatus();
+
+ boolean isRegExSearchAvailableAndActive();
+
+ /**
+ * Tells the dialog to perform searches only in the scope given by the actually
+ * selected lines.
+ *
+ * @param selectedLines true
if selected lines should be used
+ */
+ void useSelectedLines(boolean selectedLines);
+
+ /**
+ * Updates the search result after the Text was Modified. Used in combination
+ * with setIncrementalSearch(true)
. This method specifically allows
+ * for "search-as-you-type"
+ *
+ * "Search-as-you-type" is not compatible with RegEx-search. This will
+ * initialize the base-location for search (if not initialized already) but will
+ * not update it, meaning that incrementally searching the same string twice in
+ * a row will always yield the same result, unless the Base location was
+ * modified (eg., by performing "find next")
+ *
+ * @param searchString the String that is to be searched
+ */
+ void performIncrementalSearch(String searchString);
+
+ /**
+ * Replaces all occurrences of the user's findString with the replace string.
+ * Indicate to the user the number of replacements that occur.
+ *
+ * @param findString The string that will be replaced
+ * @param replaceString The string that will replace the findString
+ * @param display the display on which the busy feedback should be
+ * displayed. If the display is null, the Display for the
+ * current thread will be used. If there is no Display for
+ * the current thread,the runnable code will be executed
+ * and no busy feedback will be displayed.y
+ */
+ void performReplaceAll(String findString, String replaceString, Display display);
+
+ /**
+ * Selects all occurrences of findString.
+ *
+ * @param findString The String to find and select
+ * @param display The UI's Display The UI's Display
+ */
+ void performSelectAll(String findString, Display display);
+
+ /**
+ * Locates the user's findString in the target
+ *
+ * @param searchString the String to search for
+ * @return Whether the string was found in the target
+ *
+ */
+ boolean performSearch(String searchString);
+
+ /**
+ * Searches for a string starting at the given offset and using the specified
+ * search directives. If a string has been found it is selected and its start
+ * offset is returned.
+ *
+ * @param offset the offset at which searching starts
+ * @param findString the string which should be found
+ * @return the position of the specified string, or -1 if the string has not
+ * been found
+ */
+ int findAndSelect(int offset, String findString);
+
+ /**
+ * Replaces the selection and jumps to the next occurrence of findString
+ * instantly. Will not fail in case the selection is invalidated, eg. after a
+ * replace operation or after the target was updated
+ *
+ * @param findString the string to replace
+ * @param replaceString the string to put in place of findString
+ * @return whether a replacement has been performed
+ */
+ boolean performReplaceAndFind(String findString, String replaceString);
+
+ boolean performSelectAndReplace(String findString, String replaceString);
+
+ void updateTarget(IFindReplaceTarget newTarget, boolean canEditTarget);
+
+ void dispose();
+
+ /*
+ * @return the Target that FindReplaceLogic operates on
+ */
+ IFindReplaceTarget getTarget();
+
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/IFindReplaceLogicStatus.java b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/IFindReplaceLogicStatus.java
new file mode 100644
index 00000000000..7d367a059e6
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/IFindReplaceLogicStatus.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Vector Informatik GmbH and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Vector Informatik GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ui.internal.findandreplace;
+
+/**
+ * Marker interface for all Status-objects that a Find/Replace-Operation could
+ * return
+ */
+public interface IFindReplaceLogicStatus {
+ public T visit(IFindReplaceLogicStatusVisitor visitor);
+}
diff --git a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/IFindReplaceLogicStatusVisitor.java b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/IFindReplaceLogicStatusVisitor.java
new file mode 100644
index 00000000000..bdfdb87a740
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/IFindReplaceLogicStatusVisitor.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Vector Informatik GmbH and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Vector Informatik GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ui.internal.findandreplace;
+
+public interface IFindReplaceLogicStatusVisitor {
+ public T visit(IFindReplaceLogicStatus status);
+
+ public T visit(FindReplaceLogicReplaceAllStatus status);
+
+ public T visit(FindReplaceLogicStatus status);
+
+ public T visit(FindReplaceLogicMessage status);
+
+ public T visit(FindReplaceLogicFindAllStatus status);
+
+}
diff --git a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/SearchOptions.java b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/SearchOptions.java
new file mode 100644
index 00000000000..f3238e0989e
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/SearchOptions.java
@@ -0,0 +1,18 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Vector Informatik GmbH and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Vector Informatik GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ui.internal.findandreplace;
+
+public enum SearchOptions {
+ GLOBAL, WRAP, CASE_SENSITIVE, WHOLE_WORD, REGEX, FORWARD, INCREMENTAL,
+}
diff --git a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/EditorMessages.java b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/EditorMessages.java
index 9715d5c0e64..fcb5fd0b47c 100644
--- a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/EditorMessages.java
+++ b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/EditorMessages.java
@@ -98,34 +98,7 @@ private EditorMessages() {
public static String Editor_statusline_position_pattern_selection;
public static String Editor_statusline_error_label;
public static String WorkbenchChainedTextFontFieldEditor_defaultWorkbenchTextFont;
- public static String FindReplace_title;
- public static String FindReplace_Find_label;
- public static String FindReplace_Replace_label;
- public static String FindReplace_Direction;
- public static String FindReplace_ForwardRadioButton_label;
- public static String FindReplace_BackwardRadioButton_label;
- public static String FindReplace_Scope;
- public static String FindReplace_GlobalRadioButton_label;
- public static String FindReplace_SelectedRangeRadioButton_label;
- public static String FindReplace_Options;
- public static String FindReplace_CaseCheckBox_label;
- public static String FindReplace_WrapCheckBox_label;
- public static String FindReplace_WholeWordCheckBox_label;
- public static String FindReplace_IncrementalCheckBox_label;
- public static String FindReplace_RegExCheckbox_label;
- public static String FindReplace_FindNextButton_label;
- public static String FindReplace_ReplaceFindButton_label;
- public static String FindReplace_ReplaceSelectionButton_label;
- public static String FindReplace_ReplaceAllButton_label;
- public static String FindReplace_SelectAllButton_label;
- public static String FindReplace_CloseButton_label;
- public static String FindReplace_Status_noMatch_label;
- public static String FindReplace_Status_noMatchWithValue_label;
- public static String FindReplace_Status_replacement_label;
- public static String FindReplace_Status_replacements_label;
- public static String FindReplace_Status_selection_label;
- public static String FindReplace_Status_selections_label;
- public static String FindReplace_Status_wrapped_label;
+
public static String FindNext_Status_noMatch_label;
public static String AbstractDocumentProvider_ok;
public static String AbstractDocumentProvider_error;
diff --git a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/EditorMessages.properties b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/EditorMessages.properties
index 8ef0eb868c5..2bed0396c3e 100644
--- a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/EditorMessages.properties
+++ b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/EditorMessages.properties
@@ -95,34 +95,6 @@ Editor_statusline_error_label=?
## Others ##
WorkbenchChainedTextFontFieldEditor_defaultWorkbenchTextFont=
-FindReplace_title= Find/Replace
-FindReplace_Find_label=&Find:
-FindReplace_Replace_label=R&eplace with:
-FindReplace_Direction=Direction
-FindReplace_ForwardRadioButton_label=F&orward
-FindReplace_BackwardRadioButton_label=&Backward
-FindReplace_Scope=Scope
-FindReplace_GlobalRadioButton_label=A&ll
-FindReplace_SelectedRangeRadioButton_label=Selec&ted lines
-FindReplace_Options=Options
-FindReplace_CaseCheckBox_label=&Case sensitive
-FindReplace_WrapCheckBox_label=Wra&p search
-FindReplace_WholeWordCheckBox_label=&Whole word
-FindReplace_IncrementalCheckBox_label=&Incremental
-FindReplace_RegExCheckbox_label= Regular e&xpressions
-FindReplace_FindNextButton_label=Fi&nd
-FindReplace_ReplaceFindButton_label=Replace/Fin&d
-FindReplace_ReplaceSelectionButton_label=&Replace
-FindReplace_ReplaceAllButton_label=Replace &All
-FindReplace_SelectAllButton_label=&Select All
-FindReplace_CloseButton_label=Close
-FindReplace_Status_noMatch_label=String not found
-FindReplace_Status_noMatchWithValue_label=String ''{0}'' not found
-FindReplace_Status_replacement_label=1 match replaced
-FindReplace_Status_replacements_label={0} matches replaced
-FindReplace_Status_selection_label=1 match selected
-FindReplace_Status_selections_label={0} matches selected
-FindReplace_Status_wrapped_label=Wrapped search
FindNext_Status_noMatch_label=String ''{0}'' not found
diff --git a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceAction.java b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceAction.java
index 5839928d3c8..6c7c7fa9599 100644
--- a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceAction.java
+++ b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceAction.java
@@ -34,16 +34,15 @@
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.IWorkbenchWindow;
-
/**
- * An action which opens a Find/Replace dialog.
- * The dialog while open, tracks the active workbench part
- * and retargets itself to the active find/replace target.
+ * An action which opens a Find/Replace dialog. The dialog while open, tracks
+ * the active workbench part and retargets itself to the active find/replace
+ * target.
*
- * It can also be used without having an IWorkbenchPart e.g. for
- * dialogs or wizards by just providing a {@link Shell} and an {@link IFindReplaceTarget}.
- * In this case the dialog won't be shared with the one
- * used for the active workbench part.
+ * It can also be used without having an IWorkbenchPart e.g. for dialogs or
+ * wizards by just providing a {@link Shell} and an {@link IFindReplaceTarget}.
+ * In this case the dialog won't be shared with the one used for the active
+ * workbench part.
*
*
* This class may be instantiated; it is not intended to be subclassed.
@@ -53,17 +52,24 @@
* @noextend This class is not intended to be subclassed by clients.
*/
public class FindReplaceAction extends ResourceAction implements IUpdate {
+ private static boolean MW_FIND_REPLACE_OVERLAY_SHOULD_ABSOLUTELY_REPLACE_WITH_A_PROPERTY_LATER = true;
+
+ private static boolean shouldShowModernOverlay() {
+ return MW_FIND_REPLACE_OVERLAY_SHOULD_ABSOLUTELY_REPLACE_WITH_A_PROPERTY_LATER;
+ }
/**
- * Represents the "global" find/replace dialog. It tracks the active
- * part and retargets the find/replace dialog accordingly. The find/replace
- * target is retrieved from the active part using
+ * Represents the "global" find/replace dialog. It tracks the active part and
+ * retargets the find/replace dialog accordingly. The find/replace target is
+ * retrieved from the active part using
* getAdapter(IFindReplaceTarget.class)
.
*
- * The stub has the same life cycle as the find/replace dialog.
+ * The stub has the same life cycle as the find/replace dialog.
+ *
*
- * If no IWorkbenchPart is available a Shell must be provided
- * In this case the IFindReplaceTarget will never change.
+ * If no IWorkbenchPart is available a Shell must be provided In this case the
+ * IFindReplaceTarget will never change.
+ *
*/
static class FindReplaceDialogStub implements IPartListener2, IPageChangedListener, DisposeListener {
@@ -86,8 +92,8 @@ static class FindReplaceDialogStub implements IPartListener2, IPageChangedListen
*/
public FindReplaceDialogStub(IWorkbenchPartSite site) {
this(site.getShell());
- fWindow= site.getWorkbenchWindow();
- IPartService service= fWindow.getPartService();
+ fWindow = site.getWorkbenchWindow();
+ IPartService service = fWindow.getPartService();
service.addPartListener(this);
partActivated(service.getActivePart());
}
@@ -99,7 +105,7 @@ public FindReplaceDialogStub(IWorkbenchPartSite site) {
* @since 3.3
*/
public FindReplaceDialogStub(Shell shell) {
- fDialog= new FindReplaceDialog(shell);
+ fDialog = new FindReplaceDialog(shell);
fDialog.create();
fDialog.getShell().addDisposeListener(this);
}
@@ -114,19 +120,19 @@ public FindReplaceDialog getDialog() {
}
private void partActivated(IWorkbenchPart part) {
- IFindReplaceTarget target= part == null ? null : part.getAdapter(IFindReplaceTarget.class);
- fPreviousPart= fPart;
- fPart= target == null ? null : part;
+ IFindReplaceTarget target = part == null ? null : part.getAdapter(IFindReplaceTarget.class);
+ fPreviousPart = fPart;
+ fPart = target == null ? null : part;
if (fPreviousTarget != target) {
- fPreviousTarget= target;
+ fPreviousTarget = target;
if (fDialog != null) {
- boolean isEditable= false;
+ boolean isEditable = false;
if (fPart instanceof ITextEditorExtension2) {
- ITextEditorExtension2 extension= (ITextEditorExtension2) fPart;
- isEditable= extension.isEditorInputModifiable();
+ ITextEditorExtension2 extension = (ITextEditorExtension2) fPart;
+ isEditable = extension.isEditorInputModifiable();
} else if (target != null)
- isEditable= target.isEditable();
+ isEditable = target.isEditable();
fDialog.updateTarget(target, isEditable, false);
}
}
@@ -140,38 +146,38 @@ public void partActivated(IWorkbenchPartReference partRef) {
@Override
public void pageChanged(PageChangedEvent event) {
if (event.getSource() instanceof IWorkbenchPart)
- partActivated((IWorkbenchPart)event.getSource());
+ partActivated((IWorkbenchPart) event.getSource());
}
@Override
public void partClosed(IWorkbenchPartReference partRef) {
- IWorkbenchPart part= partRef.getPart(true);
+ IWorkbenchPart part = partRef.getPart(true);
if (part == fPreviousPart) {
- fPreviousPart= null;
- fPreviousTarget= null;
+ fPreviousPart = null;
+ fPreviousTarget = null;
}
if (part == fPart)
- partActivated((IWorkbenchPart)null);
+ partActivated((IWorkbenchPart) null);
}
@Override
public void widgetDisposed(DisposeEvent event) {
if (fgFindReplaceDialogStub == this)
- fgFindReplaceDialogStub= null;
+ fgFindReplaceDialogStub = null;
- if(fgFindReplaceDialogStubShell == this)
- fgFindReplaceDialogStubShell= null;
+ if (fgFindReplaceDialogStubShell == this)
+ fgFindReplaceDialogStubShell = null;
if (fWindow != null) {
fWindow.getPartService().removePartListener(this);
- fWindow= null;
+ fWindow = null;
}
- fDialog= null;
- fPart= null;
- fPreviousPart= null;
- fPreviousTarget= null;
+ fDialog = null;
+ fPart = null;
+ fPreviousPart = null;
+ fPreviousTarget = null;
}
@Override
@@ -199,8 +205,8 @@ public void partVisible(IWorkbenchPartReference partRef) {
}
/**
- * Checks if the dialogs shell is the same as the given shell
and if not clears
- * the stub and closes the dialog.
+ * Checks if the dialogs shell is the same as the given shell
and
+ * if not clears the stub and closes the dialog.
*
* @param shell the shell check
* @since 3.3
@@ -208,10 +214,10 @@ public void partVisible(IWorkbenchPartReference partRef) {
public void checkShell(Shell shell) {
if (fDialog != null && shell != fDialog.getParentShell()) {
if (fgFindReplaceDialogStub == this)
- fgFindReplaceDialogStub= null;
+ fgFindReplaceDialogStub = null;
if (fgFindReplaceDialogStubShell == this)
- fgFindReplaceDialogStubShell= null;
+ fgFindReplaceDialogStubShell = null;
fDialog.close();
}
@@ -219,17 +225,20 @@ public void checkShell(Shell shell) {
}
-
/**
* Listener for disabling the dialog on shell close.
*
- * This stub is shared amongst IWorkbenchPart
s.
+ * This stub is shared amongst IWorkbenchPart
s.
+ *
*/
private static FindReplaceDialogStub fgFindReplaceDialogStub;
- /** Listener for disabling the dialog on shell close.
+ /**
+ * Listener for disabling the dialog on shell close.
*
- * This stub is shared amongst Shell
s.
+ * This stub is shared amongst Shell
s.
+ *
+ *
* @since 3.3
*/
private static FindReplaceDialogStub fgFindReplaceDialogStubShell;
@@ -242,45 +251,51 @@ public void checkShell(Shell shell) {
private IWorkbenchWindow fWorkbenchWindow;
/**
* The shell to use if the action is created with a shell.
+ *
* @since 3.3
*/
private Shell fShell;
+ private FindReplaceOverlay overlay;
+
/**
* Creates a new find/replace action for the given workbench part.
*
- * The action configures its visual representation from the given
- * resource bundle.
+ * The action configures its visual representation from the given resource
+ * bundle.
+ *
*
- * @param bundle the resource bundle
- * @param prefix a prefix to be prepended to the various resource keys
- * (described in ResourceAction
constructor), or
- * null
if none
- * @param workbenchPart the workbench part
+ * @param bundle the resource bundle
+ * @param prefix a prefix to be prepended to the various resource keys
+ * (described in ResourceAction
constructor),
+ * or null
if none
+ * @param workbenchPart the workbench part
* @see ResourceAction#ResourceAction(ResourceBundle, String)
*/
public FindReplaceAction(ResourceBundle bundle, String prefix, IWorkbenchPart workbenchPart) {
super(bundle, prefix);
Assert.isLegal(workbenchPart != null);
- fWorkbenchPart= workbenchPart;
+ fWorkbenchPart = workbenchPart;
update();
}
/**
* Creates a new find/replace action for the given target and shell.
*
- * This can be used without having an IWorkbenchPart e.g. for
- * dialogs or wizards.
+ * This can be used without having an IWorkbenchPart e.g. for dialogs or
+ * wizards.
+ *
*
- * The action configures its visual representation from the given
- * resource bundle.
+ * The action configures its visual representation from the given resource
+ * bundle.
+ *
*
* @param bundle the resource bundle
* @param prefix a prefix to be prepended to the various resource keys
- * (described in ResourceAction
constructor), or
- * null
if none
+ * (described in ResourceAction
constructor), or
+ * null
if none
* @param target the IFindReplaceTarget to use
- * @param shell the shell
+ * @param shell the shell
* @see ResourceAction#ResourceAction(ResourceBundle, String)
*
* @since 3.3
@@ -288,81 +303,117 @@ public FindReplaceAction(ResourceBundle bundle, String prefix, IWorkbenchPart wo
public FindReplaceAction(ResourceBundle bundle, String prefix, Shell shell, IFindReplaceTarget target) {
super(bundle, prefix);
Assert.isLegal(target != null && shell != null);
- fTarget= target;
- fShell= shell;
+ fTarget = target;
+ fShell = shell;
update();
}
/**
- * Creates a new find/replace action for the given workbench window.
- * The action configures its visual representation from the given
- * resource bundle.
+ * Creates a new find/replace action for the given workbench window. The action
+ * configures its visual representation from the given resource bundle.
*
- * @param bundle the resource bundle
- * @param prefix a prefix to be prepended to the various resource keys
- * (described in ResourceAction
constructor), or
- * null
if none
+ * @param bundle the resource bundle
+ * @param prefix a prefix to be prepended to the various resource keys
+ * (described in ResourceAction
+ * constructor), or null
if none
* @param workbenchWindow the workbench window
* @see ResourceAction#ResourceAction(ResourceBundle, String)
*
- * @deprecated use FindReplaceAction(ResourceBundle, String, IWorkbenchPart) instead
+ * @deprecated use FindReplaceAction(ResourceBundle, String, IWorkbenchPart)
+ * instead
*/
@Deprecated
public FindReplaceAction(ResourceBundle bundle, String prefix, IWorkbenchWindow workbenchWindow) {
super(bundle, prefix);
- fWorkbenchWindow= workbenchWindow;
+ fWorkbenchWindow = workbenchWindow;
update();
}
@Override
public void run() {
- if (fTarget == null)
- return;
+ if (shouldShowModernOverlay()) {
+ showModernOverlay();
+ } else {
+ if (fTarget == null)
+ return;
+ showClassicDialog();
+ }
+ }
+
+ /**
+ * @since 3.18.0
+ */
+ public void showClassicDialog() {
final FindReplaceDialog dialog;
final boolean isEditable;
- if(fShell == null) {
+ if (fShell == null) {
if (fgFindReplaceDialogStub != null) {
- Shell shell= fWorkbenchPart.getSite().getShell();
+ Shell shell = fWorkbenchPart.getSite().getShell();
fgFindReplaceDialogStub.checkShell(shell);
}
if (fgFindReplaceDialogStub == null)
- fgFindReplaceDialogStub= new FindReplaceDialogStub(fWorkbenchPart.getSite());
+ fgFindReplaceDialogStub = new FindReplaceDialogStub(fWorkbenchPart.getSite());
if (fWorkbenchPart instanceof ITextEditorExtension2)
- isEditable= ((ITextEditorExtension2) fWorkbenchPart).isEditorInputModifiable();
+ isEditable = ((ITextEditorExtension2) fWorkbenchPart).isEditorInputModifiable();
else
- isEditable= fTarget.isEditable();
+ isEditable = fTarget.isEditable();
- dialog= fgFindReplaceDialogStub.getDialog();
+ dialog = fgFindReplaceDialogStub.getDialog();
} else {
if (fgFindReplaceDialogStubShell != null) {
fgFindReplaceDialogStubShell.checkShell(fShell);
}
if (fgFindReplaceDialogStubShell == null)
- fgFindReplaceDialogStubShell= new FindReplaceDialogStub(fShell);
+ fgFindReplaceDialogStubShell = new FindReplaceDialogStub(fShell);
- isEditable= fTarget.isEditable();
- dialog= fgFindReplaceDialogStubShell.getDialog();
+ isEditable = fTarget.isEditable();
+ dialog = fgFindReplaceDialogStubShell.getDialog();
}
dialog.updateTarget(fTarget, isEditable, true);
dialog.open();
}
+ private void showModernOverlay() {
+ if (overlay == null) {
+ Shell shellToUse;
+ if (fShell == null) {
+ shellToUse = fWorkbenchPart.getSite().getShell();
+ } else {
+ shellToUse = fShell;
+ }
+ overlay = new FindReplaceOverlay(shellToUse, fWorkbenchPart, fTarget, this);
+ }
+ overlay.create();
+ overlay.open();
+ }
+
+ /**
+ * Closes the "modern" overlay. Typically called by the overlay itself.
+ *
+ * @since 3.18
+ */
+ public void closeModernOverlay() {
+ if (overlay != null) {
+ overlay.close();
+ }
+ }
+
@Override
public void update() {
- if(fShell == null){
+ if (fShell == null) {
if (fWorkbenchPart == null && fWorkbenchWindow != null)
- fWorkbenchPart= fWorkbenchWindow.getPartService().getActivePart();
+ fWorkbenchPart = fWorkbenchWindow.getPartService().getActivePart();
if (fWorkbenchPart != null)
- fTarget= fWorkbenchPart.getAdapter(IFindReplaceTarget.class);
+ fTarget = fWorkbenchPart.getAdapter(IFindReplaceTarget.class);
else
- fTarget= null;
+ fTarget = null;
}
setEnabled(fTarget != null && fTarget.canPerformFind());
}
diff --git a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceDialog.java b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceDialog.java
index fae3682279a..2e3f6deb64a 100644
--- a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceDialog.java
+++ b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceDialog.java
@@ -15,18 +15,12 @@
*******************************************************************************/
package org.eclipse.ui.texteditor;
-import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
-import java.util.Set;
-import java.util.regex.PatternSyntaxException;
import org.osgi.framework.FrameworkUtil;
import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
@@ -62,19 +56,20 @@
import org.eclipse.jface.text.FindReplaceDocumentAdapter;
import org.eclipse.jface.text.FindReplaceDocumentAdapterContentProposalProvider;
import org.eclipse.jface.text.IFindReplaceTarget;
-import org.eclipse.jface.text.IFindReplaceTargetExtension;
import org.eclipse.jface.text.IFindReplaceTargetExtension3;
import org.eclipse.jface.text.IFindReplaceTargetExtension4;
-import org.eclipse.jface.text.IRegion;
-import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.TextUtilities;
-import org.eclipse.ui.IEditorPart;
-import org.eclipse.ui.IWorkbenchPage;
-import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.fieldassist.ContentAssistCommandAdapter;
-import org.eclipse.ui.internal.texteditor.NLSUtility;
+import org.eclipse.ui.internal.findandreplace.FindReplaceLogic;
+import org.eclipse.ui.internal.findandreplace.FindReplaceLogicMessageGenerator;
+import org.eclipse.ui.internal.findandreplace.FindReplaceLogicStatus;
+import org.eclipse.ui.internal.findandreplace.FindReplaceMessages;
+import org.eclipse.ui.internal.findandreplace.HistoryStore;
+import org.eclipse.ui.internal.findandreplace.IFindReplaceLogic;
+import org.eclipse.ui.internal.findandreplace.IFindReplaceLogicStatus;
+import org.eclipse.ui.internal.findandreplace.SearchOptions;
import org.eclipse.ui.internal.texteditor.SWTUtil;
@@ -82,9 +77,10 @@
* Find/Replace dialog. The dialog is opened on a particular
* target but can be re-targeted. Internally used by the FindReplaceAction
*/
-class FindReplaceDialog extends Dialog {
+public class FindReplaceDialog extends Dialog {
private static final int CLOSE_BUTTON_ID = 101;
+ private IFindReplaceLogic findReplacer;
/**
* Updates the find replace dialog on activation changes.
@@ -108,18 +104,14 @@ public void shellDeactivated(ShellEvent e) {
fGlobalRadioButton.setSelection(true);
fSelectedRangeRadioButton.setSelection(false);
- fUseSelectedLines= false;
-
- if (fTarget != null && (fTarget instanceof IFindReplaceTargetExtension))
- ((IFindReplaceTargetExtension) fTarget).setScope(null);
-
- fOldScope= null;
-
fActiveShell= null;
updateButtonState();
}
+
}
+ private final FindModifyListener fFindModifyListener = new FindModifyListener();
+
/**
* Modify listener to update the search result in case of incremental search.
* @since 2.0
@@ -129,7 +121,7 @@ private class FindModifyListener implements ModifyListener {
// XXX: Workaround for Combo bug on Linux (see bug 404202 and bug 410603)
private boolean fIgnoreNextEvent;
private void ignoreNextEvent() {
- fIgnoreNextEvent= true;
+ fIgnoreNextEvent = true;
}
@Override
@@ -137,57 +129,26 @@ public void modifyText(ModifyEvent e) {
// XXX: Workaround for Combo bug on Linux (see bug 404202 and bug 410603)
if (fIgnoreNextEvent) {
- fIgnoreNextEvent= false;
+ fIgnoreNextEvent = false;
return;
}
- if (isIncrementalSearch() && !isRegExSearchAvailableAndChecked()) {
- if (fFindField.getText().equals("") && fTarget != null) { //$NON-NLS-1$
- // empty selection at base location
- int offset= fIncrementalBaseLocation.x;
-
- if (isForwardSearch() && !fNeedsInitialFindBeforeReplace || !isForwardSearch() && fNeedsInitialFindBeforeReplace)
- offset= offset + fIncrementalBaseLocation.y;
+ findReplacer.performIncrementalSearch(getFindString());
- fNeedsInitialFindBeforeReplace= false;
- findAndSelect(offset, "", isForwardSearch(), isCaseSensitiveSearch(), isWholeWordSearch(), isRegExSearchAvailableAndChecked()); //$NON-NLS-1$
- } else {
- performSearch(false, false, isForwardSearch());
- }
- }
-
- updateButtonState(!isIncrementalSearch());
+ updateButtonState(!findReplacer.isActive(SearchOptions.INCREMENTAL));
}
}
/** The size of the dialogs search history. */
private static final int HISTORY_SIZE= 15;
- private Point fIncrementalBaseLocation;
- private boolean fWrapInit, fCaseInit, fWholeWordInit, fForwardInit, fGlobalInit, fIncrementalInit;
- /**
- * Tells whether an initial find operation is needed
- * before the replace operation.
- * @since 3.0
- */
- private boolean fNeedsInitialFindBeforeReplace;
- /**
- * Initial value for telling whether the search string is a regular expression.
- * @since 3.0
- */
- boolean fIsRegExInit;
-
- private List fFindHistory;
- private List fReplaceHistory;
- private IRegion fOldScope;
+ private HistoryStore findHistory;
+ private HistoryStore replaceHistory;
- private boolean fIsTargetEditable;
- private IFindReplaceTarget fTarget;
private Shell fParentShell;
private Shell fActiveShell;
private final ActivationListener fActivationListener= new ActivationListener();
- private final FindModifyListener fFindModifyListener= new FindModifyListener();
private Label fReplaceLabel, fStatusLabel;
private Button fForwardRadioButton, fGlobalRadioButton, fSelectedRangeRadioButton;
@@ -212,19 +173,9 @@ public void modifyText(ModifyEvent e) {
private IDialogSettings fDialogSettings;
/**
- * Tells whether the target supports regular expressions.
- * true
if the target supports regular expressions
- * @since 3.0
- */
- private boolean fIsTargetSupportingRegEx;
- /**
- * Tells whether fUseSelectedLines radio is checked.
- * @since 3.0
- */
- private boolean fUseSelectedLines;
- /**
- * true
if the find field should receive focus the next time
- * the dialog is activated, false
otherwise.
+ * true
if the find field should receive focus the next time the
+ * dialog is activated, false
otherwise.
+ *
* @since 3.0
*/
private boolean fGiveFocusToFindField= true;
@@ -242,23 +193,13 @@ public void modifyText(ModifyEvent e) {
*/
public FindReplaceDialog(Shell parentShell) {
super(parentShell);
-
+ findReplacer = new FindReplaceLogic();
fParentShell= null;
- fTarget= null;
-
fDialogPositionInit= null;
- fFindHistory= new ArrayList<>(HISTORY_SIZE);
- fReplaceHistory= new ArrayList<>(HISTORY_SIZE);
-
- fWrapInit= false;
- fCaseInit= false;
- fIsRegExInit= false;
- fWholeWordInit= false;
- fIncrementalInit= false;
- fGlobalInit= true;
- fForwardInit= true;
+ setupSearchHistory();
readConfiguration();
+ updateButtonState();
setShellStyle(getShellStyle() ^ SWT.APPLICATION_MODAL | SWT.MODELESS);
setBlockOnOpen(false);
@@ -302,9 +243,9 @@ public void create() {
// fill in combo contents
fFindField.removeModifyListener(fFindModifyListener);
- updateCombo(fFindField, fFindHistory);
+ updateCombo(fFindField, findHistory.get());
fFindField.addModifyListener(fFindModifyListener);
- updateCombo(fReplaceField, fReplaceHistory);
+ updateCombo(fReplaceField, replaceHistory.get());
// get find string
initFindStringFromSelection();
@@ -313,8 +254,9 @@ public void create() {
if (fDialogPositionInit != null)
shell.setBounds(fDialogPositionInit);
- shell.setText(EditorMessages.FindReplace_title);
- // shell.setImage(null);
+ shell.setText(FindReplaceMessages.FindReplace_Dialog_Title);
+
+ updateButtonState();
}
/**
@@ -330,67 +272,75 @@ private Composite createButtonSection(Composite parent) {
layout.numColumns= -2; // this is intended
panel.setLayout(layout);
- fFindNextButton= makeButton(panel, EditorMessages.FindReplace_FindNextButton_label, 102, true, new SelectionAdapter() {
+ fFindNextButton = makeButton(panel, FindReplaceMessages.FindReplace_FindNextButton_label, 102, true,
+ new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
- if (isIncrementalSearch() && !isRegExSearchAvailableAndChecked())
- initIncrementalBaseLocation();
-
- fNeedsInitialFindBeforeReplace= false;
- performSearch(((e.stateMask & SWT.MODIFIER_MASK) == SWT.SHIFT) ^ isForwardSearch());
+ boolean somethingFound = findReplacer.performSearch(getFindString());
+ writeSelection();
+ updateButtonState(!somethingFound);
updateFindHistory();
+ evaluateFindReplacerStatus();
}
});
setGridData(fFindNextButton, SWT.FILL, true, SWT.FILL, false);
- fSelectAllButton = makeButton(panel, EditorMessages.FindReplace_SelectAllButton_label, 106, false,
+ fSelectAllButton = makeButton(panel, FindReplaceMessages.FindReplace_SelectAllButton_label, 106, false,
new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
- performSelectAll();
+ findReplacer.performSelectAll(getFindString(), fActiveShell.getDisplay());
+ writeSelection();
+ updateButtonState();
updateFindAndReplaceHistory();
+ evaluateFindReplacerStatus();
}
});
setGridData(fSelectAllButton, SWT.FILL, true, SWT.FILL, false);
new Label(panel, SWT.NONE); // filler
- fReplaceFindButton= makeButton(panel, EditorMessages.FindReplace_ReplaceFindButton_label, 103, false, new SelectionAdapter() {
+ fReplaceFindButton = makeButton(panel, FindReplaceMessages.FindReplace_ReplaceFindButton_label, 103, false,
+ new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
- if (fNeedsInitialFindBeforeReplace)
- performSearch(((e.stateMask & SWT.MODIFIER_MASK) == SWT.SHIFT) ^ isForwardSearch());
- if (performReplaceSelection())
- performSearch(((e.stateMask & SWT.MODIFIER_MASK) == SWT.SHIFT) ^ isForwardSearch());
+ if (findReplacer.performReplaceAndFind(getFindString(), getReplaceString())) {
+ writeSelection();
+ }
+ updateButtonState();
updateFindAndReplaceHistory();
+ evaluateFindReplacerStatus();
}
});
setGridData(fReplaceFindButton, SWT.FILL, false, SWT.FILL, false);
- fReplaceSelectionButton= makeButton(panel, EditorMessages.FindReplace_ReplaceSelectionButton_label, 104, false, new SelectionAdapter() {
+ fReplaceSelectionButton = makeButton(panel, FindReplaceMessages.FindReplace_ReplaceSelectionButton_label, 104,
+ false, new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
- if (fNeedsInitialFindBeforeReplace)
- performSearch();
- performReplaceSelection();
+ if (findReplacer.performSelectAndReplace(getFindString(), getReplaceString())) {
+ writeSelection();
+ }
updateButtonState();
updateFindAndReplaceHistory();
+ evaluateFindReplacerStatus();
}
});
setGridData(fReplaceSelectionButton, SWT.FILL, false, SWT.FILL, false);
- fReplaceAllButton= makeButton(panel, EditorMessages.FindReplace_ReplaceAllButton_label, 105, false, new SelectionAdapter() {
+ fReplaceAllButton = makeButton(panel, FindReplaceMessages.FindReplace_ReplaceAllButton_label, 105, false,
+ new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
- performReplaceAll();
+ findReplacer.performReplaceAll(getFindString(), getReplaceString(), fActiveShell.getDisplay());
+ writeSelection();
+ updateButtonState();
updateFindAndReplaceHistory();
+ evaluateFindReplacerStatus();
}
});
setGridData(fReplaceAllButton, SWT.FILL, true, SWT.FILL, false);
- // Make the all the buttons the same size as the Remove Selection button.
- fReplaceAllButton.setEnabled(isEditable());
-
return panel;
}
@@ -527,7 +477,7 @@ private Composite createDirectionGroup(Composite parent) {
panel.setLayout(layout);
Group group= new Group(panel, SWT.SHADOW_ETCHED_IN);
- group.setText(EditorMessages.FindReplace_Direction);
+ group.setText(FindReplaceMessages.FindReplace_Direction);
GridLayout groupLayout= new GridLayout();
group.setLayout(groupLayout);
group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
@@ -535,29 +485,30 @@ private Composite createDirectionGroup(Composite parent) {
SelectionListener selectionListener= new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent e) {
- if (isIncrementalSearch() && !isRegExSearchAvailableAndChecked())
- initIncrementalBaseLocation();
+ activateInFindReplacerIf(SearchOptions.FORWARD, fForwardRadioButton.getSelection());
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {
+ // Do nothing
}
};
fForwardRadioButton= new Button(group, SWT.RADIO | SWT.LEFT);
- fForwardRadioButton.setText(EditorMessages.FindReplace_ForwardRadioButton_label);
+ fForwardRadioButton.setText(FindReplaceMessages.FindReplace_ForwardRadioButton_label);
setGridData(fForwardRadioButton, SWT.LEFT, false, SWT.CENTER, false);
fForwardRadioButton.addSelectionListener(selectionListener);
storeButtonWithMnemonicInMap(fForwardRadioButton);
Button backwardRadioButton= new Button(group, SWT.RADIO | SWT.LEFT);
- backwardRadioButton.setText(EditorMessages.FindReplace_BackwardRadioButton_label);
+ backwardRadioButton.setText(FindReplaceMessages.FindReplace_BackwardRadioButton_label);
setGridData(backwardRadioButton, SWT.LEFT, false, SWT.CENTER, false);
backwardRadioButton.addSelectionListener(selectionListener);
storeButtonWithMnemonicInMap(backwardRadioButton);
- backwardRadioButton.setSelection(!fForwardInit);
- fForwardRadioButton.setSelection(fForwardInit);
+ activateInFindReplacerIf(SearchOptions.FORWARD, true); // search forward by default
+ backwardRadioButton.setSelection(!findReplacer.isActive(SearchOptions.FORWARD));
+ fForwardRadioButton.setSelection(findReplacer.isActive(SearchOptions.FORWARD));
return panel;
}
@@ -578,22 +529,22 @@ private Composite createScopeGroup(Composite parent) {
panel.setLayout(layout);
Group group= new Group(panel, SWT.SHADOW_ETCHED_IN);
- group.setText(EditorMessages.FindReplace_Scope);
+ group.setText(FindReplaceMessages.FindReplace_Scope);
GridLayout groupLayout= new GridLayout();
group.setLayout(groupLayout);
group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
fGlobalRadioButton= new Button(group, SWT.RADIO | SWT.LEFT);
- fGlobalRadioButton.setText(EditorMessages.FindReplace_GlobalRadioButton_label);
+ fGlobalRadioButton.setText(FindReplaceMessages.FindReplace_GlobalRadioButton_label);
setGridData(fGlobalRadioButton, SWT.LEFT, false, SWT.CENTER, false);
- fGlobalRadioButton.setSelection(fGlobalInit);
+ fGlobalRadioButton.setSelection(findReplacer.isActive(SearchOptions.GLOBAL));
fGlobalRadioButton.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent e) {
- if (!fGlobalRadioButton.getSelection() || !fUseSelectedLines)
+ if (!fGlobalRadioButton.getSelection() || findReplacer.isActive(SearchOptions.GLOBAL))
return;
- fUseSelectedLines= false;
- useSelectedLines(false);
+ activateInFindReplacerIf(SearchOptions.GLOBAL, true);
+ findReplacer.useSelectedLines(false);
}
@Override
@@ -603,17 +554,16 @@ public void widgetDefaultSelected(SelectionEvent e) {
storeButtonWithMnemonicInMap(fGlobalRadioButton);
fSelectedRangeRadioButton= new Button(group, SWT.RADIO | SWT.LEFT);
- fSelectedRangeRadioButton.setText(EditorMessages.FindReplace_SelectedRangeRadioButton_label);
+ fSelectedRangeRadioButton.setText(FindReplaceMessages.FindReplace_SelectedRangeRadioButton_label);
setGridData(fSelectedRangeRadioButton, SWT.LEFT, false, SWT.CENTER, false);
- fSelectedRangeRadioButton.setSelection(!fGlobalInit);
- fUseSelectedLines= !fGlobalInit;
+ fSelectedRangeRadioButton.setSelection(!findReplacer.isActive(SearchOptions.GLOBAL));
fSelectedRangeRadioButton.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent e) {
- if (!fSelectedRangeRadioButton.getSelection() || fUseSelectedLines)
+ if (!fSelectedRangeRadioButton.getSelection() || !findReplacer.isActive(SearchOptions.GLOBAL))
return;
- fUseSelectedLines= true;
- useSelectedLines(true);
+ activateInFindReplacerIf(SearchOptions.GLOBAL, false);
+ findReplacer.useSelectedLines(true);
}
@Override
@@ -625,42 +575,6 @@ public void widgetDefaultSelected(SelectionEvent e) {
return panel;
}
- /**
- * Tells the dialog to perform searches only in the scope given by the actually selected lines.
- * @param selectedLines true
if selected lines should be used
- * @since 2.0
- */
- private void useSelectedLines(boolean selectedLines) {
- if (isIncrementalSearch() && !isRegExSearchAvailableAndChecked())
- initIncrementalBaseLocation();
-
- if (fTarget == null || !(fTarget instanceof IFindReplaceTargetExtension))
- return;
-
- IFindReplaceTargetExtension extensionTarget= (IFindReplaceTargetExtension) fTarget;
-
- if (selectedLines) {
-
- IRegion scope;
- if (fOldScope == null) {
- Point lineSelection= extensionTarget.getLineSelection();
- scope= new Region(lineSelection.x, lineSelection.y);
- } else {
- scope= fOldScope;
- fOldScope= null;
- }
-
- int offset= isForwardSearch()
- ? scope.getOffset()
- : scope.getOffset() + scope.getLength();
-
- extensionTarget.setSelection(offset, 0);
- extensionTarget.setScope(scope);
- } else {
- fOldScope= extensionTarget.getScope();
- extensionTarget.setScope(null);
- }
- }
/**
* Creates the panel where the user specifies the text to search
@@ -679,7 +593,7 @@ private Composite createInputPanel(Composite parent) {
panel.setLayout(layout);
Label findLabel= new Label(panel, SWT.LEFT);
- findLabel.setText(EditorMessages.FindReplace_Find_label);
+ findLabel.setText(FindReplaceMessages.FindReplace_Find_label);
setGridData(findLabel, SWT.LEFT, false, SWT.CENTER, false);
// Create the find content assist field
@@ -698,7 +612,7 @@ private Composite createInputPanel(Composite parent) {
fFindField.addModifyListener(fFindModifyListener);
fReplaceLabel= new Label(panel, SWT.LEFT);
- fReplaceLabel.setText(EditorMessages.FindReplace_Replace_label);
+ fReplaceLabel.setText(FindReplaceMessages.FindReplace_Replace_label);
setGridData(fReplaceLabel, SWT.LEFT, false, SWT.CENTER, false);
// Create the replace content assist field
@@ -733,7 +647,7 @@ private Composite createOptionsGroup(Composite parent) {
panel.setLayout(layout);
Group group= new Group(panel, SWT.SHADOW_NONE);
- group.setText(EditorMessages.FindReplace_Options);
+ group.setText(FindReplaceMessages.FindReplace_Options);
GridLayout groupLayout= new GridLayout();
groupLayout.numColumns= 2;
groupLayout.makeColumnsEqualWidth= true;
@@ -743,6 +657,7 @@ private Composite createOptionsGroup(Composite parent) {
SelectionListener selectionListener= new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent e) {
+ setupFindReplacer();
storeSettings();
}
@@ -752,36 +667,34 @@ public void widgetDefaultSelected(SelectionEvent e) {
};
fCaseCheckBox= new Button(group, SWT.CHECK | SWT.LEFT);
- fCaseCheckBox.setText(EditorMessages.FindReplace_CaseCheckBox_label);
+ fCaseCheckBox.setText(FindReplaceMessages.FindReplace_CaseCheckBox_label);
setGridData(fCaseCheckBox, SWT.LEFT, false, SWT.CENTER, false);
- fCaseCheckBox.setSelection(fCaseInit);
+ fCaseCheckBox.setSelection(findReplacer.isActive(SearchOptions.CASE_SENSITIVE));
fCaseCheckBox.addSelectionListener(selectionListener);
storeButtonWithMnemonicInMap(fCaseCheckBox);
fWrapCheckBox= new Button(group, SWT.CHECK | SWT.LEFT);
- fWrapCheckBox.setText(EditorMessages.FindReplace_WrapCheckBox_label);
+ fWrapCheckBox.setText(FindReplaceMessages.FindReplace_WrapCheckBox_label);
setGridData(fWrapCheckBox, SWT.LEFT, false, SWT.CENTER, false);
- fWrapCheckBox.setSelection(fWrapInit);
+ fWrapCheckBox.setSelection(findReplacer.isActive(SearchOptions.WRAP));
fWrapCheckBox.addSelectionListener(selectionListener);
storeButtonWithMnemonicInMap(fWrapCheckBox);
fWholeWordCheckBox= new Button(group, SWT.CHECK | SWT.LEFT);
- fWholeWordCheckBox.setText(EditorMessages.FindReplace_WholeWordCheckBox_label);
+ fWholeWordCheckBox.setText(FindReplaceMessages.FindReplace_WholeWordCheckBox_label);
setGridData(fWholeWordCheckBox, SWT.LEFT, false, SWT.CENTER, false);
- fWholeWordCheckBox.setSelection(fWholeWordInit);
+ fWholeWordCheckBox.setSelection(findReplacer.isActive(SearchOptions.WHOLE_WORD));
fWholeWordCheckBox.addSelectionListener(selectionListener);
storeButtonWithMnemonicInMap(fWholeWordCheckBox);
fIncrementalCheckBox= new Button(group, SWT.CHECK | SWT.LEFT);
- fIncrementalCheckBox.setText(EditorMessages.FindReplace_IncrementalCheckBox_label);
+ fIncrementalCheckBox.setText(FindReplaceMessages.FindReplace_IncrementalCheckBox_label);
setGridData(fIncrementalCheckBox, SWT.LEFT, false, SWT.CENTER, false);
- fIncrementalCheckBox.setSelection(fIncrementalInit);
+ fIncrementalCheckBox.setSelection(findReplacer.isActive(SearchOptions.INCREMENTAL));
fIncrementalCheckBox.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent e) {
- if (isIncrementalSearch() && !isRegExSearch())
- initIncrementalBaseLocation();
-
+ setupFindReplacer();
storeSettings();
}
@@ -792,29 +705,30 @@ public void widgetDefaultSelected(SelectionEvent e) {
storeButtonWithMnemonicInMap(fIncrementalCheckBox);
fIsRegExCheckBox= new Button(group, SWT.CHECK | SWT.LEFT);
- fIsRegExCheckBox.setText(EditorMessages.FindReplace_RegExCheckbox_label);
+ fIsRegExCheckBox.setText(FindReplaceMessages.FindReplace_RegExCheckbox_label);
setGridData(fIsRegExCheckBox, SWT.LEFT, false, SWT.CENTER, false);
((GridData)fIsRegExCheckBox.getLayoutData()).horizontalSpan= 2;
- fIsRegExCheckBox.setSelection(fIsRegExInit);
+ fIsRegExCheckBox.setSelection(findReplacer.isActive(SearchOptions.REGEX));
fIsRegExCheckBox.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
boolean newState= fIsRegExCheckBox.getSelection();
fIncrementalCheckBox.setEnabled(!newState);
- updateButtonState();
+ setupFindReplacer();
storeSettings();
+ updateButtonState();
setContentAssistsEnablement(newState);
}
});
storeButtonWithMnemonicInMap(fIsRegExCheckBox);
- fWholeWordCheckBox.setEnabled(!isRegExSearchAvailableAndChecked());
+ fWholeWordCheckBox.setEnabled(!findReplacer.isRegExSearchAvailableAndActive());
fWholeWordCheckBox.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
updateButtonState();
}
});
- fIncrementalCheckBox.setEnabled(!isRegExSearchAvailableAndChecked());
+ fIncrementalCheckBox.setEnabled(!findReplacer.isRegExSearchAvailableAndActive());
return panel;
}
@@ -836,7 +750,7 @@ private Composite createStatusAndCloseButton(Composite parent) {
fStatusLabel= new Label(panel, SWT.LEFT);
setGridData(fStatusLabel, SWT.FILL, true, SWT.CENTER, false);
- String label= EditorMessages.FindReplace_CloseButton_label;
+ String label = FindReplaceMessages.FindReplace_CloseButton_label;
Button closeButton = createButton(panel, CLOSE_BUTTON_ID, label, false);
setGridData(closeButton, SWT.RIGHT, false, SWT.BOTTOM, false);
@@ -856,142 +770,6 @@ protected void buttonPressed(int buttonID) {
// ------- action invocation ---------------------------------------
- /**
- * Returns the position of the specified search string, or -1
if the string can not
- * be found when searching using the given options.
- *
- * @param findString the string to search for
- * @param startPosition the position at which to start the search
- * @param forwardSearch the direction of the search
- * @param caseSensitive should the search be case sensitive
- * @param wrapSearch should the search wrap to the start/end if arrived at the end/start
- * @param wholeWord does the search string represent a complete word
- * @param regExSearch if true
findString represents a regular expression
- * @param beep if true
beeps when search does not find a match or needs to wrap
- * @return the occurrence of the find string following the options or -1
if nothing
- * found
- * @since 3.0
- */
- private int findIndex(String findString, int startPosition, boolean forwardSearch, boolean caseSensitive, boolean wrapSearch, boolean wholeWord, boolean regExSearch, boolean beep) {
-
- if (forwardSearch) {
- int index= findAndSelect(startPosition, findString, true, caseSensitive, wholeWord, regExSearch);
- if (index == -1) {
-
- if (beep && okToUse(getShell()))
- getShell().getDisplay().beep();
-
- if (wrapSearch) {
- statusMessage(EditorMessages.FindReplace_Status_wrapped_label);
- index= findAndSelect(-1, findString, true, caseSensitive, wholeWord, regExSearch);
- }
- }
- return index;
- }
-
- // backward
- int index= startPosition == 0 ? -1 : findAndSelect(startPosition - 1, findString, false, caseSensitive, wholeWord, regExSearch);
- if (index == -1) {
-
- if (beep && okToUse(getShell()))
- getShell().getDisplay().beep();
-
- if (wrapSearch) {
- statusMessage(EditorMessages.FindReplace_Status_wrapped_label);
- index= findAndSelect(-1, findString, false, caseSensitive, wholeWord, regExSearch);
- }
- }
- return index;
- }
-
- /**
- * Searches for a string starting at the given offset and using the specified search
- * directives. If a string has been found it is selected and its start offset is
- * returned.
- *
- * @param offset the offset at which searching starts
- * @param findString the string which should be found
- * @param forwardSearch the direction of the search
- * @param caseSensitive true
performs a case sensitive search, false
an insensitive search
- * @param wholeWord if true
only occurrences are reported in which the findString stands as a word by itself
- * @param regExSearch if true
findString represents a regular expression
- * @return the position of the specified string, or -1 if the string has not been found
- * @since 3.0
- */
- private int findAndSelect(int offset, String findString, boolean forwardSearch, boolean caseSensitive, boolean wholeWord, boolean regExSearch) {
- if (fTarget instanceof IFindReplaceTargetExtension3)
- return ((IFindReplaceTargetExtension3)fTarget).findAndSelect(offset, findString, forwardSearch, caseSensitive, wholeWord, regExSearch);
- return fTarget.findAndSelect(offset, findString, forwardSearch, caseSensitive, wholeWord);
- }
-
- /**
- * Replaces the selection with replaceString
. If
- * regExReplace
is true
,
- * replaceString
is a regex replace pattern which will get
- * expanded if the underlying target supports it. Returns the region of the
- * inserted text; note that the returned selection covers the expanded
- * pattern in case of regex replace.
- *
- * @param replaceString the replace string (or a regex pattern)
- * @param regExReplace true
if replaceString
- * is a pattern
- * @return the selection after replacing, i.e. the inserted text
- * @since 3.0
- */
- Point replaceSelection(String replaceString, boolean regExReplace) {
- if (fTarget instanceof IFindReplaceTargetExtension3)
- ((IFindReplaceTargetExtension3)fTarget).replaceSelection(replaceString, regExReplace);
- else
- fTarget.replaceSelection(replaceString);
-
- return fTarget.getSelection();
- }
-
- /**
- * Returns whether the specified search string can be found using the given options.
- *
- * @param findString the string to search for
- * @param forwardSearch the direction of the search
- * @param caseSensitive should the search be case sensitive
- * @param wrapSearch should the search wrap to the start/end if arrived at the end/start
- * @param wholeWord does the search string represent a complete word
- * @param incremental is this an incremental search
- * @param regExSearch if true
findString represents a regular expression
- * @param beep if true
beeps when search does not find a match or needs to wrap
- * @return true
if the search string can be found using the given options
- *
- * @since 3.0
- */
- private boolean findNext(String findString, boolean forwardSearch, boolean caseSensitive, boolean wrapSearch, boolean wholeWord, boolean incremental, boolean regExSearch, boolean beep) {
-
- if (fTarget == null)
- return false;
-
- Point r= null;
- if (incremental)
- r= fIncrementalBaseLocation;
- else
- r= fTarget.getSelection();
-
- int findReplacePosition= r.x;
- if (forwardSearch && !fNeedsInitialFindBeforeReplace || !forwardSearch && fNeedsInitialFindBeforeReplace)
- findReplacePosition += r.y;
-
- fNeedsInitialFindBeforeReplace= false;
-
- int index= findIndex(findString, findReplacePosition, forwardSearch, caseSensitive, wrapSearch, wholeWord, regExSearch, beep);
-
- if (index == -1) {
- String msg= NLSUtility.format(EditorMessages.FindReplace_Status_noMatchWithValue_label, findString);
- statusMessage(false, EditorMessages.FindReplace_Status_noMatch_label, msg);
- return false;
- }
-
- if (forwardSearch && index >= findReplacePosition || !forwardSearch && index <= findReplacePosition)
- statusMessage(""); //$NON-NLS-1$
-
- return true;
- }
/**
* Returns the dialog's boundaries.
@@ -1003,14 +781,6 @@ private Rectangle getDialogBoundaries() {
return fDialogPositionInit;
}
- /**
- * Returns the dialog's history.
- * @return the dialog's history
- */
- private List getFindHistory() {
- return fFindHistory;
- }
-
// ------- accessors ---------------------------------------
/**
@@ -1024,14 +794,6 @@ private String getFindString() {
return ""; //$NON-NLS-1$
}
- /**
- * Returns the dialog's replace history.
- * @return the dialog's replace history
- */
- private List getReplaceHistory() {
- return fReplaceHistory;
- }
-
/**
* Retrieves the replacement string from the appropriate text input field and returns it.
* @return the replacement string
@@ -1091,13 +853,10 @@ private void handleDialogClose() {
// store current settings in case of re-open
storeSettings();
- if (fTarget != null && fTarget instanceof IFindReplaceTargetExtension)
- ((IFindReplaceTargetExtension) fTarget).endSession();
+ findReplacer.dispose();
// prevent leaks
fActiveShell= null;
- fTarget= null;
-
}
/**
@@ -1105,11 +864,12 @@ private void handleDialogClose() {
* @since 3.0
*/
private void writeSelection() {
- if (fTarget == null)
+ String selection = getCurrentSelection();
+ if (selection == null)
return;
IDialogSettings s= getDialogSettings();
- s.put("selection", fTarget.getSelectionText()); //$NON-NLS-1$
+ s.put("selection", selection); //$NON-NLS-1$
}
/**
@@ -1118,12 +878,6 @@ private void writeSelection() {
*/
private void storeSettings() {
fDialogPositionInit= getDialogBoundaries();
- fWrapInit= isWrapSearch();
- fWholeWordInit= isWholeWordSetting();
- fCaseInit= isCaseSensitiveSearch();
- fIsRegExInit= isRegExSearch();
- fIncrementalInit= isIncrementalSearch();
- fForwardInit= isForwardSearch();
writeConfiguration();
}
@@ -1134,9 +888,9 @@ private void storeSettings() {
* action's target.
*/
private void initFindStringFromSelection() {
- if (fTarget != null && okToUse(fFindField)) {
- String fullSelection= fTarget.getSelectionText();
- boolean isRegEx= isRegExSearchAvailableAndChecked();
+ String fullSelection = getCurrentSelection();
+ if (fullSelection != null && okToUse(fFindField)) {
+ boolean isRegEx = findReplacer.isRegExSearchAvailableAndActive();
fFindField.removeModifyListener(fFindModifyListener);
if (!fullSelection.isEmpty()) {
String firstLine= getFirstLine(fullSelection);
@@ -1144,15 +898,14 @@ private void initFindStringFromSelection() {
fFindField.setText(pattern);
if (!firstLine.equals(fullSelection)) {
// multiple lines selected
- useSelectedLines(true);
+ findReplacer.useSelectedLines(true);
fGlobalRadioButton.setSelection(false);
fSelectedRangeRadioButton.setSelection(true);
- fUseSelectedLines= true;
}
} else {
if ("".equals(fFindField.getText())) { //$NON-NLS-1$
- if (!fFindHistory.isEmpty())
- fFindField.setText(fFindHistory.get(0));
+ if (!findHistory.isEmpty())
+ fFindField.setText(findHistory.get(0));
else
fFindField.setText(""); //$NON-NLS-1$
}
@@ -1162,114 +915,6 @@ private void initFindStringFromSelection() {
}
}
- /**
- * Initializes the anchor used as starting point for incremental searching.
- * @since 2.0
- */
- private void initIncrementalBaseLocation() {
- if (fTarget != null && isIncrementalSearch() && !isRegExSearchAvailableAndChecked()) {
- fIncrementalBaseLocation= fTarget.getSelection();
- } else {
- fIncrementalBaseLocation= new Point(0, 0);
- }
- }
-
- // ------- history ---------------------------------------
-
- /**
- * Retrieves and returns the option case sensitivity from the appropriate check box.
- * @return true
if case sensitive
- */
- private boolean isCaseSensitiveSearch() {
- if (okToUse(fCaseCheckBox)) {
- return fCaseCheckBox.getSelection();
- }
- return fCaseInit;
- }
-
- /**
- * Retrieves and returns the regEx option from the appropriate check box.
- *
- * @return true
if case sensitive
- * @since 3.0
- */
- private boolean isRegExSearch() {
- if (okToUse(fIsRegExCheckBox)) {
- return fIsRegExCheckBox.getSelection();
- }
- return fIsRegExInit;
- }
-
- /**
- * If the target supports regular expressions search retrieves and returns
- * regEx option from appropriate check box.
- *
- * @return true
if regEx is available and checked
- * @since 3.0
- */
- private boolean isRegExSearchAvailableAndChecked() {
- if (okToUse(fIsRegExCheckBox)) {
- return fIsTargetSupportingRegEx && fIsRegExCheckBox.getSelection();
- }
- return fIsRegExInit;
- }
-
- /**
- * Retrieves and returns the option search direction from the appropriate check box.
- * @return true
if searching forward
- */
- private boolean isForwardSearch() {
- if (okToUse(fForwardRadioButton)) {
- return fForwardRadioButton.getSelection();
- }
- return fForwardInit;
- }
-
- /**
- * Retrieves and returns the option search whole words from the appropriate check box.
- * @return true
if searching for whole words
- */
- private boolean isWholeWordSetting() {
- if (okToUse(fWholeWordCheckBox)) {
- return fWholeWordCheckBox.getSelection();
- }
- return fWholeWordInit;
- }
-
- /**
- * Returns true
if searching should be restricted to entire
- * words, false
if not. This is the case if the respective
- * checkbox is turned on, regex is off, and the checkbox is enabled, i.e.
- * the current find string is an entire word.
- *
- * @return true
if the search is restricted to whole words
- */
- private boolean isWholeWordSearch() {
- return isWholeWordSetting() && !isRegExSearchAvailableAndChecked() && (okToUse(fWholeWordCheckBox) ? fWholeWordCheckBox.isEnabled() : true);
- }
-
- /**
- * Retrieves and returns the option wrap search from the appropriate check box.
- * @return true
if wrapping while searching
- */
- private boolean isWrapSearch() {
- if (okToUse(fWrapCheckBox)) {
- return fWrapCheckBox.getSelection();
- }
- return fWrapInit;
- }
-
- /**
- * Retrieves and returns the option incremental search from the appropriate check box.
- * @return true
if incremental search
- * @since 2.0
- */
- private boolean isIncrementalSearch() {
- if (okToUse(fIncrementalCheckBox)) {
- return fIncrementalCheckBox.getSelection();
- }
- return fIncrementalInit;
- }
/**
* Creates a button.
@@ -1299,331 +944,6 @@ private void storeButtonWithMnemonicInMap(Button button) {
fMnemonicButtonMap.put(Character.valueOf(Character.toLowerCase(mnemonic)), button);
}
- /**
- * Returns the status line manager of the active editor or null
if there is no such editor.
- * @return the status line manager of the active editor
- */
- private IEditorStatusLine getStatusLineManager() {
- IWorkbenchWindow window= PlatformUI.getWorkbench().getActiveWorkbenchWindow();
- if (window == null)
- return null;
-
- IWorkbenchPage page= window.getActivePage();
- if (page == null)
- return null;
-
- IEditorPart editor= page.getActiveEditor();
- if (editor == null)
- return null;
-
- return editor.getAdapter(IEditorStatusLine.class);
- }
-
- /**
- * Sets the given status message in the status line.
- *
- * @param error true
if it is an error
- * @param dialogMessage the message to display in the dialog's status line
- * @param editorMessage the message to display in the editor's status line
- */
- private void statusMessage(boolean error, String dialogMessage, String editorMessage) {
- fStatusLabel.setText(dialogMessage);
-
- if (error)
- fStatusLabel.setForeground(JFaceColors.getErrorText(fStatusLabel.getDisplay()));
- else
- fStatusLabel.setForeground(null);
-
- IEditorStatusLine statusLine= getStatusLineManager();
- if (statusLine != null)
- statusLine.setMessage(error, editorMessage, null);
-
- if (error)
- getShell().getDisplay().beep();
- }
-
- /**
- * Sets the given error message in the status line.
- * @param message the message
- */
- private void statusError(String message) {
- statusMessage(true, message, message);
- }
-
- /**
- * Sets the given message in the status line.
- * @param message the message
- */
- private void statusMessage(String message) {
- statusMessage(false, message, message);
- }
-
- /**
- * Replaces all occurrences of the user's findString with
- * the replace string. Indicate to the user the number of replacements
- * that occur.
- */
- private void performReplaceAll() {
-
- int replaceCount= 0;
- final String replaceString= getReplaceString();
- final String findString= getFindString();
-
- if (findString != null && !findString.isEmpty()) {
-
- class ReplaceAllRunnable implements Runnable {
- public int numberOfOccurrences;
- @Override
- public void run() {
- numberOfOccurrences = replaceAll(findString, replaceString == null ? "" : replaceString, //$NON-NLS-1$
- isCaseSensitiveSearch(), isWholeWordSearch(), isRegExSearchAvailableAndChecked());
- }
- }
-
- try {
- ReplaceAllRunnable runnable= new ReplaceAllRunnable();
- BusyIndicator.showWhile(fActiveShell.getDisplay(), runnable);
- replaceCount= runnable.numberOfOccurrences;
-
- if (replaceCount != 0) {
- if (replaceCount == 1) { // not plural
- statusMessage(EditorMessages.FindReplace_Status_replacement_label);
- } else {
- String msg= EditorMessages.FindReplace_Status_replacements_label;
- msg= NLSUtility.format(msg, String.valueOf(replaceCount));
- statusMessage(msg);
- }
- } else {
- String msg= NLSUtility.format(EditorMessages.FindReplace_Status_noMatchWithValue_label, findString);
- statusMessage(false, EditorMessages.FindReplace_Status_noMatch_label, msg);
- }
- } catch (PatternSyntaxException ex) {
- statusError(ex.getLocalizedMessage());
- } catch (IllegalStateException ex) {
- // we don't keep state in this dialog
- }
- }
- writeSelection();
- updateButtonState();
- }
-
- /**
- * Replaces all occurrences of the user's findString with the replace string.
- * Indicate to the user the number of replacements that occur.
- */
- private void performSelectAll() {
-
- int selectCount = 0;
- final String findString = getFindString();
-
- if (findString != null && !findString.isEmpty()) {
-
- class SelectAllRunnable implements Runnable {
- public int numberOfOccurrences;
-
- @Override
- public void run() {
- numberOfOccurrences = selectAll(findString, isCaseSensitiveSearch(), isWholeWordSearch(),
- isRegExSearchAvailableAndChecked());
- }
- }
-
- try {
- SelectAllRunnable runnable = new SelectAllRunnable();
- BusyIndicator.showWhile(fActiveShell.getDisplay(), runnable);
- selectCount = runnable.numberOfOccurrences;
-
- if (selectCount != 0) {
- if (selectCount == 1) { // not plural
- statusMessage(EditorMessages.FindReplace_Status_selection_label);
- } else {
- String msg = EditorMessages.FindReplace_Status_selections_label;
- msg = NLSUtility.format(msg, String.valueOf(selectCount));
- statusMessage(msg);
- }
- } else {
- String msg = NLSUtility.format(EditorMessages.FindReplace_Status_noMatchWithValue_label,
- findString);
- statusMessage(false, EditorMessages.FindReplace_Status_noMatch_label, msg);
- }
- } catch (PatternSyntaxException ex) {
- statusError(ex.getLocalizedMessage());
- } catch (IllegalStateException ex) {
- // we don't keep state in this dialog
- }
- }
- writeSelection();
- updateButtonState();
- }
-
- /**
- * Validates the state of the find/replace target.
- *
- * @return true
if target can be changed, false
- * otherwise
- * @since 2.1
- */
- private boolean validateTargetState() {
-
- if (fTarget instanceof IFindReplaceTargetExtension2) {
- IFindReplaceTargetExtension2 extension= (IFindReplaceTargetExtension2) fTarget;
- if (!extension.validateTargetState()) {
- statusError(EditorMessages.FindReplaceDialog_read_only);
- updateButtonState();
- return false;
- }
- }
- return isEditable();
- }
-
- /**
- * Replaces the current selection of the target with the user's
- * replace string.
- *
- * @return true
if the operation was successful
- */
- private boolean performReplaceSelection() {
-
- if (!validateTargetState())
- return false;
-
- String replaceString= getReplaceString();
- if (replaceString == null)
- replaceString= ""; //$NON-NLS-1$
-
- boolean replaced;
- try {
- replaceSelection(replaceString, isRegExSearchAvailableAndChecked());
- replaced= true;
- writeSelection();
- } catch (PatternSyntaxException ex) {
- statusError(ex.getLocalizedMessage());
- replaced= false;
- } catch (IllegalStateException ex) {
- replaced= false;
- }
-
- return replaced;
- }
-
- /**
- * Locates the user's findString in the text of the target.
- */
- private void performSearch() {
- performSearch(isForwardSearch());
- }
-
- /**
- * Locates the user's findString in the text of the target.
- *
- * @param forwardSearch true
if searching forwards, false
otherwise
- * @since 3.7
- */
- private void performSearch(boolean forwardSearch) {
- performSearch(isIncrementalSearch() && !isRegExSearchAvailableAndChecked(), true, forwardSearch);
- }
-
- /**
- * Locates the user's findString in the text of the target.
- *
- * @param mustInitIncrementalBaseLocation true
if base location must be initialized
- * @param beep if true
beeps when search does not find a match or needs to wrap
- * @param forwardSearch the search direction
- * @since 3.0
- */
- private void performSearch(boolean mustInitIncrementalBaseLocation, boolean beep, boolean forwardSearch) {
-
- if (mustInitIncrementalBaseLocation)
- initIncrementalBaseLocation();
-
- String findString= getFindString();
- boolean somethingFound= false;
-
- if (findString != null && !findString.isEmpty()) {
-
- try {
- somethingFound= findNext(findString, forwardSearch, isCaseSensitiveSearch(), isWrapSearch(), isWholeWordSearch(), isIncrementalSearch() && !isRegExSearchAvailableAndChecked(), isRegExSearchAvailableAndChecked(), beep);
- } catch (PatternSyntaxException ex) {
- statusError(ex.getLocalizedMessage());
- } catch (IllegalStateException ex) {
- // we don't keep state in this dialog
- }
- }
- writeSelection();
- updateButtonState(!somethingFound);
- }
-
- /**
- * Replaces all occurrences of the user's findString with
- * the replace string. Returns the number of replacements
- * that occur.
- *
- * @param findString the string to search for
- * @param replaceString the replacement string
- * @param caseSensitive should the search be case sensitive
- * @param wholeWord does the search string represent a complete word
- * @param regExSearch if true
findString represents a regular expression
- * @return the number of occurrences
- *
- * @since 3.0
- */
- private int replaceAll(String findString, String replaceString, boolean caseSensitive, boolean wholeWord,
- boolean regExSearch) {
-
- int replaceCount= 0;
- int findReplacePosition= 0;
-
- findReplacePosition= 0;
-
- if (!validateTargetState())
- return replaceCount;
-
- if (fTarget instanceof IFindReplaceTargetExtension)
- ((IFindReplaceTargetExtension) fTarget).setReplaceAllMode(true);
-
- try {
- int index= 0;
- while (index != -1) {
- index = findAndSelect(findReplacePosition, findString, true, caseSensitive, wholeWord, regExSearch);
- if (index != -1) { // substring not contained from current position
- Point selection= replaceSelection(replaceString, regExSearch);
- replaceCount++;
- findReplacePosition = selection.x + selection.y;
- }
- }
- } finally {
- if (fTarget instanceof IFindReplaceTargetExtension)
- ((IFindReplaceTargetExtension) fTarget).setReplaceAllMode(false);
- }
-
- return replaceCount;
- }
-
- private int selectAll(String findString, boolean caseSensitive, boolean wholeWord, boolean regExSearch) {
-
- int replaceCount = 0;
- int position = 0;
-
- if (!validateTargetState())
- return replaceCount;
-
- List selectedRegions = new ArrayList<>();
- int index = 0;
- do {
- index = findAndSelect(position, findString, true, caseSensitive, wholeWord, regExSearch);
- if (index != -1) { // substring not contained from current position
- Point selection = fTarget.getSelection();
- selectedRegions.add(new Region(selection.x, selection.y));
- replaceCount++;
- position = selection.x + selection.y;
- }
- } while (index != -1);
- if (fTarget instanceof IFindReplaceTargetExtension4) {
- ((IFindReplaceTargetExtension4) fTarget).setSelection(selectedRegions.toArray(IRegion[]::new));
- }
-
- return replaceCount;
- }
// ------- UI creation ---------------------------------------
@@ -1680,23 +1000,33 @@ private void updateButtonState() {
* @since 3.0
*/
private void updateButtonState(boolean disableReplace) {
+ setupFindReplacer();
if (okToUse(getShell()) && okToUse(fFindNextButton)) {
- boolean selection= false;
- if (fTarget != null)
- selection= !fTarget.getSelectionText().isEmpty();
+ boolean hasActiveSelection = false;
+ String selection = getCurrentSelection();
+ if (selection != null)
+ hasActiveSelection = !selection.isEmpty();
- boolean enable= fTarget != null && (fActiveShell == fParentShell || fActiveShell == getShell());
+ boolean enable = (findReplacer.getTarget() != null)
+ && (fActiveShell == fParentShell || fActiveShell == getShell());
String str= getFindString();
boolean findString= str != null && !str.isEmpty();
- fWholeWordCheckBox.setEnabled(isWord(str) && !isRegExSearchAvailableAndChecked());
-
+ fWholeWordCheckBox.setEnabled(isWord(str) && !findReplacer.isRegExSearchAvailableAndActive());
fFindNextButton.setEnabled(enable && findString);
- fSelectAllButton.setEnabled(enable && findString && fTarget instanceof IFindReplaceTargetExtension4);
- fReplaceSelectionButton.setEnabled(!disableReplace && enable && isEditable() && selection && (!fNeedsInitialFindBeforeReplace || !isRegExSearchAvailableAndChecked()));
- fReplaceFindButton.setEnabled(!disableReplace && enable && isEditable() && findString && selection && (!fNeedsInitialFindBeforeReplace || !isRegExSearchAvailableAndChecked()));
- fReplaceAllButton.setEnabled(enable && isEditable() && findString);
+ fSelectAllButton.setEnabled(
+ enable && findString && (findReplacer.getTarget() instanceof IFindReplaceTargetExtension4));
+ fReplaceSelectionButton
+ .setEnabled(!disableReplace && enable && findReplacer.getTarget().isEditable() && hasActiveSelection
+ && (findReplacer.getTarget().getSelection().toString() != "" //$NON-NLS-1$
+ || !findReplacer.isRegExSearchAvailableAndActive()));
+ fReplaceFindButton
+ .setEnabled(!disableReplace && enable && findReplacer.getTarget().isEditable() && findString
+ && hasActiveSelection
+ && (findReplacer.getTarget().getSelection().toString() != "" //$NON-NLS-1$
+ || !findReplacer.isRegExSearchAvailableAndActive()));
+ fReplaceAllButton.setEnabled(enable && findReplacer.getTarget().isEditable() && findString);
}
}
@@ -1738,7 +1068,7 @@ private void updateCombo(Combo combo, List content) {
private void updateFindAndReplaceHistory() {
updateFindHistory();
if (okToUse(fReplaceField)) {
- updateHistory(fReplaceField, fReplaceHistory);
+ updateHistory(fReplaceField, replaceHistory.get());
}
}
@@ -1754,7 +1084,7 @@ private void updateFindHistory() {
if (Util.isLinux())
fFindModifyListener.ignoreNextEvent();
- updateHistory(fFindField, fFindHistory);
+ updateHistory(fFindField, findHistory.get());
fFindField.addModifyListener(fFindModifyListener);
}
}
@@ -1779,15 +1109,6 @@ private void updateHistory(Combo combo, List history) {
}
}
- /**
- * Returns whether the target is editable.
- * @return true
if target is editable
- */
- private boolean isEditable() {
- boolean isEditable= (fTarget == null ? false : fTarget.isEditable());
- return fIsTargetEditable && isEditable;
- }
-
/**
* Updates this dialog because of a different target.
* @param target the new target
@@ -1796,49 +1117,37 @@ private boolean isEditable() {
* @since 2.0
*/
public void updateTarget(IFindReplaceTarget target, boolean isTargetEditable, boolean initializeFindString) {
+ findReplacer.updateTarget(target, isTargetEditable);
- fIsTargetEditable= isTargetEditable;
- fNeedsInitialFindBeforeReplace= true;
-
- if (target != fTarget) {
- if (fTarget != null && fTarget instanceof IFindReplaceTargetExtension)
- ((IFindReplaceTargetExtension) fTarget).endSession();
+ boolean globalSearch = findReplacer.isActive(SearchOptions.GLOBAL);
- fTarget= target;
- if (fTarget != null)
- fIsTargetSupportingRegEx= fTarget instanceof IFindReplaceTargetExtension3;
-
- if (fTarget instanceof IFindReplaceTargetExtension) {
- ((IFindReplaceTargetExtension) fTarget).beginSession();
-
- fGlobalInit= true;
- fGlobalRadioButton.setSelection(fGlobalInit);
- fSelectedRangeRadioButton.setSelection(!fGlobalInit);
- fUseSelectedLines= !fGlobalInit;
- }
- }
+ fGlobalRadioButton.setSelection(globalSearch);
+ boolean useSelectedLines = !globalSearch;
+ fSelectedRangeRadioButton.setSelection(useSelectedLines);
+ findReplacer.useSelectedLines(useSelectedLines);
if (okToUse(fIsRegExCheckBox))
- fIsRegExCheckBox.setEnabled(fIsTargetSupportingRegEx);
+ fIsRegExCheckBox.setEnabled(findReplacer.getTarget() instanceof IFindReplaceTargetExtension3);
if (okToUse(fWholeWordCheckBox))
- fWholeWordCheckBox.setEnabled(!isRegExSearchAvailableAndChecked());
+ fWholeWordCheckBox.setEnabled(!findReplacer.isRegExSearchAvailableAndActive());
if (okToUse(fIncrementalCheckBox))
- fIncrementalCheckBox.setEnabled(!isRegExSearchAvailableAndChecked());
+ fIncrementalCheckBox.setEnabled(!findReplacer.isRegExSearchAvailableAndActive());
if (okToUse(fReplaceLabel)) {
- fReplaceLabel.setEnabled(isEditable());
- fReplaceField.setEnabled(isEditable());
+ fReplaceLabel.setEnabled(findReplacer.getTarget().isEditable());
+ fReplaceField.setEnabled(findReplacer.getTarget().isEditable());
+ fReplaceAllButton.setEnabled(findReplacer.getTarget().isEditable());
if (initializeFindString) {
initFindStringFromSelection();
- fGiveFocusToFindField= true;
+ fGiveFocusToFindField = true;
}
- initIncrementalBaseLocation();
}
+
updateButtonState();
- setContentAssistsEnablement(isRegExSearchAvailableAndChecked());
+ setContentAssistsEnablement(findReplacer.isRegExSearchAvailableAndActive());
}
/**
@@ -1863,6 +1172,14 @@ public void setParentShell(Shell shell) {
//--------------- configuration handling --------------
+ /**
+ * Sets up the required managers for search history
+ */
+ private void setupSearchHistory() {
+ findHistory = new HistoryStore(getDialogSettings(), "findhistory", HISTORY_SIZE); //$NON-NLS-1$
+ replaceHistory = new HistoryStore(getDialogSettings(), "replacehistory", HISTORY_SIZE); //$NON-NLS-1$
+ }
+
/**
* Returns the dialog settings object used to share state
* between several find/replace dialogs.
@@ -1901,25 +1218,19 @@ protected int getDialogBoundsStrategy() {
private void readConfiguration() {
IDialogSettings s= getDialogSettings();
- fWrapInit= s.get("wrap") == null || s.getBoolean("wrap"); //$NON-NLS-1$ //$NON-NLS-2$
- fCaseInit= s.getBoolean("casesensitive"); //$NON-NLS-1$
- fWholeWordInit= s.getBoolean("wholeword"); //$NON-NLS-1$
- fIncrementalInit= s.getBoolean("incremental"); //$NON-NLS-1$
- fIsRegExInit= s.getBoolean("isRegEx"); //$NON-NLS-1$
-
- String[] findHistory= s.getArray("findhistory"); //$NON-NLS-1$
- if (findHistory != null) {
- List history= getFindHistory();
- history.clear();
- Collections.addAll(history, findHistory);
- }
+ activateInFindReplacerIf(SearchOptions.WRAP, s.get("wrap") == null || s.getBoolean("wrap")); //$NON-NLS-1$ //$NON-NLS-2$
+ activateInFindReplacerIf(SearchOptions.CASE_SENSITIVE, s.getBoolean("casesensitive")); //$NON-NLS-1$
+ activateInFindReplacerIf(SearchOptions.WHOLE_WORD, s.getBoolean("wholeword")); //$NON-NLS-1$
+ activateInFindReplacerIf(SearchOptions.INCREMENTAL, s.getBoolean("incremental")); //$NON-NLS-1$
+ activateInFindReplacerIf(SearchOptions.REGEX, s.getBoolean("isRegEx")); //$NON-NLS-1$
+ }
- String[] replaceHistory= s.getArray("replacehistory"); //$NON-NLS-1$
- if (replaceHistory != null) {
- List history= getReplaceHistory();
- history.clear();
- Collections.addAll(history, replaceHistory);
- }
+ private void setupFindReplacer() {
+ activateInFindReplacerIf(SearchOptions.WRAP, fWrapCheckBox.getSelection());
+ activateInFindReplacerIf(SearchOptions.CASE_SENSITIVE, fCaseCheckBox.getSelection());
+ activateInFindReplacerIf(SearchOptions.WHOLE_WORD, fWholeWordCheckBox.getSelection());
+ activateInFindReplacerIf(SearchOptions.INCREMENTAL, fIncrementalCheckBox.getSelection());
+ activateInFindReplacerIf(SearchOptions.REGEX, fIsRegExCheckBox.getSelection());
}
/**
@@ -1928,52 +1239,65 @@ private void readConfiguration() {
private void writeConfiguration() {
IDialogSettings s= getDialogSettings();
- s.put("wrap", fWrapInit); //$NON-NLS-1$
- s.put("casesensitive", fCaseInit); //$NON-NLS-1$
- s.put("wholeword", fWholeWordInit); //$NON-NLS-1$
- s.put("incremental", fIncrementalInit); //$NON-NLS-1$
- s.put("isRegEx", fIsRegExInit); //$NON-NLS-1$
+ s.put("wrap", findReplacer.isActive(SearchOptions.WRAP)); //$NON-NLS-1$
+ s.put("casesensitive", findReplacer.isActive(SearchOptions.CASE_SENSITIVE)); //$NON-NLS-1$
+ s.put("wholeword", findReplacer.isActive(SearchOptions.WHOLE_WORD)); //$NON-NLS-1$
+ s.put("incremental", findReplacer.isActive(SearchOptions.INCREMENTAL)); //$NON-NLS-1$
+ s.put("isRegEx", findReplacer.isActive(SearchOptions.REGEX)); //$NON-NLS-1$
- List history= getFindHistory();
String findString= getFindString();
- if (!findString.isEmpty())
- history.add(0, findString);
- writeHistory(history, s, "findhistory"); //$NON-NLS-1$
+ findHistory.add(findString);
- history= getReplaceHistory();
String replaceString= getReplaceString();
- if (!replaceString.isEmpty())
- history.add(0, replaceString);
- writeHistory(history, s, "replacehistory"); //$NON-NLS-1$
+ replaceHistory.add(replaceString);
}
- /**
- * Writes the given history into the given dialog store.
- *
- * @param history the history
- * @param settings the dialog settings
- * @param sectionName the section name
- * @since 3.2
- */
- private void writeHistory(List history, IDialogSettings settings, String sectionName) {
- int itemCount= history.size();
- Set distinctItems= new HashSet<>(itemCount);
- for (int i= 0; i < itemCount; i++) {
- String item= history.get(i);
- if (distinctItems.contains(item)) {
- history.remove(i--);
- itemCount--;
- } else {
- distinctItems.add(item);
+ private void activateInFindReplacerIf(SearchOptions option, boolean shouldActivate) {
+ if (shouldActivate) {
+ findReplacer.activate(option);
+ } else {
+ findReplacer.deactivate(option);
+ }
+ }
+
+ private void evaluateFindReplacerStatus() {
+ IFindReplaceLogicStatus status = findReplacer.getStatus();
+
+ String dialogMessage = status.visit(new FindReplaceLogicMessageGenerator());
+
+ fStatusLabel.setText(dialogMessage);
+
+ if (status instanceof FindReplaceLogicStatus statusMessage) {
+ switch (statusMessage.getMessageCode()) {
+ case NO_MATCH:
+ case READONLY:
+ fStatusLabel.setForeground(JFaceColors.getErrorText(fStatusLabel.getDisplay()));
+ tryToBeep();
+ break;
+ case WRAPPED:
+ tryToBeep();
+ break;
+ case NONE:
+ default:
+ break;
}
}
+ else {
+ fStatusLabel.setForeground(null);
+ }
- while (history.size() > HISTORY_SIZE)
- history.remove(HISTORY_SIZE);
+ }
- String[] names= new String[history.size()];
- history.toArray(names);
- settings.put(sectionName, names);
+ private void tryToBeep() {
+ if (okToUse(getShell())) {
+ getShell().getDisplay().beep();
+ }
+ }
+ private String getCurrentSelection() {
+ IFindReplaceTarget target = findReplacer.getTarget();
+ if (target == null)
+ return null;
+ return target.getSelectionText();
}
}
diff --git a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceOverlay.java b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceOverlay.java
new file mode 100644
index 00000000000..eda138187d8
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceOverlay.java
@@ -0,0 +1,756 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Vector Informatik GmbH and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Vector Informatik GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ui.texteditor;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.ControlListener;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Link;
+import org.eclipse.swt.widgets.Scrollable;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+import org.eclipse.swt.widgets.Widget;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.jface.window.Window;
+
+import org.eclipse.jface.text.IFindReplaceTarget;
+
+import org.eclipse.ui.IPartListener;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.findandreplace.FindReplaceLogic;
+import org.eclipse.ui.internal.findandreplace.FindReplaceLogicMessageGenerator;
+import org.eclipse.ui.internal.findandreplace.FindReplaceLogicStatus;
+import org.eclipse.ui.internal.findandreplace.IFindReplaceLogicStatus;
+import org.eclipse.ui.internal.findandreplace.SearchOptions;
+
+/**
+ * @since 3.18
+ */
+public class FindReplaceOverlay extends Dialog {
+
+ FindReplaceAction parentAction;
+ FindReplaceLogic findReplacer;
+ IWorkbenchPart targetPart;
+ boolean overlayOpen;
+ boolean replaceBarOpen;
+
+ Composite container;
+ Button replaceToggle;
+
+ Composite contentGroup;
+
+ Composite searchContainer;
+ Composite searchBarContainer;
+ Text searchBar;
+ ToolBar searchTools;
+ ToolItem wholeWordSearchButton;
+ ToolItem caseSensitiveSearchButton;
+ ToolItem regexSearchButton;
+ ToolItem searchUpButton;
+ ToolItem searchDownButton;
+ ToolItem searchAllButton;
+
+ Composite replaceContainer;
+ Composite replaceBarContainer;
+ Text replaceBar;
+ ToolBar replaceTools;
+ ToolItem replaceButton;
+ ToolItem replaceAllButton;
+
+ Link openOldDialog;
+
+ public FindReplaceOverlay(Shell parent, IWorkbenchPart part, IFindReplaceTarget target,
+ FindReplaceAction parentAction) {
+ super(parent);
+ this.parentAction = parentAction;
+ createFindReplacer(target);
+
+ setShellStyle(SWT.MODELESS);
+ setBlockOnOpen(false);
+ targetPart = part;
+ }
+
+ @Override
+ protected boolean isResizable() {
+ return false;
+ }
+
+ private void createFindReplacer(IFindReplaceTarget target) {
+ findReplacer = new FindReplaceLogic();
+ boolean isTargetEditable = false;
+ if (target != null) {
+ isTargetEditable = target.isEditable();
+ }
+ findReplacer.updateTarget(target, isTargetEditable);
+ findReplacer.activate(SearchOptions.INCREMENTAL);
+ findReplacer.activate(SearchOptions.GLOBAL);
+ findReplacer.activate(SearchOptions.WRAP);
+ findReplacer.activate(SearchOptions.FORWARD);
+ }
+
+ KeyListener shortcuts = new KeyListener() {
+
+ private void performEnterAction(KeyEvent e) {
+ // probably not the right way to implement this.
+ // What do you think, @HeikoKlare?
+ boolean isShiftPressed = (e.stateMask & SWT.SHIFT) != 0;
+ boolean isCtrlPressed = (e.stateMask & SWT.CTRL) != 0;
+ if (okayToUse(replaceBar) && replaceBar.isFocusControl()) {
+ if (isCtrlPressed) {
+ findReplacer.performReplaceAll(getFindString(), getReplaceString(), getShell().getDisplay());
+ } else {
+ performSingleReplace();
+ }
+ } else {
+ if (isCtrlPressed) {
+ findReplacer.performSelectAll(getFindString(), getShell().getDisplay());
+ } else {
+ boolean oldForwardSearchSetting = findReplacer.isActive(SearchOptions.FORWARD);
+ activateInFindReplacerIf(SearchOptions.FORWARD, !isShiftPressed);
+ findReplacer.deactivate(SearchOptions.INCREMENTAL);
+ findReplacer.performSearch(getFindString());
+ activateInFindReplacerIf(SearchOptions.FORWARD, oldForwardSearchSetting);
+ findReplacer.activate(SearchOptions.INCREMENTAL);
+ }
+ }
+ }
+
+ @Override
+ public void keyPressed(KeyEvent e) {
+ if ((e.stateMask & SWT.CTRL) != 0 && (e.keyCode == 'F' || e.keyCode == 'f')) {
+ parentAction.closeModernOverlay();
+ } else if ((e.stateMask & SWT.CTRL) != 0 && (e.keyCode == 'R' || e.keyCode == 'r')) {
+ replaceToggle.setSelection(!replaceToggle.getSelection());
+ replaceToggle.notifyListeners(SWT.Selection, null);
+ } else if ((e.stateMask & SWT.CTRL) != 0 && (e.keyCode == 'W' || e.keyCode == 'w')) {
+ wholeWordSearchButton.setSelection(!wholeWordSearchButton.getSelection());
+ wholeWordSearchButton.notifyListeners(SWT.Selection, null);
+ } else if (e.keyCode == SWT.CR) {
+ performEnterAction(e);
+ }
+ }
+
+ @Override
+ public void keyReleased(KeyEvent e) {
+ // Do nothing
+ }
+
+ };
+ ControlListener shellMovementListener = new ControlListener() {
+ @Override
+ public void controlMoved(ControlEvent e) {
+ positionToPart();
+ }
+
+ @Override
+ public void controlResized(ControlEvent e) {
+ positionToPart();
+ }
+ };
+ PaintListener widgetMovementListener = new PaintListener() {
+
+ @Override
+ public void paintControl(PaintEvent e) {
+ positionToPart();
+ }
+
+ };
+ IPartListener partListener = new IPartListener() {
+ @Override
+ public void partActivated(IWorkbenchPart part) {
+ if (getShell() != null) {
+ getShell().setVisible(isPartCurrentlyDisplayedInPartSash());
+ }
+ }
+
+ @Override
+ public void partDeactivated(IWorkbenchPart part) {
+ // Do nothing
+ }
+
+ @Override
+ public void partBroughtToTop(IWorkbenchPart part) {
+ if (getShell() != null) {
+ getShell().setVisible(isPartCurrentlyDisplayedInPartSash());
+ }
+ }
+
+ @Override
+ public void partClosed(IWorkbenchPart part) {
+ close();
+ }
+
+ @Override
+ public void partOpened(IWorkbenchPart part) {
+ // Do nothing
+ }
+ };
+
+ public boolean isPartCurrentlyDisplayedInPartSash() {
+ IWorkbenchPage activePage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+
+ // Check if the targetPart is currently displayed on the active page
+ boolean isPartDisplayed = false;
+
+ if (activePage != null) {
+ IWorkbenchPart activePart = activePage.getActivePart();
+ if (activePart != null && activePart == targetPart) {
+ isPartDisplayed = true;
+ }
+ }
+
+ return isPartDisplayed;
+ }
+
+ @Override
+ public void create() {
+ if (overlayOpen) {
+ return;
+ }
+ super.create();
+ }
+
+ @Override
+ public boolean close() {
+ if (!overlayOpen) {
+ return true;
+ }
+ overlayOpen = false;
+ replaceBarOpen = false;
+ unbindListeners();
+ container.dispose();
+ return super.close();
+ }
+
+ @Override
+ public int open() {
+ int returnCode;
+ positionToPart();
+ if (overlayOpen) {
+ searchBar.forceFocus();
+ findReplacer.performIncrementalSearch(getFindString());
+ returnCode = Window.CANCEL;
+ } else {
+ bindListeners();
+ returnCode = super.open();
+ }
+ overlayOpen = true;
+ return returnCode;
+ }
+
+ private void unbindListeners() {
+ if (targetPart != null && targetPart instanceof StatusTextEditor textEditor) {
+ Control targetWidget = textEditor.getSourceViewer().getTextWidget();
+ if (targetWidget != null) {
+ targetWidget.getShell().removeControlListener(shellMovementListener);
+ targetWidget.removePaintListener(widgetMovementListener);
+ targetPart.getSite().getPage().removePartListener(partListener);
+ }
+ }
+ }
+
+ private void bindListeners() {
+ if (targetPart instanceof StatusTextEditor textEditor) {
+ Control targetWidget = textEditor.getSourceViewer().getTextWidget();
+
+ targetWidget.getShell().addControlListener(shellMovementListener);
+ targetWidget.addPaintListener(widgetMovementListener);
+ targetPart.getSite().getPage().addPartListener(partListener);
+ }
+ }
+
+ @Override
+ public Control createContents(Composite parent) {
+ Control ret = createDialog(parent);
+ initFindStringFromSelection();
+ positionToPart();
+ return ret;
+ }
+
+ public Control createDialog(final Composite parent) {
+ createMainContainer(parent);
+
+ // createLinks();
+ createFindContainer();
+ createSearchBar();
+ createSearchTools();
+
+ container.layout();
+
+ applyDialogFont(container);
+ return container;
+ }
+
+ @SuppressWarnings("unused")
+ private void createLinks() {
+ openOldDialog = new Link(contentGroup, SWT.NONE);
+ GridDataFactory.fillDefaults().align(SWT.BEGINNING, SWT.BEGINNING).applyTo(openOldDialog);
+ openOldDialog.setText("classic Find/Replace"); //$NON-NLS-1$
+ openOldDialog.addSelectionListener(new SelectionListener() {
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ parentAction.showClassicDialog();
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ // Do nothing
+ }
+
+ });
+ }
+
+ private void createSearchTools() {
+ searchTools = new ToolBar(searchContainer, SWT.HORIZONTAL);
+ GridDataFactory.fillDefaults().grab(false, true).align(GridData.CENTER, GridData.CENTER).applyTo(searchTools);
+ wholeWordSearchButton = new ToolItem(searchTools, SWT.CHECK);
+ wholeWordSearchButton.setImage(FindReplaceOverlayImages.get(FindReplaceOverlayImages.OBJ_WHOLE_WORD));
+ wholeWordSearchButton.setToolTipText("Only find in whole words"); //$NON-NLS-1$
+ wholeWordSearchButton.addSelectionListener(new SelectionListener() {
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ activateInFindReplacerIf(SearchOptions.WHOLE_WORD, wholeWordSearchButton.getSelection());
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ // Do Nothing
+ }
+ });
+ caseSensitiveSearchButton = new ToolItem(searchTools, SWT.CHECK);
+ caseSensitiveSearchButton.setImage(FindReplaceOverlayImages.get(FindReplaceOverlayImages.OBJ_CASE_SENSITIVE));
+ caseSensitiveSearchButton.setToolTipText("Match case"); //$NON-NLS-1$
+ caseSensitiveSearchButton.addSelectionListener(new SelectionListener() {
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ activateInFindReplacerIf(SearchOptions.CASE_SENSITIVE, caseSensitiveSearchButton.getSelection());
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ // Do Nothing
+ }
+ });
+ regexSearchButton = new ToolItem(searchTools, SWT.CHECK);
+ regexSearchButton.setImage(FindReplaceOverlayImages.get(FindReplaceOverlayImages.OBJ_FIND_REGEX));
+ regexSearchButton.setToolTipText("Search for a regular expression"); //$NON-NLS-1$
+ regexSearchButton.addSelectionListener(new SelectionListener() {
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ activateInFindReplacerIf(SearchOptions.REGEX, regexSearchButton.getSelection());
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ // Do nothing
+ }
+ });
+
+ regexSearchButton = new ToolItem(searchTools, SWT.SEPARATOR);
+
+ searchAllButton = new ToolItem(searchTools, SWT.PUSH);
+ searchAllButton.setImage(FindReplaceOverlayImages.get(FindReplaceOverlayImages.OBJ_SEARCH_ALL));
+ searchAllButton.setToolTipText("Search all (Ctrl + Enter)"); //$NON-NLS-1$
+ searchAllButton.addSelectionListener(new SelectionListener() {
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ findReplacer.performSelectAll(getFindString(), getShell().getDisplay());
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ // Do nothing
+ }
+
+ });
+ searchUpButton = new ToolItem(searchTools, SWT.PUSH);
+ searchUpButton.setImage(FindReplaceOverlayImages.get(FindReplaceOverlayImages.ELCL_FIND_PREV));
+ searchUpButton.setToolTipText("Search backward (Shift + Enter)"); //$NON-NLS-1$
+ searchUpButton.addSelectionListener(new SelectionListener() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ findReplacer.deactivate(SearchOptions.FORWARD);
+ findReplacer.performSearch(getFindString());
+ findReplacer.activate(SearchOptions.FORWARD);
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ // Do Nothing
+ }
+ });
+ searchDownButton = new ToolItem(searchTools, SWT.PUSH);
+ searchDownButton.setSelection(true); // by default, search down
+ searchDownButton.setImage(FindReplaceOverlayImages.get(FindReplaceOverlayImages.ELCL_FIND_NEXT));
+ searchDownButton.setToolTipText("Search forward (Enter)"); //$NON-NLS-1$
+ searchDownButton.addSelectionListener(new SelectionListener() {
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ // TODO extract into transaction
+ findReplacer.activate(SearchOptions.FORWARD);
+ findReplacer.activate(SearchOptions.INCREMENTAL);
+ findReplacer.deactivate(SearchOptions.FORWARD);
+ findReplacer.performSearch(getFindString());
+ findReplacer.deactivate(SearchOptions.INCREMENTAL);
+ findReplacer.activate(SearchOptions.FORWARD);
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ // Do nothing
+ }
+ });
+
+ }
+
+ private void createReplaceTools() {
+ replaceTools = new ToolBar(replaceContainer, SWT.HORIZONTAL);
+ GridDataFactory.fillDefaults().grab(false, true).align(GridData.CENTER, GridData.CENTER).applyTo(replaceTools);
+ replaceButton = new ToolItem(replaceTools, SWT.PUSH);
+ replaceButton.setImage(FindReplaceOverlayImages.get(FindReplaceOverlayImages.OBJ_REPLACE));
+ replaceButton.setToolTipText("Replace (Enter)"); //$NON-NLS-1$
+ replaceButton.addSelectionListener(new SelectionListener() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ performSingleReplace();
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ // Do nothing
+ }
+ });
+ replaceAllButton = new ToolItem(replaceTools, SWT.PUSH);
+ replaceAllButton.setImage(FindReplaceOverlayImages.get(FindReplaceOverlayImages.OBJ_REPLACE_ALL));
+ replaceAllButton.setToolTipText("Replace All (Ctrl + Enter)"); //$NON-NLS-1$
+ replaceAllButton.addSelectionListener(new SelectionListener() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ findReplacer.performReplaceAll(getFindString(), getReplaceString(), getShell().getDisplay());
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ // Do Nothing
+ }
+ });
+ }
+
+ private void createSearchBar() {
+ searchBar = new Text(searchBarContainer, SWT.SINGLE);
+ GridDataFactory.fillDefaults().grab(true, true).align(GridData.FILL, GridData.FILL).applyTo(searchBar);
+ searchBar.forceFocus();
+ searchBar.selectAll();
+ searchBar.addModifyListener(new ModifyListener() {
+ @Override
+ public void modifyText(ModifyEvent e) {
+ findReplacer.performIncrementalSearch(getFindString());
+ }
+ });
+
+ searchBar.addKeyListener(shortcuts);
+
+ searchBar.setMessage("Find"); //$NON-NLS-1$
+ }
+
+ private void createReplaceBar() {
+ replaceBar = new Text(replaceBarContainer, SWT.SINGLE);
+ GridDataFactory.fillDefaults().grab(true, true).align(SWT.FILL, SWT.FILL).applyTo(replaceBar);
+ replaceBar.setMessage("Replace"); //$NON-NLS-1$
+ replaceBar.addKeyListener(shortcuts);
+ }
+
+ private void createFindContainer() {
+ searchContainer = new Composite(contentGroup, SWT.NONE);
+ GridDataFactory.fillDefaults().grab(true, true).align(GridData.FILL, GridData.FILL)
+ .applyTo(searchContainer);
+ GridLayoutFactory.fillDefaults().numColumns(2).equalWidth(false).applyTo(searchContainer);
+ searchBarContainer = new Composite(searchContainer, SWT.BORDER);
+ GridDataFactory.fillDefaults().grab(true, true).align(GridData.FILL, GridData.FILL).applyTo(searchBarContainer);
+ GridLayoutFactory.fillDefaults().numColumns(1).equalWidth(false).applyTo(searchBarContainer);
+ }
+
+ private void createReplaceContainer() {
+ replaceContainer = new Composite(contentGroup, SWT.NONE);
+ GridDataFactory.fillDefaults().grab(true, true).align(GridData.FILL, GridData.FILL).applyTo(replaceContainer);
+ GridLayoutFactory.fillDefaults().margins(0, 1).numColumns(2).equalWidth(false)
+ .applyTo(replaceContainer);
+ replaceBarContainer = new Composite(replaceContainer, SWT.BORDER);
+ GridDataFactory.fillDefaults().grab(true, true).align(GridData.FILL, GridData.FILL)
+ .applyTo(replaceBarContainer);
+ GridLayoutFactory.fillDefaults().numColumns(1).equalWidth(false)
+ .applyTo(replaceBarContainer);
+ }
+
+ private void createMainContainer(final Composite parent) {
+ container = new Composite(parent, SWT.NONE);
+ GridLayoutFactory.fillDefaults().numColumns(2).equalWidth(false).margins(2, 2).spacing(2, 0).applyTo(container);
+ GridDataFactory.fillDefaults().grab(true, true).align(GridData.FILL, GridData.FILL).applyTo(container);
+
+ if (findReplacer.getTarget().isEditable()) {
+ createReplaceToggle();
+ }
+
+ contentGroup = new Composite(container, SWT.NULL);
+ GridLayoutFactory.fillDefaults().numColumns(1).equalWidth(false).spacing(2, 2).applyTo(contentGroup);
+ GridDataFactory.fillDefaults().grab(true, true).align(GridData.FILL, GridData.FILL).applyTo(contentGroup);
+ }
+
+ private void createReplaceToggle() {
+ replaceToggle = new Button(container, SWT.PUSH); // https://stackoverflow.com/questions/33161797/how-to-remove-border-of-swt-button-so-that-it-seems-like-a-label
+ GridDataFactory.fillDefaults().grab(false, true).align(GridData.BEGINNING, GridData.FILL)
+ .applyTo(replaceToggle);
+ replaceToggle.setToolTipText("Toggle input for replace (Ctrl+R)"); //$NON-NLS-1$
+ replaceToggle.setImage(FindReplaceOverlayImages.get(FindReplaceOverlayImages.OBJ_OPEN_REPLACE));
+ replaceToggle.addSelectionListener(new SelectionListener() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if (!replaceBarOpen) {
+ createReplaceDialog();
+ replaceToggle.setImage(FindReplaceOverlayImages.get(FindReplaceOverlayImages.OBJ_CLOSE_REPLACE));
+ } else {
+ hideReplace();
+ replaceToggle.setImage(FindReplaceOverlayImages.get(FindReplaceOverlayImages.OBJ_OPEN_REPLACE));
+ }
+ replaceToggle.setSelection(false);
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ // Do nothing
+ }
+ });
+ }
+
+ public void hideReplace() {
+ if (!replaceBarOpen) {
+ return;
+ }
+ replaceBarOpen = false;
+ replaceContainer.dispose();
+ replaceTools.dispose();
+ replaceBar.dispose();
+ positionToPart();
+ searchBar.forceFocus();
+ }
+
+ public void createReplaceDialog() {
+ if (replaceBarOpen) {
+ return;
+ }
+ replaceBarOpen = true;
+ createReplaceContainer();
+ createReplaceBar();
+ createReplaceTools();
+ positionToPart();
+ replaceBar.forceFocus();
+ }
+
+ private void enableSearchTools(boolean enable) {
+ ((GridData) searchTools.getLayoutData()).exclude = !enable;
+ searchTools.setVisible(enable);
+
+ if (enable) {
+ ((GridLayout) searchTools.getParent().getLayout()).numColumns = 2;
+ } else {
+ ((GridLayout) searchTools.getParent().getLayout()).numColumns = 1;
+ }
+ }
+
+ private void enableReplaceToggle(boolean enable) {
+ if (!okayToUse(replaceToggle)) {
+ return;
+ }
+ ((GridData) replaceToggle.getLayoutData()).exclude = !enable;
+ replaceToggle.setVisible(enable);
+ }
+
+ private void enableReplaceTools(boolean enable) {
+ if (!okayToUse(replaceTools)) {
+ return;
+ }
+ ((GridData) replaceTools.getLayoutData()).exclude = !enable;
+ replaceTools.setVisible(enable);
+
+ if (enable) {
+ ((GridLayout) replaceTools.getParent().getLayout()).numColumns = 2;
+ } else {
+ ((GridLayout) replaceTools.getParent().getLayout()).numColumns = 1;
+ }
+ }
+
+ private int getIdealDialogWidth(Rectangle targetBounds) {
+ enableSearchTools(true);
+ enableReplaceTools(true);
+ enableReplaceToggle(true);
+ Point toolBarWidth = searchTools.getSize();
+ GC gc = new GC(searchBar);
+ gc.setFont(searchBar.getFont());
+ Point idealWidth = gc.stringExtent("THIS TEXT HAS A REASONABLE LENGTH FOR SEARCHING"); //$NON-NLS-1$
+ Point idealCompromiseWidth = gc.stringExtent("THIS TEXT HAS A REASONABLE"); //$NON-NLS-1$
+ Point worstCompromiseWidth = gc.stringExtent("THIS TEXT "); //$NON-NLS-1$
+
+ int newWidth = idealWidth.x + toolBarWidth.x;
+ if (newWidth > targetBounds.width * 0.7) {
+ newWidth = (int) (targetBounds.width * 0.7);
+ }
+ if (newWidth < idealCompromiseWidth.x + toolBarWidth.x) {
+ enableSearchTools(false);
+ enableReplaceTools(false);
+ }
+ if (newWidth < worstCompromiseWidth.x + toolBarWidth.x) {
+ newWidth = (int) (targetBounds.width * 0.95);
+ enableReplaceToggle(false);
+ }
+ return newWidth;
+ }
+
+ private Point getNewPosition(Widget targetTextWidget, Point targetOrigin, Rectangle targetBounds) {
+ Point scrollBarSize = ((Scrollable) targetTextWidget).getVerticalBar().getSize();
+
+ int newX = targetOrigin.x + targetBounds.width - container.getBounds().width - scrollBarSize.x
+ - ((StyledText) targetTextWidget).getRightMargin();
+ int newY = targetOrigin.y;
+ return new Point(newX, newY);
+ }
+
+ /**
+ * When making the text-bar 100% small and then regrowing it, we want the text
+ * to start at the first character again.
+ */
+ private void repositionTextSelection() {
+ if (okayToUse(searchBar) && !searchBar.isFocusControl()) {
+ searchBar.setSelection(0, 0);
+ }
+ if (okayToUse(replaceBar) && !replaceBar.isFocusControl()) {
+ replaceBar.setSelection(0, 0);
+ }
+ }
+
+ public void positionToPart() {
+ getShell().layout(true);
+ container.layout(true);
+ if (targetPart instanceof StatusTextEditor textEditor) {
+ Control targetWidget = textEditor.getSourceViewer().getTextWidget();
+ if (targetWidget == null || targetWidget.isDisposed()) {
+ this.close();
+ return;
+ }
+ StyledText targetTextWidget = textEditor.getSourceViewer().getTextWidget();
+ Point targetOrigin = targetTextWidget.toDisplay(0, 0);
+ Rectangle targetBounds = targetTextWidget.getBounds();
+
+ int newWidth = getIdealDialogWidth(targetBounds);
+ int newHeight = container.computeSize(SWT.DEFAULT, SWT.DEFAULT).y;
+ getShell().setSize(new Point(newWidth, newHeight));
+
+ Point newPosition = getNewPosition(targetTextWidget, targetOrigin, targetBounds);
+ getShell().setLocation(newPosition);
+
+ repositionTextSelection();
+ }
+ container.layout(true);
+ getShell().layout(true);
+ }
+
+ private String getFindString() {
+ return searchBar.getText();
+ }
+
+ private String getReplaceString() {
+ if (replaceBar.isDisposed())
+ return ""; //$NON-NLS-1$
+ return replaceBar.getText();
+
+ }
+
+ private void performSingleReplace() {
+ findReplacer.performSelectAndReplace(getFindString(), getReplaceString());
+ findReplacer.performIncrementalSearch(getFindString());
+ evaluateFindReplacerStatus();
+ }
+
+ private void initFindStringFromSelection() {
+ searchBar.setText(findReplacer.getTarget().getSelectionText());
+ }
+
+ private void evaluateFindReplacerStatus() {
+ IFindReplaceLogicStatus status = findReplacer.getStatus();
+
+ String dialogMessage = status.visit(new FindReplaceLogicMessageGenerator());
+
+ if (status instanceof FindReplaceLogicStatus statusMessage) {
+ switch (statusMessage.getMessageCode()) {
+ case NO_MATCH:
+ case READONLY:
+ case WRAPPED:
+ tryToBeep();
+ break;
+ case NONE:
+ default:
+ break;
+ }
+ }
+
+ }
+
+ private void tryToBeep() {
+ Shell dialogShell = getShell();
+ if (dialogShell != null && !dialogShell.isDisposed()) {
+ getShell().getDisplay().beep();
+ }
+ }
+
+ private void activateInFindReplacerIf(SearchOptions option, boolean shouldActivate) {
+ if (shouldActivate) {
+ findReplacer.activate(option);
+ } else {
+ findReplacer.deactivate(option);
+ }
+ }
+
+ private boolean okayToUse(Widget widget) {
+ return widget != null && !widget.isDisposed();
+ }
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceOverlayImages.java b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceOverlayImages.java
new file mode 100644
index 00000000000..5430426e1f8
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceOverlayImages.java
@@ -0,0 +1,172 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Vector Informatik GmbH and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Vector Informatik GmbH - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ui.texteditor;
+
+import java.net.URL;
+
+import org.osgi.framework.Bundle;
+
+import org.eclipse.swt.graphics.Image;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Platform;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.ImageRegistry;
+
+import org.eclipse.ui.internal.texteditor.TextEditorPlugin;
+
+/**
+ * @HeikoKlare Modeled after TemplatePageImages.java - I'm not sure if this
+ * approach is good or bad. I copy-pasted methods, increasing
+ * code-duplication. We should consider implementing a unified
+ * method for inserting icons (.. or does it already exist?)
+ */
+class FindReplaceOverlayImages {
+
+ static final String PREFIX_ELCL = TextEditorPlugin.PLUGIN_ID + ".elcl."; //$NON-NLS-1$
+
+ static final String PREFIX_DLCL = TextEditorPlugin.PLUGIN_ID + ".dlcl."; //$NON-NLS-1$
+
+ static final String PREFIX_OBJ = TextEditorPlugin.PLUGIN_ID + ".obj."; //$NON-NLS-1$
+
+ static final String ELCL_FIND_NEXT = PREFIX_ELCL + "select_next.png"; //$NON-NLS-1$
+
+ static final String ELCL_FIND_PREV = PREFIX_ELCL + "select_prev.png"; //$NON-NLS-1$
+
+ static final String OBJ_FIND_REGEX = PREFIX_OBJ + "regex_gear.gif"; //$NON-NLS-1$
+
+ static final String OBJ_REPLACE = PREFIX_OBJ + "replace.png"; //$NON-NLS-1$
+
+ static final String OBJ_REPLACE_ALL = PREFIX_OBJ + "replace_all.png"; //$NON-NLS-1$
+
+ static final String OBJ_WHOLE_WORD = PREFIX_OBJ + "whole_word.png"; //$NON-NLS-1$
+
+ static final String OBJ_CASE_SENSITIVE = PREFIX_OBJ + "case_sensitive.png"; //$NON-NLS-1$
+
+ static final String OBJ_OPEN_REPLACE = PREFIX_OBJ + "open_replace.png"; //$NON-NLS-1$
+
+ static final String OBJ_CLOSE_REPLACE = PREFIX_OBJ + "close_replace.png"; //$NON-NLS-1$
+
+ static final String OBJ_SEARCH_ALL = PREFIX_OBJ + "search_all.png"; //$NON-NLS-1$
+
+ /**
+ * The image registry containing {@link Image images}.
+ */
+ private static ImageRegistry fgImageRegistry;
+
+ private static String ICONS_PATH = "$nl$/icons/full/"; //$NON-NLS-1$
+
+ // Use IPath and toOSString to build the names to ensure they have the
+ // slashes correct
+ private final static String ELCL = ICONS_PATH + "elcl16/"; //$NON-NLS-1$
+
+ private final static String DLCL = ICONS_PATH + "dlcl16/"; //$NON-NLS-1$
+
+ private final static String OBJ = ICONS_PATH + "obj16/"; //$NON-NLS-1$
+
+ /**
+ * Declare all images
+ */
+ private static void declareImages() {
+ declareRegistryImage(ELCL_FIND_NEXT, ELCL + "select_next.png"); //$NON-NLS-1$
+ declareRegistryImage(ELCL_FIND_PREV, ELCL + "select_prev.png"); //$NON-NLS-1$
+ declareRegistryImage(OBJ_FIND_REGEX, OBJ + "regex_gear.gif"); //$NON-NLS-1$
+ declareRegistryImage(OBJ_REPLACE_ALL, OBJ + "replace_all.png"); //$NON-NLS-1$
+ declareRegistryImage(OBJ_REPLACE, OBJ + "replace.png"); //$NON-NLS-1$
+ declareRegistryImage(OBJ_WHOLE_WORD, OBJ + "whole_word.png"); //$NON-NLS-1$
+ declareRegistryImage(OBJ_CASE_SENSITIVE, OBJ + "case_sensitive.png"); //$NON-NLS-1$
+ declareRegistryImage(OBJ_OPEN_REPLACE, OBJ + "open_replace.png"); //$NON-NLS-1$
+ declareRegistryImage(OBJ_CLOSE_REPLACE, OBJ + "close_replace.png"); //$NON-NLS-1$
+ declareRegistryImage(OBJ_SEARCH_ALL, OBJ + "search_all.png"); //$NON-NLS-1$
+ }
+
+ /**
+ * Declare an Image in the registry table.
+ *
+ * @param key the key to use when registering the image
+ * @param path the path where the image can be found. This path is relative to
+ * where this plugin class is found (i.e. typically the packages
+ * directory)
+ */
+ private final static void declareRegistryImage(String key, String path) {
+ ImageDescriptor desc = ImageDescriptor.getMissingImageDescriptor();
+ Bundle bundle = Platform.getBundle(TextEditorPlugin.PLUGIN_ID);
+ URL url = null;
+ if (bundle != null) {
+ url = FileLocator.find(bundle, IPath.fromOSString(path), null);
+ desc = ImageDescriptor.createFromURL(url);
+ }
+ fgImageRegistry.put(key, desc);
+ }
+
+ /**
+ * Returns the ImageRegistry.
+ *
+ * @return image registry
+ */
+ public static ImageRegistry getImageRegistry() {
+ if (fgImageRegistry == null) {
+ initializeImageRegistry();
+ }
+ return fgImageRegistry;
+ }
+
+ /**
+ * Initialize the image registry by declaring all of the required graphics. This
+ * involves creating JFace image descriptors describing how to create/find the
+ * image should it be needed. The image is not actually allocated until
+ * requested.
+ *
+ * Prefix conventions Wizard Banners WIZBAN_ Preference Banners PREF_BAN_
+ * Property Page Banners PROPBAN_ Color toolbar CTOOL_ Enable toolbar ETOOL_
+ * Disable toolbar DTOOL_ Local enabled toolbar ELCL_ Local Disable toolbar
+ * DLCL_ Object large OBJL_ Object small OBJS_ View VIEW_ Product images PROD_
+ * Misc images MISC_
+ *
+ * Where are the images? The images (typically pngs) are found in the same
+ * location as this plugin class. This may mean the same package directory as
+ * the package holding this class. The images are declared using this.getClass()
+ * to ensure they are looked up via this plugin class.
+ *
+ * @return the image registry
+ * @see org.eclipse.jface.resource.ImageRegistry
+ */
+ public static ImageRegistry initializeImageRegistry() {
+ fgImageRegistry = TextEditorPlugin.getDefault().getImageRegistry();
+ declareImages();
+ return fgImageRegistry;
+ }
+
+ /**
+ * Returns the image managed under the given key in this registry.
+ *
+ * @param key the image's key
+ * @return the image managed under the given key
+ */
+ public static Image get(String key) {
+ return getImageRegistry().get(key);
+ }
+
+ /**
+ * Returns the image descriptor for the given key in this registry.
+ *
+ * @param key the image's key
+ * @return the image descriptor for the given key
+ */
+ public static ImageDescriptor getDescriptor(String key) {
+ return getImageRegistry().getDescriptor(key);
+ }
+}
diff --git a/tests/org.eclipse.ui.workbench.texteditor.tests/META-INF/MANIFEST.MF b/tests/org.eclipse.ui.workbench.texteditor.tests/META-INF/MANIFEST.MF
index 1c65868afab..fcaf52a7b07 100644
--- a/tests/org.eclipse.ui.workbench.texteditor.tests/META-INF/MANIFEST.MF
+++ b/tests/org.eclipse.ui.workbench.texteditor.tests/META-INF/MANIFEST.MF
@@ -9,7 +9,8 @@ Export-Package:
org.eclipse.ui.workbench.texteditor.tests,
org.eclipse.ui.workbench.texteditor.tests.minimap,
org.eclipse.ui.workbench.texteditor.tests.revisions,
- org.eclipse.ui.workbench.texteditor.tests.rulers
+ org.eclipse.ui.workbench.texteditor.tests.rulers,
+ org.eclipse.ui.findandreplace
Require-Bundle:
org.eclipse.core.runtime;bundle-version="[3.29.0,4.0.0)",
org.eclipse.jface.text;bundle-version="[3.5.0,4.0.0)",
@@ -21,3 +22,5 @@ Require-Bundle:
Bundle-RequiredExecutionEnvironment: JavaSE-17
Eclipse-BundleShape: dir
Automatic-Module-Name: org.eclipse.ui.workbench.texteditor.tests
+Import-Package: org.mockito,
+ org.mockito.stubbing;version="5.5.0"
diff --git a/tests/org.eclipse.ui.workbench.texteditor.tests/src/org/eclipse/ui/findandreplace/FindReplaceLogicTest.java b/tests/org.eclipse.ui.workbench.texteditor.tests/src/org/eclipse/ui/findandreplace/FindReplaceLogicTest.java
new file mode 100644
index 00000000000..211d59d945e
--- /dev/null
+++ b/tests/org.eclipse.ui.workbench.texteditor.tests/src/org/eclipse/ui/findandreplace/FindReplaceLogicTest.java
@@ -0,0 +1,315 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Vector Informatik GmbH and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Vector Informatik GmbH - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ui.findandreplace;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertEquals;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+import org.eclipse.jface.text.Document;
+import org.eclipse.jface.text.IFindReplaceTarget;
+import org.eclipse.jface.text.TextViewer;
+
+import org.eclipse.ui.internal.findandreplace.FindReplaceLogic;
+import org.eclipse.ui.internal.findandreplace.FindReplaceLogicFindAllStatus;
+import org.eclipse.ui.internal.findandreplace.FindReplaceLogicMessage;
+import org.eclipse.ui.internal.findandreplace.FindReplaceLogicReplaceAllStatus;
+import org.eclipse.ui.internal.findandreplace.FindReplaceLogicStatus;
+import org.eclipse.ui.internal.findandreplace.IFindReplaceLogic;
+import org.eclipse.ui.internal.findandreplace.SearchOptions;
+
+
+public class FindReplaceLogicTest {
+ Shell parentShell;
+
+ private IFindReplaceLogic setupFindReplaceLogicObject(TextViewer target) {
+ IFindReplaceLogic findReplaceLogic= new FindReplaceLogic();
+ if (target != null) {
+ findReplaceLogic.updateTarget(target.getFindReplaceTarget(), true);
+ }
+
+ return findReplaceLogic;
+ }
+
+ private TextViewer setupTextViewer(String contentText) {
+ TextViewer textViewer= new TextViewer(parentShell, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
+ textViewer.setDocument(new Document(contentText));
+ textViewer.getControl().setFocus();
+ return textViewer;
+ }
+
+ @After
+ public void disposeShell() {
+ if (parentShell != null) {
+ parentShell.dispose();
+ }
+ }
+
+ @Before
+ public void setupShell() {
+ parentShell= new Shell();
+ }
+
+ @Test
+ @Ignore("https://github.com/eclipse-platform/eclipse.platform.ui/issues/1203")
+ public void testPerformReplaceAllBackwards() {
+ TextViewer textViewer= setupTextViewer("");
+ IFindReplaceLogic findReplaceLogic= setupFindReplaceLogicObject(textViewer);
+
+ performReplaceAllBaseTestcases(findReplaceLogic, textViewer);
+ }
+
+ @Test
+ public void testPerformReplaceAllForwards() {
+ TextViewer textViewer= setupTextViewer("");
+ IFindReplaceLogic findReplaceLogic= setupFindReplaceLogicObject(textViewer);
+ findReplaceLogic.activate(SearchOptions.FORWARD);
+
+ performReplaceAllBaseTestcases(findReplaceLogic, textViewer);
+ }
+
+ /**
+ * Expects the TextViewer to contain a document with "aaaa"
+ *
+ * @param findReplaceLogic logic-object that will be tested
+ * @param textViewer textviewer-object that contains the contents on which findReplaceLogic
+ * operates
+ */
+ @SuppressWarnings("boxing")
+ private void performReplaceAllBaseTestcases(IFindReplaceLogic findReplaceLogic, TextViewer textViewer) {
+ Display display= parentShell.getDisplay();
+ textViewer.setDocument(new Document("aaaa"));
+
+ findReplaceLogic.performReplaceAll("a", "b", display);
+ assertThat(textViewer.getDocument().get(), equalTo("bbbb"));
+ expectStatusIsReplaceAllWithCount(findReplaceLogic, 4);
+
+ findReplaceLogic.performReplaceAll("b", "aa", display);
+ assertThat(textViewer.getDocument().get(), equalTo("aaaaaaaa"));
+ expectStatusIsReplaceAllWithCount(findReplaceLogic, 4);
+
+ findReplaceLogic.performReplaceAll("b", "c", display);
+ assertThat(textViewer.getDocument().get(), equalTo("aaaaaaaa"));
+ expectStatusIsCode(findReplaceLogic, FindReplaceLogicStatus.MessageCode.NO_MATCH);
+
+ findReplaceLogic.performReplaceAll("aaaaaaaa", "d", display); // https://github.com/eclipse-platform/eclipse.platform.ui/issues/1203
+ assertThat(textViewer.getDocument().get(), equalTo("d"));
+ expectStatusIsReplaceAllWithCount(findReplaceLogic, 1);
+
+ findReplaceLogic.performReplaceAll("d", null, display);
+ assertThat(textViewer.getDocument().get(), equalTo(""));
+ expectStatusIsReplaceAllWithCount(findReplaceLogic, 1);
+
+ textViewer.getDocument().set("f");
+ findReplaceLogic.performReplaceAll("f", "", display);
+ assertThat(textViewer.getDocument().get(), equalTo(""));
+ expectStatusIsReplaceAllWithCount(findReplaceLogic, 1);
+
+
+ IFindReplaceTarget mockFindReplaceTarget= Mockito.mock(IFindReplaceTarget.class);
+ Mockito.when(mockFindReplaceTarget.isEditable()).thenReturn(false);
+
+ findReplaceLogic.updateTarget(mockFindReplaceTarget, false);
+ findReplaceLogic.performReplaceAll("a", "b", display);
+ expectStatusIsCode(findReplaceLogic, FindReplaceLogicStatus.MessageCode.NO_MATCH);
+ }
+
+ @Test
+ public void testPerformReplaceAllForwardRegEx() {
+ TextViewer textViewer= setupTextViewer("hello@eclipse.com looks.almost@like_an_email");
+ IFindReplaceLogic findReplaceLogic= setupFindReplaceLogicObject(textViewer);
+ findReplaceLogic.activate(SearchOptions.REGEX);
+ findReplaceLogic.activate(SearchOptions.FORWARD);
+
+ findReplaceLogic.performReplaceAll(".+\\@.+\\.com", "", parentShell.getDisplay());
+ assertThat(textViewer.getDocument().get(), equalTo(" looks.almost@like_an_email"));
+ expectStatusIsReplaceAllWithCount(findReplaceLogic, 1);
+
+ findReplaceLogic.performReplaceAll("( looks.)|(like_)", "", parentShell.getDisplay());
+ assertThat(textViewer.getDocument().get(), equalTo("almost@an_email"));
+ expectStatusIsReplaceAllWithCount(findReplaceLogic, 2);
+
+ findReplaceLogic.performReplaceAll("[", "", parentShell.getDisplay());
+ assertThat(textViewer.getDocument().get(), equalTo("almost@an_email"));
+ expectStatusIsMessageWithString(findReplaceLogic, "Unclosed character class near index 0\r\n"
+ + "[\r\n"
+ + "^");
+
+ }
+
+ @Test
+ public void testPerformReplaceAllForward() {
+ TextViewer textViewer= setupTextViewer("hello@eclipse.com looks.almost@like_an_email");
+ IFindReplaceLogic findReplaceLogic= setupFindReplaceLogicObject(textViewer);
+ findReplaceLogic.activate(SearchOptions.REGEX);
+ findReplaceLogic.activate(SearchOptions.FORWARD);
+
+ findReplaceLogic.performReplaceAll(".+\\@.+\\.com", "", parentShell.getDisplay());
+ assertThat(textViewer.getDocument().get(), equalTo(" looks.almost@like_an_email"));
+ expectStatusIsReplaceAllWithCount(findReplaceLogic, 1);
+
+ findReplaceLogic.performReplaceAll("( looks.)|(like_)", "", parentShell.getDisplay());
+ assertThat(textViewer.getDocument().get(), equalTo("almost@an_email"));
+ expectStatusIsReplaceAllWithCount(findReplaceLogic, 2);
+
+ findReplaceLogic.performReplaceAll("[", "", parentShell.getDisplay());
+ assertThat(textViewer.getDocument().get(), equalTo("almost@an_email"));
+ expectStatusIsMessageWithString(findReplaceLogic, "Unclosed character class near index 0\r\n"
+ + "[\r\n"
+ + "^");
+ }
+
+ @Test
+ public void testPerformSelectAndReplace() {
+ TextViewer textViewer= setupTextViewer("HelloWorld!");
+ IFindReplaceLogic findReplaceLogic= setupFindReplaceLogicObject(textViewer);
+ findReplaceLogic.activate(SearchOptions.FORWARD);
+
+ findReplaceLogic.performSearch(""); // select first, then replace. We don't need to perform a second search
+ findReplaceLogic.performSelectAndReplace("", " ");
+ assertThat(textViewer.getDocument().get(), equalTo("Hello World!"));
+ expectStatusEmpty(findReplaceLogic);
+
+ findReplaceLogic.performSelectAndReplace("", " "); // perform the search yourself and replace that automatically
+ assertThat(textViewer.getDocument().get(), equalTo("Hello World !"));
+ expectStatusEmpty(findReplaceLogic);
+ }
+
+ @Test
+ public void testPerformSelectAndReplaceBackward() {
+ TextViewer textViewer= setupTextViewer("HelloWorld!");
+ IFindReplaceLogic findReplaceLogic= setupFindReplaceLogicObject(textViewer);
+ findReplaceLogic.deactivate(SearchOptions.FORWARD);
+ findReplaceLogic.activate(SearchOptions.WRAP); // this only works if the search was wrapped
+
+ findReplaceLogic.performSearch(""); // select first, then replace. We don't need to perform a second search
+ expectStatusIsCode(findReplaceLogic, FindReplaceLogicStatus.MessageCode.WRAPPED);
+ findReplaceLogic.performSelectAndReplace("", " ");
+ assertThat(textViewer.getDocument().get(), equalTo("HelloWorld !"));
+
+ findReplaceLogic.performSelectAndReplace("", " "); // perform the search yourself and replace that automatically
+ assertThat(textViewer.getDocument().get(), equalTo("Hello World !"));
+ expectStatusEmpty(findReplaceLogic);
+ }
+
+
+ @SuppressWarnings("boxing")
+ @Test
+ public void testPerformReplaceAndFind() {
+ TextViewer textViewer= setupTextViewer("HelloWorld!");
+ IFindReplaceLogic findReplaceLogic= setupFindReplaceLogicObject(textViewer);
+ findReplaceLogic.activate(SearchOptions.FORWARD);
+
+ boolean status = findReplaceLogic.performReplaceAndFind("", " ");
+ assertThat(status, is(true));
+ assertThat(textViewer.getDocument().get(), equalTo("Hello World!"));
+ assertThat(findReplaceLogic.getTarget().getSelectionText(), equalTo(""));
+ expectStatusEmpty(findReplaceLogic);
+
+ status= findReplaceLogic.performReplaceAndFind("", " ");
+ assertThat(status, is(true));
+ assertThat(textViewer.getDocument().get(), equalTo("Hello World !"));
+ expectStatusIsCode(findReplaceLogic, FindReplaceLogicStatus.MessageCode.NO_MATCH);
+
+ status= findReplaceLogic.performReplaceAndFind("", " ");
+ assertEquals("Status wasn't correctly returned", false, status);
+ assertEquals("Text shouldn't have been changed", "Hello World !", textViewer.getDocument().get());
+ expectStatusIsCode(findReplaceLogic, FindReplaceLogicStatus.MessageCode.NO_MATCH);
+ }
+
+ @Test
+ public void testPerformSelectAllForward() {
+ TextViewer textViewer= setupTextViewer("AbAbAbAb");
+ IFindReplaceLogic findReplaceLogic= setupFindReplaceLogicObject(textViewer);
+ findReplaceLogic.activate(SearchOptions.FORWARD);
+
+ findReplaceLogic.performSelectAll("b", parentShell.getDisplay());
+ expectStatusIsFindAllWithCount(findReplaceLogic, 4);
+ // I don't have access to getAllSelectionPoints or similar (not yet implemented), so I cannot really test for correct behavior
+ // related to https://github.com/eclipse-platform/eclipse.platform.ui/issues/1047
+
+ findReplaceLogic.performSelectAll("AbAbAbAb", parentShell.getDisplay());
+ expectStatusIsFindAllWithCount(findReplaceLogic, 1);
+ }
+
+
+ @Test
+ @Ignore("https://github.com/eclipse-platform/eclipse.platform.ui/issues/1203")
+ public void testPerformSelectAllBackward() {
+ TextViewer textViewer= setupTextViewer("AbAbAbAb");
+ IFindReplaceLogic findReplaceLogic= setupFindReplaceLogicObject(textViewer);
+ findReplaceLogic.deactivate(SearchOptions.FORWARD);
+
+ findReplaceLogic.performSelectAll("b", parentShell.getDisplay()); // https://github.com/eclipse-platform/eclipse.platform.ui/issues/1203 maybe related?
+ expectStatusIsFindAllWithCount(findReplaceLogic, 4);
+ // I don't have access to getAllSelectionPoints or similar (not yet implemented), so I cannot really test for correct behavior
+ // related to https://github.com/eclipse-platform/eclipse.platform.ui/issues/1047
+
+ findReplaceLogic.performSelectAll("AbAbAbAb", parentShell.getDisplay());
+ expectStatusIsFindAllWithCount(findReplaceLogic, 1);
+ }
+
+ @Test
+ public void testSelectWholeWords() {
+ TextViewer textViewer= setupTextViewer("Hello World of get and getters, set and setters");
+ IFindReplaceLogic findReplaceLogic= setupFindReplaceLogicObject(textViewer);
+ findReplaceLogic.activate(SearchOptions.FORWARD);
+ findReplaceLogic.activate(SearchOptions.WHOLE_WORD);
+ findReplaceLogic.deactivate(SearchOptions.WRAP);
+
+ findReplaceLogic.performSearch("get");
+ findReplaceLogic.performSearch("get");
+ expectStatusIsCode(findReplaceLogic, FindReplaceLogicStatus.MessageCode.NO_MATCH);
+ }
+
+ private void expectStatusEmpty(IFindReplaceLogic findReplaceLogic) {
+ expectStatusIsCode(findReplaceLogic, FindReplaceLogicStatus.MessageCode.NONE);
+ }
+
+ private void expectStatusIsCode(IFindReplaceLogic findReplaceLogic, FindReplaceLogicStatus.MessageCode code) {
+ assertThat(findReplaceLogic.getStatus(), instanceOf(FindReplaceLogicStatus.class));
+ assertThat(((FindReplaceLogicStatus) findReplaceLogic.getStatus()).getMessageCode(), equalTo(code));
+ }
+
+ @SuppressWarnings("boxing")
+ private void expectStatusIsReplaceAllWithCount(IFindReplaceLogic findReplaceLogic, int count) {
+ assertThat(findReplaceLogic.getStatus(), instanceOf(FindReplaceLogicReplaceAllStatus.class));
+ assertThat(((FindReplaceLogicReplaceAllStatus) findReplaceLogic.getStatus()).getReplaceCount(), equalTo(count));
+ }
+
+ @SuppressWarnings("boxing")
+ private void expectStatusIsFindAllWithCount(IFindReplaceLogic findReplaceLogic, int count) {
+ assertThat(findReplaceLogic.getStatus(), instanceOf(FindReplaceLogicFindAllStatus.class));
+ assertThat(((FindReplaceLogicFindAllStatus) findReplaceLogic.getStatus()).getSelectCount(), equalTo(count));
+ }
+
+ private void expectStatusIsMessageWithString(IFindReplaceLogic findReplaceLogic, String message) {
+ assertThat(findReplaceLogic.getStatus(), instanceOf(FindReplaceLogicMessage.class));
+ assertThat(((FindReplaceLogicMessage) findReplaceLogic.getStatus()).getMessage(), equalTo(message));
+ }
+
+}
diff --git a/tests/org.eclipse.ui.workbench.texteditor.tests/src/org/eclipse/ui/workbench/texteditor/tests/FindReplaceDialogTest.java b/tests/org.eclipse.ui.workbench.texteditor.tests/src/org/eclipse/ui/workbench/texteditor/tests/FindReplaceDialogTest.java
deleted file mode 100644
index 0cef0d6329c..00000000000
--- a/tests/org.eclipse.ui.workbench.texteditor.tests/src/org/eclipse/ui/workbench/texteditor/tests/FindReplaceDialogTest.java
+++ /dev/null
@@ -1,319 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2016 IBM Corporation and others.
- *
- * This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License 2.0
- * which accompanies this distribution, and is available at
- * https://www.eclipse.org/legal/epl-2.0/
- *
- * SPDX-License-Identifier: EPL-2.0
- *
- * Contributors:
- * IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.ui.workbench.texteditor.tests;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import java.util.ResourceBundle;
-
-import org.junit.After;
-import org.junit.FixMethodOrder;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TestName;
-import org.junit.runners.MethodSorters;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Combo;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Event;
-import org.eclipse.swt.widgets.Shell;
-
-import org.eclipse.text.tests.Accessor;
-
-import org.eclipse.jface.util.Util;
-
-import org.eclipse.jface.text.Document;
-import org.eclipse.jface.text.IFindReplaceTarget;
-import org.eclipse.jface.text.TextViewer;
-
-import org.eclipse.ui.PlatformUI;
-
-/**
- * Tests the FindReplaceDialog.
- *
- * @since 3.1
- */
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class FindReplaceDialogTest {
-
- @Rule
- public TestName testName = new TestName();
-
- private Accessor fFindReplaceDialog;
- private TextViewer fTextViewer;
-
- private void runEventQueue() {
- Display display= PlatformUI.getWorkbench().getDisplay();
- for (int i= 0; i < 10; i++) { // workaround for https://bugs.eclipse.org/323272
- while (display.readAndDispatch()) {
- // do nothing
- }
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
- // do nothing
- }
- }
- }
-
- private void openFindReplaceDialog() {
- Shell shell= PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
- fFindReplaceDialog= new Accessor("org.eclipse.ui.texteditor.FindReplaceDialog", getClass().getClassLoader(), new Object[] { shell });
- fFindReplaceDialog.invoke("create", null);
- }
-
- private void openTextViewerAndFindReplaceDialog() {
- fTextViewer= new TextViewer(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
- fTextViewer.setDocument(new Document("line\nline\nline"));
- fTextViewer.getControl().setFocus();
-
- Accessor fFindReplaceAction;
- fFindReplaceAction= new Accessor("org.eclipse.ui.texteditor.FindReplaceAction", getClass().getClassLoader(), new Class[] {ResourceBundle.class, String.class, Shell.class, IFindReplaceTarget.class}, new Object[] {ResourceBundle.getBundle("org.eclipse.ui.texteditor.ConstructedEditorMessages"), "Editor.FindReplace.", fTextViewer.getControl().getShell(), fTextViewer.getFindReplaceTarget()});
- fFindReplaceAction.invoke("run", null);
-
- Object fFindReplaceDialogStub= fFindReplaceAction.get("fgFindReplaceDialogStub");
- if (fFindReplaceDialogStub == null)
- fFindReplaceDialogStub= fFindReplaceAction.get("fgFindReplaceDialogStubShell");
- Accessor fFindReplaceDialogStubAccessor= new Accessor(fFindReplaceDialogStub, "org.eclipse.ui.texteditor.FindReplaceAction$FindReplaceDialogStub", getClass().getClassLoader());
-
- fFindReplaceDialog= new Accessor(fFindReplaceDialogStubAccessor.invoke("getDialog", null), "org.eclipse.ui.texteditor.FindReplaceDialog", getClass().getClassLoader());
- }
-
- @After
- public void tearDown() throws Exception {
- if (fFindReplaceDialog != null) {
- fFindReplaceDialog.invoke("close", null);
- fFindReplaceDialog= null;
- }
-
- if (fTextViewer != null) {
- fTextViewer.getControl().dispose();
- fTextViewer= null;
- }
- }
-
- @Test
- public void test01InitialButtonState() {
- openFindReplaceDialog();
-
- Boolean value;
- value= (Boolean)fFindReplaceDialog.invoke("isWholeWordSearch", null);
- assertFalse(value.booleanValue());
- value= (Boolean)fFindReplaceDialog.invoke("isWholeWordSetting", null);
- assertFalse(value.booleanValue());
- value= (Boolean)fFindReplaceDialog.invoke("isWrapSearch", null);
- assertTrue(value.booleanValue());
- value= (Boolean)fFindReplaceDialog.invoke("isRegExSearch", null);
- assertFalse(value.booleanValue());
- value= (Boolean)fFindReplaceDialog.invoke("isRegExSearchAvailableAndChecked", null);
- assertFalse(value.booleanValue());
- Button checkbox= (Button)fFindReplaceDialog.get("fIsRegExCheckBox");
- assertTrue(checkbox.isEnabled());
- checkbox= (Button)fFindReplaceDialog.get("fWholeWordCheckBox");
- assertFalse(checkbox.isEnabled()); // there's no word in the Find field
- }
-
- @Test
- public void testDisableWholeWordIfRegEx() {
- openFindReplaceDialog();
-
- Combo findField= (Combo)fFindReplaceDialog.get("fFindField");
- findField.setText("word");
-
- Button isRegExCheckBox= (Button)fFindReplaceDialog.get("fIsRegExCheckBox");
- Button wholeWordCheckbox= (Button)fFindReplaceDialog.get("fWholeWordCheckBox");
-
- assertTrue(isRegExCheckBox.isEnabled());
- assertTrue(wholeWordCheckbox.isEnabled());
-
- fFindReplaceDialog.set("fIsTargetSupportingRegEx", true);
- isRegExCheckBox.setSelection(true);
- wholeWordCheckbox.setSelection(true);
- fFindReplaceDialog.invoke("updateButtonState", null);
-
- assertTrue(isRegExCheckBox.isEnabled());
- assertFalse(wholeWordCheckbox.isEnabled());
- assertTrue(wholeWordCheckbox.getSelection());
- }
-
- @Test
- public void testDisableWholeWordIfNotWord() {
- openFindReplaceDialog();
-
- Combo findField= (Combo)fFindReplaceDialog.get("fFindField");
- Button isRegExCheckBox= (Button)fFindReplaceDialog.get("fIsRegExCheckBox");
- Button wholeWordCheckbox= (Button)fFindReplaceDialog.get("fWholeWordCheckBox");
-
- fFindReplaceDialog.set("fIsTargetSupportingRegEx", false);
- isRegExCheckBox.setSelection(false);
- wholeWordCheckbox.setSelection(true);
- fFindReplaceDialog.invoke("updateButtonState", null);
-
- findField.setText("word");
- assertTrue(isRegExCheckBox.isEnabled());
- assertTrue(wholeWordCheckbox.isEnabled());
- assertTrue(wholeWordCheckbox.getSelection());
-
- findField.setText("no word");
- assertTrue(isRegExCheckBox.isEnabled());
- assertFalse(wholeWordCheckbox.isEnabled());
- assertTrue(wholeWordCheckbox.getSelection());
- }
-
- @Test
- public void testFocusNotChangedWhenEnterPressed() {
- openTextViewerAndFindReplaceDialog();
-
- Combo findField= (Combo)fFindReplaceDialog.get("fFindField");
- findField.setFocus();
- findField.setText("line");
- final Event event= new Event();
-
- event.type= SWT.Traverse;
- event.detail= SWT.TRAVERSE_RETURN;
- event.character= SWT.CR;
- event.doit= true;
- findField.traverse(SWT.TRAVERSE_RETURN, event);
- runEventQueue();
-
- Shell shell= ((Shell)fFindReplaceDialog.get("fActiveShell"));
- if (shell == null && Util.isGtk()) {
- if (ScreenshotTest.isRunByGerritHudsonJob()) {
- takeScreenshot();
- return;
- } else
- fail("this test does not work on GTK unless the runtime workbench has focus. Screenshot: " + takeScreenshot());
- }
-
- if (Util.isMac())
- /* On the Mac, checkboxes only take focus if "Full Keyboard Access" is enabled in the System Preferences.
- * Let's not assume that someone pressed Ctrl+F7 on every test machine... */
- return;
-
- assertTrue(findField.isFocusControl());
-
- Button wrapSearchBox= (Button)fFindReplaceDialog.get("fWrapCheckBox");
- wrapSearchBox.setFocus();
- event.doit= true;
- findField.traverse(SWT.TRAVERSE_RETURN, event);
- runEventQueue();
- assertTrue(wrapSearchBox.isFocusControl());
-
- Button allScopeBox= (Button)fFindReplaceDialog.get("fGlobalRadioButton");
- allScopeBox.setFocus();
- event.doit= true;
- findField.traverse(SWT.TRAVERSE_RETURN, event);
- runEventQueue();
- assertTrue(allScopeBox.isFocusControl());
- }
-
- private String takeScreenshot() {
- return ScreenshotTest.takeScreenshot(FindReplaceDialogTest.class, testName.getMethodName(), System.out);
- }
-
- @Test
- public void testFocusNotChangedWhenButtonMnemonicPressed() {
- if (Util.isMac())
- return; // Mac doesn't support mnemonics.
-
- openTextViewerAndFindReplaceDialog();
-
- Combo findField= (Combo)fFindReplaceDialog.get("fFindField");
- findField.setText("line");
- final Event event= new Event();
-
- runEventQueue();
- Shell shell= ((Shell)fFindReplaceDialog.get("fActiveShell"));
- if (shell == null && Util.isGtk())
- if (ScreenshotTest.isRunByGerritHudsonJob()) {
- takeScreenshot();
- return;
- } else
- fail("this test does not work on GTK unless the runtime workbench has focus. Screenshot: " + takeScreenshot());
-
- Button wrapSearchBox= (Button)fFindReplaceDialog.get("fWrapCheckBox");
- wrapSearchBox.setFocus();
- event.detail= SWT.TRAVERSE_MNEMONIC;
- event.character= 'n';
- event.doit= false;
- wrapSearchBox.traverse(SWT.TRAVERSE_MNEMONIC, event);
- runEventQueue();
- assertTrue(wrapSearchBox.isFocusControl());
-
- Button allScopeBox= (Button)fFindReplaceDialog.get("fGlobalRadioButton");
- allScopeBox.setFocus();
- event.detail= SWT.TRAVERSE_MNEMONIC;
- event.doit= false;
- allScopeBox.traverse(SWT.TRAVERSE_MNEMONIC, event);
- runEventQueue();
- assertTrue(allScopeBox.isFocusControl());
-
- event.detail= SWT.TRAVERSE_MNEMONIC;
- event.character= 'r';
- event.doit= false;
- allScopeBox.traverse(SWT.TRAVERSE_MNEMONIC, event);
- runEventQueue();
- assertTrue(allScopeBox.isFocusControl());
- }
-
- @Test
- public void testShiftEnterReversesSearchDirection() {
- openTextViewerAndFindReplaceDialog();
-
- Combo findField= (Combo)fFindReplaceDialog.get("fFindField");
- findField.setText("line");
- IFindReplaceTarget target= (IFindReplaceTarget)fFindReplaceDialog.get("fTarget");
- runEventQueue();
- Shell shell= ((Shell)fFindReplaceDialog.get("fActiveShell"));
- if (shell == null && Util.isGtk()) {
- if (ScreenshotTest.isRunByGerritHudsonJob()) {
- takeScreenshot();
- return;
- } else
- fail("this test does not work on GTK unless the runtime workbench has focus. Screenshot: " + takeScreenshot());
- }
- final Event event= new Event();
-
- event.detail= SWT.TRAVERSE_RETURN;
- event.character= SWT.CR;
- findField.traverse(SWT.TRAVERSE_RETURN, event);
- runEventQueue();
- assertEquals(0, (target.getSelection()).x);
- assertEquals(4, (target.getSelection()).y);
-
- event.doit= true;
- findField.traverse(SWT.TRAVERSE_RETURN, event);
- runEventQueue();
- assertEquals(5, (target.getSelection()).x);
- assertEquals(4, (target.getSelection()).y);
-
- event.stateMask= SWT.SHIFT;
- event.doit= true;
- findField.traverse(SWT.TRAVERSE_RETURN, event);
- assertEquals(0, (target.getSelection()).x);
- assertEquals(4, (target.getSelection()).y);
-
- Button forwardRadioButton= (Button)fFindReplaceDialog.get("fForwardRadioButton");
- forwardRadioButton.setSelection(false);
- event.doit= true;
- forwardRadioButton.traverse(SWT.TRAVERSE_RETURN, event);
- assertEquals(5, (target.getSelection()).x);
- }
-
-}
diff --git a/tests/org.eclipse.ui.workbench.texteditor.tests/src/org/eclipse/ui/workbench/texteditor/tests/WorkbenchTextEditorTestSuite.java b/tests/org.eclipse.ui.workbench.texteditor.tests/src/org/eclipse/ui/workbench/texteditor/tests/WorkbenchTextEditorTestSuite.java
index c1b2c55bd49..9d34cf24f25 100644
--- a/tests/org.eclipse.ui.workbench.texteditor.tests/src/org/eclipse/ui/workbench/texteditor/tests/WorkbenchTextEditorTestSuite.java
+++ b/tests/org.eclipse.ui.workbench.texteditor.tests/src/org/eclipse/ui/workbench/texteditor/tests/WorkbenchTextEditorTestSuite.java
@@ -32,7 +32,6 @@
*/
@RunWith(Suite.class)
@SuiteClasses({
- FindReplaceDialogTest.class,
HippieCompletionTest.class,
RangeTest.class,
ChangeRegionTest.class,