/******************************************************************************* * Copyright (c) 2017 itemis AG and others. * * 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: * Matthias Wienand (itemis AG) - initial API and implementation * *******************************************************************************/ package org.eclipse.gef.mvc.fx.ui.actions; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.gef.mvc.fx.domain.IDomain; import org.eclipse.gef.mvc.fx.operations.ITransactionalOperation; import org.eclipse.gef.mvc.fx.viewer.IViewer; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IAction; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.swt.widgets.Event; import javafx.beans.property.ReadOnlyBooleanProperty; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; /** * The {@link AbstractViewerAction} provides an abstract implementation of * {@link IViewerAction}. It saves the {@link IViewer} for which the action is * {@link #init(IViewer) initialized}. Additionally, a mechanism * ({@link #createOperation(Event)}) is provided for creating an * {@link ITransactionalOperation} that is executed on the {@link IDomain} of * the {@link IViewer}. * * @author mwienand * */ public abstract class AbstractViewerAction extends Action implements IViewerAction { private IViewer viewer; private ChangeListener<Boolean> activationListener = new ChangeListener<Boolean>() { @Override public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) { if (newValue.booleanValue()) { register(); } else { unregister(); } } }; private ReadOnlyBooleanProperty viewerActiveProperty; // private ObjectProperty<IViewer> viewerProperty; // private BooleanProperty checked = new BooleanProperty(false); // private BooleanProperty enabled = new BooleanProperty(false); // @Override public BooleanProperty enabledProperty() { return enabled; } // @Override public BooleanProperty checkedProperty() { return checked; } /** * Creates a new {@link IViewerAction}. * * @param text * Text for the action. */ protected AbstractViewerAction(String text) { this(text, IAction.AS_PUSH_BUTTON, null); } /** * Constructs a new {@link AbstractViewerAction} with the given text and * style. Also sets the given {@link ImageDescriptor} for this action. * * @param text * Text for the action. * @param style * Style for the action, see {@link IAction} for details. * @param imageDescriptor * {@link ImageDescriptor} specifying the icon for the action. */ protected AbstractViewerAction(String text, int style, ImageDescriptor imageDescriptor) { super(text, style); setImageDescriptor(imageDescriptor); setEnabled(false); } /** * Returns an {@link ITransactionalOperation} that performs the desired * changes, or <code>null</code> if no changes should be performed. If * <code>null</code> is returned, then the "doit" flag of the initiating * {@link Event} is not altered. Otherwise, the "doit" flag is set to * <code>false</code> so that no further event processing is done by SWT. * * @param event * The initiating {@link Event}. * * @return An {@link ITransactionalOperation} that performs the desired * changes. */ protected abstract ITransactionalOperation createOperation(Event event); /** * Returns the {@link IViewer} for which this {@link IViewerAction} was * {@link #init(IViewer) initialized}. * * @return The {@link IViewer} for which this {@link IViewerAction} was * {@link #init(IViewer) initialized}. */ protected IViewer getViewer() { return viewer; } @Override public void init(IViewer viewer) { if (this.viewer == viewer) { // nothing changed return; } // unregister listeners and clean up for the old viewer if (this.viewer != null) { viewerActiveProperty.removeListener(activationListener); if (viewerActiveProperty.get()) { unregister(); } } // save new viewer this.viewer = viewer; // register listeners and prepare for the new viewer if (this.viewer != null) { viewerActiveProperty = this.viewer.activeProperty(); viewerActiveProperty.addListener(activationListener); if (viewerActiveProperty.get()) { register(); } } } /** * This method is called when this action obtains an {@link IViewer} which * is {@link IViewer#activeProperty() active} or when a previously obtained * viewer is activated. Per default, this method {@link #setEnabled(boolean) * enables} this action. */ protected void register() { setEnabled(true); } @Override public void run() { throw new UnsupportedOperationException( "Only runWithEvent(Event) supported."); } @Override public void runWithEvent(Event event) { if (!isEnabled()) { return; } ITransactionalOperation operation = createOperation(event); if (operation != null) { try { viewer.getDomain().execute(operation, new NullProgressMonitor()); } catch (ExecutionException e) { throw new RuntimeException(e); } // cancel further event processing if (event != null) { event.doit = false; } } } /** * This method is called when this action loses its {@link IViewer} or when * its {@link #getViewer() viewer} is deactivated. Per default, this method * {@link #setEnabled(boolean) disables} this action. */ protected void unregister() { setEnabled(false); } }