Skip to content

Commit c4d7646

Browse files
HeikoKlareCopilot
andcommitted
Find/Replace overlay: separate command infrastructure into dedicated
class Introduce FindReplaceOverlayCommandSupport to own the overlay's command-related infrastructure. As a first step, move the workaround that disables the target text editor's global action handlers (setTextEditorActionsActivated and DeactivateGlobalActionHandlers) out of FindReplaceOverlay into this new class. FindReplaceOverlay now only calls commandSupport.onFocusGained/Lost(). Contributes to #1912 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent ef70250 commit c4d7646

2 files changed

Lines changed: 106 additions & 65 deletions

File tree

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

Lines changed: 5 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,8 @@
1313
*******************************************************************************/
1414
package org.eclipse.ui.internal.findandreplace.overlay;
1515

16-
import java.lang.reflect.Method;
1716
import java.util.ArrayList;
18-
import java.util.HashMap;
1917
import java.util.List;
20-
import java.util.Map;
2118
import java.util.concurrent.atomic.AtomicReference;
2219

2320
import org.osgi.framework.FrameworkUtil;
@@ -47,9 +44,6 @@
4744
import org.eclipse.swt.widgets.ToolItem;
4845
import org.eclipse.swt.widgets.Widget;
4946

50-
import org.eclipse.core.runtime.ILog;
51-
52-
import org.eclipse.jface.action.IAction;
5347
import org.eclipse.jface.bindings.keys.KeyStroke;
5448
import org.eclipse.jface.dialogs.Dialog;
5549
import org.eclipse.jface.dialogs.IDialogSettings;
@@ -64,7 +58,6 @@
6458
import org.eclipse.jface.text.IFindReplaceTarget;
6559
import org.eclipse.jface.text.ITextViewer;
6660

67-
import org.eclipse.ui.IActionBars;
6861
import org.eclipse.ui.IWorkbenchPart;
6962
import org.eclipse.ui.PlatformUI;
7063
import org.eclipse.ui.fieldassist.ContentAssistCommandAdapter;
@@ -74,12 +67,9 @@
7467
import org.eclipse.ui.internal.findandreplace.HistoryStore;
7568
import org.eclipse.ui.internal.findandreplace.IFindReplaceLogic;
7669
import org.eclipse.ui.internal.findandreplace.SearchOptions;
77-
import org.eclipse.ui.part.MultiPageEditorSite;
7870

79-
import org.eclipse.ui.texteditor.AbstractTextEditor;
8071
import org.eclipse.ui.texteditor.FindReplaceAction;
8172
import org.eclipse.ui.texteditor.IAbstractTextEditorHelpContextIds;
82-
import org.eclipse.ui.texteditor.ITextEditorActionConstants;
8373
import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
8474
import org.eclipse.ui.texteditor.StatusTextEditor;
8575

