X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.views.text%2Fsrc%2Forg%2Fsimantics%2Fviews%2Ftext%2Finternal%2FTextViewerUndoHandler.java;fp=bundles%2Forg.simantics.views.text%2Fsrc%2Forg%2Fsimantics%2Fviews%2Ftext%2Finternal%2FTextViewerUndoHandler.java;h=f1c8adeabf1c20e9ba602725a012fcdd6137636e;hb=5b3a1f2d3bffe5a79e344b55087fb161541a4301;hp=0000000000000000000000000000000000000000;hpb=894991ee53490cb8e28dd48b0da686203411324a;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.views.text/src/org/simantics/views/text/internal/TextViewerUndoHandler.java b/bundles/org.simantics.views.text/src/org/simantics/views/text/internal/TextViewerUndoHandler.java new file mode 100644 index 000000000..f1c8adeab --- /dev/null +++ b/bundles/org.simantics.views.text/src/org/simantics/views/text/internal/TextViewerUndoHandler.java @@ -0,0 +1,169 @@ +/******************************************************************************* + * Copyright (c) 2017 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Semantum Oy - (#7066) initial API and implementation + *******************************************************************************/ +package org.simantics.views.text.internal; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.concurrent.Callable; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExecutableExtension; +import org.eclipse.jface.text.IUndoManager; +import org.eclipse.jface.text.TextViewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; + +/** + * Handles the undo/redo command for {@link TextViewer}s through + * {@link IUndoManager}. + * + *

+ * The implementation looks for an IUndoManager from the current focus control + * using the {@link TextViewerConstants#KEY_UNDO_MANAGER} data key. Its + * existence determines whether this handler {@link #isHandled()} returns + * true or false. + * + *

+ * The handler expects to receive a single string as an argument through the + * extension definitions ({@link IExecutableExtension}) that determines which + * method is invoked from IUndoManager (undo or redo). + * + *

+ * Implementation is partially copied from + * org.eclipse.ui.internal.handlers.WidgetMethodHandler. + * + * @since 1.28.0 + */ +public class TextViewerUndoHandler extends AbstractHandler implements IExecutableExtension { + + /** + * The parameters to pass to the method this handler invokes. This handler + * always passes no parameters. + */ + protected static final Class[] NO_PARAMETERS = new Class[0]; + + public TextViewerUndoHandler() { + display = Display.getCurrent(); + if (display != null) { + focusListener = new Listener() { + @Override + public void handleEvent(Event event) { + updateEnablement(); + } + }; + display.addFilter(SWT.FocusIn, focusListener); + } + } + + void updateEnablement() { + boolean rc = isHandled(); + if (rc != isEnabled()) { + setBaseEnabled(rc); + } + } + + /** + * The name of the method to be invoked by this handler. This value should + * never be null. + */ + protected String methodName; + private Listener focusListener; + private Display display; + + @Override + public Object execute(final ExecutionEvent event) throws ExecutionException { + Callable runnable = getMethodToExecute(); + if (runnable != null) { + try { + runnable.call(); + } catch (ExecutionException e) { + throw e; + } catch (Exception e) { + throw new ExecutionException("Unexpected failure executing method " + methodName + " through " + runnable); + } + } + return null; + } + + @Override + public final boolean isHandled() { + return getMethodToExecute() != null; + } + + /** + * Looks up the method on the focus control. + * + * @return The method on the focus control; null if none. + */ + protected Callable getMethodToExecute() { + Display display = Display.getCurrent(); + if (display == null) + return null; + + Control focusControl = display.getFocusControl(); + if (focusControl == null) + return null; + + IUndoManager undoManager = (IUndoManager) focusControl.getData(TextViewerConstants.KEY_UNDO_MANAGER); + if (undoManager == null) + return null; + + try { + Method method = undoManager.getClass().getMethod(methodName, NO_PARAMETERS); + if (method != null) + return runner(undoManager, method); + } catch (NoSuchMethodException e) { + // Fall through... + } + + return null; + } + + protected Callable runner(IUndoManager undoManager, Method method) { + return () -> { + try { + method.invoke(undoManager); + return true; + } catch (IllegalAccessException e) { + // The method is protected, so do nothing. + return false; + } catch (InvocationTargetException e) { + throw new ExecutionException( + "An exception occurred while executing " //$NON-NLS-1$ + + method.getName(), e + .getTargetException()); + + } + }; + } + + @Override + public void setInitializationData(IConfigurationElement config, String propertyName, Object data) { + methodName = data.toString(); + } + + @Override + public void dispose() { + if (display != null && !display.isDisposed()) { + display.removeFilter(SWT.FocusIn, focusListener); + } + display = null; + focusListener = null; + } + +} \ No newline at end of file