Update org.apache.commons:commons-compress to 1.25.0
[egit/eclipse.git] / org.eclipse.egit.ui / src / org / eclipse / egit / ui / internal / ActionUtils.java
blobcb29bfc35f74eda8d28dbf70abfb7a07f951b887
1 /*******************************************************************************
2 * Copyright (C) 2016 Thomas Wolf <thomas.wolf@paranor.ch>
4 * All rights reserved. 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/
9 * SPDX-License-Identifier: EPL-2.0
10 *******************************************************************************/
11 package org.eclipse.egit.ui.internal;
13 import java.util.ArrayList;
14 import java.util.Arrays;
15 import java.util.Collection;
16 import java.util.function.BooleanSupplier;
18 import org.eclipse.jface.action.Action;
19 import org.eclipse.jface.action.IAction;
20 import org.eclipse.jface.action.MenuManager;
21 import org.eclipse.jface.action.Separator;
22 import org.eclipse.jface.commands.ActionHandler;
23 import org.eclipse.jface.text.ITextOperationTarget;
24 import org.eclipse.swt.SWT;
25 import org.eclipse.swt.widgets.Control;
26 import org.eclipse.swt.widgets.Event;
27 import org.eclipse.swt.widgets.Listener;
28 import org.eclipse.ui.ActiveShellExpression;
29 import org.eclipse.ui.PlatformUI;
30 import org.eclipse.ui.actions.ActionFactory;
31 import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction;
32 import org.eclipse.ui.handlers.IHandlerActivation;
33 import org.eclipse.ui.handlers.IHandlerService;
34 import org.eclipse.ui.texteditor.IUpdate;
36 /**
37 * Action-related utilities.
39 public final class ActionUtils {
41 private ActionUtils() {
42 // Utility class shall not be instantiated.
45 /**
46 * Create an {@link IAction} taking the text, id, and action definition id
47 * from the given {@link ActionFactory}.
49 * @param factory
50 * from which the new {@link IAction} shall be derived
51 * @param action
52 * to execute
53 * @return the new {@link IAction}
55 public static IAction createGlobalAction(ActionFactory factory,
56 final Runnable action) {
57 IWorkbenchAction template = factory
58 .create(PlatformUI.getWorkbench().getActiveWorkbenchWindow());
59 IAction result = new Action(template.getText()) {
61 @Override
62 public void run() {
63 action.run();
66 result.setActionDefinitionId(template.getActionDefinitionId());
67 result.setId(template.getId());
68 result.setImageDescriptor(template.getImageDescriptor());
69 result.setDisabledImageDescriptor(
70 template.getDisabledImageDescriptor());
71 template.dispose();
72 return result;
75 /**
76 * Create an {@link UpdateableAction} taking the text, id, and action
77 * definition id from the given {@link ActionFactory}. The using code of
78 * such an action is responsible for calling {@link IUpdate#update()
79 * update()} on the action when its enablement should be updated.
81 * @param factory
82 * from which the new {@link IAction} shall be derived
83 * @param action
84 * to execute
85 * @param enabled
86 * to obtain the action's enablement
87 * @return the new {@link UpdateableAction}
89 public static UpdateableAction createGlobalAction(ActionFactory factory,
90 final Runnable action, final BooleanSupplier enabled) {
91 IWorkbenchAction template = factory
92 .create(PlatformUI.getWorkbench().getActiveWorkbenchWindow());
93 UpdateableAction result = new UpdateableAction(template.getText()) {
95 @Override
96 public void run() {
97 action.run();
100 @Override
101 public void update() {
102 setEnabled(enabled.getAsBoolean());
105 result.setActionDefinitionId(template.getActionDefinitionId());
106 result.setId(template.getId());
107 result.setImageDescriptor(template.getImageDescriptor());
108 result.setDisabledImageDescriptor(
109 template.getDisabledImageDescriptor());
110 result.update();
111 template.dispose();
112 return result;
116 * Creates a new text action using a given {@link ActionFactory} to use as a
117 * template to set the label, image, and action definition id.
119 * @param target
120 * for the action
121 * @param factory
122 * to configure the action
123 * @param operationCode
124 * for the action
125 * @return the configured {@link UpdateableAction}
127 public static UpdateableAction createTextAction(
128 ITextOperationTarget target, ActionFactory factory,
129 int operationCode) {
130 if (operationCode == ITextOperationTarget.REDO) {
131 // XXX: workaround for
132 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=206111
133 return createGlobalAction(factory,
134 () -> target.doOperation(operationCode), () -> true);
136 return createGlobalAction(factory,
137 () -> target.doOperation(operationCode),
138 () -> target.canDoOperation(operationCode));
141 private static UpdateableAction[] createStandardTextActions(
142 ITextOperationTarget target, boolean editable) {
143 UpdateableAction[] actions = new UpdateableAction[ITextOperationTarget.SELECT_ALL
144 + 1];
145 if (editable) {
146 actions[ITextOperationTarget.UNDO] = createTextAction(target,
147 ActionFactory.UNDO, ITextOperationTarget.UNDO);
148 actions[ITextOperationTarget.REDO] = createTextAction(target,
149 ActionFactory.REDO, ITextOperationTarget.REDO);
150 actions[ITextOperationTarget.CUT] = createTextAction(target,
151 ActionFactory.CUT, ITextOperationTarget.CUT);
152 actions[ITextOperationTarget.PASTE] = createTextAction(
153 target, ActionFactory.PASTE, ITextOperationTarget.PASTE);
154 actions[ITextOperationTarget.DELETE] = createTextAction(
155 target, ActionFactory.DELETE, ITextOperationTarget.DELETE);
157 actions[ITextOperationTarget.COPY] = createTextAction(target,
158 ActionFactory.COPY, ITextOperationTarget.COPY);
159 actions[ITextOperationTarget.SELECT_ALL] = createTextAction(
160 target, ActionFactory.SELECT_ALL,
161 ITextOperationTarget.SELECT_ALL);
162 return actions;
166 * Create the standard text actions, fill them into a {@MenuManager} and
167 * return them as an array indexed by the {@link ITextOperationTarget}
168 * operation codes. For an editable target, creates undo, redo | cut, copy,
169 * paste | delete, select all; otherwise just copy, select all.
171 * @param target
172 * for the actions to operate on
173 * @param editable
174 * whether the target is editable
175 * @param manager
176 * to fill in; may be {@code null} if the actions shall not be
177 * added to a {@link MenuManager}
178 * @return the actions; may contain {@code null} values (index 0 will always
179 * be {@code null})
181 public static UpdateableAction[] fillStandardTextActions(
182 ITextOperationTarget target, boolean editable,
183 MenuManager manager) {
184 UpdateableAction[] actions = createStandardTextActions(target,
185 editable);
186 if (manager != null) {
187 if (editable) {
188 manager.add(actions[ITextOperationTarget.UNDO]);
189 manager.add(actions[ITextOperationTarget.REDO]);
190 manager.add(new Separator());
191 manager.add(actions[ITextOperationTarget.CUT]);
193 manager.add(actions[ITextOperationTarget.COPY]);
194 if (editable) {
195 manager.add(actions[ITextOperationTarget.PASTE]);
196 manager.add(new Separator());
197 manager.add(actions[ITextOperationTarget.DELETE]);
199 manager.add(actions[ITextOperationTarget.SELECT_ALL]);
201 return actions;
205 * Hooks up the {@link Control} such that the given {@link IAction}s are
206 * registered with the given {@link IHandlerService} while the control has
207 * the focus. Ensures that actions are properly de-registered when the
208 * control is disposed.
210 * @param control
211 * to hook up
212 * @param actions
213 * to be registered while the control has the focus; {@code null}
214 * items are skipped.
215 * @param service
216 * to register the actions with
218 public static void setGlobalActions(Control control,
219 Collection<? extends IAction> actions, IHandlerService service) {
220 ActiveShellExpression expression = new ActiveShellExpression(
221 control.getShell());
222 class ActivationListener implements Listener {
224 private Collection<IHandlerActivation> handlerActivations = new ArrayList<>();
226 @Override
227 public void handleEvent(Event event) {
228 switch (event.type) {
229 case SWT.Deactivate:
230 case SWT.FocusOut:
231 case SWT.Dispose:
232 if (!handlerActivations.isEmpty()) {
233 service.deactivateHandlers(handlerActivations);
234 handlerActivations.clear();
236 break;
237 case SWT.FocusIn:
238 if (!handlerActivations.isEmpty()) {
239 // Looks like sometimes we get two focusGained events.
240 return;
242 for (IAction action : actions) {
243 if (action != null) {
244 handlerActivations.add(service.activateHandler(
245 action.getActionDefinitionId(),
246 new ActionHandler(action), expression,
247 false));
248 if (action instanceof IUpdate) {
249 ((IUpdate) action).update();
253 break;
254 default:
255 break;
259 ActivationListener activationListener = new ActivationListener();
260 control.addListener(SWT.Deactivate, activationListener);
261 control.addListener(SWT.FocusOut, activationListener);
262 control.addListener(SWT.FocusIn, activationListener);
263 control.addListener(SWT.Dispose, activationListener);
267 * Hooks up the {@link Control} such that the given {@link IAction}s are
268 * registered with the given {@link IHandlerService} while the control has
269 * the focus. Ensures that actions are properly de-registered when the
270 * control is disposed.
272 * @param control
273 * to hook up
274 * @param service
275 * to register the actions with
276 * @param actions
277 * to be registered while the control has the focus
279 public static void setGlobalActions(Control control,
280 IHandlerService service, IAction... actions) {
281 setGlobalActions(control, Arrays.asList(actions), service);
285 * Hooks up the {@link Control} such that the given {@link IAction}s are
286 * registered with the workbench-global {@link IHandlerService} while the
287 * control has the focus. Ensures that actions are properly de-registered
288 * when the control is disposed.
290 * @param control
291 * to hook up
292 * @param actions
293 * to be registered while the control has the focus
295 public static void setGlobalActions(Control control,
296 Collection<? extends IAction> actions) {
297 setGlobalActions(control, actions,
298 PlatformUI.getWorkbench().getService(IHandlerService.class));
302 * Hooks up the {@link Control} such that the given {@link IAction}s are
303 * registered with the workbench-global {@link IHandlerService} while the
304 * control has the focus. Ensures that actions are properly de-registered
305 * when the control is disposed.
307 * @param control
308 * to hook up
309 * @param actions
310 * to be registered while the control has the focus
312 public static void setGlobalActions(Control control, IAction... actions) {
313 setGlobalActions(control, Arrays.asList(actions));
317 * An {@link Action} that is updateable via {@link IUpdate}.
319 public static abstract class UpdateableAction extends Action
320 implements IUpdate {
323 * Creates a new {@link UpdateableAction} with the given text.
325 * @param text
327 public UpdateableAction(String text) {
328 super(text);