/******************************************************************************* * 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: * Matthias Wienand (itemis AG) - initial API and implementation * *******************************************************************************/ package org.eclipse.gef.mvc.fx.models; import java.beans.PropertyChangeEvent; import org.eclipse.gef.common.dispose.IDisposable; import org.eclipse.gef.mvc.fx.parts.IContentPart; import org.eclipse.gef.mvc.fx.parts.IVisualPart; import org.eclipse.gef.mvc.fx.viewer.IViewer; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.collections.MapChangeListener; import javafx.scene.Node; /** * The {@link FocusModel} stores the {@link IContentPart} which has keyboard * focus. Note that you are responsible for synchronizing keyboard focus with * the model. * * @author mwienand * @author anyssen * */ public class FocusModel extends org.eclipse.gef.common.adapt.IAdaptable.Bound.Impl<IViewer> implements IDisposable { /** * The {@link FocusModel} fires {@link PropertyChangeEvent}s when the * focused part changes. This is the name of the property that is delivered * with the event. * * @see #setFocus(IContentPart) */ final public static String FOCUS_PROPERTY = "focus"; private ObjectProperty<IContentPart<? extends Node>> focusedProperty = new SimpleObjectProperty<>( this, FOCUS_PROPERTY); private MapChangeListener<Node, IVisualPart<? extends Node>> visualPartMapListener = new MapChangeListener<Node, IVisualPart<? extends Node>>() { @Override public void onChanged( javafx.collections.MapChangeListener.Change<? extends Node, ? extends IVisualPart<? extends Node>> change) { // keep model in sync with part hierarchy if (change.wasRemoved()) { if (focusedProperty.get() == change.getValueRemoved()) { setFocus(null); } } } }; /** * Constructs a new {@link FocusModel}. The {@link #getFocus() focused} * {@link IContentPart} is set to <code>null</code>. */ public FocusModel() { } /** * @since 1.1 */ @Override public void dispose() { // setAdaptable() already clears focus } /** * Returns an object property providing the currently focused * {@link IContentPart}. * * @return An object property named {@link #FOCUS_PROPERTY}. */ public ObjectProperty<IContentPart<? extends Node>> focusProperty() { return focusedProperty; } /** * Returns the {@link IContentPart} which has keyboard focus, or * <code>null</code> if no {@link IContentPart} currently has keyboard * focus. * * @return the IContentPart which has keyboard focus, or <code>null</code> */ public IContentPart<? extends Node> getFocus() { return focusedProperty.get(); } @Override public void setAdaptable(IViewer adaptable) { if (getAdaptable() != null) { // unregister visual-part-map listener getAdaptable().visualPartMapProperty() .removeListener(visualPartMapListener); } super.setAdaptable(adaptable); if (adaptable != null) { // register for visual-part-map changes adaptable.visualPartMapProperty() .addListener(visualPartMapListener); } // start with a clean FocusModel setFocus(null); } /** * Selects the given IContentPart as the focus part. Note that setting the * focus part does not assign keyboard focus to the part. * * @param focusPart * The {@link IContentPart} which should become the new focus * part. */ public void setFocus(IContentPart<? extends Node> focusPart) { focusedProperty.set(focusPart); } }