package ru.khasang.cachoeira.view.mainwindow.diagram.ganttplan.relationlayer.relationline; import javafx.beans.binding.Bindings; import javafx.beans.binding.DoubleBinding; import javafx.beans.property.ObjectProperty; import javafx.beans.value.ChangeListener; import javafx.beans.value.WeakChangeListener; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.scene.Group; import javafx.scene.Node; import javafx.scene.paint.Color; import javafx.scene.shape.Line; import javafx.scene.shape.Polygon; import ru.khasang.cachoeira.model.ITask; import ru.khasang.cachoeira.model.TaskDependencyType; import ru.khasang.cachoeira.view.mainwindow.diagram.ganttplan.objectslayer.taskbar.TaskBar; public abstract class RelationLine extends Group { @SuppressWarnings("FieldCanBeLocal") private final double[] ARROW_SHAPE = {3, 0, -3, -3, -3, 3}; private final Color LINE_COLOR = Color.valueOf("03bdf4"); private final TaskBar parentTaskBar; private final TaskBar childTaskBar; private ObjectProperty<TaskDependencyType> dependenceType; private ITask parentTask; private ITask childTask; @SuppressWarnings("FieldCanBeLocal") private ChangeListener<TaskDependencyType> dependentTypeChangeListener; public RelationLine(TaskBar parentTaskBar, TaskBar childTaskBar, ObjectProperty<TaskDependencyType> dependenceType) { this.parentTaskBar = parentTaskBar; this.childTaskBar = childTaskBar; this.dependenceType = dependenceType; this.parentTask = parentTaskBar.getTask(); this.childTask = childTaskBar.getTask(); setListener(); if (dependenceType.getValue().equals(TaskDependencyType.FINISHSTART)) { this.getChildren().addAll(initFinishStartRelationLine(parentTaskBar, childTaskBar)); } } public void setListener() { dependentTypeChangeListener = (observable, oldValue, newValue) -> { this.getChildren().clear(); if (dependenceType.getValue().equals(TaskDependencyType.FINISHSTART)) { this.getChildren().addAll(initFinishStartRelationLine(parentTaskBar, childTaskBar)); } if (dependenceType.getValue().equals(TaskDependencyType.STARTFINISH)) { this.getChildren().addAll(iniStartFinishRelationLine(parentTaskBar, childTaskBar)); } if (dependenceType.getValue().equals(TaskDependencyType.FINISHFINISH)) { this.getChildren().addAll(initFinishFinishRelationLine(parentTaskBar, childTaskBar)); } if (dependenceType.getValue().equals(TaskDependencyType.STARTSTART)) { this.getChildren().addAll(initStartStartRelationLine(parentTaskBar, childTaskBar)); } }; dependenceType.addListener(new WeakChangeListener<>(dependentTypeChangeListener)); } private ObservableList<Node> initFinishStartRelationLine(TaskBar parentTaskBar, TaskBar childTaskBar) { DoubleBinding startXProperty = parentTaskBar.layoutXProperty().add(parentTaskBar.widthProperty()).add(12); DoubleBinding startYProperty = parentTaskBar.layoutYProperty().add(parentTaskBar.heightProperty().divide(2)); DoubleBinding endXProperty = childTaskBar.layoutXProperty().subtract(12); DoubleBinding endYProperty = childTaskBar.layoutYProperty().add(childTaskBar.heightProperty().divide(2)); BoundLine startLine = new BoundLine( startXProperty.subtract(12), startYProperty, startXProperty, startYProperty ); BoundLine line1 = new BoundLine( startXProperty, startYProperty, (DoubleBinding) Bindings .when(endXProperty.greaterThanOrEqualTo(startXProperty)) .then(endXProperty) .otherwise(startXProperty), startYProperty ); BoundLine line2 = new BoundLine( (DoubleBinding) Bindings .when(endXProperty.greaterThanOrEqualTo(startXProperty)) .then(endXProperty) .otherwise(startXProperty), startYProperty, (DoubleBinding) Bindings .when(endXProperty.greaterThanOrEqualTo(startXProperty)) .then(endXProperty) .otherwise(startXProperty), (DoubleBinding) Bindings .when(endYProperty.greaterThan(startYProperty)) .then(startYProperty.add(15.5)) .otherwise(startYProperty.subtract(15.5)) ); BoundLine line3 = new BoundLine( (DoubleBinding) Bindings .when(endXProperty.greaterThanOrEqualTo(startXProperty)) .then(endXProperty) .otherwise(startXProperty), (DoubleBinding) Bindings .when(endYProperty.greaterThan(startYProperty)) .then(startYProperty.add(15.5)) .otherwise(startYProperty.subtract(15.5)), endXProperty, (DoubleBinding) Bindings .when(endYProperty.greaterThan(startYProperty)) .then(startYProperty.add(15.5)) .otherwise(startYProperty.subtract(15.5)) ); BoundLine line4 = new BoundLine( endXProperty, (DoubleBinding) Bindings .when(endYProperty.greaterThan(startYProperty)) .then(startYProperty.add(15.5)) .otherwise(startYProperty.subtract(15.5)), endXProperty, endYProperty ); BoundLine endLine = new BoundLine( endXProperty, endYProperty, endXProperty.add(12), endYProperty ); Arrow arrow = new Arrow( endXProperty.add(12).subtract(2), endYProperty, ARROW_SHAPE ); ObservableList<Node> relationLine = FXCollections.observableArrayList(); relationLine.addAll(startLine, line1, line2, line3, line4, endLine, arrow); return relationLine; } private ObservableList<Node> initStartStartRelationLine(TaskBar parentTaskBar, TaskBar childTaskBar) { DoubleBinding startXProperty = parentTaskBar.layoutXProperty().subtract(12); DoubleBinding startYProperty = parentTaskBar.layoutYProperty().add(parentTaskBar.heightProperty().divide(2)); DoubleBinding endXProperty = childTaskBar.layoutXProperty().subtract(12); DoubleBinding endYProperty = childTaskBar.layoutYProperty().add(childTaskBar.heightProperty().divide(2)); BoundLine startLine = new BoundLine( startXProperty.add(12), startYProperty, startXProperty, startYProperty ); BoundLine line1 = new BoundLine( startXProperty, startYProperty, (DoubleBinding) Bindings .when(endXProperty.lessThanOrEqualTo(startXProperty)) .then(endXProperty) .otherwise(startXProperty), startYProperty ); BoundLine line2 = new BoundLine( (DoubleBinding) Bindings .when(endXProperty.lessThanOrEqualTo(startXProperty)) .then(endXProperty) .otherwise(startXProperty), startYProperty, (DoubleBinding) Bindings .when(endXProperty.lessThanOrEqualTo(startXProperty)) .then(endXProperty) .otherwise(startXProperty), endYProperty ); BoundLine line3 = new BoundLine( (DoubleBinding) Bindings .when(endXProperty.lessThanOrEqualTo(startXProperty)) .then(endXProperty) .otherwise(startXProperty), endYProperty, endXProperty, endYProperty ); BoundLine endLine = new BoundLine( endXProperty, endYProperty, endXProperty.add(12), endYProperty ); Arrow arrow = new Arrow( endXProperty.add(12).subtract(2), endYProperty, ARROW_SHAPE ); ObservableList<Node> relationLine = FXCollections.observableArrayList(); relationLine.addAll(startLine, line1, line2, line3, endLine, arrow); return relationLine; } private ObservableList<Node> initFinishFinishRelationLine(TaskBar parentTaskBar, TaskBar childTaskBar) { DoubleBinding startXProperty = parentTaskBar.layoutXProperty().add(parentTaskBar.widthProperty()).add(12); DoubleBinding startYProperty = parentTaskBar.layoutYProperty().add(parentTaskBar.heightProperty().divide(2)); DoubleBinding endXProperty = childTaskBar.layoutXProperty().add(childTaskBar.widthProperty()).add(12); DoubleBinding endYProperty = childTaskBar.layoutYProperty().add(childTaskBar.heightProperty().divide(2)); BoundLine startLine = new BoundLine( startXProperty.subtract(12), startYProperty, startXProperty, startYProperty ); BoundLine line1 = new BoundLine( startXProperty, startYProperty, (DoubleBinding) Bindings .when(endXProperty.greaterThanOrEqualTo(startXProperty)) .then(endXProperty) .otherwise(startXProperty), startYProperty ); BoundLine line2 = new BoundLine( (DoubleBinding) Bindings .when(endXProperty.greaterThanOrEqualTo(startXProperty)) .then(endXProperty) .otherwise(startXProperty), startYProperty, (DoubleBinding) Bindings .when(endXProperty.greaterThanOrEqualTo(startXProperty)) .then(endXProperty) .otherwise(startXProperty), endYProperty ); BoundLine line3 = new BoundLine( (DoubleBinding) Bindings .when(endXProperty.greaterThanOrEqualTo(startXProperty)) .then(endXProperty) .otherwise(startXProperty), endYProperty, endXProperty, endYProperty ); BoundLine endLine = new BoundLine( endXProperty, endYProperty, endXProperty.subtract(12), endYProperty ); Arrow arrow = new Arrow( endXProperty.subtract(12).add(2), endYProperty, ARROW_SHAPE ); arrow.setRotate(180); ObservableList<Node> relationLine = FXCollections.observableArrayList(); relationLine.addAll(startLine, line1, line2, line3, endLine, arrow); return relationLine; } private ObservableList<Node> iniStartFinishRelationLine(TaskBar parentTaskBar, TaskBar childTaskBar) { DoubleBinding startXProperty = parentTaskBar.layoutXProperty().subtract(12); DoubleBinding startYProperty = parentTaskBar.layoutYProperty().add(parentTaskBar.heightProperty().divide(2)); DoubleBinding endXProperty = childTaskBar.layoutXProperty().add(childTaskBar.widthProperty()).add(12); DoubleBinding endYProperty = childTaskBar.layoutYProperty().add(childTaskBar.heightProperty().divide(2)); BoundLine startLine = new BoundLine( startXProperty.add(12), startYProperty, startXProperty, startYProperty ); BoundLine line1 = new BoundLine( startXProperty, startYProperty, startXProperty, (DoubleBinding) Bindings .when(endYProperty.greaterThan(startYProperty)) .then(startYProperty.add(15.5)) .otherwise(startYProperty.subtract(15.5)) ); BoundLine line2 = new BoundLine( startXProperty, (DoubleBinding) Bindings .when(endYProperty.greaterThan(startYProperty)) .then(startYProperty.add(15.5)) .otherwise(startYProperty.subtract(15.5)), (DoubleBinding) Bindings .when(endXProperty.greaterThanOrEqualTo(startXProperty)) .then(endXProperty) .otherwise(startXProperty), (DoubleBinding) Bindings .when(endYProperty.greaterThan(startYProperty)) .then(startYProperty.add(15.5)) .otherwise(startYProperty.subtract(15.5)) ); BoundLine line3 = new BoundLine( (DoubleBinding) Bindings .when(endXProperty.greaterThanOrEqualTo(startXProperty)) .then(endXProperty) .otherwise(startXProperty), (DoubleBinding) Bindings .when(endYProperty.greaterThan(startYProperty)) .then(startYProperty.add(15.5)) .otherwise(startYProperty.subtract(15.5)), (DoubleBinding) Bindings .when(endXProperty.greaterThanOrEqualTo(startXProperty)) .then(endXProperty) .otherwise(startXProperty), endYProperty ); BoundLine line4 = new BoundLine( (DoubleBinding) Bindings .when(endXProperty.greaterThanOrEqualTo(startXProperty)) .then(endXProperty) .otherwise(startXProperty), endYProperty, endXProperty, endYProperty ); BoundLine endLine = new BoundLine( endXProperty, endYProperty, endXProperty.subtract(12), endYProperty ); Arrow arrow = new Arrow( endXProperty.subtract(12).add(2), endYProperty, ARROW_SHAPE ); arrow.setRotate(180); ObservableList<Node> relationLine = FXCollections.observableArrayList(); relationLine.addAll(startLine, line1, line2, line3, line4, endLine, arrow); return relationLine; } class BoundLine extends Line { BoundLine(DoubleBinding startX, DoubleBinding startY, DoubleBinding endX, DoubleBinding endY) { startXProperty().bind(startX); startYProperty().bind(startY); endXProperty().bind(endX); endYProperty().bind(endY); setStrokeWidth(1); setStroke(LINE_COLOR); // setMouseTransparent(true); } } class Arrow extends Polygon { Arrow(DoubleBinding x, DoubleBinding y, double... points) { super(points); setFill(LINE_COLOR); this.layoutXProperty().bind(x); this.layoutYProperty().bind(y); } } public ITask getParentTask() { return parentTask; } public ITask getChildTask() { return childTask; } }