/*******************************************************************************
* Copyright (c) 2015, 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:
* Alexander Nyßen (itemis AG) - initial API and implementation
* Matthias Wienand (itemis AG) - refactoring for Bugzilla #480959
*
*******************************************************************************/
package org.eclipse.gef.mvc.fx.ui.actions;
import java.util.ArrayList;
import org.eclipse.gef.fx.swt.canvas.FXCanvasEx;
import org.eclipse.gef.mvc.fx.domain.IDomain;
import org.eclipse.gef.mvc.fx.gestures.TypeGesture;
import org.eclipse.gef.mvc.fx.models.SelectionModel;
import org.eclipse.gef.mvc.fx.operations.ITransactionalOperation;
import org.eclipse.gef.mvc.fx.parts.IContentPart;
import org.eclipse.gef.mvc.fx.policies.DeletionPolicy;
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 org.eclipse.ui.actions.ActionFactory;
import javafx.application.Platform;
import javafx.collections.ListChangeListener;
import javafx.embed.swt.FXCanvas;
import javafx.scene.Node;
import javafx.scene.Scene;
/**
* An {@link Action} to handle deletion of selection elements in an
* {@link IViewer}
* <P>
* IMPORTANT: Usually, an action handler will only be executed in case the
* widget that currently has focus does not already consume the triggering key
* event. However, in case of an {@link FXCanvas} the triggering SWT key event
* is never consumed, because it is forwarded to the embedded JavaFX
* {@link Scene}, while a consumption of the mapping JavaFX event is not
* propagated back.
* <p>
* Additionally, the JavaFX event handler (i.e. the {@link TypeGesture}, in case it
* is registered at the {@link IDomain}), will be notified after the execution
* of the action handler, because {@link FXCanvasEx} wraps the event forwarding
* in a {@link Platform#runLater(Runnable)} call.
*
* @author anyssen
*
*/
public class DeleteAction extends AbstractViewerAction {
private ListChangeListener<IContentPart<? extends Node>> selectionListener = new ListChangeListener<IContentPart<? extends Node>>() {
@Override
public void onChanged(
ListChangeListener.Change<? extends IContentPart<? extends Node>> c) {
setEnabled(!c.getList().isEmpty());
}
};
/**
* Constructs a new {@link DeleteAction}.
*/
public DeleteAction() {
this("Delete", IAction.AS_PUSH_BUTTON, null);
setId(ActionFactory.DELETE.getId());
}
/**
* Constructs a new {@link DeleteAction} 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 DeleteAction(String text, int style,
ImageDescriptor imageDescriptor) {
super(text, style, imageDescriptor);
}
/**
* Computes an {@link ITransactionalOperation} that performs the desired
* changes, or <code>null</code> if no changes should be performed.
*
* @return An {@link ITransactionalOperation} that performs the desired
* changes.
*/
@Override
protected ITransactionalOperation createOperation(Event event) {
// delete selected parts
DeletionPolicy deletionPolicy = getViewer().getRootPart()
.getAdapter(DeletionPolicy.class);
if (deletionPolicy == null) {
throw new IllegalStateException(
"DeleteActionHandler requires a DeletionPolicy to be registered at the viewer's root part.");
}
deletionPolicy.init();
for (IContentPart<? extends Node> s : new ArrayList<>(
getSelectionModel().getSelectionUnmodifiable())) {
deletionPolicy.delete(s);
}
ITransactionalOperation deleteOperation = deletionPolicy.commit();
return deleteOperation;
}
/**
* Returns the {@link SelectionModel} for the currently bound
* {@link IViewer} or <code>null</code> if this action handler is either not
* bound or the viewer does not provide a {@link SelectionModel}.
*
* @return The {@link SelectionModel} or <code>null</code>.
*/
protected SelectionModel getSelectionModel() {
return getViewer() == null ? null
: getViewer().getAdapter(SelectionModel.class);
}
@Override
protected void register() {
SelectionModel newSelectionModel = getSelectionModel();
if (newSelectionModel != null) {
newSelectionModel.getSelectionUnmodifiable()
.addListener(selectionListener);
}
setEnabled(newSelectionModel != null
&& !newSelectionModel.getSelectionUnmodifiable().isEmpty());
}
@Override
protected void unregister() {
setEnabled(false);
SelectionModel oldSelectionModel = getSelectionModel();
if (oldSelectionModel != null) {
oldSelectionModel.getSelectionUnmodifiable()
.removeListener(selectionListener);
}
}
}