@@ -159,69 +149,18 @@ private static final class KeyboardShortcuts {
159149
private ControlDecoration searchBarDecoration;
160150
private ContentAssistCommandAdapter contentAssistSearchField, contentAssistReplaceField;
161151

162-
private final FocusListener targetActionActivationHandling = new FocusListener() {
163-
private DeactivateGlobalActionHandlers globalActionHandlerDeaction;
152+
private FindReplaceOverlayCommandSupport commandSupport;
164153

154+
private final FocusListener targetActionActivationHandling = new FocusListener() {
165155
@Override
166156
public void focusGained(FocusEvent e) {
167-
setTextEditorActionsActivated(false);
157+
commandSupport.overlayActivated();
168158
}
169159

170160
@Override
171161
public void focusLost(FocusEvent e) {
172-
setTextEditorActionsActivated(true);
173-
}
174-
175-
/*
176-
* Adapted from
177-
* org.eclipse.jdt.internal.ui.javaeditor.JavaEditor#setActionsActivated(
178-
* boolean)
179-
*/
180-
private void setTextEditorActionsActivated(boolean state) {
181-
if (!(targetPart instanceof AbstractTextEditor) || targetPart.getSite().getWorkbenchWindow().isClosing()) {
182-
return;
183-
}
184-
if (targetPart.getSite() instanceof MultiPageEditorSite multiEditorSite) {
185-
if (!state && globalActionHandlerDeaction == null) {
186-
globalActionHandlerDeaction = new DeactivateGlobalActionHandlers(multiEditorSite.getActionBars());
187-
} else if (state && globalActionHandlerDeaction != null) {
188-
globalActionHandlerDeaction.reactivate();
189-
globalActionHandlerDeaction = null;
190-
}
191-
}
192-
try {
193-
Method method = AbstractTextEditor.class.getDeclaredMethod("setActionActivation", boolean.class); //$NON-NLS-1$
194-
method.setAccessible(true);
195-
method.invoke(targetPart, Boolean.valueOf(state));
196-
} catch (IllegalArgumentException | ReflectiveOperationException ex) {
197-
ILog.of(FindReplaceOverlay.class).error("cannot (de-)activate actions for text editor", ex); //$NON-NLS-1$
198-
}
162+
commandSupport.overlayDeactivated();
199163
}
200-
201-
static final class DeactivateGlobalActionHandlers {
202-
private final static List<String> ACTIONS = List.of(ITextEditorActionConstants.CUT,
203-
ITextEditorActionConstants.COPY, ITextEditorActionConstants.PASTE,
204-
ITextEditorActionConstants.DELETE, ITextEditorActionConstants.SELECT_ALL,
205-
ITextEditorActionConstants.FIND);
206-
207-
private final Map<String, IAction> deactivatedActions = new HashMap<>();
208-
private final IActionBars actionBars;
209-
210-
public DeactivateGlobalActionHandlers(IActionBars actionBars) {
211-
this.actionBars = actionBars;
212-
for (String actionID : ACTIONS) {
213-
deactivatedActions.putIfAbsent(actionID, actionBars.getGlobalActionHandler(actionID));
214-
actionBars.setGlobalActionHandler(actionID, null);
215-
}
216-
}
217-
218-
public void reactivate() {
219-
for (String actionID : deactivatedActions.keySet()) {
220-
actionBars.setGlobalActionHandler(actionID, deactivatedActions.get(actionID));
221-
}
222-
}
223-
}
224-
225164
};
226165

227166
private final CustomFocusOrder customFocusOrder = new CustomFocusOrder();
@@ -301,6 +240,7 @@ void dispose() {
301240

302241
public FindReplaceOverlay(Shell parent, IWorkbenchPart part, IFindReplaceTarget target) {
303242
targetPart = part;
243+
commandSupport = new FindReplaceOverlayCommandSupport(targetPart);
304244
targetControl = getTargetControl(parent, part);
305245
findReplaceLogic = createFindReplaceLogic(target);
306246
createContainerAndSearchControls(targetControl);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
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 java.lang.reflect.Method;
14+
import java.util.HashMap;
15+
import java.util.List;
16+
import java.util.Map;
17+
18+
import org.eclipse.core.runtime.ILog;
19+
20+
import org.eclipse.jface.action.IAction;
21+
22+
import org.eclipse.ui.IActionBars;
23+
import org.eclipse.ui.IWorkbenchPart;
24+
import org.eclipse.ui.part.MultiPageEditorSite;
25+
26+
import org.eclipse.ui.texteditor.AbstractTextEditor;
27+
import org.eclipse.ui.texteditor.ITextEditorActionConstants;
28+
29+
/**
30+
* Owns the Find/Replace overlay's command-related infrastructure. Currently
31+
* encapsulates the workaround that disables the target text editor's global
32+
* action handlers while the overlay has focus, preventing them from consuming
33+
* key events that are meant for the overlay's text fields.
34+
*/
35+
class FindReplaceOverlayCommandSupport {
36+
37+
private final IWorkbenchPart targetPart;
38+
private DeactivateGlobalActionHandlers globalActionHandlerDeaction;
39+
40+
FindReplaceOverlayCommandSupport(IWorkbenchPart targetPart) {
41+
this.targetPart = targetPart;
42+
}
43+
44+
void overlayActivated() {
45+
setTextEditorActionsActivated(false);
46+
}
47+
48+
void overlayDeactivated() {
49+
setTextEditorActionsActivated(true);
50+
}
51+
52+
/*
53+
* Adapted from
54+
* org.eclipse.jdt.internal.ui.javaeditor.JavaEditor#setActionsActivated(boolean)
55+
*/
56+
private void setTextEditorActionsActivated(boolean state) {
57+
if (!(targetPart instanceof AbstractTextEditor) || targetPart.getSite().getWorkbenchWindow().isClosing()) {
58+
return;
59+
}
60+
if (targetPart.getSite() instanceof MultiPageEditorSite multiEditorSite) {
61+
if (!state && globalActionHandlerDeaction == null) {
62+
globalActionHandlerDeaction = new DeactivateGlobalActionHandlers(multiEditorSite.getActionBars());
63+
} else if (state && globalActionHandlerDeaction != null) {
64+
globalActionHandlerDeaction.reactivate();
65+
globalActionHandlerDeaction = null;
66+
}
67+
}
68+
try {
69+
Method method = AbstractTextEditor.class.getDeclaredMethod("setActionActivation", boolean.class); //$NON-NLS-1$
70+
method.setAccessible(true);
71+
method.invoke(targetPart, Boolean.valueOf(state));
72+
} catch (IllegalArgumentException | ReflectiveOperationException ex) {
73+
ILog.of(FindReplaceOverlayCommandSupport.class).error("cannot (de-)activate actions for text editor", ex); //$NON-NLS-1$
74+
}
75+
}
76+
77+
private static final class DeactivateGlobalActionHandlers {
78+
private static final List<String> ACTIONS = List.of(ITextEditorActionConstants.CUT,
79+
ITextEditorActionConstants.COPY, ITextEditorActionConstants.PASTE,
80+
ITextEditorActionConstants.DELETE, ITextEditorActionConstants.SELECT_ALL,
81+
ITextEditorActionConstants.FIND);
82+
83+
private final Map<String, IAction> deactivatedActions = new HashMap<>();
84+
private final IActionBars actionBars;
85+
86+
DeactivateGlobalActionHandlers(IActionBars actionBars) {
87+
this.actionBars = actionBars;
88+
for (String actionID : ACTIONS) {
89+
deactivatedActions.putIfAbsent(actionID, actionBars.getGlobalActionHandler(actionID));
90+
actionBars.setGlobalActionHandler(actionID, null);
91+
}
92+
}
93+
94+
void reactivate() {
95+
for (String actionID : deactivatedActions.keySet()) {
96+
actionBars.setGlobalActionHandler(actionID, deactivatedActions.get(actionID));
97+
}
98+
}
99+
}
100+
101+
}

0 commit comments

Comments
 (0)