1 /*******************************************************************************
2 * Copyright (c) 2017 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * Semantum Oy - (#7066) initial API and implementation
11 *******************************************************************************/
12 package org.simantics.views.text.internal;
14 import java.lang.reflect.InvocationTargetException;
15 import java.lang.reflect.Method;
16 import java.util.concurrent.Callable;
18 import org.eclipse.core.commands.AbstractHandler;
19 import org.eclipse.core.commands.ExecutionEvent;
20 import org.eclipse.core.commands.ExecutionException;
21 import org.eclipse.core.runtime.IConfigurationElement;
22 import org.eclipse.core.runtime.IExecutableExtension;
23 import org.eclipse.jface.text.IUndoManager;
24 import org.eclipse.jface.text.TextViewer;
25 import org.eclipse.swt.SWT;
26 import org.eclipse.swt.widgets.Control;
27 import org.eclipse.swt.widgets.Display;
28 import org.eclipse.swt.widgets.Event;
29 import org.eclipse.swt.widgets.Listener;
32 * Handles the undo/redo command for {@link TextViewer}s through
33 * {@link IUndoManager}.
36 * The implementation looks for an IUndoManager from the current focus control
37 * using the {@link TextViewerConstants#KEY_UNDO_MANAGER} data key. Its
38 * existence determines whether this handler {@link #isHandled()} returns
39 * <code>true</code> or <code>false</code>.
42 * The handler expects to receive a single string as an argument through the
43 * extension definitions ({@link IExecutableExtension}) that determines which
44 * method is invoked from IUndoManager (<code>undo</code> or <code>redo</code>).
47 * Implementation is partially copied from
48 * <code>org.eclipse.ui.internal.handlers.WidgetMethodHandler</code>.
52 public class TextViewerUndoHandler extends AbstractHandler implements IExecutableExtension {
55 * The parameters to pass to the method this handler invokes. This handler
56 * always passes no parameters.
58 protected static final Class<?>[] NO_PARAMETERS = new Class[0];
60 public TextViewerUndoHandler() {
61 display = Display.getCurrent();
62 if (display != null) {
63 focusListener = new Listener() {
65 public void handleEvent(Event event) {
69 display.addFilter(SWT.FocusIn, focusListener);
73 void updateEnablement() {
74 boolean rc = isHandled();
75 if (rc != isEnabled()) {
81 * The name of the method to be invoked by this handler. This value should
82 * never be <code>null</code>.
84 protected String methodName;
85 private Listener focusListener;
86 private Display display;
89 public Object execute(final ExecutionEvent event) throws ExecutionException {
90 Callable<?> runnable = getMethodToExecute();
91 if (runnable != null) {
94 } catch (ExecutionException e) {
96 } catch (Exception e) {
97 throw new ExecutionException("Unexpected failure executing method " + methodName + " through " + runnable);
104 public final boolean isHandled() {
105 return getMethodToExecute() != null;
109 * Looks up the method on the focus control.
111 * @return The method on the focus control; <code>null</code> if none.
113 protected Callable<Boolean> getMethodToExecute() {
114 Display display = Display.getCurrent();
118 Control focusControl = display.getFocusControl();
119 if (focusControl == null)
122 IUndoManager undoManager = (IUndoManager) focusControl.getData(TextViewerConstants.KEY_UNDO_MANAGER);
123 if (undoManager == null)
127 Method method = undoManager.getClass().getMethod(methodName, NO_PARAMETERS);
129 return runner(undoManager, method);
130 } catch (NoSuchMethodException e) {
137 protected Callable<Boolean> runner(IUndoManager undoManager, Method method) {
140 method.invoke(undoManager);
142 } catch (IllegalAccessException e) {
143 // The method is protected, so do nothing.
145 } catch (InvocationTargetException e) {
146 throw new ExecutionException(
147 "An exception occurred while executing " //$NON-NLS-1$
148 + method.getName(), e
149 .getTargetException());
156 public void setInitializationData(IConfigurationElement config, String propertyName, Object data) {
157 methodName = data.toString();
161 public void dispose() {
162 if (display != null && !display.isDisposed()) {
163 display.removeFilter(SWT.FocusIn, focusListener);
166 focusListener = null;