Skip to content

Commit ac98c9f

Browse files
committed
Find/replace overlay: replace shell with integrated composite #2099
The FindReplaceOverlay is currently realized as a separate shell (more precisely, a JFace Dialog), which is placed at a proper position on top of the workbench shell. This has some drawback: - It has to manually adapt to movements of the parent shell or the target part/widget - It has to manually hide and show depending on visibility changes of the target part/widget - It does not follow events of the target immediately, i.e., movements are always some milliseconds behind, minimize/maximize operations/animations are not synchronous etc. - It does not locate properly when the platform uses Wayland, as manual shell positioning is not possible there. This change replaces the dialog-based implementation of the FindReplaceOverlay with an in-place composite-based implementation. A composite is created in the target widget and placed relative to this composite. In consequence, the overlay automatically follows all move, resize, hide/show operations of the target widget. Fixes eclipse-platform/eclipse.platform.swt#1447 Fixes #2099
1 parent 5c74619 commit ac98c9f

File tree

12 files changed

+152
-344
lines changed

12 files changed

+152
-344
lines changed
-15 Bytes
Loading
34 Bytes
Loading
5 Bytes
Loading
32 Bytes
Loading

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

Lines changed: 107 additions & 275 deletions
Large diffs are not rendered by default.

bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceAction.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,7 @@ private void showOverlayInEditor() {
429429
overlay.setPositionToTop(shouldPositionOverlayOnTop());
430430

431431
hookDialogPreferenceListener();
432-
overlay.getShell().addDisposeListener(__ -> removeDialogPreferenceListener());
432+
overlay.addDisposeListener(__ -> removeDialogPreferenceListener());
433433
}
434434

435435
@Override

