package de.eisfeldj.augendiagnosefx.fxelements; import de.eisfeldj.augendiagnosefx.controller.Controller; import de.eisfeldj.augendiagnosefx.controller.DisplayImageHolderController; import de.eisfeldj.augendiagnosefx.controller.DisplayImagePairController; import de.eisfeldj.augendiagnosefx.controller.DisplayPhotosController; import de.eisfeldj.augendiagnosefx.controller.MainController; import de.eisfeldj.augendiagnosefx.util.DialogUtil; import de.eisfeldj.augendiagnosefx.util.DialogUtil.ConfirmDialogListener; import de.eisfeldj.augendiagnosefx.util.FxmlConstants; import de.eisfeldj.augendiagnosefx.util.FxmlUtil; import de.eisfeldj.augendiagnosefx.util.PreferenceUtil; import de.eisfeldj.augendiagnosefx.util.ResourceConstants; import de.eisfeldj.augendiagnosefx.util.ResourceUtil; import de.eisfeldj.augendiagnosefx.util.imagefile.EyePhoto; import de.eisfeldj.augendiagnosefx.util.imagefile.EyePhotoPair; import de.eisfeldj.augendiagnosefx.util.imagefile.ImageUtil.Resolution; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import javafx.application.Platform; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.fxml.FXML; import javafx.scene.Parent; import javafx.scene.control.ContextMenu; import javafx.scene.control.Label; import javafx.scene.control.MenuItem; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.input.MouseButton; import javafx.scene.input.MouseEvent; import javafx.scene.layout.GridPane; /** * Special GridPane for displaying a pair of eye photos. */ public class EyePhotoPairNode extends GridPane implements Controller { /** * The parent controller. */ private DisplayPhotosController mParentController; /** * Height of the left image. */ private double mHeightLeft = 0; /** * Height of the right image. */ private double mHeightRight = 0; /** * The eye photo pair. */ private EyePhotoPair mPair; /** * The label for the date. */ @FXML private Label mLabelDate; /** * The image view of the right eye. */ @FXML private ImageViewPane mImageViewRight; /** * The image view of the left eye. */ @FXML private ImageViewPane mImageViewLeft; @Override public final Parent getRoot() { return this; } /** * A boolean property indicating if images are loaded. */ private BooleanProperty mImagesLoadedProperty = new SimpleBooleanProperty(false); public final BooleanProperty getImagesLoadedProperty() { return mImagesLoadedProperty; } /** * Constructor given a pair of eye photos. * * @param pair * The eye photo pair. * @param initialParentController * The parent controller. */ @SuppressFBWarnings(value = "UR_UNINIT_READ", justification = "Is initialized via fxml") public EyePhotoPairNode(final EyePhotoPair pair, final DisplayPhotosController initialParentController) { mParentController = initialParentController; mPair = pair; FxmlUtil.loadFromFxml(this, FxmlConstants.FXML_EYE_PHOTO_PAIR_NODE); mLabelDate.setText(pair.getDateDisplayString()); if (pair.getRightEye() != null) { mImageViewRight.setImageView(getImageView(pair.getRightEye())); } if (pair.getLeftEye() != null) { mImageViewLeft.setImageView(getImageView(pair.getLeftEye())); } mLabelDate.setOnMouseClicked(new EventHandler<MouseEvent>() { @Override public void handle(final MouseEvent event) { if (event.getButton() != MouseButton.PRIMARY) { return; } if (MainController.getInstance().isSplitPane()) { return; } if (pair.isComplete()) { DisplayImagePairController controller = (DisplayImagePairController) FxmlUtil.displaySubpage(FxmlConstants.FXML_DISPLAY_IMAGE_PAIR, -1, true); controller.setEyePhotos(pair); } } }); mLabelDate.setContextMenu(createDateContextMenu()); } /** * Create the context menu for the date. * * @return the context menu. */ private ContextMenu createDateContextMenu() { ContextMenu menu = new ContextMenu(); MenuItem menuItemRemove = new MenuItem(); menuItemRemove.setText(ResourceUtil.getString(ResourceConstants.MENU_DELETE_IMAGES)); menuItemRemove.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(final ActionEvent event) { DialogUtil.displayConfirmationMessage(new ConfirmDialogListener() { @Override public void onDialogPositiveClick() { mParentController.removeItem(EyePhotoPairNode.this); mPair.delete(); } @Override public void onDialogNegativeClick() { // do nothing } }, ResourceConstants.BUTTON_DELETE, ResourceConstants.MESSAGE_DIALOG_CONFIRM_DELETE_DATE, mPair.getPersonName(), mLabelDate.getText()); } }); menu.getItems().add(menuItemRemove); return menu; } /** * Get the image view for a thumbnail. * * @param eyePhoto * The eye photo to be displayed. * @return The image view. */ private ImageView getImageView(final EyePhoto eyePhoto) { Image image = eyePhoto.getImage(Resolution.THUMB); image.progressProperty().addListener(new ChangeListener<Number>() { @Override public void changed(final ObservableValue<? extends Number> observable, final Number oldValue, final Number newValue) { if (newValue.doubleValue() == 1) { checkIfImagesLoaded(); } } }); ImageView imageView = new ImageView(image); imageView.setPreserveRatio(true); imageView.setOnMouseClicked(new EventHandler<MouseEvent>() { @Override public void handle(final MouseEvent event) { if (PreferenceUtil.getPreferenceBoolean(PreferenceUtil.KEY_SHOW_SPLIT_WINDOW) && !MainController.getInstance().isSplitPane()) { MainController.getInstance().setSplitPane(FxmlConstants.FXML_DISPLAY_PHOTOS); } DisplayImageHolderController controller = (DisplayImageHolderController) FxmlUtil .displaySubpage(FxmlConstants.FXML_DISPLAY_IMAGE_HOLDER, mParentController.getPaneIndex(), true); controller.setEyePhoto(eyePhoto); } }); // Ensure that height is adapted to image width. imageView.fitHeightProperty().addListener(new ChangeListener<Number>() { @Override public void changed(final ObservableValue<? extends Number> observable, final Number oldValue, final Number newValue) { switch (eyePhoto.getRightLeft()) { case RIGHT: mHeightRight = newValue.doubleValue(); break; case LEFT: mHeightLeft = newValue.doubleValue(); break; default: } setPrefHeight(Math.max(mHeightLeft, mHeightRight)); Platform.runLater(new Runnable() { @Override public void run() { requestParentLayout(); } }); } }); return imageView; } /** * Check if the images are loaded. * * @return true if the images are loaded. */ private boolean checkIfImagesLoaded() { if (mImagesLoadedProperty.get()) { return true; } Image imageRight = mImageViewRight.getImageView().getImage(); Image imageLeft = mImageViewRight.getImageView().getImage(); boolean loaded = imageRight.getProgress() == 1 && imageLeft.getProgress() == 1; if (loaded) { mImagesLoadedProperty.set(true); } return loaded; } }