/* * org.openmicroscopy.shoola.agents.metadata.rnd.RendererControl * *------------------------------------------------------------------------------ * Copyright (C) 2006-2014 University of Dundee. All rights reserved. * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * *------------------------------------------------------------------------------ */ package org.openmicroscopy.shoola.agents.metadata.rnd; //Java imports import java.awt.Color; import java.awt.Point; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import javax.swing.Action; import javax.swing.JFrame; //Third-party libraries //Application-internal dependencies import org.openmicroscopy.shoola.agents.metadata.MetadataViewerAgent; import org.openmicroscopy.shoola.agents.metadata.actions.ColorModelAction; import org.openmicroscopy.shoola.agents.metadata.actions.ContrastStretchingAction; import org.openmicroscopy.shoola.agents.metadata.actions.HistogramAction; import org.openmicroscopy.shoola.agents.metadata.actions.ManageRndSettingsAction; import org.openmicroscopy.shoola.agents.metadata.actions.NoiseReductionAction; import org.openmicroscopy.shoola.agents.metadata.actions.PlaneSlicingAction; import org.openmicroscopy.shoola.agents.metadata.actions.ReverseIntensityAction; import org.openmicroscopy.shoola.agents.metadata.actions.RndAction; import org.openmicroscopy.shoola.agents.metadata.actions.ViewAction; import org.openmicroscopy.shoola.agents.metadata.view.MetadataViewerFactory; import org.openmicroscopy.shoola.agents.util.ui.ChannelButton; import org.openmicroscopy.shoola.util.ui.UIUtilities; import org.openmicroscopy.shoola.util.ui.colourpicker.ColourPicker; /** * The Renderer's controller. * * @author Jean-Marie Burel      * <a href="mailto:j.burel@dundee.ac.uk">j.burel@dundee.ac.uk</a> * @author Andrea Falconi      * <a href="mailto:a.falconi@dundee.ac.uk">a.falconi@dundee.ac.uk</a> * @author Donald MacDonald      * <a href="mailto:donald@lifesci.dundee.ac.uk">donald@lifesci.dundee.ac.uk</a> * @version 3.0 * @since 3.0-Beta4 */ class RendererControl implements PropertyChangeListener { /** Identifies the action to select the bit resolution. */ static final Integer BIT_RESOLUTION = Integer.valueOf(0); /** Identifies the action to select the family. */ static final Integer FAMILY = Integer.valueOf(1); /** Identifies the action to select the coefficient. */ static final Integer COEFFICIENT = Integer.valueOf(2); /** Identifies the action to select the noise reduction algorithm. */ static final Integer NOISE_REDUCTION = Integer.valueOf(3); /** Identifies the action to select the reverse intensity transformation. */ static final Integer REVERSE_INTENSITY = Integer.valueOf(4); /** Identifies the action to select the plane slicing transformation. */ static final Integer PLANE_SLICING = Integer.valueOf(5); /** * Identifies the action to select the contrast stretching transformation. */ static final Integer CONTRAST_STRETCHING = Integer.valueOf(6); /** Identifies the action to bring up the histogram widget. */ static final Integer HISTOGRAM = Integer.valueOf(7); /** Identifies the action to modify the color model. */ static final Integer COLOR_MODEL = Integer.valueOf(8); /** Identifies the action to set the intensity values to min, max. */ static final Integer RND_MIN_MAX = Integer.valueOf(9); /** Identifies the action to rest the settings. */ static final Integer RND_RESET = Integer.valueOf(10); /** Identifies the action to undo the changes. */ static final Integer RND_UNDO = Integer.valueOf(11); /** Identifies the action to undo the changes. */ static final Integer RND_OWNER = Integer.valueOf(12); /** Identifies the action to view the image. */ static final Integer VIEW = Integer.valueOf(13); /** Identifies the action to apply settings to all. */ static final Integer APPLY_TO_ALL = Integer.valueOf(14); /** Identifies the action to set the intensity values to min, max. */ static final Integer RND_ABSOLUTE_MIN_MAX = Integer.valueOf(15); /** Identifies the action to save the rendering settings. */ static final Integer SAVE = Integer.valueOf(16); /** Identifies the action to redo the changes. */ static final Integer RND_REDO = Integer.valueOf(17); /** Identifies the action to copy the rendering settings. */ static final Integer COPY = Integer.valueOf(18); /** Identifies the action to paste the rendering settings. */ static final Integer PASTE = Integer.valueOf(19); /** * Reference to the {@link Renderer} component, which, in this context, * is regarded as the Model. */ private Renderer model; /** Reference to the View. */ private RendererUI view; /** Maps actions identifier onto actual <code>Action</code> object. */ private Map<Integer, RndAction> actionsMap; /** Index of the channel invoking the color picker. */ private int colorPickerIndex; /** Helper method to create all the UI actions. */ private void createActions() { actionsMap.put(REVERSE_INTENSITY, new ReverseIntensityAction(model)); actionsMap.put(PLANE_SLICING, new PlaneSlicingAction(model)); actionsMap.put(CONTRAST_STRETCHING, new ContrastStretchingAction(model)); actionsMap.put(NOISE_REDUCTION, new NoiseReductionAction(model)); actionsMap.put(HISTOGRAM, new HistogramAction(model)); actionsMap.put(COLOR_MODEL, new ColorModelAction(model)); actionsMap.put(VIEW, new ViewAction(model)); actionsMap.put(RND_MIN_MAX, new ManageRndSettingsAction(model, ManageRndSettingsAction.MIN_MAX)); actionsMap.put(RND_RESET, new ManageRndSettingsAction(model, ManageRndSettingsAction.RESET)); actionsMap.put(APPLY_TO_ALL, new ManageRndSettingsAction(model, ManageRndSettingsAction.APPLY_TO_ALL)); actionsMap.put(RND_ABSOLUTE_MIN_MAX, new ManageRndSettingsAction(model, ManageRndSettingsAction.ABSOLUTE_MIN_MAX)); actionsMap.put(SAVE, new ManageRndSettingsAction(model, ManageRndSettingsAction.SAVE)); ManageRndSettingsAction a = new ManageRndSettingsAction(model, ManageRndSettingsAction.UNDO); a.setEnabled(false); actionsMap.put(RND_UNDO, a); a = new ManageRndSettingsAction(model, ManageRndSettingsAction.REDO); a.setEnabled(false); actionsMap.put(RND_REDO, a); a = new ManageRndSettingsAction(model, ManageRndSettingsAction.COPY); actionsMap.put(COPY, a); a = new ManageRndSettingsAction(model, ManageRndSettingsAction.PASTE); a.setEnabled(false); actionsMap.put(PASTE, a); } /** * Attaches a window listener to the view and a property listener to the * model. */ private void attachListeners() { model.addPropertyChangeListener(this); } /** * Brings up the color picker with the color associated to the passed * channel. * * @param channel The index of the selected channel. */ void showColorPicker(int channel) { showColorPicker(channel, null); } /** * Brings up the color picker with the color associated to the passed * channel. * * @param channel The index of the selected channel. * @param location The location where to show the dialog */ void showColorPicker(int channel, Point location) { colorPickerIndex = channel; Color c = view.getChannelColor(channel); JFrame f = MetadataViewerAgent.getRegistry().getTaskBar().getFrame(); ColourPicker dialog = new ColourPicker(f, c); dialog.setPreviewVisible(true); dialog.addPropertyChangeListener(this); if (location == null) UIUtilities.centerAndShow(dialog); else UIUtilities.showOnScreen(dialog, location); } /** * Creates a new instance. * The {@link #initialize(Renderer, RendererUI) initialize} method should * be called straight after to link this Controller to the other MVC * components. */ RendererControl() { actionsMap = new HashMap<Integer, RndAction>(); } /** * Links this Controller to its Model and View. * * @param model Reference to the {@link Renderer} component, which, in this * context, is regarded as the Model. Mustn't be * <code>null</code>. * @param view Reference to the View. Mustn't be <code>null</code>. */ void initialize(Renderer model, RendererUI view) { if (model == null) throw new NullPointerException("No model."); if (view == null) throw new NullPointerException("No view."); this.model = model; this.view = view; createActions(); attachListeners(); } /** * Returns the action corresponding to the specified id. * * @param id One of the flags defined by this class. * @return The specified action. */ Action getAction(Integer id) { return actionsMap.get(id); } /** * Registers the specified observer. * * @param observer The observer to register. */ void addPropertyListener(PropertyChangeListener observer) { model.addPropertyChangeListener(observer); } /** * Sets the the pixels intensity interval for the * currently selected channel. * * @param s The lower bound of the interval. * @param e The upper bound of the interval. */ void setInputInterval(double s, double e) { model.setInputInterval(s, e); } /** * Sets the the pixels intensity interval for the specified channel. * * @param s The lower bound of the interval. * @param e The upper bound of the interval. * @param channel The channel to handle. */ void setInputInterval(double s, double e, int channel) { model.setChannelWindow(channel, s, e); } /** * Checks if the image pixel type is integer * @return See above */ boolean isIntegerPixelData() { return model.isIntegerPixelData(); }; /** * Sets the sub-interval of the device space. * * @param s The lower bound of the interval. * @param e The upper bound of the interval. */ void setCodomainInterval(int s, int e) { model.setCodomainInterval(s, e); } /** * Sets the selected plane. * * @param z The selected z-section. * @param t The selected timepoint. */ void setSelectedXYPlane(int z, int t) { setSelectedXYPlane(z, t, -1); } /** * Renders the specified XY-Plane. * * @param z The selected z-section. * @param t The selected timepoint. * @param bin The selected bin, only used for lifetime. */ void setSelectedXYPlane(int z, int t, int bin) { model.setSelectedXYPlane(z, t, bin); } /** * Indicates that a channel has been selected using the channel button. * * @param index The index of the channel. * @param active Pass <code>true</code> to indicate that the channel is * active, <code>false</code> otherwise. */ void setChannelSelection(int index, boolean active) { model.setChannelSelection(index, active); } /** * Sets the family. * * @param channel The index of the channel. * @param family The family to set. */ void setChannelFamily(int channel, String family) { model.setFamily(channel, family); view.onCurveChange(); } /** * Sets the coefficient identifying a curve in the family * and updates the image. * * @param channel The channel to handle. * @param k The new curve coefficient. */ void setCurveCoefficient(int channel, double k) { model.setCurveCoefficient(channel, k); view.onCurveChange(); } /** * Enables/Disables the paste action depending on if * there are rendering settings which can be pasted */ void updatePasteAction() { boolean enabled = MetadataViewerFactory.hasRndSettingsCopied(model.getRefImage().getId()); actionsMap.get(PASTE).setEnabled(enabled); } /** * Reacts to property change events. * @see PropertyChangeListener#propertyChange(PropertyChangeEvent) */ public void propertyChange(PropertyChangeEvent evt) { String name = evt.getPropertyName(); if (RenderingDefinitionHistory.CAN_REDO.equals(name)) { boolean value = (Boolean)evt.getNewValue(); actionsMap.get(RND_REDO).setEnabled(value); } if (RenderingDefinitionHistory.CAN_UNDO.equals(name)) { boolean value = (Boolean)evt.getNewValue(); actionsMap.get(RND_UNDO).setEnabled(value); } /* } else if (name.equals( CodomainMapContextDialog.UPDATE_MAP_CONTEXT_PROPERTY)) { CodomainMapContext ctx = (CodomainMapContext) evt.getNewValue(); model.updateCodomainMap(ctx); */ if (ControlPane.BIT_RESOLUTION_PROPERTY.equals(name)) { Integer oldValue = (Integer) evt.getOldValue(); Integer newValue = (Integer) evt.getNewValue(); if (newValue.equals(oldValue)) return; model.setBitResolution(newValue.intValue()); } if (ChannelButton.CHANNEL_SELECTED_PROPERTY.equals(name)) { Map map = (Map) evt.getNewValue(); if (map == null) return; if (map.size() != 1) return; Entry entry = (Entry) map.entrySet().iterator().next(); Integer index = (Integer) entry.getKey(); setChannelSelection(index.intValue(), (Boolean) entry.getValue()); } else if (ChannelButton.CHANNEL_COLOUR_PROPERTY.equals(name)) { showColorPicker(((Integer) evt.getNewValue()).intValue()); } else if (Renderer.INPUT_INTERVAL_PROPERTY.equals(name)) { view.setInputInterval(); } else if (Renderer.RANGE_INPUT_PROPERTY.equals(name)) { Boolean b = (Boolean) evt.getNewValue(); view.setInputRange(b.booleanValue()); } else if (ColourPicker.COLOUR_PROPERTY.equals(name)) { Color c = (Color) evt.getNewValue(); if (colorPickerIndex != -1) { model.setChannelColor(colorPickerIndex, c, false); } } else if (ColourPicker.COLOUR_PREVIEW_PROPERTY.equals(name)) { Color c = (Color) evt.getNewValue(); if (colorPickerIndex != -1) { model.setChannelColor(colorPickerIndex, c, true); } } else if (ColourPicker.CANCEL_PROPERTY.equals(name)) { model.setChannelColor(colorPickerIndex, null, true); } else if (Renderer.Z_SELECTED_PROPERTY.equals(name)) { view.setZSection(((Integer) evt.getNewValue()).intValue()); } else if (Renderer.T_SELECTED_PROPERTY.equals(name)) { view.setTimepoint(((Integer) evt.getNewValue()).intValue()); } if(Renderer.SAVE_SETTINGS_PROPERTY.equals(name)) { actionsMap.get(SAVE).setEnabled(false); } else { boolean settingsModified = model.isModified(); actionsMap.get(SAVE).setEnabled(settingsModified && model.canAnnotate()); } boolean pasteEnabled = MetadataViewerFactory.hasRndSettingsCopied(model.getRefImage().getId()); actionsMap.get(PASTE).setEnabled(pasteEnabled); } }