tests/org.eclipse.ui.workbench.texteditor.tests/src/org/eclipse/ui/internal/findandreplace/FindReplaceUITest.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,6 @@ public void testDisableWholeWordIfRegEx() {
119119
dialog.assertEnabled(SearchOptions.REGEX);
120120
dialog.assertEnabled(SearchOptions.WHOLE_WORD);
121121

122-
dialog.getFindReplaceLogic().updateTarget(fTextViewer.getFindReplaceTarget(), false);
123122
dialog.select(SearchOptions.WHOLE_WORD);
124123
dialog.select(SearchOptions.REGEX);
125124
dialog.assertEnabled(SearchOptions.REGEX);
@@ -161,7 +160,7 @@ public void testShiftEnterReversesSearchDirection() {
161160
dialog.select(SearchOptions.INCREMENTAL);
162161
dialog.setFindText("line");
163162
ensureHasFocusOnGTK();
164-
IFindReplaceTarget target= dialog.getTarget();
163+
IFindReplaceTarget target= getFindReplaceTarget();
165164

166165
assertEquals(0, (target.getSelection()).x);
167166
assertEquals(4, (target.getSelection()).y);
@@ -190,7 +189,7 @@ public void testChangeInputForIncrementalSearch() {
190189
dialog.select(SearchOptions.INCREMENTAL);
191190

192191
dialog.setFindText("lin");
193-
IFindReplaceTarget target= dialog.getTarget();
192+
IFindReplaceTarget target= getFindReplaceTarget();
194193
assertEquals(0, (target.getSelection()).x);
195194
assertEquals(dialog.getFindText().length(), (target.getSelection()).y);
196195

@@ -206,7 +205,7 @@ public void testFindWithWholeWordEnabledWithMultipleWords() {
206205
dialog.select(SearchOptions.WHOLE_WORD);
207206
dialog.select(SearchOptions.WRAP);
208207
dialog.setFindText("two");
209-
IFindReplaceTarget target= dialog.getTarget();
208+
IFindReplaceTarget target= getFindReplaceTarget();
210209
assertEquals(0, (target.getSelection()).x);
211210
assertEquals(3, (target.getSelection()).y);
212211

@@ -227,7 +226,7 @@ public void testRegExSearch() {
227226
dialog.select(SearchOptions.REGEX);
228227
dialog.setFindText("(a|bc)");
229228

230-
IFindReplaceTarget target= dialog.getTarget();
229+
IFindReplaceTarget target= getFindReplaceTarget();
231230
dialog.simulateKeyboardInteractionInFindInputField(SWT.CR, false);
232231
assertEquals(0, (target.getSelection()).x);
233232
assertEquals(1, (target.getSelection()).y);
@@ -374,4 +373,8 @@ protected TextViewer getTextViewer() {
374373
return fTextViewer;
375374
}
376375

376+
protected final IFindReplaceTarget getFindReplaceTarget() {
377+
return fTextViewer.getFindReplaceTarget();
378+
}
379+
377380
}

tests/org.eclipse.ui.workbench.texteditor.tests/src/org/eclipse/ui/internal/findandreplace/IFindReplaceUIAccess.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,11 @@
1212

1313
import org.eclipse.swt.widgets.Widget;
1414

15-
import org.eclipse.jface.text.IFindReplaceTarget;
16-
1715
/**
1816
* Wraps UI access for different find/replace UIs
1917
*/
2018
public interface IFindReplaceUIAccess {
2119

22-
IFindReplaceTarget getTarget();
23-
2420
void closeAndRestore();
2521

2622
void close();
@@ -47,8 +43,6 @@ public interface IFindReplaceUIAccess {
4743

4844
Widget getButtonForSearchOption(SearchOptions option);
4945

50-
IFindReplaceLogic getFindReplaceLogic();
51-
5246
void performReplaceAll();
5347

5448
void performReplace();

tests/org.eclipse.ui.workbench.texteditor.tests/src/org/eclipse/ui/internal/findandreplace/overlay/FindReplaceOverlayTest.java

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public OverlayAccess openUIFromTextViewer(TextViewer viewer) {
4646
Accessor actionAccessor= new Accessor(getFindReplaceAction(), FindReplaceAction.class);
4747
actionAccessor.invoke("showOverlayInEditor", null);
4848
Accessor overlayAccessor= new Accessor(actionAccessor.get("overlay"), "org.eclipse.ui.internal.findandreplace.overlay.FindReplaceOverlay", getClass().getClassLoader());
49-
return new OverlayAccess(overlayAccessor);
49+
return new OverlayAccess(getFindReplaceTarget(), overlayAccessor);
5050
}
5151

5252
@Test
@@ -55,7 +55,7 @@ public void testDirectionalSearchButtons() {
5555
OverlayAccess dialog= getDialog();
5656

5757
dialog.setFindText("line");
58-
IFindReplaceTarget target= dialog.getTarget();
58+
IFindReplaceTarget target= getFindReplaceTarget();
5959

6060
assertEquals(0, (target.getSelection()).x);
6161
assertEquals(4, (target.getSelection()).y);
@@ -89,14 +89,14 @@ public void testDirectionalSearchButtons() {
8989
public void testIncrementalSearchUpdatesAfterChangingOptions() {
9090
initializeTextViewerWithFindReplaceUI("alinee\naLinee\nline\nline");
9191
OverlayAccess dialog= getDialog();
92-
IFindReplaceTarget target= dialog.getTarget();
92+
IFindReplaceTarget target= getFindReplaceTarget();
9393
dialog.setFindText("Line");
94-
assertThat(dialog.getTarget().getSelectionText(), is("line"));
95-
assertEquals(new Point(1,4), dialog.getTarget().getSelection());
94+
assertThat(target.getSelectionText(), is("line"));
95+
assertEquals(new Point(1, 4), target.getSelection());
9696

9797
dialog.select(SearchOptions.CASE_SENSITIVE);
98-
assertThat(dialog.getTarget().getSelectionText(), is("Line"));
99-
assertEquals(new Point(8,4), dialog.getTarget().getSelection());
98+
assertThat(target.getSelectionText(), is("Line"));
99+
assertEquals(new Point(8, 4), target.getSelection());
100100

101101
dialog.unselect(SearchOptions.CASE_SENSITIVE);
102102
assertEquals(1, (target.getSelection()).x);
@@ -110,7 +110,7 @@ public void testIncrementalSearchUpdatesAfterChangingOptions() {
110110
dialog.unselect(SearchOptions.WHOLE_WORD);
111111
assertEquals(1, (target.getSelection()).x);
112112
assertEquals(4, (target.getSelection()).y);
113-
assertThat(dialog.getTarget().getSelectionText(), is("line"));
113+
assertThat(target.getSelectionText(), is("line"));
114114
}
115115

116116
@Test
@@ -153,18 +153,19 @@ public void testRememberReplaceExpandState() {
153153
@Test
154154
public void testSearchBackwardsWithRegEx() {
155155
initializeTextViewerWithFindReplaceUI("text text text");
156+
IFindReplaceTarget target= getFindReplaceTarget();
156157

157158
OverlayAccess dialog= getDialog();
158159
dialog.select(SearchOptions.REGEX);
159160
dialog.setFindText("text"); // with RegEx enabled, there is no incremental search!
160161
dialog.pressSearch(true);
161-
assertThat(dialog.getTarget().getSelection().y, is(4));
162+
assertThat(target.getSelection().y, is(4));
162163
dialog.pressSearch(true);
163-
assertThat(dialog.getTarget().getSelection().x, is("text ".length()));
164+
assertThat(target.getSelection().x, is("text ".length()));
164165
dialog.pressSearch(true);
165-
assertThat(dialog.getTarget().getSelection().x, is("text text ".length()));
166+
assertThat(target.getSelection().x, is("text text ".length()));
166167
dialog.pressSearch(false);
167-
assertThat(dialog.getTarget().getSelection().x, is("text ".length()));
168+
assertThat(target.getSelection().x, is("text ".length()));
168169
}
169170

170171
@Test

tests/org.eclipse.ui.workbench.texteditor.tests/src/org/eclipse/ui/internal/findandreplace/overlay/OverlayAccess.java

Lines changed: 20 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -21,28 +21,27 @@
2121
import java.util.Objects;
2222
import java.util.Set;
2323
import java.util.function.Predicate;
24-
import java.util.function.Supplier;
2524
import java.util.stream.Collectors;
2625

2726
import org.eclipse.swt.SWT;
2827
import org.eclipse.swt.widgets.Button;
28+
import org.eclipse.swt.widgets.Composite;
2929
import org.eclipse.swt.widgets.Control;
3030
import org.eclipse.swt.widgets.Event;
31-
import org.eclipse.swt.widgets.Shell;
3231
import org.eclipse.swt.widgets.ToolItem;
3332

3433
import org.eclipse.text.tests.Accessor;
3534

3635
import org.eclipse.jface.text.IFindReplaceTarget;
3736
import org.eclipse.jface.text.IFindReplaceTargetExtension;
3837

39-
import org.eclipse.ui.internal.findandreplace.FindReplaceLogic;
40-
import org.eclipse.ui.internal.findandreplace.IFindReplaceLogic;
4138
import org.eclipse.ui.internal.findandreplace.IFindReplaceUIAccess;
4239
import org.eclipse.ui.internal.findandreplace.SearchOptions;
4340

4441
class OverlayAccess implements IFindReplaceUIAccess {
45-
FindReplaceLogic findReplaceLogic;
42+
private final IFindReplaceTarget findReplaceTarget;
43+
44+
Composite overlayControl;
4645

4746
HistoryTextWrapper find;
4847

@@ -70,11 +69,10 @@ class OverlayAccess implements IFindReplaceUIAccess {
7069

7170
Accessor dialogAccessor;
7271

73-
private Supplier<Shell> shellRetriever;
74-
75-
OverlayAccess(Accessor findReplaceOverlayAccessor) {
72+
OverlayAccess(IFindReplaceTarget findReplaceTarget, Accessor findReplaceOverlayAccessor) {
73+
this.findReplaceTarget= findReplaceTarget;
7674
dialogAccessor= findReplaceOverlayAccessor;
77-
findReplaceLogic= (FindReplaceLogic) findReplaceOverlayAccessor.get("findReplaceLogic");
75+
overlayControl= (Composite) findReplaceOverlayAccessor.get("overlayControl");
7876
find= (HistoryTextWrapper) findReplaceOverlayAccessor.get("searchBar");
7977
replace= (HistoryTextWrapper) findReplaceOverlayAccessor.get("replaceBar");
8078
caseSensitive= (ToolItem) findReplaceOverlayAccessor.get("caseSensitiveSearchButton");
@@ -87,12 +85,6 @@ class OverlayAccess implements IFindReplaceUIAccess {
8785
replaceButton= (ToolItem) findReplaceOverlayAccessor.get("replaceButton");
8886
replaceAllButton= (ToolItem) findReplaceOverlayAccessor.get("replaceAllButton");
8987
inSelection= (ToolItem) findReplaceOverlayAccessor.get("searchInSelectionButton");
90-
shellRetriever= () -> ((Shell) findReplaceOverlayAccessor.invoke("getShell", null));
91-
}
92-
93-
@Override
94-
public IFindReplaceTarget getTarget() {
95-
return findReplaceLogic.getTarget();
9688
}
9789

9890
private void restoreInitialConfiguration() {
@@ -228,11 +220,6 @@ public void pressSearch(boolean forward) {
228220
}
229221
}
230222

231-
@Override
232-
public IFindReplaceLogic getFindReplaceLogic() {
233-
return findReplaceLogic;
234-
}
235-
236223
@Override
237224
public void performReplaceAll() {
238225
openReplaceDialog();
@@ -277,25 +264,23 @@ public void assertInitialConfiguration() {
277264
assertUnselected(SearchOptions.REGEX);
278265
assertUnselected(SearchOptions.WHOLE_WORD);
279266
assertUnselected(SearchOptions.CASE_SENSITIVE);
280-
if (!doesTextViewerHaveMultiLineSelection(findReplaceLogic.getTarget())) {
267+
if (!doesTextViewerHaveMultiLineSelection()) {
281268
assertSelected(SearchOptions.GLOBAL);
282-
assertTrue(findReplaceLogic.isActive(SearchOptions.GLOBAL));
283269
} else {
284270
assertUnselected(SearchOptions.GLOBAL);
285-
assertFalse(findReplaceLogic.isActive(SearchOptions.GLOBAL));
286271
}
287272
assertEnabled(SearchOptions.GLOBAL);
288273
assertEnabled(SearchOptions.REGEX);
289274
assertEnabled(SearchOptions.CASE_SENSITIVE);
290-
if (getFindText().equals("") || findReplaceLogic.isAvailable(SearchOptions.WHOLE_WORD)) {
275+
if (!getFindText().contains(" ")) {
291276
assertEnabled(SearchOptions.WHOLE_WORD);
292277
} else {
293278
assertDisabled(SearchOptions.WHOLE_WORD);
294279
}
295280
}
296281

297-
private boolean doesTextViewerHaveMultiLineSelection(IFindReplaceTarget target) {
298-
if (target instanceof IFindReplaceTargetExtension scopeProvider) {
282+
private boolean doesTextViewerHaveMultiLineSelection() {
283+
if (findReplaceTarget instanceof IFindReplaceTargetExtension scopeProvider) {
299284
return scopeProvider.getScope() != null; // null is returned for global scope
300285
}
301286
return false;
@@ -323,15 +308,19 @@ public void assertEnabled(SearchOptions option) {
323308

324309
@Override
325310
public boolean isShown() {
326-
return shellRetriever.get() != null && shellRetriever.get().isVisible();
311+
return overlayControl.isVisible();
327312
}
328313

329314
@Override
330315
public boolean hasFocus() {
331-
Shell overlayShell= shellRetriever.get();
332-
Control focusControl= overlayShell.getDisplay().getFocusControl();
333-
Shell focusControlShell= focusControl != null ? focusControl.getShell() : null;
334-
return focusControlShell == overlayShell;
316+
Control focusControl= overlayControl.getDisplay().getFocusControl();
317+
while (focusControl != null) {
318+
if (overlayControl == focusControl) {
319+
return true;
320+
}
321+
focusControl= focusControl.getParent();
322+
}
323+
return false;
335324
}
336325

337326
}

0 commit comments

Comments
 (0)