Skip to content

Commit e642f04

Browse files
committed
Find/Replace overlay: encapsulate handling of search option changes
The configuration and implementation of search option modifications in the find/replace overlay was scattered across the overlay implementation as well the implementation of logic and the specific UI (tool) items. With this change, the state and execution handling of search option changes is further encapsulated in a specialization of the existing FindReplaceOverlayAction. The UI just listens to changes/executions of this action or the underlying models. In addition, the builder for the tool items for changing the search options is enhanced to a fluent builder that does not implicitly require specific combinations of properties being set. Contributes to #1912
1 parent c4d7646 commit e642f04

4 files changed

Lines changed: 120 additions & 66 deletions

File tree

bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/overlay/AccessibleToolItemBuilder.java

Lines changed: 58 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,6 @@ class AccessibleToolItemBuilder {
3030
private int styleBits = SWT.NONE;
3131
private Image image;
3232
private String toolTipText;
33-
private FindReplaceOverlayAction action;
34-
private SearchOptions searchOption;
35-
private IFindReplaceLogic findReplaceLogic;
36-
private boolean invertSearchOption;
3733

3834
public AccessibleToolItemBuilder(AccessibleToolBar accessibleToolBar) {
3935
this.accessibleToolBar = Objects.requireNonNull(accessibleToolBar);
@@ -54,51 +50,53 @@ public AccessibleToolItemBuilder withToolTipText(String newToolTipText) {
5450
return this;
5551
}
5652

57-
public AccessibleToolItemBuilder withAction(FindReplaceOverlayAction newAction) {
58-
this.action = newAction;
59-
return this;
53+
public AccessibleToolItemForActionBuilder withAction(FindReplaceOverlayAction action) {
54+
return new AccessibleToolItemForActionBuilder(this, action);
6055
}
6156

62-
/**
63-
* Binds a {@link SearchOptions} value to this item. When built, the item's
64-
* selection state is initialized from the logic's current activation state and
65-
* kept in sync automatically. The item's enabled state is also initialized from
66-
* and kept in sync with the option's availability.
67-
*/
68-
public AccessibleToolItemBuilder withSearchOption(SearchOptions option, IFindReplaceLogic logic) {
69-
this.searchOption = option;
70-
this.findReplaceLogic = logic;
71-
this.invertSearchOption = false;
72-
return this;
57+
public class AccessibleToolItemForActionBuilder {
58+
private final AccessibleToolItemBuilder parentBuilder;
59+
60+
private final FindReplaceOverlayAction action;
61+
62+
private AccessibleToolItemForActionBuilder(AccessibleToolItemBuilder parentBuilder,
63+
FindReplaceOverlayAction action) {
64+
this.parentBuilder = parentBuilder;
65+
this.action = action;
66+
}
67+
68+
public ToolItem build() {
69+
AccessibleToolItem accessibleToolItem = parentBuilder.buildAccessibleToolItem();
70+
accessibleToolItem.setAction(action);
71+
return accessibleToolItem.getToolItem();
72+
}
7373
}
7474

75-
/**
76-
* Like {@link #withSearchOption(SearchOptions, IFindReplaceLogic)} but inverts
77-
* the selection mapping: the item is selected when the option is
78-
* <em>inactive</em>. Useful for options like {@link SearchOptions#GLOBAL} where
79-
* a "search in selection" button should be selected when searching globally is
80-
* turned off.
81-
*/
82-
public AccessibleToolItemBuilder withInvertedSearchOption(SearchOptions option, IFindReplaceLogic logic) {
83-
this.searchOption = option;
84-
this.findReplaceLogic = logic;
85-
this.invertSearchOption = true;
86-
return this;
75+
public AccessibleToolItemForSearchOptionBuilder withAction(FindReplaceOverlaySearchOptionAction action) {
76+
return new AccessibleToolItemForSearchOptionBuilder(this, action);
8777
}
8878

89-
public ToolItem build() {
90-
AccessibleToolItem accessibleToolItem = accessibleToolBar.createToolItem(styleBits);
91-
if (image != null) {
92-
accessibleToolItem.setImage(image);
93-
}
94-
if (toolTipText != null) {
95-
accessibleToolItem.setToolTipText(toolTipText);
79+
public class AccessibleToolItemForSearchOptionBuilder extends AccessibleToolItemForActionBuilder {
80+
private final FindReplaceOverlaySearchOptionAction searchOptionAction;
81+
82+
private boolean invertSearchOption;
83+
84+
private AccessibleToolItemForSearchOptionBuilder(AccessibleToolItemBuilder parentBuilder,
85+
FindReplaceOverlaySearchOptionAction searchOptionAction) {
86+
super(parentBuilder, searchOptionAction);
87+
this.searchOptionAction = searchOptionAction;
9688
}
97-
if (action != null) {
98-
accessibleToolItem.setAction(action);
89+
90+
public AccessibleToolItemForSearchOptionBuilder displayInverted() {
91+
this.invertSearchOption = true;
92+
return this;
9993
}
100-
ToolItem toolItem = accessibleToolItem.getToolItem();
101-
if (searchOption != null) {
94+
95+
@Override
96+
public ToolItem build() {
97+
ToolItem toolItem = super.build();
98+
IFindReplaceLogic findReplaceLogic = searchOptionAction.getFindReplaceLogic();
99+
SearchOptions searchOption = searchOptionAction.getSearchOption();
102100
boolean initial = findReplaceLogic.isActive(searchOption);
103101
toolItem.setSelection(invertSearchOption ? !initial : initial);
104102
findReplaceLogic.addSearchOptionActivationChangedListener(searchOption, state -> {
@@ -107,12 +105,28 @@ public ToolItem build() {
107105
}
108106
});
109107
toolItem.setEnabled(findReplaceLogic.isAvailable(searchOption));
110-
findReplaceLogic.addSearchOptionAvailabilityChangedListener(searchOption, available -> {
108+
findReplaceLogic.addSearchOptionAvailabilityChangedListener(searchOption, state -> {
111109
if (!toolItem.isDisposed()) {
112-
toolItem.setEnabled(available);
110+
toolItem.setEnabled(state);
113111
}
114112
});
113+
return toolItem;
115114
}
116-
return toolItem;
117115
}
116+
117+
public ToolItem build() {
118+
return buildAccessibleToolItem().getToolItem();
119+
}
120+
121+
private AccessibleToolItem buildAccessibleToolItem() {
122+
AccessibleToolItem accessibleToolItem = accessibleToolBar.createToolItem(styleBits);
123+
if (image != null) {
124+
accessibleToolItem.setImage(image);
125+
}
126+
if (toolTipText != null) {
127+
accessibleToolItem.setToolTipText(toolTipText);
128+
}
129+
return accessibleToolItem;
130+
}
131+
118132
}

bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/overlay/FindReplaceOverlay.java

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -570,30 +570,25 @@ private void createCloseTools() {
570570
}
571571

572572
private void createAreaSearchButton() {
573-
FindReplaceOverlayAction searchInSelectionAction = new FindReplaceOverlayAction(() -> {
574-
findReplaceLogic.toggle(SearchOptions.GLOBAL);
575-
updateIncrementalSearch();
576-
});
573+
FindReplaceOverlaySearchOptionAction searchInSelectionAction = new FindReplaceOverlaySearchOptionAction(SearchOptions.GLOBAL, findReplaceLogic);
574+
searchInSelectionAction.addExecutionListener(this::updateIncrementalSearch);
577575
searchInSelectionAction.addShortcuts(KeyboardShortcuts.OPTION_SEARCH_IN_SELECTION);
578576
commonActions.add(searchInSelectionAction);
579577
searchInSelectionButton = new AccessibleToolItemBuilder(searchTools).withStyleBits(SWT.CHECK)
580578
.withImage(FindReplaceOverlayImages.get(FindReplaceOverlayImages.KEY_SEARCH_IN_AREA))
581579
.withToolTipText(FindReplaceMessages.FindReplaceOverlay_searchInSelectionButton_toolTip)
582-
.withInvertedSearchOption(SearchOptions.GLOBAL, findReplaceLogic)
583-
.withAction(searchInSelectionAction).build();
580+
.withAction(searchInSelectionAction).displayInverted().build();
584581
}
585582

586583
private void createRegexSearchButton() {
587-
FindReplaceOverlayAction regexAction = new FindReplaceOverlayAction(() -> {
588-
findReplaceLogic.toggle(SearchOptions.REGEX);
589-
updateIncrementalSearch();
590-
});
584+
FindReplaceOverlaySearchOptionAction regexAction = new FindReplaceOverlaySearchOptionAction(SearchOptions.REGEX,
585+
findReplaceLogic);
586+
regexAction.addExecutionListener(this::updateIncrementalSearch);
591587
regexAction.addShortcuts(KeyboardShortcuts.OPTION_REGEX);
592588
commonActions.add(regexAction);
593589
regexSearchButton = new AccessibleToolItemBuilder(searchTools).withStyleBits(SWT.CHECK)
594590
.withImage(FindReplaceOverlayImages.get(FindReplaceOverlayImages.KEY_FIND_REGEX))
595591
.withToolTipText(FindReplaceMessages.FindReplaceOverlay_regexSearchButton_toolTip)
596-
.withSearchOption(SearchOptions.REGEX, findReplaceLogic)
597592
.withAction(regexAction).build();
598593
findReplaceLogic.addSearchOptionActivationChangedListener(SearchOptions.REGEX, activated -> {
599594
updateContentAssistAvailability();
@@ -602,30 +597,26 @@ private void createRegexSearchButton() {
602597
}
603598

604599
private void createCaseSensitiveButton() {
605-
FindReplaceOverlayAction caseSensitiveAction = new FindReplaceOverlayAction(() -> {
606-
findReplaceLogic.toggle(SearchOptions.CASE_SENSITIVE);
607-
updateIncrementalSearch();
608-
});
600+
FindReplaceOverlaySearchOptionAction caseSensitiveAction = new FindReplaceOverlaySearchOptionAction(
601+
SearchOptions.CASE_SENSITIVE, findReplaceLogic);
602+
caseSensitiveAction.addExecutionListener(this::updateIncrementalSearch);
609603
caseSensitiveAction.addShortcuts(KeyboardShortcuts.OPTION_CASE_SENSITIVE);
610604
commonActions.add(caseSensitiveAction);
611605
caseSensitiveSearchButton = new AccessibleToolItemBuilder(searchTools).withStyleBits(SWT.CHECK)
612606
.withImage(FindReplaceOverlayImages.get(FindReplaceOverlayImages.KEY_CASE_SENSITIVE))
613607
.withToolTipText(FindReplaceMessages.FindReplaceOverlay_caseSensitiveButton_toolTip)
614-
.withSearchOption(SearchOptions.CASE_SENSITIVE, findReplaceLogic)
615608
.withAction(caseSensitiveAction).build();
616609
}
617610

618611
private void createWholeWordsButton() {
619-
FindReplaceOverlayAction wholeWordAction = new FindReplaceOverlayAction(() -> {
620-
findReplaceLogic.toggle(SearchOptions.WHOLE_WORD);
621-
updateIncrementalSearch();
622-
});
612+
FindReplaceOverlaySearchOptionAction wholeWordAction = new FindReplaceOverlaySearchOptionAction(
613+
SearchOptions.WHOLE_WORD, findReplaceLogic);
614+
wholeWordAction.addExecutionListener(this::updateIncrementalSearch);
623615
wholeWordAction.addShortcuts(KeyboardShortcuts.OPTION_WHOLE_WORD);
624616
commonActions.add(wholeWordAction);
625617
wholeWordSearchButton = new AccessibleToolItemBuilder(searchTools).withStyleBits(SWT.CHECK)
626618
.withImage(FindReplaceOverlayImages.get(FindReplaceOverlayImages.KEY_WHOLE_WORD))
627619
.withToolTipText(FindReplaceMessages.FindReplaceOverlay_wholeWordsButton_toolTip)
628-
.withSearchOption(SearchOptions.WHOLE_WORD, findReplaceLogic)
629620
.withAction(wholeWordAction).build();
630621
}
631622

@@ -1055,4 +1046,4 @@ private void decorate() {
10551046
}
10561047
}
10571048

1058-
}
1049+
}

bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/overlay/FindReplaceOverlayAction.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
class FindReplaceOverlayAction {
2020
private final Runnable operation;
2121

22+
private final List<Runnable> executionListeners = new ArrayList<>();
23+
2224
private final List<KeyStroke> shortcuts = new ArrayList<>();
2325

2426
FindReplaceOverlayAction(Runnable operation) {
@@ -31,6 +33,7 @@ void addShortcuts(List<KeyStroke> shortcutsToAdd) {
3133

3234
void execute() {
3335
operation.run();
36+
notifyExecutionListeners();
3437
}
3538

3639
List<KeyStroke> getShortcuts() {
@@ -52,4 +55,14 @@ String addShortcutHintToTooltipText(String originalTooltipText) {
5255
return originalTooltipText + " (" + shortcuts.get(0).format() + ")"; //$NON-NLS-1$ //$NON-NLS-2$
5356
}
5457

58+
void addExecutionListener(Runnable listener) {
59+
executionListeners.add(listener);
60+
}
61+
62+
void notifyExecutionListeners() {
63+
for (Runnable listener : executionListeners) {
64+
listener.run();
65+
}
66+
}
67+
5568
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2026 Vector Informatik GmbH and others.
3+
*
4+
* This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Public License 2.0
6+
* which accompanies this distribution, and is available at
7+
* https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
*******************************************************************************/
11+
package org.eclipse.ui.internal.findandreplace.overlay;
12+
13+
import org.eclipse.ui.internal.findandreplace.IFindReplaceLogic;
14+
import org.eclipse.ui.internal.findandreplace.SearchOptions;
15+
16+
class FindReplaceOverlaySearchOptionAction extends FindReplaceOverlayAction {
17+
18+
private final SearchOptions searchOption;
19+
20+
private final IFindReplaceLogic findReplaceLogic;
21+
22+
FindReplaceOverlaySearchOptionAction(SearchOptions searchOption, IFindReplaceLogic findReplaceLogic) {
23+
super(() -> findReplaceLogic.toggle(searchOption));
24+
this.searchOption = searchOption;
25+
this.findReplaceLogic = findReplaceLogic;
26+
}
27+
28+
SearchOptions getSearchOption() {
29+
return searchOption;
30+
}
31+
32+
IFindReplaceLogic getFindReplaceLogic() {
33+
return findReplaceLogic;
34+
}
35+
36+
}

0 commit comments

Comments
 (0)