use regions instead of drawing into canvas. thx to Dirk Lemmermann

This commit is contained in:
Andreas Billmann
2016-01-27 23:11:39 +01:00
parent c996ce660d
commit 4c9f468e08

View File

@@ -31,16 +31,10 @@ import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.ListChangeListener;
import javafx.collections.WeakListChangeListener;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.util.Duration;
import ninja.javafx.smartcsv.fx.table.model.CSVModel;
import ninja.javafx.smartcsv.validation.ValidationError;
import org.controlsfx.control.PopOver;
@@ -49,31 +43,30 @@ import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import static javafx.geometry.Pos.CENTER;
import static ninja.javafx.smartcsv.fx.util.I18nValidationUtil.getI18nValidatioMessage;
/**
* clickable side bar with error markers
*/
public class ErrorSideBar extends Pane {
public class ErrorSideBar extends Region {
private static final double WIDTH = 20.0;
private static final int BLOCKSIZE = 6;
private ListChangeListener<ValidationError> errorListListener = c -> requestLayout();
private ListChangeListener<ValidationError> errorListListener = c -> {setErrorMarker();};
private WeakListChangeListener<ValidationError> weakErrorListListener = new WeakListChangeListener<>(errorListListener);
private ObjectProperty<CSVModel> model = new SimpleObjectProperty<>();
private Canvas canvas = new Canvas();
private ObjectProperty<ValidationError> selectedValidationError = new SimpleObjectProperty<>();
private PopOver popOver = new PopOver();
private List<ValidationError> lastPopupErrors = null;
private ResourceBundle resourceBundle;
public ErrorSideBar(ResourceBundle resourceBundle) {
getChildren().add(canvas);
this.resourceBundle = resourceBundle;
setFixWidth();
configurePopOver();
addModelListener();
addMouseClickListener();
addOnMouseOverListenerForPopOver(resourceBundle);
popOver.setAutoHide(true);
popOver.setArrowLocation(PopOver.ArrowLocation.RIGHT_CENTER);
}
public void setModel(CSVModel model) {
@@ -100,120 +93,53 @@ public class ErrorSideBar extends Pane {
this.selectedValidationError.set(selectedValidationError);
}
private void addOnMouseOverListenerForPopOver(ResourceBundle resourceBundle) {
setOnMouseMoved(event -> showPopOver(event, resourceBundle));
setOnMouseEntered(event -> showPopOver(event, resourceBundle));
}
private void addMouseClickListener() {
setOnMouseClicked(event -> {
List<ValidationError> errors = findValidationErrors(event.getY());
if (!errors.isEmpty()) {
selectedValidationError.setValue(errors.get(0));
}
});
}
private void addModelListener() {
model.addListener((observable, oldValue, newValue) -> {
newValue.getValidationError().addListener(weakErrorListListener);
requestLayout();
setErrorMarker();
});
}
private void showPopOver(MouseEvent event, ResourceBundle resourceBundle) {
List<ValidationError> errors = findValidationErrors(event.getY());
if (!errors.isEmpty()) {
if (!areErrorsAlreadyInPopup(errors)) {
lastPopupErrors = errors;
popOver.setContentNode(popupContent(getI18nValidatioMessage(resourceBundle, errors)));
popOver.show(ErrorSideBar.this.getParent(), event.getScreenX() - WIDTH, event.getScreenY());
}
} else {
lastPopupErrors = null;
popOver.hide(Duration.millis(50));
}
}
private boolean areErrorsAlreadyInPopup(List<ValidationError> errors) {
return lastPopupErrors != null && lastPopupErrors.size() == errors.size() && lastPopupErrors.containsAll(errors);
}
private void configurePopOver() {
popOver.setArrowLocation(PopOver.ArrowLocation.RIGHT_CENTER);
}
private void setFixWidth() {
setMinWidth(WIDTH);
setPrefWidth(WIDTH);
setMaxWidth(WIDTH);
}
@Override
protected void layoutChildren() {
int top = (int) snappedTopInset();
int right = (int) snappedRightInset();
int bottom = (int) snappedBottomInset();
int left = (int) snappedLeftInset();
int w = (int) getWidth() - left - right;
int h = (int) getHeight() - top - bottom;
canvas.setLayoutX(left);
canvas.setLayoutY(top);
if (w != canvas.getWidth() || h != canvas.getHeight()) {
canvas.setWidth(w);
canvas.setHeight(h);
}
drawErrorMarker(w, h);
}
private List<ValidationError> findValidationErrors(double y) {
List<ValidationError> errors = new ArrayList<>();
private void setErrorMarker() {
List<Region> errorMarkerList = new ArrayList<>();
if (model.get() != null) {
List<ValidationError> errorList = model.get().getValidationError();
if (errorList != null && !errorList.isEmpty()) {
int rows = model.get().getRows().size();
double space = ((int)canvas.getHeight()) / rows;
double space = ((int)getHeight()) / rows;
for (ValidationError error : errorList) {
double blockStart = space * error.getLineNumber();
if (blockStart - 1 <= y && y <= blockStart + BLOCKSIZE + 1) {
errors.add(error);
errorMarkerList.add(generateErrorMarker(space, error));
}
}
}
}
return errors;
getChildren().setAll(errorMarkerList);
}
private void drawErrorMarker(int w, int h) {
GraphicsContext g = canvas.getGraphicsContext2D();
g.clearRect(0, 0, w, h);
g.setFill(Color.valueOf("#ff8888"));
if (model.get() != null) {
List<ValidationError> errorList = model.get().getValidationError();
if (errorList != null && !errorList.isEmpty()) {
int rows = model.get().getRows().size();
double space = h / rows;
for (ValidationError error : errorList) {
double blockStart = space * error.getLineNumber();
g.fillRect(0, blockStart, w, BLOCKSIZE - 2);
private Region generateErrorMarker(double space, ValidationError error) {
Region errorMarker = new Region();
errorMarker.setLayoutY(space * error.getLineNumber());
errorMarker.setPrefSize(WIDTH, 2);
errorMarker.setStyle("-fx-background-color: #ff8888");
errorMarker.setOnMouseClicked(event -> selectedValidationError.setValue(error));
errorMarker.setOnMouseEntered(event -> {
popOver.setContentNode(popupContent(getI18nValidatioMessage(resourceBundle, error)));
popOver.show(errorMarker, -16);
});
return errorMarker;
}
for (ValidationError error : errorList) {
double blockStart = space * error.getLineNumber();
g.clearRect(0, blockStart + BLOCKSIZE + 1, w, 1);
}
}
}
}
private Node popupContent(String text) {
VBox vBox = new VBox();
vBox.setPadding(new Insets(10,10,10,10));
vBox.getChildren().add(new Text(text));
vBox.setAlignment(Pos.CENTER);
vBox.setAlignment(CENTER);
return vBox;
}
}