org.openmicroscopy.shoola.agents.metadata.rnd.GraphicsPane.java Source code

Java tutorial

Introduction

Here is the source code for org.openmicroscopy.shoola.agents.metadata.rnd.GraphicsPane.java

Source

/*
 * org.openmicroscopy.shoola.agents.metadata.rnd.GraphicsPane 
 *
 *------------------------------------------------------------------------------
 *  Copyright (C) 2006-2013 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.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSeparator;

//Third-party libraries
import info.clearthought.layout.TableLayout;

import org.apache.commons.collections.CollectionUtils;
import org.jdesktop.swingx.JXTaskPane;

//Application-internal dependencies
import org.openmicroscopy.shoola.agents.metadata.IconManager;
import org.openmicroscopy.shoola.agents.metadata.actions.ManageRndSettingsAction;
import org.openmicroscopy.shoola.agents.util.ViewedByItem;
import org.openmicroscopy.shoola.util.ui.UIUtilities;
import org.openmicroscopy.shoola.util.ui.slider.TextualTwoKnobsSlider;
import org.openmicroscopy.shoola.util.ui.slider.TwoKnobsSlider;
import pojos.ChannelData;

/** 
 * Component hosting the diagram and the controls to select the pixels intensity
 * interval and the codomain interval.
 *
 * @author Jean-Marie Burel     
 *         <a href="mailto:j.burel@dundee.ac.uk">j.burel@dundee.ac.uk</a>
 * @author Andrea Falconi &nbsp;&nbsp;&nbsp;&nbsp;
 *          <a href="mailto:a.falconi@dundee.ac.uk">a.falconi@dundee.ac.uk</a>
 * @author Donald MacDonald &nbsp;&nbsp;&nbsp;&nbsp;
 *    <a href="mailto:donald@lifesci.dundee.ac.uk">donald@lifesci.dundee.ac.uk</a>
 * @version 3.0
 * @since 3.0-Beta4
 */
class GraphicsPane extends JPanel implements PropertyChangeListener {

    /** 
     * Factor used to determine the percentage of the range added 
     * (resp. removed) to (resp. from) the maximum (resp. the minimum).
     */
    static final double RATIO = 0.2;

    /** Slider to select a sub-interval of [0, 255]. */
    private TwoKnobsSlider codomainSlider;

    /** Slider to select the pixels intensity interval. */
    private TextualTwoKnobsSlider domainSlider;

    /** The label displaying the global max. */
    private JLabel maxLabel;

    /** The label displaying the global minimum. */
    private JLabel minLabel;

    /** The component displaying the plane histogram. */
    private GraphicsPaneUI uiDelegate;

    /** Reference to the Model.*/
    protected RendererModel model;

    /** Reference to the Control.*/
    protected RendererControl controller;

    /** Flag indicating to paint a vertical line. */
    private boolean paintVertical;

    /** Flag indicating to paint a vertical line. */
    private boolean paintHorizontal;

    /** The equation the horizontal line. */
    private int horizontalLine = -1;

    /** The equation of the vertical line. */
    private int verticalLine = -1;

    /** Hosts the sliders controlling the pixels intensity values. */
    private List<ChannelSlider> sliders;

    /** The component displaying the controls. */
    private PreviewControlBar controlsBar;

    /** The Tasks pane, only visible if already viewed by others. */
    private JXTaskPane viewedBy;

    /** The preview tool bar. */
    private PreviewToolBar previewToolBar;

    /**
     * Formats the specified value.
     * 
     * @param value The value to format.
     * @return See above.
     */
    private String formatValue(double value) {
        if (model.getRoundFactor() == 1)
            return "" + (int) value;
        return UIUtilities.formatToDecimal(value);
    }

    /** Initializes the domain slider. */
    private void initDomainSlider() {
        int f = model.getRoundFactor();
        int s = (int) (model.getWindowStart() * f);
        int e = (int) (model.getWindowEnd() * f);
        int absMin = (int) (model.getLowestValue() * f);
        int absMax = (int) (model.getHighestValue() * f);
        int min = (int) (model.getGlobalMin() * f);
        int max = (int) (model.getGlobalMax() * f);
        double range = (max - min) * RATIO;
        int lowestBound = (int) (min - range);
        if (lowestBound < absMin)
            lowestBound = absMin;
        int highestBound = (int) (max + range);
        if (highestBound > absMax)
            highestBound = absMax;
        domainSlider.setValues(max, min, highestBound, lowestBound, max, min, s, e, f);
        if (model.getMaxC() > Renderer.MAX_CHANNELS)
            domainSlider.setInterval(min, max);
    }

