/*******************************************************************************
* Copyright (c) 2014, 2016 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) - multi selection handles in root part
*
*******************************************************************************/
package org.eclipse.gef.mvc.fx.behaviors;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.gef.common.collections.CollectionUtils;
import org.eclipse.gef.mvc.fx.models.SelectionModel;
import org.eclipse.gef.mvc.fx.parts.IContentPart;
import org.eclipse.gef.mvc.fx.parts.IFeedbackPartFactory;
import org.eclipse.gef.mvc.fx.parts.IHandlePartFactory;
import org.eclipse.gef.mvc.fx.viewer.IViewer;
import javafx.collections.ListChangeListener;
import javafx.scene.Node;
/**
* The default selection behavior is responsible for creating and removing
* selection feedback and handles.
*
* @author anyssen
* @author mwienand
*
*/
public class SelectionBehavior extends AbstractBehavior {
/**
* The adapter role for the {@link IFeedbackPartFactory} that is used to
* generate hover feedback parts.
*/
public static final String SELECTION_FEEDBACK_PART_FACTORY = "SELECTION_FEEDBACK_PART_FACTORY";
/**
* The adapter role for the {@link IHandlePartFactory} that is used to
* generate hover handle parts.
*/
public static final String SELECTION_HANDLE_PART_FACTORY = "SELECTION_HANDLE_PART_FACTORY";
private ListChangeListener<IContentPart<? extends Node>> selectionObserver = new ListChangeListener<IContentPart<? extends Node>>() {
@Override
public void onChanged(
ListChangeListener.Change<? extends IContentPart<? extends Node>> c) {
// order of selection should not be relevant for feedback and
// handles, as such we ignore permutations
List<IContentPart<? extends Node>> newSelection = new ArrayList<>(
c.getList());
List<? extends IContentPart<? extends Node>> oldSelection = CollectionUtils
.getPreviousContents(c);
removeFeedbackAndHandles(oldSelection);
addFeedbackAndHandles(newSelection);
}
};
/**
* @param selected
* List of {@link IContentPart}s for which to add feedback and
* handles.
*/
protected void addFeedbackAndHandles(
List<? extends IContentPart<? extends Node>> selected) {
if (!selected.isEmpty()) {
// add feedback individually for the selected parts
for (IContentPart<? extends Node> sel : selected) {
addFeedback(sel);
}
// XXX: For a multi selection, handles are generated for the whole
// selection and not for each part individually. For a single
// selection, handles are generated for the only selected part.
if (selected.size() == 1) {
// add handles for the single selection
addHandles(selected.get(0));
} else {
// add handles for the whole multi selection
addHandles(selected);
}
}
}
@Override
protected void doActivate() {
// register
final SelectionModel selectionModel = getSelectionModel();
selectionModel.getSelectionUnmodifiable()
.addListener(selectionObserver);
// create feedback and handles if we are already selected
addFeedbackAndHandles(selectionModel.getSelectionUnmodifiable());
}
@Override
protected void doDeactivate() {
final SelectionModel selectionModel = getSelectionModel();
// remove any pending feedback
removeFeedbackAndHandles(selectionModel.getSelectionUnmodifiable());
// unregister
selectionModel.getSelectionUnmodifiable()
.removeListener(selectionObserver);
}
@Override
protected IFeedbackPartFactory getFeedbackPartFactory(IViewer viewer) {
return getFeedbackPartFactory(viewer, SELECTION_FEEDBACK_PART_FACTORY);
}
@Override
protected IHandlePartFactory getHandlePartFactory(IViewer viewer) {
return getHandlePartFactory(viewer, SELECTION_HANDLE_PART_FACTORY);
}
/**
* Returns the {@link SelectionModel} in the context of the
* {@link #getHost() host}.
*
* @return The {@link SelectionModel} in the context of the
* {@link #getHost() host}.
*/
protected SelectionModel getSelectionModel() {
IViewer viewer = getHost().getRoot().getViewer();
SelectionModel selectionModel = viewer.getAdapter(SelectionModel.class);
return selectionModel;
}
/**
* @param selected
* List of {@link IContentPart}s for which to remove feedback and
* handles.
*/
protected void removeFeedbackAndHandles(
List<? extends IContentPart<? extends Node>> selected) {
if (!selected.isEmpty()) {
// remove feedback individually for all parts
for (IContentPart<? extends Node> sel : selected) {
removeFeedback(sel);
}
// XXX: For a multi selection, handles are generated for the whole
// selection and not for each part individually. For a single
// selection, handles are generated for the only selected part.
if (selected.size() == 1) {
// remove handles for the single selection
removeHandles(selected.get(0));
} else {
// remove handles for the multi selection
removeHandles(selected);
}
}
}
}