package de.eisfeldj.augendiagnosefx.controller; import java.net.URL; import java.util.ResourceBundle; import de.eisfeldj.augendiagnosefx.fxelements.OverlayImageView; import de.eisfeldj.augendiagnosefx.fxelements.SizableImageView.MetadataPosition; import de.eisfeldj.augendiagnosefx.util.DateUtil; 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.ImageUtil.Resolution; import de.eisfeldj.augendiagnosefx.util.imagefile.JpegMetadata; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.Parent; import javafx.scene.control.Button; import javafx.scene.control.ColorPicker; import javafx.scene.control.ContextMenu; import javafx.scene.control.Label; import javafx.scene.control.MenuItem; import javafx.scene.control.SeparatorMenuItem; import javafx.scene.control.Slider; import javafx.scene.control.TextArea; import javafx.scene.control.ToggleButton; import javafx.scene.input.MouseEvent; import javafx.scene.layout.ColumnConstraints; import javafx.scene.layout.ConstraintsBase; import javafx.scene.layout.GridPane; import javafx.scene.layout.Pane; import javafx.scene.layout.RowConstraints; import static de.eisfeldj.augendiagnosefx.util.PreferenceUtil.KEY_INDEXED_OVERLAY_TYPE; import static de.eisfeldj.augendiagnosefx.util.PreferenceUtil.KEY_OVERLAY_COLOR; import static de.eisfeldj.augendiagnosefx.util.PreferenceUtil.KEY_SHOW_COMMENT_PANE; import static de.eisfeldj.augendiagnosefx.util.PreferenceUtil.KEY_SHOW_OVERLAY_PANE; import static de.eisfeldj.augendiagnosefx.util.ResourceConstants.BUTTON_EDIT_COMMENT; import static de.eisfeldj.augendiagnosefx.util.ResourceConstants.BUTTON_SAVE_COMMENT; import static de.eisfeldj.augendiagnosefx.util.imagefile.ImageUtil.Resolution.FULL; import static de.eisfeldj.augendiagnosefx.util.imagefile.ImageUtil.Resolution.NORMAL; import static de.eisfeldj.augendiagnosefx.util.imagefile.ImageUtil.Resolution.THUMB; /** * BaseController for the "Display Image" page. */ public class DisplayImageController extends BaseController implements Initializable { /** * The number of available overlay buttons (excluding circle). Must be at most OVERLAY_COUNT. */ public static final int OVERLAY_BUTTON_COUNT = 8; /** * The number of available overlays (excluding circle). */ public static final int OVERLAY_COUNT = 8; /** * The names of the overlays. */ private static final String[] OVERLAY_NAMES = new String[OVERLAY_COUNT]; /** * The button texts of the overlays. */ private static final String[] OVERLAY_BUTTON_STRINGS = new String[OVERLAY_BUTTON_COUNT]; /** * The main pane holding the image. */ @FXML private GridPane mDisplayImage; /** * The scroll pane holding the image. */ @FXML private OverlayImageView mDisplayImageView; /** * The pane used for displaying and editing the comment. */ @FXML private Pane mCommentPane; /** * The constraints of the comment pane. */ @FXML private ConstraintsBase mCommentConstraints; /** * The pane used for toggling the overlay. */ @FXML private Pane mOverlayPane; /** * The constraints of the overlay pane. */ @FXML private ConstraintsBase mOverlayConstraints; /** * The label showing the image name. */ @FXML private Label mNameLabel; /** * The text field for the image comment. */ @FXML private TextArea mTxtImageComment; /** * The Button for editing/saving the image comment. */ @FXML private ToggleButton mBtnEditComment; /** * The Button for adding the circle overlay. */ @FXML private ToggleButton mBtnOverlayCircle; /** * The button for displaying the view in full resolution. * * <p>This is a ToggleButton, as it is incompatible with overlays. */ @FXML private ToggleButton mClarityButton; /** * The button for displaying the image on full screen. */ @FXML private Button mFullScreenButton; /** * The slider for brightness. */ @FXML private Slider mSliderBrightness; /** * The slider for contrast. */ @FXML private Slider mSliderContrast; /** * The slider for saturation. */ @FXML private Slider mSliderSaturation; /** * The slider for color temperature. */ @FXML private Slider mSliderColorTemperature; /** * The Buttons for overlays. */ // JAVADOC:OFF @FXML private ToggleButton mBtnOverlay1; @FXML private ToggleButton mBtnOverlay2; @FXML private ToggleButton mBtnOverlay3; @FXML private ToggleButton mBtnOverlay4; @FXML private ToggleButton mBtnOverlay5; @FXML private ToggleButton mBtnOverlay6; @FXML private ToggleButton mBtnOverlay7; @FXML private ToggleButton mBtnOverlay8; private ToggleButton[] mOverlayButtons; // JAVADOC:ON /** * The Button for selecting the overlay color. */ @FXML private ColorPicker mColorPicker; /** * The displayed eye photo. */ private EyePhoto mEyePhoto; /** * Flag storing if the view is already initialized. (However, the image may be loaded later asynchronously.) */ private boolean mIsInitialized = false; /** * Temporary storage for the comment while editing. */ private String mOldComment; /** * Slider indicating if the current state displays only a thumbnail. */ private Resolution mCurrentResolution = NORMAL; /** * Storage for the current overlay type. */ private Integer mCurrentOverlayType = null; static { for (int i = 0; i < OVERLAY_COUNT; i++) { OVERLAY_NAMES[i] = ResourceUtil.getString("overlay_" + (i + 1) + "_name"); } for (int i = 0; i < OVERLAY_BUTTON_COUNT; i++) { OVERLAY_BUTTON_STRINGS[i] = ResourceUtil.getString("button_overlay_" + (i + 1)); } } /** * Update the stored current resolution, redisplay if the resolution changed, and update the clarityButton if * appicable. * * @param newResolution * The current resolution. */ private void updateResolution(final Resolution newResolution) { if (newResolution != mCurrentResolution) { mCurrentResolution = newResolution; if (newResolution != FULL) { mClarityButton.setSelected(false); } mDisplayImageView.redisplay(newResolution); } } @Override public final void initialize(final URL location, final ResourceBundle resources) { try { MenuController.getInstance().setCommentPaneMenuEnablement(true); MenuController.getInstance().getMenuOverlayPane().setDisable(false); } catch (RuntimeException e) { // Catching exception so that JavaFX preview works. } showCommentPane(PreferenceUtil.getPreferenceBoolean(KEY_SHOW_COMMENT_PANE)); showOverlayPane(PreferenceUtil.getPreferenceBoolean(KEY_SHOW_OVERLAY_PANE)); mColorPicker.setValue(PreferenceUtil.getPreferenceColor(KEY_OVERLAY_COLOR)); mColorPicker.getStyleClass().add("button"); mSliderBrightness.setMin(-1); mSliderBrightness.setValue(0); mSliderBrightness.setMax(1); mSliderContrast.setMin(-1); mSliderContrast.setValue(0); mSliderContrast.setMax(1); mSliderSaturation.setMin(-1); mSliderSaturation.setValue(0); mSliderSaturation.setMax(1); mSliderColorTemperature.setMin(-1); mSliderColorTemperature.setValue(0); mSliderColorTemperature.setMax(1); mOverlayButtons = new ToggleButton[] {mBtnOverlayCircle, mBtnOverlay1, mBtnOverlay2, mBtnOverlay3, mBtnOverlay4, mBtnOverlay5, mBtnOverlay6, mBtnOverlay7, mBtnOverlay8}; createOverlayButtonContextMenus(); mIsInitialized = true; } /** * Create the context menus of the overlay buttons. */ private void createOverlayButtonContextMenus() { for (int i = 1; i < mOverlayButtons.length; i++) { mOverlayButtons[i].setContextMenu(createOverlayButtonContextMenu(i, false)); } } /** * Create the context menu of an overlay button. * * @param position * The position of the button. * @param forNewButton * Flag indicating the popup is displayed for a new button. Then it is enforced to select a new overlay. * @return the context menu. */ private ContextMenu createOverlayButtonContextMenu(final int position, final boolean forNewButton) { ToggleButton button = mOverlayButtons[position]; ContextMenu menu = new ContextMenu(); if (position == getHighestOverlayButtonIndex()) { if (position > 1) { MenuItem menuItemRemove = new MenuItem(); menuItemRemove.setText(ResourceUtil.getString(ResourceConstants.MENU_REMOVE_OVERLAY_BUTTON)); menuItemRemove.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(final ActionEvent event) { mOverlayButtons[position].setSelected(false); handleBtnOverlayPressed(mOverlayButtons[position]); PreferenceUtil.setIndexedPreference(KEY_INDEXED_OVERLAY_TYPE, position, -1); mOverlayButtons[position].setVisible(false); mOverlayButtons[position].setManaged(false); createOverlayButtonContextMenus(); } }); menu.getItems().add(menuItemRemove); } if (position < OVERLAY_BUTTON_COUNT) { MenuItem menuItemAdd = new MenuItem(); menuItemAdd.setText(ResourceUtil.getString(ResourceConstants.MENU_ADD_OVERLAY_BUTTON)); menuItemAdd.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(final ActionEvent event) { ContextMenu contextMenu = createOverlayButtonContextMenu(position + 1, true); contextMenu.show(button, menu.getAnchorX(), menu.getAnchorY()); } }); menu.getItems().add(menuItemAdd); } menu.getItems().add(new SeparatorMenuItem()); } MenuItem[] secondaryMenuItems = new MenuItem[OVERLAY_BUTTON_COUNT]; for (int i = 1; i <= OVERLAY_COUNT; i++) { final int index = i; final Integer oldButtonPosition = getButtonForOverlayWithIndex(i); MenuItem menuItem = null; if (oldButtonPosition == null) { menuItem = new MenuItem(); menuItem.setText(OVERLAY_NAMES[i - 1]); menu.getItems().add(menuItem); } else { if (!forNewButton) { menuItem = new MenuItem(); menuItem.setText(OVERLAY_BUTTON_STRINGS[oldButtonPosition - 1] + " " + OVERLAY_NAMES[i - 1]); if (oldButtonPosition == position) { menuItem.getStyleClass().add("bold"); } secondaryMenuItems[oldButtonPosition - 1] = menuItem; } } if (menuItem != null) { menuItem.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(final ActionEvent event) { if (oldButtonPosition != null && oldButtonPosition != position) { // If the same overlay is already used, switch overlays int currentOverlay = PreferenceUtil.getIndexedPreferenceInt(KEY_INDEXED_OVERLAY_TYPE, position, -1); PreferenceUtil.setIndexedPreference(KEY_INDEXED_OVERLAY_TYPE, oldButtonPosition, currentOverlay); } PreferenceUtil.setIndexedPreference(KEY_INDEXED_OVERLAY_TYPE, position, index); mOverlayButtons[position].setSelected(true); mOverlayButtons[position].setVisible(true); mOverlayButtons[position].setManaged(true); handleBtnOverlayPressed(mOverlayButtons[position]); createOverlayButtonContextMenus(); } }); } } for (MenuItem menuItem : secondaryMenuItems) { if (menuItem != null) { menu.getItems().add(menuItem); } } return menu; } /** * Get the index of the highest active overlay button. * * @return The index of the highest active overlay button. */ public static int getHighestOverlayButtonIndex() { int maxIndex = -1; for (int i = 0; i <= OVERLAY_BUTTON_COUNT; i++) { if (PreferenceUtil.getIndexedPreferenceInt(KEY_INDEXED_OVERLAY_TYPE, i, -1) >= 0) { maxIndex = i; } } return maxIndex; } /** * Check if there is already a button configured for a certain overlay type. * * @param index * The index of the overlay type. * @return The button index configured for this overlay type. */ private static Integer getButtonForOverlayWithIndex(final int index) { if (index < 0) { return null; } for (int i = 0; i <= OVERLAY_BUTTON_COUNT; i++) { if (PreferenceUtil.getIndexedPreferenceInt(KEY_INDEXED_OVERLAY_TYPE, i, -1) == index) { return i; } } return null; } /** * Initialize the sliders for contrast, brightness, saturation and color temperature. */ private void initializeSliders() { // Initialize slider for brightness. mSliderBrightness.valueProperty().addListener(new ChangeListener<Number>() { @Override public void changed(final ObservableValue<? extends Number> observable, final Number oldValue, final Number newValue) { mDisplayImageView.setColorSettings(newValue.floatValue(), null, null, null, mCurrentResolution); } }); mSliderBrightness.setOnMousePressed(new EventHandler<MouseEvent>() { @Override public void handle(final MouseEvent event) { updateResolution(THUMB); } }); mSliderBrightness.setOnMouseReleased(new EventHandler<MouseEvent>() { @Override public void handle(final MouseEvent event) { updateResolution(NORMAL); } }); // Inititalize slider for contrast. mSliderContrast.valueProperty().addListener(new ChangeListener<Number>() { @Override public void changed(final ObservableValue<? extends Number> observable, final Number oldValue, final Number newValue) { mDisplayImageView.setColorSettings(null, newValue.floatValue(), null, null, mCurrentResolution); } }); mSliderContrast.setOnMousePressed(new EventHandler<MouseEvent>() { @Override public void handle(final MouseEvent event) { updateResolution(THUMB); } }); mSliderContrast.setOnMouseReleased(new EventHandler<MouseEvent>() { @Override public void handle(final MouseEvent event) { updateResolution(NORMAL); } }); // Initialize slider for saturation. mSliderSaturation.valueProperty().addListener(new ChangeListener<Number>() { @Override public void changed(final ObservableValue<? extends Number> observable, final Number oldValue, final Number newValue) { mDisplayImageView.setColorSettings(null, null, newValue.floatValue(), null, mCurrentResolution); } }); mSliderSaturation.setOnMousePressed(new EventHandler<MouseEvent>() { @Override public void handle(final MouseEvent event) { updateResolution(THUMB); } }); mSliderSaturation.setOnMouseReleased(new EventHandler<MouseEvent>() { @Override public void handle(final MouseEvent event) { updateResolution(NORMAL); } }); // Inititalize slider for color temperature. mSliderColorTemperature.valueProperty().addListener(new ChangeListener<Number>() { @Override public void changed(final ObservableValue<? extends Number> observable, final Number oldValue, final Number newValue) { mDisplayImageView.setColorSettings(null, null, null, newValue.floatValue(), mCurrentResolution); } }); mSliderColorTemperature.setOnMousePressed(new EventHandler<MouseEvent>() { @Override public void handle(final MouseEvent event) { updateResolution(THUMB); } }); mSliderColorTemperature.setOnMouseReleased(new EventHandler<MouseEvent>() { @Override public void handle(final MouseEvent event) { updateResolution(NORMAL); } }); } @Override public final Parent getRoot() { return mDisplayImage; } /** * Action method for button "Edit Comment". * * @param event * The action event. */ @FXML public final void btnEditCommentPressed(final ActionEvent event) { if (mBtnEditComment.isSelected()) { // make comment editable mOldComment = mTxtImageComment.getText(); mTxtImageComment.setEditable(true); mTxtImageComment.requestFocus(); mBtnEditComment.setText(ResourceUtil.getString(BUTTON_SAVE_COMMENT)); setDirty(true); } else { mTxtImageComment.setEditable(false); String newComment = mTxtImageComment.getText(); // Save only if comment changed. if (!(newComment == null && mOldComment == null) && !(newComment != null && newComment.equals(mOldComment))) { JpegMetadata metadata = mEyePhoto.getImageMetadata(); metadata.setComment(newComment); mEyePhoto.storeImageMetadata(metadata); } mBtnEditComment.setText(ResourceUtil.getString(BUTTON_EDIT_COMMENT)); setDirty(false); } } /** * Action method for button "Overlay x". * * @param event * The action event. */ @FXML public final void btnOverlayPressed(final ActionEvent event) { handleBtnOverlayPressed((ToggleButton) event.getSource()); } /** * Perform the display of overlay after toggleButton is pressed. * * @param button * The button. */ private void handleBtnOverlayPressed(final ToggleButton button) { if (button.isSelected()) { String btnId = button.getId(); int buttonPosition; switch (btnId) { case "mBtnOverlayCircle": buttonPosition = 0; break; default: String indexStr = btnId.substring("mBtnOverlay".length()); buttonPosition = Integer.parseInt(indexStr); } int overlayType = PreferenceUtil.getIndexedPreferenceInt(KEY_INDEXED_OVERLAY_TYPE, buttonPosition, -1); updateResolution(NORMAL); showOverlay(overlayType); } else { showOverlay(null); } } /** * Action method for clarity button. * * @param event * The action event. */ @FXML public final void btnClarityPressed(final ActionEvent event) { if (mClarityButton.isSelected()) { showOverlay(null); updateResolution(FULL); } else { updateResolution(NORMAL); } } /** * Action method for color picker. * * @param event * The action event. */ @FXML public final void onColorChanged(final ActionEvent event) { showOverlay(mCurrentOverlayType); } /** * Action method for storing brightness and contrast. * * @param event * The action event. */ @FXML public final void storeColorSettings(final ActionEvent event) { if (isInitialized()) { JpegMetadata metadata = mEyePhoto.getImageMetadata(); if (metadata != null) { metadata.setBrightness((float) mSliderBrightness.getValue()); metadata.setContrast(OverlayImageView.seekbarContrastToStoredContrast((float) mSliderContrast.getValue())); metadata.setSaturation(OverlayImageView.seekbarSaturationToStoredSaturation((float) mSliderSaturation.getValue())); metadata.setColorTemperature((float) mSliderColorTemperature.getValue()); mEyePhoto.storeImageMetadata(metadata); } } } /** * Action method for resetting brightness and contrast. * * @param event * The action event. */ @FXML public final void resetColorSettings(final ActionEvent event) { mSliderBrightness.setValue(0); mSliderContrast.setValue(0); mSliderSaturation.setValue(0); mSliderColorTemperature.setValue(0); storeColorSettings(event); } /** * Action method for storing the view position. * * @param event * The action event. */ @FXML public final void storeViewPosition(final ActionEvent event) { if (isInitialized()) { JpegMetadata metadata = mEyePhoto.getImageMetadata(); if (metadata != null) { MetadataPosition position = mDisplayImageView.getPosition(); metadata.setXPosition(position.mXCenter); metadata.setYPosition(position.mYCenter); metadata.setZoomFactor(position.mZoom); mEyePhoto.storeImageMetadata(metadata); } } } /** * Action method for resetting the view position. * * @param event * The action event. */ @FXML public final void resetViewPosition(final ActionEvent event) { if (isInitialized()) { JpegMetadata metadata = mEyePhoto.getImageMetadata(); if (metadata != null) { metadata.setXPosition((Float) null); metadata.setYPosition((Float) null); metadata.setZoomFactor((Float) null); mEyePhoto.storeImageMetadata(metadata); // re-set eyePhoto in order to do initial scaling again. mDisplayImageView.setEyePhoto(mEyePhoto); } } } /** * Action method for displaying the image on the full window. * * @param event * The action event. */ @FXML public final void displayInFullWindow(final ActionEvent event) { DisplayImageFullController controller = (DisplayImageFullController) FxmlUtil.displaySubpage(FxmlConstants.FXML_DISPLAY_IMAGE_FULL, -1, true); if (isInitialized()) { JpegMetadata metadata = mEyePhoto.getImageMetadata(); if (metadata != null) { MetadataPosition position = mDisplayImageView.getPosition(); metadata.setXPosition(position.mXCenter); metadata.setYPosition(position.mYCenter); metadata.setZoomFactor(position.mZoom); controller.setImage(metadata, mDisplayImageView.getImageView().getImage()); } } } /** * Action method for displaying the original saturation and color temperature of the image. * * @param event * The action event. */ @FXML public final void showOriginalSaturation(final MouseEvent event) { mDisplayImageView.setColorSettings(null, null, 0f, 0f, mCurrentResolution); } /** * Action method for displaying the original colors of the image, disabling the slidebar values. * * @param event * The action event. */ @FXML public final void showOriginalColors(final MouseEvent event) { mDisplayImageView.setColorSettings(0f, 0f, 0f, 0f, mCurrentResolution); } /** * Action method for re-applying the slidebar settings of the image. * * @param event * The action event. */ @FXML public final void showSlidebarColors(final MouseEvent event) { mDisplayImageView.setColorSettings((float) mSliderBrightness.getValue(), (float) mSliderContrast.getValue(), (float) mSliderSaturation.getValue(), (float) mSliderColorTemperature.getValue(), mCurrentResolution); } /** * Setter for the eye photo. Initializes the view. * * @param eyePhoto * The eye photo. */ public final void setEyePhoto(final EyePhoto eyePhoto) { this.mEyePhoto = eyePhoto; JpegMetadata metadata = eyePhoto.getImageMetadata(); if (metadata.hasBrightnessContrast()) { mSliderBrightness.setValue(metadata.getBrightness()); mSliderContrast.setValue(OverlayImageView.storedContrastToSeekbarContrast(metadata.getContrast())); mSliderSaturation.setValue(OverlayImageView.storedSaturationToSeekbarSaturation( metadata.getSaturation() == null ? 1f : metadata.getSaturation())); mSliderColorTemperature.setValue(metadata.getColorTemperature() == null ? 0f : metadata.getColorTemperature()); mDisplayImageView.initializeColorSettings(metadata.getBrightness(), metadata.getContrast(), metadata.getSaturation(), metadata.getColorTemperature()); } // Only now the listeners should be initialized, as image is not yet loaded and listeners should not // react on initial slider setup. initializeSliders(); mDisplayImageView.setEyePhoto(eyePhoto); enableOverlayButtons(metadata.hasOverlayPosition()); mNameLabel.setText(eyePhoto.getPersonName() + " - " + DateUtil.format(eyePhoto.getDate()) + " - " + eyePhoto.getRightLeft().getTitleSuffix()); mTxtImageComment.setText(metadata.getComment()); } /** * Display a specific overlay on the eye photo. * * @param overlayType * The overlay type to be displayed. */ public final void showOverlay(final Integer overlayType) { mCurrentOverlayType = overlayType; if (overlayType != null) { mCurrentResolution = NORMAL; } mDisplayImageView.displayOverlay(overlayType, mColorPicker.getValue(), mCurrentResolution); } /** * Show or hide the comment pane. * * @param visible * Indicator if the pane should be visible. */ public final void showCommentPane(final boolean visible) { mDisplayImageView.storePosition(); mCommentPane.setVisible(visible); mCommentPane.setManaged(visible); if (mCommentConstraints instanceof ColumnConstraints) { ((ColumnConstraints) mCommentConstraints).setPercentWidth(visible ? 20 : 0); // MAGIC_NUMBER } if (mCommentConstraints instanceof RowConstraints) { ((RowConstraints) mCommentConstraints).setPercentHeight(visible ? 20 : 0); // MAGIC_NUMBER } mDisplayImage.layout(); mDisplayImageView.retrievePosition(); } /** * Show or hide the overlay pane. * * @param visible * Indicator if the pane should be visible. */ public final void showOverlayPane(final boolean visible) { mDisplayImageView.storePosition(); mOverlayPane.setVisible(visible); mOverlayPane.setManaged(visible); if (mOverlayConstraints instanceof ColumnConstraints) { ((ColumnConstraints) mOverlayConstraints).setMinWidth(visible ? 75 : 0); // MAGIC_NUMBER } mDisplayImage.layout(); mDisplayImageView.retrievePosition(); } /** * Enable or disable the overlay buttons. * * @param enabled * Indicator if the overlay buttons should be enabled. */ private void enableOverlayButtons(final boolean enabled) { for (int i = 0; i < mOverlayButtons.length; i++) { mOverlayButtons[i].setDisable(!enabled); boolean isVisible = PreferenceUtil.getIndexedPreferenceInt(KEY_INDEXED_OVERLAY_TYPE, i, -1) >= 0; mOverlayButtons[i].setVisible(isVisible); mOverlayButtons[i].setManaged(isVisible); } mColorPicker.setDisable(!enabled); } /** * Give information if the image is already loaded and the view is initialized. * * @return true if the image is loaded and the view is initialized. */ private boolean isInitialized() { return mIsInitialized && mDisplayImageView.isInitialized(); } /** * Clone the contents from another instance. * * @param controller The other instance. */ protected void cloneContents(final DisplayImageController controller) { this.mEyePhoto = controller.mEyePhoto; JpegMetadata metadata = controller.mEyePhoto.getImageMetadata(); if (metadata != null) { MetadataPosition position = controller.mDisplayImageView.getPosition(); metadata.setXPosition(position.mXCenter); metadata.setYPosition(position.mYCenter); metadata.setZoomFactor(position.mZoom); enableOverlayButtons(metadata.hasOverlayPosition()); } mDisplayImageView.cloneContents(controller.mDisplayImageView); mSliderBrightness.setValue(controller.mSliderBrightness.getValue()); mSliderContrast.setValue(controller.mSliderContrast.getValue()); mSliderSaturation.setValue(controller.mSliderSaturation.getValue()); mSliderColorTemperature.setValue(controller.mSliderColorTemperature.getValue()); mColorPicker.setValue(controller.mColorPicker.getValue()); for (int i = 0; i < Math.min(mOverlayButtons.length, controller.mOverlayButtons.length); i++) { mOverlayButtons[i].setSelected(controller.mOverlayButtons[i].isSelected()); } mCurrentOverlayType = controller.mCurrentOverlayType; mCurrentResolution = controller.mCurrentResolution; updateResolution(THUMB); mTxtImageComment.setText(controller.mTxtImageComment.getText()); mTxtImageComment.setEditable(controller.mTxtImageComment.isEditable()); mNameLabel.setText(controller.mNameLabel.getText()); mBtnEditComment.setSelected(controller.mBtnEditComment.isSelected()); mClarityButton.setSelected(controller.mClarityButton.isSelected()); setDirty(controller.isDirty()); mDisplayImageView.setImage(metadata, controller.mDisplayImageView.getImageView().getImage()); initializeSliders(); } }