    /** Initializes the components. */
    private void initComponents() {
        IconManager icons = IconManager.getInstance();
        viewedBy = new JXTaskPane();
        viewedBy.setCollapsed(true);
        viewedBy.setVisible(false);
        Font font = viewedBy.getFont();
        viewedBy.setFont(font.deriveFont(font.getSize2D() - 2));
        viewedBy.setTitle(ManageRndSettingsAction.NAME_OWNER);
        viewedBy.setIcon(icons.getIcon(IconManager.RND_OWNER));
        controlsBar = new PreviewControlBar(controller, model);
        uiDelegate = new GraphicsPaneUI(this, model);
        codomainSlider = new TwoKnobsSlider(RendererModel.CD_START, RendererModel.CD_END, model.getCodomainStart(),
                model.getCodomainEnd());
        codomainSlider.setBackground(UIUtilities.BACKGROUND_COLOR);
        codomainSlider.setPaintLabels(false);
        codomainSlider.setPaintEndLabels(false);
        codomainSlider.setPaintTicks(false);
        codomainSlider.setColourGradients(Color.BLACK, Color.WHITE);
        codomainSlider.addPropertyChangeListener(this);

        domainSlider = new TextualTwoKnobsSlider();
        domainSlider.setBackground(UIUtilities.BACKGROUND_COLOR);
        initDomainSlider();
        domainSlider.getSlider().setPaintLabels(false);
        domainSlider.getSlider().setPaintEndLabels(false);
        domainSlider.getSlider().setPaintTicks(false);
        domainSlider.addPropertyChangeListener(this);
        maxLabel = new JLabel(formatValue(model.getGlobalMax()));
        minLabel = new JLabel(formatValue(model.getGlobalMin()));
        maxLabel.setBackground(UIUtilities.BACKGROUND_COLOR);
        minLabel.setBackground(UIUtilities.BACKGROUND_COLOR);
        sliders = new ArrayList<ChannelSlider>();
        if (model.getModuloT() != null || !model.isLifetimeImage()) {
            List<ChannelData> channels = model.getChannelData();
            Iterator<ChannelData> i = channels.iterator();
            ChannelSlider slider;
            int columns = 0;
            while (i.hasNext()) {
                slider = new ChannelSlider(this, model, controller, i.next());
                columns = Math.max(columns, slider.getColumns());
                sliders.add(slider);
            }
            Iterator<ChannelSlider> j = sliders.iterator();
            while (j.hasNext()) {
                j.next().setColumns(columns);
            }
        }
        previewToolBar = new PreviewToolBar(controller, model);
    }

    /** Builds and lays out the GUI. */
    private void buildGUI() {
        setBackground(UIUtilities.BACKGROUND_COLOR);
        double size[][] = { { TableLayout.FILL }, // Columns
                { TableLayout.PREFERRED, 5, TableLayout.FILL } }; // Rows
        setLayout(new TableLayout(size));
        if (model.isGeneralIndex()) {
            add(buildGeneralPane(), "0, 0");
        } else {
            add(buildPane(), "0, 0");
            add(buildGeneralPane(), "0, 2");
        }
    }

    /** 
     * Builds hosting the various sliders
     * 
     * @return See above.
     */
    private JPanel buildGeneralPane() {
        JPanel content = new JPanel();
        content.setBackground(UIUtilities.BACKGROUND_COLOR);
        content.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        content.setLayout(new GridBagLayout());
        GridBagConstraints c = new GridBagConstraints();
        c.anchor = GridBagConstraints.WEST;
        c.insets = new Insets(0, 2, 2, 0);
        c.gridy = 0;
        c.gridx = 0;
        if (model.isGeneralIndex()) {
            content.add(previewToolBar, c);
            c.gridy++;
            c.gridwidth = GridBagConstraints.RELATIVE; //next-to-last
            c.fill = GridBagConstraints.HORIZONTAL;
            content.add(new JSeparator(), c);
            c.gridy++;
        }
        content.add(controlsBar, c);
        c.gridwidth = GridBagConstraints.RELATIVE; //next-to-last
        c.fill = GridBagConstraints.NONE;//reset to default
        c.weightx = 0.0;

        Iterator<ChannelSlider> i = sliders.iterator();
        while (i.hasNext()) {
            c.gridy++;
            content.add(i.next(), c);
        }
        c.gridy++;
        c.gridwidth = GridBagConstraints.REMAINDER; //end row
        c.fill = GridBagConstraints.BOTH;
        c.weightx = 1.0;
        c.weighty = 1.0;
        content.add(viewedBy, c);
        JPanel p = UIUtilities.buildComponentPanel(content);
        p.setBackground(content.getBackground());
        return p;
    }

    /** 
     * Builds and lays out the slider.
     * 
     * @return See above.
     */
    private JPanel buildPane() {
        JPanel p = new JPanel();
        p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
        p.setBackground(UIUtilities.BACKGROUND_COLOR);
        p.add(codomainSlider);
        return p;
    }

