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;
}
}