org.openmicroscopy.shoola.agents.metadata.editor.ChannelAcquisitionComponent.java Source code

Java tutorial

Introduction

Here is the source code for org.openmicroscopy.shoola.agents.metadata.editor.ChannelAcquisitionComponent.java

Source

/*
 *------------------------------------------------------------------------------
 *  Copyright (C) 2006-2015 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.editor;

import java.awt.Color;
import java.awt.Dimension;
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.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;

import org.apache.commons.lang.time.DateUtils;
import org.jdesktop.swingx.JXTaskPane;

import omero.model.AcquisitionMode;
import omero.model.ContrastMethod;
import omero.model.Illumination;
import omero.model.LengthI;
import omero.model.PlaneInfo;
import ome.formats.model.UnitsFactory;
import ome.model.units.BigResult;

import org.openmicroscopy.shoola.agents.metadata.MetadataViewerAgent;
import org.openmicroscopy.shoola.agents.util.DataComponent;
import org.openmicroscopy.shoola.agents.util.EditorUtil;
import org.openmicroscopy.shoola.env.data.model.EnumerationObject;
import org.openmicroscopy.shoola.util.ui.ColourIcon;
import org.openmicroscopy.shoola.util.ui.JLabelButton;
import org.openmicroscopy.shoola.util.ui.NumericalTextField;
import org.openmicroscopy.shoola.util.ui.OMEComboBox;
import org.openmicroscopy.shoola.util.ui.OMETextArea;
import org.openmicroscopy.shoola.util.ui.UIUtilities;
import omero.gateway.model.ChannelAcquisitionData;
import omero.gateway.model.ChannelData;
import omero.gateway.model.DataObject;
import omero.gateway.model.LightSourceData;

/** 
 * Displays the metadata related to the channel.
 *
 * @author  Jean-Marie Burel     
 * <a href="mailto:j.burel@dundee.ac.uk">j.burel@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 ChannelAcquisitionComponent extends JPanel implements PropertyChangeListener {

    /** Action ID to show or hide the unset general data. */
    private static final int GENERAL = 0;

    /** Format used for displaying time in ms */
    private static final DecimalFormat msFormat = new DecimalFormat("# ms");

    /** Format used for displaying time in s */
    private static final DecimalFormat sFormat = new DecimalFormat("0.0 s");

    /** Reference to the parent of this component. */
    private AcquisitionDataUI parent;

    /** The channel data. */
    private ChannelData channel;

    /** The component displaying the illumination's options. */
    private OMEComboBox illuminationBox;

    /** The component displaying the contrast Method options. */
    private OMEComboBox contrastMethodBox;

    /** The component displaying the contrast Method options. */
    private OMEComboBox modeBox;

    /** The fields displaying the metadata. */
    private Map<String, DataComponent> fieldsGeneral;

    /** The UI component hosting the lightSource metadata. */
    private LightSourceComponent lightPane;

    /** The UI component hosting the detector metadata. */
    private DetectorComponent detectorPane;

    /** The UI component hosting the filter set or <code>null</code>. */
    private FilterGroupComponent filterSetPane;

    /** The UI component hosting the light path or <code>null</code>. */
    private FilterGroupComponent lightPathPane;

    /** Button to show or hides the unset fields of the detector. */
    private JLabelButton unsetGeneral;

    /** Flag indicating the unset fields for the general are displayed. */
    private boolean unsetGeneralShown;

    /** The UI component hosting the general metadata. */
    private JPanel generalPane;

    /** Flag indicating if the components have been initialized. */
    private boolean init;

    /** Reference to the Model. */
    private EditorModel model;

    /** The component hosting the exposure time. */
    private JXTaskPane exposureTask;

    /** The icon displaying the color associated to the channel. */
    private ColourIcon icon;

    /** Resets the various boxes with enumerations. */
    private void resetBoxes() {
        List<EnumerationObject> l;
        l = model.getChannelEnumerations(Editor.ILLUMINATION_TYPE);
        EnumerationObject[] array = new EnumerationObject[l.size() + 1];
        Iterator<EnumerationObject> j = l.iterator();
        int i = 0;
        while (j.hasNext()) {
            array[i] = j.next();
            i++;
        }
        array[i] = new EnumerationObject(AnnotationUI.NO_SET_TEXT);
        illuminationBox = EditorUtil.createComboBox(array);

        l = model.getChannelEnumerations(Editor.CONTRAST_METHOD);
        array = new EnumerationObject[l.size() + 1];
        j = l.iterator();
        i = 0;
        while (j.hasNext()) {
            array[i] = j.next();
            i++;
        }
        array[i] = new EnumerationObject(AnnotationUI.NO_SET_TEXT);
        contrastMethodBox = EditorUtil.createComboBox(array);

        l = model.getChannelEnumerations(Editor.MODE);
        array = new EnumerationObject[l.size() + 1];
        j = l.iterator();
        i = 0;
        while (j.hasNext()) {
            array[i] = j.next();
            i++;
        }
        array[i] = new EnumerationObject(AnnotationUI.NO_SET_TEXT);
        modeBox = EditorUtil.createComboBox(array);

        l = model.getChannelEnumerations(Editor.BINNING);
        array = new EnumerationObject[l.size() + 1];
        j = l.iterator();
        i = 0;
        while (j.hasNext()) {
            array[i] = j.next();
            i++;
        }
        array[i] = new EnumerationObject(AnnotationUI.NO_SET_TEXT);
    }

    /** Initializes the components */
    private void initComponents() {
        resetBoxes();
        fieldsGeneral = new LinkedHashMap<String, DataComponent>();
        detectorPane = new DetectorComponent(parent, model);
        lightPane = new LightSourceComponent(parent, model);
        unsetGeneral = null;
        unsetGeneralShown = false;
        generalPane = new JPanel();
        generalPane.setBorder(BorderFactory.createTitledBorder("Info"));
        generalPane.setBackground(UIUtilities.BACKGROUND_COLOR);
        generalPane.setLayout(new GridBagLayout());
        exposureTask = EditorUtil.createTaskPane("Exposure Time");
        exposureTask.addPropertyChangeListener(this);
    }

    /** Shows or hides the unset fields. */
    private void displayUnsetGeneralFields() {
        unsetGeneralShown = !unsetGeneralShown;
        String s = AcquisitionDataUI.SHOW_UNSET;
        if (unsetGeneralShown)
            s = AcquisitionDataUI.HIDE_UNSET;
        unsetGeneral.setText(s);
        parent.layoutFields(generalPane, unsetGeneral, fieldsGeneral, unsetGeneralShown);
    }

    /**
     * Transforms the detector metadata.
     * 
     * @param details The value to transform.
     */
    private void transformGeneralSource(Map<String, Object> details) {
        DataComponent comp;
        JLabel label;
        JComponent area;
        String key;
        Object value;
        label = new JLabel();
        Font font = label.getFont();
        int sizeLabel = font.getSize() - 2;
        Object selected;
        List notSet = (List) details.get(EditorUtil.NOT_SET);
        details.remove(EditorUtil.NOT_SET);
        if (notSet.size() > 0 && unsetGeneral == null) {
            unsetGeneral = parent.formatUnsetFieldsControl();
            unsetGeneral.setActionID(GENERAL);
            unsetGeneral.addPropertyChangeListener(this);
        }

        Set entrySet = details.entrySet();
        Entry entry;
        Iterator i = entrySet.iterator();
        boolean set;
        while (i.hasNext()) {
            entry = (Entry) i.next();
            key = (String) entry.getKey();
            set = !notSet.contains(key);
            value = entry.getValue();
            label = UIUtilities.setTextFont(key, Font.BOLD, sizeLabel);
            label.setBackground(UIUtilities.BACKGROUND_COLOR);
            if (EditorUtil.ILLUMINATION.equals(key)) {
                selected = model.getChannelEnumerationSelected(Editor.ILLUMINATION_TYPE, (String) value);
                if (selected != null)
                    illuminationBox.setSelectedItem(selected);
                else {
                    set = false;
                    illuminationBox.setSelectedIndex(illuminationBox.getItemCount() - 1);
                }

                illuminationBox.setEditedColor(UIUtilities.EDITED_COLOR);
                area = illuminationBox;//parent.replaceCombobox(illuminationBox);
            } else if (EditorUtil.CONTRAST_METHOD.equals(key)) {
                selected = model.getChannelEnumerationSelected(Editor.ILLUMINATION_TYPE, (String) value);
                if (selected != null)
                    contrastMethodBox.setSelectedItem(selected);
                else {
                    set = false;
                    contrastMethodBox.setSelectedIndex(contrastMethodBox.getItemCount() - 1);
                }

                contrastMethodBox.setEditedColor(UIUtilities.EDITED_COLOR);
                area = contrastMethodBox;//parent.replaceCombobox(contrastMethodBox);
            } else if (EditorUtil.MODE.equals(key)) {
                selected = model.getChannelEnumerationSelected(Editor.MODE, (String) value);
                if (selected != null)
                    modeBox.setSelectedItem(selected);
                else {
                    set = false;
                    modeBox.setSelectedIndex(modeBox.getItemCount() - 1);
                }
                modeBox.setEditedColor(UIUtilities.EDITED_COLOR);
                area = modeBox;//parent.replaceCombobox(modeBox);
            } else {
                if (value instanceof Number) {
                    area = UIUtilities.createComponent(NumericalTextField.class, null);
                    String v = "";
                    if (value instanceof Double) {
                        v = "" + UIUtilities.roundTwoDecimals(((Number) value).doubleValue());
                        ((NumericalTextField) area).setNumberType(Double.class);
                    } else if (value instanceof Float) {
                        v = "" + UIUtilities.roundTwoDecimals(((Number) value).doubleValue());
                        ((NumericalTextField) area).setNumberType(Float.class);
                    } else
                        v = "" + value;
                    ((NumericalTextField) area).setText(v);
                    ((NumericalTextField) area).setEditedColor(UIUtilities.EDITED_COLOR);
                } else {
                    area = UIUtilities.createComponent(OMETextArea.class, null);
                    if (value == null || value.equals("")) {
                        set = false;
                        value = AnnotationUI.DEFAULT_TEXT;
                    }
                    ((OMETextArea) area).setEditable(false);
                    ((OMETextArea) area).setText((String) value);
                    ((OMETextArea) area).setEditedColor(UIUtilities.EDITED_COLOR);
                }
            }
            area.setEnabled(!set);
            comp = new DataComponent(label, area);
            comp.setEnabled(false);
            comp.setSetField(!notSet.contains(key));
            fieldsGeneral.put(key, comp);
        }
    }

    /** Builds and lays out the UI. */
    private void buildGUI() {
        setBackground(UIUtilities.BACKGROUND_COLOR);
        parent.layoutFields(generalPane, unsetGeneral, fieldsGeneral, unsetGeneralShown);

        setLayout(new GridBagLayout());
        GridBagConstraints constraints = new GridBagConstraints();
        constraints.fill = GridBagConstraints.BOTH;
        constraints.anchor = GridBagConstraints.WEST;
        constraints.insets = new Insets(0, 2, 2, 0);
        constraints.weightx = 1.0;
        constraints.gridy = 0;
        if (generalPane.isVisible()) {
            add(generalPane, constraints);
            ++constraints.gridy;
        }
        if (detectorPane.isVisible()) {
            add(detectorPane, constraints);
            ++constraints.gridy;
        }
        if (lightPane.isVisible()) {
            add(lightPane, constraints);
            ++constraints.gridy;
        }
        if (lightPathPane != null) {
            add(lightPathPane, constraints);
            ++constraints.gridy;
        }
        if (filterSetPane != null) {
            add(filterSetPane, constraints);
            ++constraints.gridy;
        }
        constraints.fill = GridBagConstraints.HORIZONTAL;
        add(exposureTask, constraints);
        parent.attachListener(fieldsGeneral);
    }

    /**
     * Creates a new instance.
     * 
     * @param parent   Reference to the Parent. Mustn't be <code>null</code>.
     * @param model      Reference to the Model. Mustn't be <code>null</code>.
     * @param channel    The channel to display. Mustn't be <code>null</code>.
     */
    ChannelAcquisitionComponent(AcquisitionDataUI parent, EditorModel model, ChannelData channel) {
        if (model == null)
            throw new IllegalArgumentException("No model.");
        if (parent == null)
            throw new IllegalArgumentException("No parent.");
        if (channel == null)
            throw new IllegalArgumentException("No channel.");
        this.model = model;
        this.channel = channel;
        this.parent = parent;
        initComponents();
    }

    /**
     * Returns the index of the channel hosted by this component.
     * 
     * @return See above.
     */
    int getChannelIndex() {
        return channel.getIndex();
    }

    /**
     * Sets the color associated to that channel.
     * 
     * @param color The associated color.
     */
    void setChannelColor(Color color) {
        if (color == null)
            return;
        if (icon == null) {
            icon = new ColourIcon(color);
            icon.paintLineBorder(true);
        } else
            icon.setColour(color);
    }

    /** 
     * Returns the color icon associated to the channel or <code>null</code>.
     * 
     * @return
     */
    Icon getIcon() {
        return icon;
    }

    /**
     * Displays the acquisition data for the passed channel.
     * 
     * @param index The index of the channel.
     */
    void setChannelAcquisitionData(int index) {
        if (channel.getIndex() != index)
            return;
        if (!init) {
            init = true;
            resetBoxes();
            removeAll();
            fieldsGeneral.clear();
            ChannelAcquisitionData data = model.getChannelAcquisitionData(channel.getIndex());
            Map<String, Object> details = EditorUtil.transformChannelData(channel);
            List notSet = (List) details.get(EditorUtil.NOT_SET);
            generalPane.setVisible(false);
            if (notSet.size() != EditorUtil.MAX_FIELDS_CHANNEL) {
                transformGeneralSource(details);
                generalPane.setVisible(true);
            }
            //if no detector info: don't display.
            details = EditorUtil.transformDetectorAndSettings(data);
            notSet = (List) details.get(EditorUtil.NOT_SET);
            detectorPane.setVisible(false);
            if (notSet.size() != EditorUtil.MAX_FIELDS_DETECTOR_AND_SETTINGS) {
                detectorPane.displayDetector(details);
                detectorPane.setVisible(true);
            }
            details = EditorUtil.transformLightSourceAndSetting(data);
            String kind = (String) details.get(EditorUtil.LIGHT_TYPE);
            details.remove(EditorUtil.LIGHT_TYPE);
            notSet = (List) details.get(EditorUtil.NOT_SET);
            lightPane.setVisible(false);
            int n = EditorUtil.MAX_FIELDS_LIGHT_AND_SETTINGS;
            if (LightSourceData.LASER.equals(kind))
                n = EditorUtil.MAX_FIELDS_LASER_AND_SETTINGS;

            if (notSet.size() != n) {
                lightPane.displayLightSource(kind, details);
                lightPane.setVisible(true);
            }
            DataObject set = data.getFilterSet();
            if (set != null)
                filterSetPane = new FilterGroupComponent(parent, model, set);
            set = data.getLightPath();
            if (set != null)
                lightPathPane = new FilterGroupComponent(parent, model, set);
            buildGUI();
            //load the exposure time
            exposureTask.setCollapsed(false);
        }
    }

    /**
     * Formats time into a more human readable format
     * 
     * @param tInS
     *            The time in seconds
     * @return See above.
     */
    private String getReadableTime(double tInS) {
        if (tInS == 0.0)
            return "0 s";

        Calendar date = Calendar.getInstance();
        date = DateUtils.truncate(date, Calendar.YEAR);
        date.add(Calendar.MILLISECOND, (int) (tInS * 1000));

        int d, h, m, s;

        if (tInS > (23 * 60 * 60)) {
            date = DateUtils.round(date, Calendar.MINUTE);
            d = date.get(Calendar.DAY_OF_YEAR) - 1;
            h = date.get(Calendar.HOUR_OF_DAY);
            m = date.get(Calendar.MINUTE);
            return d + " d " + h + " h " + (m > 0 ? m + " min " : "");
        } else if (tInS > (59 * 60)) {
            date = DateUtils.round(date, Calendar.MINUTE);
            h = date.get(Calendar.HOUR_OF_DAY);
            m = date.get(Calendar.MINUTE);
            return h + " h " + m + " min";
        } else if (tInS > 59) {
            date = DateUtils.round(date, Calendar.SECOND);
            m = date.get(Calendar.MINUTE);
            s = date.get(Calendar.SECOND);
            return m + " min " + s + " s";
        } else if (tInS > 0.9)
            return sFormat.format(tInS);

        return msFormat.format(tInS * 1000);
    }

    /**
     * Sets the plane info for the specified channel.
     * 
     * @param index  The index of the channel.
     */
    void setPlaneInfo(int index) {
        if (channel.getIndex() != index)
            return;
        Collection result = model.getChannelPlaneInfo(index);
        String[][] values = new String[2][result.size() + 1];
        String[] names = new String[result.size() + 1];
        int i = 0;
        Iterator j = result.iterator();
        PlaneInfo info;
        Map<String, Object> details;
        List<String> notSet;
        names[0] = "t";
        values[0][i] = "Delta T";
        values[1][i] = "Exposure";
        i++;
        while (j.hasNext()) {
            info = (PlaneInfo) j.next();
            details = EditorUtil.transformPlaneInfo(info);
            notSet = (List<String>) details.get(EditorUtil.NOT_SET);
            if (!notSet.contains(EditorUtil.DELTA_T)) {
                if (details.get(EditorUtil.DELTA_T) instanceof BigResult) {
                    MetadataViewerAgent.logBigResultExeption(this, details.get(EditorUtil.DELTA_T),
                            EditorUtil.DELTA_T);
                    values[0][i] = "N/A";
                } else {
                    double tInS = ((Double) details.get(EditorUtil.DELTA_T));
                    values[0][i] = getReadableTime(tInS);
                }
            } else
                values[0][i] = "--";

            if (!notSet.contains(EditorUtil.EXPOSURE_TIME)) {
                if (details.get(EditorUtil.EXPOSURE_TIME) instanceof BigResult) {
                    MetadataViewerAgent.logBigResultExeption(this, details.get(EditorUtil.EXPOSURE_TIME),
                            EditorUtil.EXPOSURE_TIME);
                    values[1][i] = "N/A";
                } else {
                    double tInS = ((Double) details.get(EditorUtil.EXPOSURE_TIME));
                    values[1][i] = getReadableTime(tInS);
                }
            } else
                values[1][i] = "--";
            names[i] = "t=" + i;
            i++;
        }
        if (i > 1) {
            JTable table = new JTable(values, names);
            table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
            table.setShowGrid(true);
            table.setGridColor(Color.LIGHT_GRAY);
            JScrollPane pane = new JScrollPane(table);
            Dimension d = table.getPreferredSize();
            Dimension de = exposureTask.getPreferredSize();
            pane.setPreferredSize(new Dimension(de.width - 10, 4 * d.height));
            exposureTask.add(pane);
            exposureTask.setVisible(true);
        } else {
            exposureTask.setVisible(false);
        }
    }

    /**
     * Returns <code>true</code> if data to save, <code>false</code>
     * otherwise.
     * 
     * @return See above.
     */
    boolean hasDataToSave() {
        boolean b = parent.hasDataToSave(fieldsGeneral);
        if (b)
            return true;
        b = detectorPane.hasDataToSave();
        if (b)
            return true;
        b = lightPane.hasDataToSave();
        if (b)
            return true;
        if (lightPathPane != null) {
            b = lightPathPane.hasDataToSave();
            if (b)
                return true;
        }
        if (filterSetPane != null) {
            b = filterSetPane.hasDataToSave();
            if (b)
                return true;
        }
        return false;
    }

    /**
     * Prepares the data to save.
     * 
     * @return See above.
     */
    List<Object> prepareDataToSave() {
        List<Object> data = new ArrayList<Object>();
        if (!hasDataToSave())
            return data;
        String key;
        DataComponent comp;
        Object value;
        EnumerationObject enumObject;
        Number number;
        Iterator i;
        Entry entry;
        if (channel.isDirty()) {
            i = fieldsGeneral.entrySet().iterator();
            while (i.hasNext()) {
                entry = (Entry) i.next();
                key = (String) entry.getKey();
                comp = (DataComponent) entry.getValue();
                if (comp.isDirty()) {
                    value = comp.getAreaValue();
                    if (EditorUtil.NAME.equals(key)) {
                        channel.setName((String) value);
                    } else if (EditorUtil.PIN_HOLE_SIZE.equals(key)) {
                        number = UIUtilities.extractNumber((String) value, Float.class);
                        if (number != null)
                            channel.setPinholeSize(new LengthI((Float) number, UnitsFactory.Channel_PinholeSize));
                    } else if (EditorUtil.ND_FILTER.equals(key)) {
                        number = UIUtilities.extractNumber((String) value, Float.class);
                        if (number != null)
                            channel.setNDFilter((Float) number);
                    } else if (EditorUtil.POCKEL_CELL.equals(key)) {
                        number = UIUtilities.extractNumber((String) value, Integer.class);
                        if (number != null)
                            channel.setPockelCell((Integer) value);
                    } else if (EditorUtil.EMISSION.equals(key)) {
                        number = UIUtilities.extractNumber((String) value, Double.class);
                        if (number != null)
                            channel.setEmissionWavelength(
                                    new LengthI((Double) number, UnitsFactory.Channel_EmissionWavelength));
                    } else if (EditorUtil.EXCITATION.equals(key)) {
                        number = UIUtilities.extractNumber((String) value, Double.class);
                        if (number != null)
                            channel.setExcitationWavelength(
                                    new LengthI((Double) number, UnitsFactory.Channel_ExcitationWavelength));
                    } else if (EditorUtil.ILLUMINATION.equals(key)) {
                        enumObject = (EnumerationObject) value;
                        if (enumObject.getObject() instanceof Illumination)
                            channel.setIllumination((Illumination) enumObject.getObject());
                    } else if (EditorUtil.MODE.equals(key)) {
                        enumObject = (EnumerationObject) value;
                        if (enumObject.getObject() instanceof AcquisitionMode)
                            channel.setMode((AcquisitionMode) enumObject.getObject());
                    } else if (EditorUtil.CONTRAST_METHOD.equals(key)) {
                        enumObject = (EnumerationObject) value;
                        if (enumObject.getObject() instanceof ContrastMethod)
                            channel.setContrastMethod((ContrastMethod) enumObject.getObject());
                    }
                }
            }
            data.add(channel);
        }
        return data;
    }

    /**
     * Reacts to property fired by the <code>JLabelButton</code>.
     * @see PropertyChangeListener#propertyChange(PropertyChangeEvent)
     */
    public void propertyChange(PropertyChangeEvent evt) {
        String name = evt.getPropertyName();
        if (JLabelButton.SELECTED_PROPERTY.equals(name)) {
            displayUnsetGeneralFields();
        } else if (UIUtilities.COLLAPSED_PROPERTY_JXTASKPANE.equals(name)) {
            parent.loadPlaneInfo(channel.getIndex());
        }
    }

}