    /**
     * Creates a new instance.
     * 
     * @param model Reference to the model. Mustn't be <code>null</code>.
     * @param controller Reference to the control. Mustn't be <code>null</code>.
     */
    GraphicsPane(RendererModel model, RendererControl controller) {
        if (model == null)
            throw new NullPointerException("No model.");
        if (controller == null)
            throw new NullPointerException("No controller.");
        this.model = model;
        this.controller = controller;
        initComponents();
        buildGUI();
    }

    /** Sets the value of the selected plane.*/
    void setSelectedPlane() {
        if (previewToolBar != null)
            previewToolBar.setSelectedPlane();
    }

    /** Updates the controls when a new channel is selected. */
    void setSelectedChannel() {
        Iterator<ChannelSlider> i = sliders.iterator();
        ChannelSlider slider;
        while (i.hasNext()) {
            slider = i.next();
            slider.setSelectedChannel();
        }
    }

    /** Sets the pixels intensity interval. */
    void setInputInterval() {
        int f, s, e;
        Iterator<ChannelSlider> i = sliders.iterator();
        ChannelSlider slider;
        while (i.hasNext()) {
            slider = i.next();
            f = model.getRoundFactor(slider.getIndex());
            s = (int) (model.getWindowStart(slider.getIndex()) * f);
            e = (int) (model.getWindowEnd(slider.getIndex()) * f);
            slider.setInterval(s, e);
        }
    }

    /** 
     * Modifies the input range of the channel sliders.
     * 
     *  @param absolute Pass <code>true</code> to set it to the absolute value,
     *                  <code>false</code> to the minimum and maximum.
     */
    void setInputRange(boolean booleanValue) {
        if (CollectionUtils.isEmpty(sliders))
            return;
        Iterator<ChannelSlider> i = sliders.iterator();
        while (i.hasNext())
            i.next().setInputRange(booleanValue);
    }

    /** Sets the value of the codomain interval. */
    void setCodomainInterval() {
        codomainSlider.setInterval(model.getCodomainStart(), model.getCodomainEnd());
        onCurveChange();
    }

    /** 
     * Updates the UI when a new curve is selected i.e. when a new family
     * is selected or when a new gamma value is selected.
     */
    void onCurveChange() {
        uiDelegate.invalidate();
        uiDelegate.repaint();
    }

    /**
     * Returns <code>true</code> if a vertical or horizontal line has
     * to be painted, <code>false</code> otherwise.
     * 
     * @return See above.
     */
    boolean isPaintLine() {
        return paintVertical() || paintHorizontal();
    }

    /**
     * Returns <code>true</code> if the life update is selected,
     * <code>false</code> otherwise.
     * 
     * @return See above.
     */
    boolean isLiveUpdate() {
        return controlsBar.isLiveUpdate();
    }

    /**
     * Returns <code>true</code> if a vertical line has
     * to be painted, <code>false</code> otherwise.
     * 
     * @return See above.
     */
    boolean paintVertical() {
        return paintVertical;
    }

    /**
     * Returns <code>true</code> if a horizontal line has
     * to be painted, <code>false</code> otherwise.
     * 
     * @return See above.
     */
    boolean paintHorizontal() {
        return paintHorizontal;
    }

    /**
     * Returns the equation of the horizontal line or <code>-1</code>
     * if no horizontal line defined.
     * 
     * @return See above.
     */
    int getHorizontalLine() {
        return horizontalLine;
    }

    /**
     * Returns the equation of the vertical line or <code>-1</code>
     * if no vertical line defined.
     * 
     * @return See above.
     */
    int getVerticalLine() {
        return verticalLine;
    }

    /**
     * Returns the value of the partial minimum.
     * 
     * @return See above.
     */
    int getPartialMinimum() {
        return domainSlider.getSlider().getPartialMinimum();
    }

    /**
     * Returns the value of the partial maximum.
     * 
     * @return See above.
     */
    int getPartialMaximum() {
        return domainSlider.getSlider().getPartialMaximum();
    }

    /** 
     * Sets the enabled flag of the UI components.
     * 
     * @param b The value to set.
     */
    void onStateChange(boolean b) {
        if (codomainSlider != null)
            codomainSlider.setEnabled(b);
        if (domainSlider != null)
            domainSlider.setEnabled(b);
    }

    /** Toggles between color model and Greyscale. */
    void setColorModelChanged() {
        if (CollectionUtils.isEmpty(sliders))
            return;
        Iterator<ChannelSlider> i = sliders.iterator();
        while (i.hasNext()) {
            i.next().setColorModelChanged();
        }
    }

    /**
     * Sets the color of the passed channel.
     *  
     * @param index The index of the channel.
     */
    void setChannelColor(int index) {
        if (CollectionUtils.isNotEmpty(sliders)) {
            Iterator<ChannelSlider> i = sliders.iterator();
            ChannelSlider slider;
            while (i.hasNext()) {
                slider = i.next();
                if (slider.getIndex() == index) {
                    slider.setChannelColor();
                    break;
                }
            }
        }
        repaint();
    }

