/* * org.openmicroscopy.shoola.agents.metadata.util.FigureComponent * *------------------------------------------------------------------------------ * Copyright (C) 2006-2009 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.util; //Java imports import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Font; import java.awt.image.BufferedImage; import java.awt.image.DataBuffer; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JLayeredPane; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.event.ChangeEvent; //Third-party libraries //Application-internal dependencies import org.openmicroscopy.shoola.agents.util.ui.ChannelButton; import org.openmicroscopy.shoola.env.data.model.FigureParam; import org.openmicroscopy.shoola.util.image.geom.Factory; import org.openmicroscopy.shoola.util.ui.UIUtilities; /** * Component displaying a given channel. * * @author Jean-Marie Burel      * <a href="mailto:j.burel@dundee.ac.uk">j.burel@dundee.ac.uk</a> * @author Donald MacDonald      * <a href="mailto:donald@lifesci.dundee.ac.uk">donald@lifesci.dundee.ac.uk</a> * @version 3.0 * <small> * (<b>Internal version:</b> $Revision: $Date: $) * </small> * @since 3.0-Beta4 */ class FigureComponent extends JPanel implements PropertyChangeListener { /** The default size of the button. */ static final Dimension DEFAULT_SIZE = new Dimension(16, 16); /** Reference to the canvas displaying the image. */ private FigureCanvas canvas; /** The layered pane hosting the canvas. */ private JLayeredPane pane; /** * The component displaying the label of the channel so that * the use can edit it. */ private JTextField field; /** The component used instead of the text field. */ private JCheckBox box; /** The channel buttons. */ private List<ChannelButton> buttons; /** The image associated to that channel. */ private BufferedImage image; /** Reference to the grey version of the image. */ private BufferedImage greyImage; /** The image associated to that channel. */ private BufferedImage displayedImage; /** Reference to the model. */ private FigureDialog model; /** * Flag indicating that the component is for a single channel * if set to <code>true</code>, <code>false</code> otherwise. */ private boolean single; /** * Initializes the components composing the display. * * @param name The name to give to the channel. */ private void initComponents(String name) { field = new JTextField(name); Font f = field.getFont(); field.setFont(f.deriveFont(f.getStyle(), ChannelButton.MIN_FONT_SIZE)); field.setColumns(8); canvas = new FigureCanvas(); pane = new JLayeredPane(); pane.add(canvas, Integer.valueOf(0)); box = new JCheckBox("Channel names"); box.setToolTipText("Label the merged panel with channel names " + "if selected. Otherwise label with 'Merged'."); box.setBorder(null); } /** Builds and lays out the UI. */ private void buildGUI() { JPanel p = new JPanel(); p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS)); Iterator<ChannelButton> i = buttons.iterator(); while (i.hasNext()) { p.add(i.next()); p.add(Box.createHorizontalStrut(2)); } JPanel controls = new JPanel(); controls.setLayout(new BoxLayout(controls, BoxLayout.Y_AXIS)); if (!single) { //JPanel pBox = UIUtilities.buildComponentPanel(box); //pBox.setBorder(null); controls.add(UIUtilities.buildComponentPanel(box, 5, 4)); } else controls.add(field); controls.add(UIUtilities.buildComponentPanel(p)); //controls.add(UIUtilities.buildComponentPanelCenter(pane)); setLayout(new BorderLayout(0, 0)); add(UIUtilities.buildComponentPanel(controls, 0, 0), BorderLayout.NORTH); add(UIUtilities.buildComponentPanelCenter(pane), BorderLayout.CENTER); } /** * Creates a new instance. * * @param model Reference to the model. * @param color The color associated to the channel. * @param name The name to give to the channel. * @param index The index of the channel. */ FigureComponent(FigureDialog model, Color color, String name, int index) { this.model = model; single = true; ChannelButton b = new ChannelButton("", color, index); b.setPreferredSize(DEFAULT_SIZE); b.addPropertyChangeListener(this); buttons = new ArrayList<ChannelButton>(); buttons.add(b); initComponents(name); buildGUI(); } /** * Creates a new instance. * * @param model Reference to the model. * @param channels The channels to handle. */ FigureComponent(FigureDialog model, List<ChannelButton> channels) { this.model = model; single = false; buttons = channels; initComponents(FigureParam.MERGED_TEXT); buildGUI(); } /** * Adds the passed component to the layer. * * @param component The component to add. */ void addToView(JComponent component) { if (component != null) { Dimension d = pane.getPreferredSize(); component.setPreferredSize(d); component.setSize(d); pane.add(component, Integer.valueOf(1)); } } /** * Returns the label associated to the component. * * @return See above. */ String getLabel() { String value = field.getText(); if (value == null || value.trim().length() == 0) { if (single) { ChannelButton b = buttons.get(0); return ""+b.getChannelIndex(); } return FigureParam.MERGED_TEXT; } return value.trim(); } /** * Returns <code>true</code> if the names of the channels are merged * and displayed next to the merged image, <code>false</code> to * display the default text i.e. {@link FigureParam#MERGED_TEXT}. * * @return See above. */ boolean isChannelsName() { if (single) return false; return box.isSelected(); } /** * Resets the image. * * @param grey Pass <code>true</code> to reset the image as grey, * <code>false</code> otherwise. */ void resetImage(boolean grey) { if (image == null || !single) return; ChannelButton button = buttons.get(0); Color color = button.getColor(); if (grey) { if (greyImage == null) { int r = color.getRed(); int g = color.getGreen(); int b = color.getBlue(); int mask = -1; //red if (r == 255 && g == 0 && b == 0) mask = Factory.RED_MASK; else if (r == 0 && g == 255 && b == 0) mask = Factory.GREEN_MASK; else if (r == 0 && g == 0 && b == 255) mask = Factory.BLUE_MASK; if (mask != -1) { //not primary color DataBuffer buf = image.getRaster().getDataBuffer(); greyImage = Factory.createBandImage(buf, image.getWidth(), image.getHeight(), mask, mask, mask); } else { greyImage = model.createSingleGreyScaleImage( button.getChannelIndex()); } } displayedImage = greyImage; } else displayedImage = image; canvas.setImage(displayedImage); } /** * Sets the image. The original image should always be a colored image. * * @param image The value to set. */ void setOriginalImage(BufferedImage image) { this.image = image; displayedImage = image; greyImage = null; canvas.setImage(image); } /** * Sets the size of the canvas. * * @param width The width to set. * @param height The height to set. */ void setCanvasSize(int width, int height) { Dimension d = new Dimension(width, height); pane.setPreferredSize(d); pane.setSize(d); //canvas.setPreferredSize(d); //canvas.setSize(d); Component[] comps = pane.getComponents(); for (int i = 0; i < comps.length; i++) { comps[i].setPreferredSize(d); comps[i].setSize(d); } } /** * Returns <code>true</code> if the component is selected, * <code>false</code> otherwise. * * @return See above. */ boolean isSelected() { if (buttons.size() != 1) return false; ChannelButton b = buttons.get(0); return b.isSelected(); } /** * Selects or not the selection box. * * @param selected The value to set. */ void setSelected(boolean selected) { if (buttons.size() != 1) return; ChannelButton b = buttons.get(0); b.setSelected(selected); b.repaint(); } /** * Returns the collection of channels associated to this component. * * @return See above. */ List<ChannelButton> getChannels() { return buttons; } /** * Returns the displayed image. * * @return See above. */ BufferedImage getDisplayedImage() { return displayedImage; } /** * Overridden to set the enabled flag of the selection box. * @see JPanel#setEnabled(boolean) */ public void setEnabled(boolean enabled) { field.setEnabled(enabled); } /** * Selects the channel and updates the canvas. * @see PropertyChangeListener#propertyChange(ChangeEvent) */ public void propertyChange(PropertyChangeEvent evt) { String name = evt.getPropertyName(); if (ChannelButton.CHANNEL_SELECTED_PROPERTY.equals(name)) { if (single) { Map m = (Map) evt.getNewValue(); ChannelButton button = buttons.get(0); Boolean b = (Boolean) m.get(button.getChannelIndex()); if (b != null) { button.setSelected(b); model.setChannelSelection(button.getChannelIndex(), b, false); canvas.setImageVisible(b); } } } } }