blob: d7935f3a097e42e72e566301b62adcc35c8e2d70 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2017, 2019 Dortmund University of Applied Sciences and Arts and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Dortmund University of Applied Sciences and Arts - initial API and implementation
*******************************************************************************/
package org.eclipse.app4mc.multicore.execution.ui.widget.gantt;
import javafx.collections.FXCollections;
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import org.eclipse.app4mc.multicore.execution.ui.widget.gantt.elements.AbstractGanttViewElement;
import org.eclipse.app4mc.multicore.execution.ui.widget.gantt.elements.ProgressViewElement;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class FXGanttWidget extends XYChart<Number, String> implements IGantt {
private double blockPadding = 10;
private double blockHeight = 15;
private final boolean deugPrint = true;
private NumberAxis xAxi;
private CategoryAxis catAxi;
/** A series for every category. Just for easier access. */
private Map<String, XYChart.Series<Number, String>> series = new HashMap<>();
public FXGanttWidget(int vieport) {
this(new NumberAxis(), new CategoryAxis());
xAxi.setMinorTickCount(1);
xAxi.setTickUnit(1);
xAxi.setTickLabelFormatter(new IntegerStringConverter());
xAxi.setLabel("");
xAxi.setTickLabelFill(Color.CHOCOLATE);
xAxi.setAutoRanging(false);
xAxi.setLowerBound(0);
xAxi.setUpperBound(vieport);
catAxi.setAutoRanging(false);
getYAxis().setLabel("");
getYAxis().setTickLabelFill(Color.CHOCOLATE);
getYAxis().setTickLabelGap(5);
setLegendVisible(false);
prefHeightProperty().bind(minHeightProperty());
setupDragging();
setupScrolling();
if (deugPrint) {
System.out.println("FXGanttWidget Consturctur Start");
}
}
private FXGanttWidget(NumberAxis xAxis, CategoryAxis yAxis) {
super(xAxis, yAxis);
setData(FXCollections.<Series<Number, String>> observableArrayList());
this.xAxi = xAxis;
this.catAxi = yAxis;
}
private double deltX = 0;
private double xBefore = 0;
/**
* Setup moving the view port by dragging over the chart.
*/
private void setupDragging() {
setOnMouseDragged(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
if (xBefore == 0.0) {
xBefore = event.getX();
}
deltX += event.getX() - xBefore;
double pxPerUnit = getNumberAxis().getScale();
if (deltX >= pxPerUnit) {
moveViewPort(-1);
deltX = 0.0;
}
else if (deltX <= -pxPerUnit) {
moveViewPort(1);
deltX = 0.0;
}
xBefore = event.getX();
}
});
setOnMouseDragReleased(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
deltX = 0.0;
xBefore = 0.0;
}
});
}
/**
* Setup the scrolling capabilities: 1. Scroll the view port 2. Scroll +
* STRG: zoom the view port
*/
private void setupScrolling() {
// Tooltip t = new Tooltip("Navigation Hints\n 1. Scroll: Move Chart \n
// 2. Scroll + STRG: Zoom Chart");
// Tooltip.install(this, t);
setOnScroll(new EventHandler<ScrollEvent>() {
static final double moveSpeed = 0.1;
static final int zoomSpeed = 75;
@Override
public void handle(ScrollEvent event) {
if (event.isControlDown()) {
if (event.getDeltaY() < 0) {
zoomViewPort(zoomSpeed);
}
else {
zoomViewPort(-zoomSpeed);
}
}
else {
if (event.getDeltaY() < 0) {
// scrolling depends on zoom level
moveViewPort(-(int) (moveSpeed * getViewSize()));
// moveViewPort(-moveSpeed);
}
else {
moveViewPort((int) (moveSpeed * getViewSize()));
// moveViewPort(moveSpeed);
}
}
event.consume();
}
});
}
/**
* Add a new category to the horizontal x-axi.
*
* @param categorie
*/
public void addCategorie(String categorie) {
if (getMinHeight() == -1) {
// only invoked by adding first categorie
// standard height for x and y axis
setMinHeight(100);
}
double delta = getBlockHeight() + getBlockPadding() / 2.0;
setMinHeight(getMinHeight() + delta);
catAxi.getCategories().add(0, categorie);
Series<Number, String> s = new Series<>();
series.put(categorie, s); // only to get easier access
getData().add(s);
// getData().add(0, s);
// getData().add(getData().size(),s);
}
@Override
public void addEvent(String categorie, long start, AbstractGanttViewElement v) {
XYChart.Data<Number, String> d = new XYChart.Data<>(start, categorie, v);
series.get(categorie).getData().add(d);
}
public void moveViewPort(int move) {
double ub = xAxi.getUpperBound() + move;
double lb = xAxi.getLowerBound() + move;
if (lb >= 0) {
xAxi.setUpperBound(ub);
xAxi.setLowerBound(lb);
}
}
public void setViewPort(double lower, double upper) {
lower = lower < 0 ? 0 : lower;
if (upper > 0 && lower < upper) {
xAxi.setLowerBound(lower);
xAxi.setUpperBound(upper);
}
}
public void zoomViewPort(int zoom) {
double ub = xAxi.getUpperBound() + zoom;
double lb = xAxi.getLowerBound() - zoom;
setViewPort(lb, ub);
}
public double getViewSize() {
return xAxi.getUpperBound() - xAxi.getLowerBound();
}
@Override
protected void layoutPlotChildren() {
for (int seriesIndex = 0; seriesIndex < getData().size(); seriesIndex++) {
Series<Number, String> series = getData().get(seriesIndex);
Iterator<Data<Number, String>> it = getDisplayedDataIterator(series);
while (it.hasNext()) {
Data<Number, String> item = it.next();
double x = getXAxis().getDisplayPosition(item.getXValue());
double y = getYAxis().getDisplayPosition(item.getYValue());
if (Double.isNaN(x) || Double.isNaN(y)) {
continue;
}
Node node = item.getNode();
if (node != null) {
if (node instanceof AbstractGanttViewElement) {
AbstractGanttViewElement ev = (AbstractGanttViewElement) node;
y -= getBlockHeight() / 2.0;
ev.update(this, x, y);
}
}
}
}
}
@Override
protected void dataItemAdded(Series<Number, String> series, int itemIndex, Data<Number, String> item) {
if (deugPrint && (item.getExtraValue() instanceof ProgressViewElement)) {
// System.out.println("FXGanttWidget -> dataItemAdded
// "+item.getExtraValue() );
}
Node block = createNode(item);
getPlotChildren().add(block);
}
@Override
protected void dataItemRemoved(final Data<Number, String> item, final Series<Number, String> series) {
final Node block = item.getNode();
getPlotChildren().remove(block);
removeDataItemFromDisplay(series, item);
}
@Override
protected void dataItemChanged(Data<Number, String> item) {
}
@Override
protected void seriesAdded(Series<Number, String> series, int seriesIndex) {
for (int j = 0; j < series.getData().size(); j++) {
Data<Number, String> item = series.getData().get(j);
Node container = createNode(item);
getPlotChildren().add(container);
}
}
@Override
protected void seriesRemoved(final Series<Number, String> series) {
for (XYChart.Data<Number, String> d : series.getData()) {
final Node container = d.getNode();
getPlotChildren().remove(container);
}
removeSeriesFromDisplay(series);
}
private static Node createNode(final Data<Number, String> item) {
Node container = item.getNode();
if (container == null) {
if (item.getExtraValue() instanceof AbstractGanttViewElement) {
container = (AbstractGanttViewElement) item.getExtraValue();
}
else {
container = new StackPane();
}
item.setNode(container);
}
return container;
}
// @Override
// protected void updateAxisRange() {
// final Axis<Number> xa = getXAxis();
// final Axis<String> ya = getYAxis();
// List<Number> xData = null;
// List<String> yData = null;
// if (xa.isAutoRanging())
// xData = new ArrayList<Number>();
// if (ya.isAutoRanging())
// yData = new ArrayList<String>();
// if (xData != null || yData != null) {
// for (Series<Number, String> series : getData()) {
// for (Data<Number, String> data : series.getData()) {
// if (xData != null) {
// xData.add(data.getXValue());
// //if autoranging the last event is fully displayed
// xData.add(
// xa.toRealValue(xa.toNumericValue(data.getXValue()) +
// getLength(data.getExtraValue())));
// }
// if (yData != null) {
// yData.add(data.getYValue());
// }
// }
// }
// if (xData != null)
// xa.invalidateRange(xData);
// if (yData != null)
// ya.invalidateRange(yData);
// }
// }
/**
* Get the height of the gantt-blocks.
*
* @return Height of the gantt-blocks in pixel.
*/
public double getBlockHeight() {
return blockHeight;
}
/**
* Set the height of the Gantt-blocks.
*
* @param blockHeight
* Height of the Gantt-blocks in pixel.
*/
public void setBlockHeight(double blockHeight) {
this.blockHeight = blockHeight;
}
/**
* Get the padding between the Gantt-blocks.
*
* @return Distance in pixel.
*/
public double getBlockPadding() {
return blockPadding;
}
/**
* Set the min padding between the Gantt-blocks.
*
* @param blockPadding
* Distance in pixel.
*/
public void setBlockPadding(double blockPadding) {
this.blockPadding = blockPadding;
}
/**
* Get the x-number-axi.
*
* @return
*/
public NumberAxis getNumberAxis() {
return xAxi;
}
/**
* Get the y-category-axi
*
* @return
*/
public CategoryAxis getCatAxi() {
return catAxi;
}
}