    /** 
     * Builds and lays out the images as seen by other experimenters.
     *  
     * @param results The thumbnails to lay out.
     */
    void displayViewedBy(List results) {
        if (results == null)
            return;
        JPanel p = new JPanel();
        p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
        p.setBackground(UIUtilities.BACKGROUND_COLOR);
        Iterator<ViewedByItem> i = results.iterator();
        JPanel row = null;
        int index = 0;
        ViewedByItem item;
        int maxPerRow = 2;
        while (i.hasNext()) {
            item = i.next();
            if (index == 0) {
                row = new JPanel();
                row.setBackground(UIUtilities.BACKGROUND_COLOR);
                row.setLayout(new FlowLayout(FlowLayout.LEFT));
                row.add(item);
                index++;
            } else if (index == maxPerRow) {
                row.add(item);
                p.add(row);
                index = 0;
            } else {
                row.add(item);
                index++;
            }
        }
        if (index > 0)
            p.add(row);
        viewedBy.removeAll();
        JPanel content = UIUtilities.buildComponentPanel(p);
        content.setBackground(UIUtilities.BACKGROUND_COLOR);
        viewedBy.add(content);
        viewedBy.setVisible(true);
        viewedBy.setCollapsed(false);
    }

    /**
     * Returns the slider used to set the codomain interval.
     * 
     * @return See above.
     */
    JComponent getCodomainSlider() {
        return codomainSlider;
    }

    /**
     * Reacts to property changes fired by the {@link TwoKnobsSlider}s.
     * @see PropertyChangeListener#propertyChange(PropertyChangeEvent)
     */
    public void propertyChange(PropertyChangeEvent evt) {
        String name = evt.getPropertyName();
        Object source = evt.getSource();
        if (!controlsBar.isLiveUpdate()) {
            if (TwoKnobsSlider.KNOB_RELEASED_PROPERTY.equals(name)) {
                paintHorizontal = false;
                paintVertical = false;
                if (source.equals(domainSlider)) {
                    controller.setInputInterval(domainSlider.getStartValue(), domainSlider.getEndValue());
                    onCurveChange();
                } else if (source.equals(codomainSlider)) {
                    int s = codomainSlider.getStartValue();
                    int e = codomainSlider.getEndValue();
                    controller.setCodomainInterval(s, e);
                    onCurveChange();
                }
            } else if (TwoKnobsSlider.LEFT_MOVED_PROPERTY.equals(name)) {
                if (source.equals(domainSlider)) {
                    verticalLine = (int) (domainSlider.getStartValue() * domainSlider.getRoundingFactor());
                    paintHorizontal = false;
                    paintVertical = true;
                    onCurveChange();
                } else if (source.equals(codomainSlider)) {
                    horizontalLine = codomainSlider.getEndValue();
                    paintHorizontal = true;
                    paintVertical = false;
                    onCurveChange();
                }
            } else if (TwoKnobsSlider.RIGHT_MOVED_PROPERTY.equals(name)) {
                if (source.equals(domainSlider)) {
                    verticalLine = (int) (domainSlider.getEndValue() * domainSlider.getRoundingFactor());
                    horizontalLine = -1;
                    paintHorizontal = false;
                    paintVertical = true;
                    onCurveChange();
                } else if (source.equals(codomainSlider)) {
                    horizontalLine = codomainSlider.getStartValue();
                    verticalLine = -1;
                    paintHorizontal = true;
                    paintVertical = false;
                    onCurveChange();
                }
            }
        } else {
            paintHorizontal = false;
            paintVertical = false;
            if (TwoKnobsSlider.LEFT_MOVED_PROPERTY.equals(name)
                    || TwoKnobsSlider.RIGHT_MOVED_PROPERTY.equals(name)) {
                if (source.equals(domainSlider)) {
                    controller.setInputInterval(domainSlider.getStartValue(), domainSlider.getEndValue());
                    onCurveChange();
                } else if (source.equals(codomainSlider)) {
                    int s = codomainSlider.getStartValue();
                    int e = codomainSlider.getEndValue();
                    controller.setCodomainInterval(s, e);
                    onCurveChange();
                }
            } else if (TwoKnobsSlider.KNOB_RELEASED_PROPERTY.equals(name)) {
                if (source.equals(domainSlider)) {
                    controller.setInputInterval(domainSlider.getStartValue(), domainSlider.getEndValue());
                } else if (source.equals(codomainSlider)) {
                    int s = codomainSlider.getStartValue();
                    int e = codomainSlider.getEndValue();
                    controller.setCodomainInterval(s, e);
                    onCurveChange();
                }
            }
        }
    }

}