/*******************************************************************************
* 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.models;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.gef.common.beans.property.ReadOnlyListWrapperEx;
import org.eclipse.gef.common.collections.CollectionUtils;
import org.eclipse.gef.mvc.fx.parts.IContentPart;
import javafx.beans.property.ReadOnlyListProperty;
import javafx.beans.property.ReadOnlyListWrapper;
import javafx.collections.ObservableList;
import javafx.geometry.Orientation;
import javafx.scene.Node;
/**
* The {@link SnappingModel} stores {@link SnappingLocation}s for which feedback
* is generated by the SnappingBehavior.
*/
public class SnappingModel {
/**
* A {@link SnappingLocation} combines an {@link IContentPart}, a position
* coordinate in the scene coordinate system, and an {@link Orientation}.
* The position coordinate is evaluated in dependence of the location's
* {@link Orientation}. For horizontal locations, the position coordinate is
* a y-coordinate. For vertical locations, the position coordinate is an
* x-coordinate.
*/
public static class SnappingLocation {
private IContentPart<? extends Node> part;
private Orientation orientation;
private double positionInScene;
/**
* Constructs a new {@link SnappingLocation}.
*
* @param part
* The {@link IContentPart} from which this location is
* derived.
* @param orientation
* The {@link Orientation} for this {@link SnappingLocation}.
* @param positionInScene
* The position coordinate for this {@link SnappingLocation}.
* The coordinate is either the x- or y-coordinate, depending
* on the {@link Orientation}. For horizontal locations, the
* y-coordinate needs to be specified. For vertical
* locations, the x-coordinate needs to be specified.
*/
public SnappingLocation(IContentPart<? extends Node> part,
Orientation orientation, double positionInScene) {
this.part = part;
this.orientation = orientation;
this.positionInScene = positionInScene;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
SnappingLocation other = (SnappingLocation) obj;
if (orientation != other.orientation) {
return false;
}
if (part == null) {
if (other.part != null) {
return false;
}
} else if (!part.equals(other.part)) {
return false;
}
if (Double.doubleToLongBits(positionInScene) != Double
.doubleToLongBits(other.positionInScene)) {
return false;
}
return true;
}
/**
* Returns a copy of this {@link SnappingLocation}.
*
* @return A copy of this {@link SnappingLocation}.
*/
public SnappingLocation getCopy() {
return new SnappingLocation(getPart(), getOrientation(),
getPositionInScene());
}
/**
* Returns the {@link Orientation} of this {@link SnappingLocation}.
*
* @return The {@link Orientation} of this {@link SnappingLocation}.
*/
public Orientation getOrientation() {
return orientation;
}
/**
* Returns the {@link IContentPart} from which this
* {@link SnappingLocation} was derived.
*
* @return The {@link IContentPart} from which this
* {@link SnappingLocation} was derived.
*/
public IContentPart<? extends Node> getPart() {
return part;
}
/**
* Returns the position coordinate of this {@link SnappingLocation}.
*
* @return The position coordinate of this {@link SnappingLocation}.
*/
public double getPositionInScene() {
return positionInScene;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((orientation == null) ? 0 : orientation.hashCode());
result = prime * result + ((part == null) ? 0 : part.hashCode());
long temp;
temp = Double.doubleToLongBits(positionInScene);
result = prime * result + (int) (temp ^ (temp >>> 32));
return result;
}
/**
* Sets the {@link Orientation} of this {@link SnappingLocation} to the
* given value.
*
* @param orientation
* The new {@link Orientation} for this
* {@link SnappingLocation}.
*/
public void setOrientation(Orientation orientation) {
this.orientation = orientation;
}
/**
* Sets the {@link IContentPart} of this {@link SnappingLocation} to the
* given value.
*
* @param part
* The new {@link IContentPart} for this
* {@link SnappingLocation}.
*/
public void setPart(IContentPart<? extends Node> part) {
this.part = part;
}
/**
* Sets the position coordinate of this {@link SnappingLocation} to the
* given value.
*
* @param positionInScene
* The new position coordinate for this
* {@link SnappingLocation}.
*/
public void setPositionInScene(double positionInScene) {
this.positionInScene = positionInScene;
}
@Override
public String toString() {
return "SnappingLocation[part="
+ getPart().getClass().getSimpleName() + "@"
+ System.identityHashCode(getPart()) + ", orientation="
+ getOrientation() + ", position=" + getPositionInScene()
+ "]";
}
}
/**
* Name of the {@link #snappingLocationsProperty()}.
*/
public static final String SNAPPING_LOCATIONS_PROPERTY = "snappingLocation";
private ObservableList<SnappingLocation> snappingLocations = CollectionUtils
.observableArrayList();
private ReadOnlyListWrapper<SnappingLocation> snappingLocationsProperty = new ReadOnlyListWrapperEx<>(
this, SNAPPING_LOCATIONS_PROPERTY, snappingLocations);
/**
* Returns a {@link List} containing the {@link SnappingLocation}s currently
* stored in this {@link SnappingModel}.
*
* @return A {@link List} containing the {@link SnappingLocation}s currently
* stored in this {@link SnappingModel}.
*/
public List<SnappingLocation> getSnappingLocations() {
return snappingLocationsProperty.get();
}
/**
* Returns a {@link List} containing the {@link SnappingLocation}s that were
* derived from the given {@link IContentPart}.
*
* @param part
* The {@link IContentPart} for which to return the derived
* {@link SnappingLocation}s.
* @return A {@link List} containing the {@link SnappingLocation}s that were
* derived from the given {@link IContentPart}.
*/
public List<SnappingLocation> getSnappingLocationsFor(
IContentPart<? extends Node> part) {
List<SnappingLocation> locations = new ArrayList<>();
for (SnappingLocation p : getSnappingLocations()) {
if (p.getPart() == part) {
locations.add(p);
}
}
return locations;
}
/**
* Replaces the {@link SnappingLocation}s that are stored in this
* {@link SnappingModel} by the given {@link List} of
* {@link SnappingLocation}s.
*
* @param snappingLocations
* A {@link List} containing the new {@link SnappingLocation}s to
* store in this {@link SnappingModel}.
*/
public void setSnappingLocations(
List<? extends SnappingLocation> snappingLocations) {
if (!snappingLocationsProperty.equals(snappingLocations)) {
snappingLocationsProperty.setAll(snappingLocations);
}
}
/**
* A read-only property containing the current {@link SnappingLocation}s.
*
* @return A read-only list property named
* {@link #SNAPPING_LOCATIONS_PROPERTY}.
*/
public ReadOnlyListProperty<SnappingLocation> snappingLocationsProperty() {
return snappingLocationsProperty.getReadOnlyProperty();
}
}