/* *------------------------------------------------------------------------------ * 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.util; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.geom.Rectangle2D; 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.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; import java.util.Map.Entry; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.ButtonGroup; import javax.swing.DefaultComboBoxModel; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JSeparator; import javax.swing.JSpinner; import javax.swing.JTextField; import javax.swing.SpinnerNumberModel; import javax.swing.WindowConstants; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.text.Document; import info.clearthought.layout.TableLayout; import org.jdesktop.swingx.JXBusyLabel; import org.jdesktop.swingx.JXTaskPane; import org.jhotdraw.draw.AttributeKeys; import org.jhotdraw.draw.Drawing; import omero.gateway.model.ROIResult; import omero.model.PlaneInfo; import omero.romio.PlaneDef; import ome.model.units.BigResult; import org.openmicroscopy.shoola.agents.metadata.IconManager; import org.openmicroscopy.shoola.agents.metadata.MetadataViewerAgent; import org.openmicroscopy.shoola.agents.metadata.rnd.Renderer; import org.openmicroscopy.shoola.agents.util.EditorUtil; import org.openmicroscopy.shoola.agents.util.ViewerSorter; import org.openmicroscopy.shoola.agents.util.ui.ChannelButton; import org.openmicroscopy.shoola.agents.util.ui.ScriptingDialog; import org.openmicroscopy.shoola.env.data.model.ProjectionParam; import org.openmicroscopy.shoola.env.data.model.FigureParam; import org.openmicroscopy.shoola.env.rnd.RndProxyDef; import org.openmicroscopy.shoola.util.image.geom.Factory; import org.openmicroscopy.shoola.util.roi.ROIComponent; import org.openmicroscopy.shoola.util.roi.figures.ROIFigure; import org.openmicroscopy.shoola.util.roi.model.ROI; import org.openmicroscopy.shoola.util.roi.model.ROIShape; import org.openmicroscopy.shoola.util.roi.model.util.Coord3D; import org.openmicroscopy.shoola.util.ui.ColorListRenderer; import org.openmicroscopy.shoola.util.ui.NumericalTextField; import org.openmicroscopy.shoola.util.ui.TitlePanel; import org.openmicroscopy.shoola.util.ui.UIUtilities; import org.openmicroscopy.shoola.util.ui.drawingtools.DrawingComponent; import org.openmicroscopy.shoola.util.ui.drawingtools.canvas.DrawingCanvasView; import org.openmicroscopy.shoola.util.ui.lens.LensComponent; import org.openmicroscopy.shoola.util.ui.slider.GridSlider; import org.openmicroscopy.shoola.util.ui.slider.TextualTwoKnobsSlider; import omero.gateway.model.ChannelData; import omero.gateway.model.DatasetData; import omero.gateway.model.ImageData; import omero.gateway.model.PixelsData; import omero.gateway.model.TagAnnotationData; /** * Modal dialog displaying option to create a figure of a collection of * images. * * @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 * @since 3.0-Beta4 */ public class FigureDialog extends JDialog implements ActionListener, ChangeListener, DocumentListener, PropertyChangeListener { /** Indicates that the dialog is for a split view. */ public static final int SPLIT = 0; /** Indicates that the dialog is for a split view and ROI. */ public static final int SPLIT_ROI = 1; /** Indicates that the dialog is for a movie figure. */ public static final int MOVIE = 2; /** Indicates that the dialog is for a thumbnails figure. */ public static final int THUMBNAILS = 3; /** Indicates that the dialog is ROI movie figure. */ public static final int ROI_MOVIE = 4; /** Bound property indicating to create a split view figure. */ public static final String CREATE_FIGURE_PROPERTY = "createFigure"; /** Bound property indicating to close the dialog. */ public static final String CLOSE_FIGURE_PROPERTY = "closeFigure"; /** Action id indicating to close the dialog. */ public static final int CLOSE = 0; /** Action id indicating to create a movie. */ public static final int SAVE = 1; /** Action id indicating to allow the modification of the scale bar. */ private static final int SCALE_BAR = 2; /** Action id indicating to arrange the thumbnails by tags. */ private static final int ARRANGE_BY_TAGS = 3; /** Action id indicating to turn on or off the projection's controls. */ private static final int PROJECTION = 4; /** Action id indicating a change in the magnification factor. */ private static final int ZOOM_FACTOR = 5; /** Action id indicating that the color has changed. */ private static final int COLOR_SELECTION = 7; /** Indicates to download the script. */ private static final int DOWNLOAD = 8; /** Indicates to view the script. */ private static final int VIEW = 9; /** The maximum number of time-points visible at a time. */ private static final int MAX_CELLS = 20; /** The default text for the movie. */ private static final String FRAMES_TEXT = "Number of frames: "; /** The default text for the movie. */ private static final String MAGNIFICATION_TEXT = "Magnification x"; /** Default text describing the compression check box. */ private static final String PROJECTION_DESCRIPTION = "Select the type of projection."; /** The default text of thumbnails per row. */ private static final String ITEMS_PER_ROW_TEXT = "Images per row"; /** The default number of thumbnails per row. */ private static final int ITEMS_PER_ROW = 10; /** The height of the component displaying the available tags. */ private static final int MAX_HEIGHT = 150; /** The stroke width of the ROI displayed on the image. */ private static final double STROKE_WIDTH = 2.5; /** The possible options for row names. */ private static final String[] ROW_NAMES; /** The possible options for row names. */ private static final String[] MAGNIFICATION; /** Index to <code>100%</code> magnification. */ private static final int ZOOM_100 = 0; /** Index to <code>200%</code> magnification. */ private static final int ZOOM_200 = 1; /** Index to <code>300%</code> magnification. */ private static final int ZOOM_300 = 2; /** Index to <code>400%</code> magnification. */ private static final int ZOOM_400 = 3; /** Index to <code>500%</code> magnification. */ private static final int ZOOM_500 = 4; /** Index to <code>Auto</code>. */ private static final int ZOOM_AUTO = 5; /** Index corresponding to a <code>24x24</code> thumbnail. */ private static final int SIZE_24 = 0; /** Index corresponding to a <code>32x32</code> thumbnail. */ private static final int SIZE_32 = 1; /** Index corresponding to a <code>48x48</code> thumbnail. */ private static final int SIZE_48 = 2; /** Index corresponding to a <code>64x64</code> thumbnail. */ private static final int SIZE_64 = 3; /** Index corresponding to a <code>96x96</code> thumbnail. */ private static final int SIZE_96 = 4; /** Index corresponding to a <code>128x128</code> thumbnail. */ private static final int SIZE_128 = 5; /** Index corresponding to a <code>160x160</code> thumbnail. */ private static final int SIZE_160 = 6; /** The size available for thumbnails creation. */ private static final String[] SIZE_OPTIONS; static { ROW_NAMES = new String[3]; ROW_NAMES[FigureParam.IMAGE_NAME] = "Image's name"; ROW_NAMES[FigureParam.DATASET_NAME] = "Datasets"; ROW_NAMES[FigureParam.TAG_NAME] = "Tags"; MAGNIFICATION = new String[6]; MAGNIFICATION[ZOOM_100] = "100%"; MAGNIFICATION[ZOOM_200] = "200%"; MAGNIFICATION[ZOOM_300] = "300%"; MAGNIFICATION[ZOOM_400] = "400%"; MAGNIFICATION[ZOOM_500] = "500%"; MAGNIFICATION[ZOOM_AUTO] = "Zoom To Fit"; SIZE_OPTIONS = new String[7]; SIZE_OPTIONS[SIZE_24] = "24x24"; SIZE_OPTIONS[SIZE_32] = "32x32"; SIZE_OPTIONS[SIZE_48] = "48x48"; SIZE_OPTIONS[SIZE_64] = "64x64"; SIZE_OPTIONS[SIZE_96] = "96x96"; SIZE_OPTIONS[SIZE_128] = "128x128"; SIZE_OPTIONS[SIZE_160] = "160x160"; } /** The name to give to the figure. */ private JTextField nameField; /** Component to select the z-section interval. */ private TextualTwoKnobsSlider zRange; /** Button to close the dialog. */ private JButton closeButton; /** Button to save the result. */ private JButton saveButton; /** The supported movie formats. */ private JComboBox formats; /** The type of supported projections. */ private JComboBox projectionTypesBox; /** The type of supported projections. */ private JRadioButton splitPanelColor; /** The type of supported projections. */ private JRadioButton splitPanelGrey; /** The type of projection. */ private Map<Integer, Integer> projectionTypes; /** Sets the stepping for the mapping. */ private JSpinner projectionFrequency; /** The possible options for naming the rows. */ private JComboBox rowName; /** Components displaying the image. */ private Map<Integer, FigureComponent> components; /** Option chosen by the user. */ private int option; /** Reference to the renderer. */ private Renderer renderer; /** The default plate object. */ private PlaneDef pDef; /** The width of a thumbnail. */ private int thumbnailWidth; /** The height of a thumbnail. */ private int thumbnailHeight; /** The width of the image. */ private NumericalTextField widthField; /** The height of the image. */ private NumericalTextField heightField; /** The supported value of the scale bar. */ private NumericalTextField scaleBar; /** Add a scale bar if selected. */ private JCheckBox showScaleBar; /** The selected color for scale bar. */ private JComboBox colorBox; /** The index of the dialog. One of the constants. */ private int dialogType; /** The pixels set of reference. */ private PixelsData pixels; /** The components hosting the channel components. */ private JXTaskPane channelsPane; /** Component hosting the ROI. */ private ROIComponent roiComponent; /** * The drawing component to create drawing, view and editor and link them. */ private DrawingComponent drawingComponent; /** The size of the thumbnail. */ private Dimension size; /** The magnification factor. */ private JComboBox zoomBox; /** The size of thumbnails. */ private JComboBox sizeBox; /** The number of items. */ private NumericalTextField numberPerRow; /** Indicates to create a figure with the displayed objects. */ private JRadioButton displayedObjects; /** Indicates to create a figure with the selected objects. */ private JRadioButton selectedObjects; /** The type of objects to handle. */ private Class type; /** Indicates to arrange thumbnails by tags. */ private JCheckBox arrangeByTags; /** Indicates to include images w/o tags. */ private JCheckBox includeUntagged; /** * The component displaying the controls to create the thumbnails figure. */ private JPanel thumbnailsPane; /** The map containing the selected tags. */ private Map<JCheckBox, TagAnnotationData> tagsSelection; /** Use to sort data objects.*/ private ViewerSorter sorter; /** The component displaying the collection of selected tags. */ private JPanel selectedTags; /** The selection of tags. */ private List<JCheckBox> selection; /** Determines the time-points frequency for the movie figure. */ private JSpinner movieFrequency; /** The slider displaying the number of time-points. */ private GridSlider movieSlider; /** Indicates to select the last view Z-section. */ private JRadioButton planeSelection; /** Indicates to select project the stack. */ private JRadioButton projectionBox; /** The time of options. */ private JComboBox timesBox; /** Label used to display various info e.g. number of frames for movie. */ private JLabel generalLabel; /** This component is only be used for the Split ROI figure. */ private LensComponent lens; /** The merged image not scaled. */ private BufferedImage mergeUnscaled; /** The ROI box. */ private Rectangle2D roiBox; /** The default figure. */ private FigureComponent mergedComponent; /** Copy of the rendering definition. */ private RndProxyDef rndDef; /** The ROIs currently displayed on the image. */ private List<ROI> displayedROIs; /** The original scaling factor for the ROI. */ private double scalingFactor; /** The menu offering various options to manipulate the script. */ private JPopupMenu optionMenu; /** Menu offering the ability to download or view the script. */ private JButton menuButton; /** * Turns off controls if the binary data are not available. */ private void checkBinaryAvailability() { if (!MetadataViewerAgent.isBinaryAvailable()) saveButton.setEnabled(false); } /** * Creates the option menu. * * @return See above. */ private JPopupMenu createOptionMenu() { if (optionMenu != null) return optionMenu; optionMenu = new JPopupMenu(); optionMenu.add(createMenuItem("Download", DOWNLOAD)); optionMenu.add(createMenuItem("View", VIEW)); return optionMenu; } /** * Creates a menu item. * * @param text The text of the button. * @param actionID The action command id. * @return See above. */ private JMenuItem createMenuItem(String text, int actionID) { JMenuItem b = new JMenuItem(text); b.setActionCommand(""+actionID); b.addActionListener(this); return b; } /** * Returns the selected color or <code>null</code>. * * @return See above. */ private String getSelectedColor() { int index = colorBox.getSelectedIndex(); Map<Color, String> m = EditorUtil.COLORS_BAR; Iterator<Entry<Color, String>> i = m.entrySet().iterator(); int j = 0; Entry<Color, String> entry; while (i.hasNext()) { entry = i.next(); if (j == index) return entry.getValue(); j++; } return null; } /** * Returns the selected color or <code>null</code>. * * @return See above. */ private Color getColor() { int index = colorBox.getSelectedIndex(); Map<Color, String> m = EditorUtil.COLORS_BAR; Iterator<Entry<Color, String>> i = m.entrySet().iterator(); int j = 0; Entry<Color, String> entry; while (i.hasNext()) { entry = i.next(); if (j == index) return entry.getKey(); j++; } return null; } /** Modifies the color of the ROIs. */ private void modifyROIDisplay() { if (displayedROIs == null) return; Color c = getColor(); if (c == null) return; Entry<Coord3D, ROIShape> entry; Iterator<ROI> ro; TreeMap<Coord3D, ROIShape> shapes; Iterator<Entry<Coord3D, ROIShape>> k; ROIShape shape; ROI roi; ROIFigure fig; ro = displayedROIs.iterator(); while (ro.hasNext()) { roi = (ROI) ro.next(); shapes = roi.getShapes(); k = shapes.entrySet().iterator(); while (k.hasNext()) { entry = k.next(); shape = entry.getValue(); fig = shape.getFigure(); AttributeKeys.STROKE_WIDTH.set(fig, STROKE_WIDTH); AttributeKeys.STROKE_COLOR.set(fig, c); } } } /** Displays the magnification factor. */ private void setFactor() { int v = zoomBox.getSelectedIndex(); if (v == ZOOM_AUTO) { int h = (Integer) heightField.getValueAsNumber(); float f = (float) h/(float) roiBox.getHeight(); float ff = (float) (Math.round(f*100)/100.0); lens.setZoomFactor(ff); generalLabel.setText(MAGNIFICATION_TEXT+ff); } else { v++; generalLabel.setText(MAGNIFICATION_TEXT+v); lens.setZoomFactor(v); } } /** Modifies the lens factor. */ private void setLensFactor() { setFactor(); //reset Iterator<Entry<Integer, FigureComponent>> k = components.entrySet().iterator(); Entry<Integer, FigureComponent> entry; FigureComponent fc; int j; List<Integer> active = renderer.getActiveChannels(); int w, h; BufferedImage img; while (k.hasNext()) { entry = k.next(); j = entry.getKey(); fc = entry.getValue(); lens.setPlaneImage(renderer.createSingleChannelImage(true, j, pDef)); img = lens.getZoomedImage(); if (img != null) { w = img.getWidth()*size.width/pixels.getSizeX(); h = img.getHeight()*size.height/pixels.getSizeY(); if (w != 0 && h != 0) { fc.setOriginalImage(Factory.scaleBufferedImage(img, w, h)); fc.setCanvasSize(w, h); fc.revalidate(); if (!active.contains(j)) fc.resetImage(true); } } } } /** * Lays out the selected tags. * * @param selectedTag Control to select or not the tags. */ private void layoutSelectedTags(JCheckBox selectedTag) { selectedTags.removeAll(); if (selection == null) selection = new ArrayList<JCheckBox>(); if (selection.contains(selectedTag)) selection.remove(selectedTag); else selection.add(selectedTag); Iterator<JCheckBox> i = selection.iterator(); JCheckBox box; int index = 1; JLabel label; TagAnnotationData tag; while (i.hasNext()) { box = i.next(); label = new JLabel(); tag = tagsSelection.get(box); label.setText(index+". "+tag.getTagValue()); selectedTags.add(label); index++; } selectedTags.revalidate(); selectedTags.repaint(); } /** * Returns the merged image. * * @return See above. */ private BufferedImage getMergedImage() { mergeUnscaled = renderer.renderPlane(pDef); return scaleImage(mergeUnscaled); } /** * Scales the passed image. * * @param image The image to scale down. * @return See above. */ private BufferedImage scaleImage(BufferedImage image) { return Factory.scaleBufferedImage(image, size.width, size.height); } /** * Returns the image corresponding to the passed index. * * @param index The index of the channel. * @param scale Pass <code>true</code> to scale down the image, * <code>false</code> otherwise. * @return See above. */ private BufferedImage getChannelImage(int index, boolean scale) { //merge image is RGB if (renderer.isChannelActive(index)) { if (renderer.isMappedImageRGB(renderer.getActiveChannels())) { //if red DataBuffer buf = null; if (!scale) buf = mergeUnscaled.getRaster().getDataBuffer(); else { BufferedImage image = mergedComponent.getDisplayedImage(); if (image != null) buf = image.getRaster().getDataBuffer(); } if (buf == null) return scaleImage(renderer.createSingleChannelImage(true, index, pDef)); if (renderer.isColorComponent(Renderer.RED_BAND, index)) { if (!scale) return Factory.createBandImage(buf, mergeUnscaled.getWidth(), mergeUnscaled.getHeight(), Factory.RED_MASK, Factory.BLANK_MASK, Factory.BLANK_MASK); return Factory.createBandImage(buf, size.width, size.height, Factory.RED_MASK, Factory.BLANK_MASK, Factory.BLANK_MASK); } else if (renderer.isColorComponent(Renderer.GREEN_BAND, index)) { if (!scale) return Factory.createBandImage(buf, mergeUnscaled.getWidth(), mergeUnscaled.getHeight(), Factory.BLANK_MASK, Factory.GREEN_MASK, Factory.BLANK_MASK); return Factory.createBandImage(buf, size.width, size.height, Factory.BLANK_MASK, Factory.GREEN_MASK, Factory.BLANK_MASK); } else if (renderer.isColorComponent(Renderer.BLUE_BAND, index)) { if (!scale) return Factory.createBandImage(buf, mergeUnscaled.getWidth(), mergeUnscaled.getHeight(), Factory.BLANK_MASK, Factory.BLANK_MASK, Factory.BLUE_MASK); return Factory.createBandImage(buf, size.width, size.height, Factory.BLANK_MASK, Factory.BLANK_MASK, Factory.BLUE_MASK); } } else { //not rgb if (!scale) renderer.createSingleChannelImage(true, index, pDef); return scaleImage(renderer.createSingleChannelImage(true, index, pDef)); } } //turn off all other channels, create an image and reset channels if (!scale) return renderer.createSingleChannelImage(true, index, pDef); return scaleImage(renderer.createSingleChannelImage(true, index, pDef)); } /** Initializes the components. */ private void initialize() { size = Factory.computeThumbnailSize(thumbnailWidth, thumbnailHeight, pixels.getSizeX(), pixels.getSizeY()); if (pDef == null) initPlane(renderer.getDefaultZ(), renderer.getDefaultT()); } /** * Returns the magnification factor. * * @return See above. */ private double getMagnificationFactor() { int maxY = pixels.getSizeY(); int maxX = pixels.getSizeX(); if (maxX > thumbnailWidth || maxY >thumbnailHeight) { double ratioX = (double) thumbnailWidth/maxX; double ratioY = (double) thumbnailHeight/maxY; if (ratioX < ratioY) return ratioX; return ratioY; } return -1; } /** Initializes the channels components. */ private void initChannelComponents() { initialize(); components = new LinkedHashMap<Integer, FigureComponent>(); if (dialogType == SPLIT_ROI) { initChannelComponentsForROI(); return; } List<ChannelData> data = renderer.getChannelData(); List<Integer> active = renderer.getActiveChannels(); Iterator<ChannelData> k = data.iterator(); List<ChannelButton> buttons = new ArrayList<ChannelButton>(); ChannelButton comp; int j; ChannelData d; while (k.hasNext()) { d = k.next(); j = d.getIndex(); comp = new ChannelButton("", renderer.getChannelColor(j), j, active.contains(j)); comp.setPreferredSize(FigureComponent.DEFAULT_SIZE); buttons.add(comp); comp.addPropertyChangeListener(this); } mergedComponent = new FigureComponent(this, buttons); mergedComponent.setCanvasSize(thumbnailWidth, thumbnailHeight); mergedComponent.setOriginalImage(getMergedImage()); //Initializes the channels k = data.iterator(); FigureComponent split; while (k.hasNext()) { d = k.next(); j = d.getIndex(); split = new FigureComponent(this, renderer.getChannelColor(j), d.getChannelLabeling(), j); //split.setSelected(active.contains(j)); split.setSelected(true); split.setOriginalImage(getChannelImage(j, true)); split.setCanvasSize(thumbnailWidth, thumbnailHeight); if (!active.contains(j)) split.resetImage(true); components.put(j, split); } } /** Initializes the components for the ROI. */ private void initChannelComponentsForROI() { zoomBox = new JComboBox(MAGNIFICATION); zoomBox.setActionCommand(""+ZOOM_FACTOR); zoomBox.addActionListener(this); DrawingCanvasView canvasView = drawingComponent.getDrawingView(); scalingFactor = getMagnificationFactor(); if (scalingFactor != -1) canvasView.setScaleFactor(scalingFactor); try { Drawing drawing = drawingComponent.getDrawing(); Coord3D c; TreeMap<Long, ROI> map = roiComponent.getROIMap(); if (map != null && map.size() > 0) { Iterator<ROI> i = map.values().iterator(); ROI roi; TreeMap<Coord3D, ROIShape> shapesMap; ROIShape shape; Iterator<Entry<Coord3D, ROIShape>> j; Entry<Coord3D, ROIShape> entry; while (i.hasNext()) { roi = i.next(); shapesMap = roi.getShapes(); j = shapesMap.entrySet().iterator(); while (j.hasNext()) { entry = j.next(); c = entry.getKey(); shape = entry.getValue(); if (shape != null) { if (roiBox == null) { roiBox = shape.getBoundingBox(); drawing.add(shape.getFigure()); initPlane(c.getZSection(), c.getTimePoint()); } } } } } int rw = (int) roiBox.getWidth(); int rh = (int) roiBox.getHeight(); lens = new LensComponent((JFrame) getOwner(), rw, rh); lens.setLensLocation((int) roiBox.getX(), (int) roiBox.getY()); setFactor(); canvasView.setDrawing(drawing); } catch (Exception e) { } List<Integer> active = renderer.getActiveChannels(); List<ChannelData> data = renderer.getChannelData(); ChannelData d; Iterator<ChannelData> k = data.iterator(); List<ChannelButton> buttons = new ArrayList<ChannelButton>(); ChannelButton comp; int j; while (k.hasNext()) { d = k.next(); j = d.getIndex(); comp = new ChannelButton("", renderer.getChannelColor(j), j, active.contains(j)); comp.setPreferredSize(FigureComponent.DEFAULT_SIZE); buttons.add(comp); comp.addPropertyChangeListener(this); } mergedComponent = new FigureComponent(this, buttons); mergedComponent.setCanvasSize(thumbnailWidth, thumbnailHeight); mergedComponent.setOriginalImage(getMergedImage()); //Add the view to the canvas. mergedComponent.addToView(canvasView); //Initializes the channels k = data.iterator(); FigureComponent split; BufferedImage img; int w = (int) roiBox.getWidth()*size.width/pixels.getSizeX(); int h = (int) roiBox.getHeight()*size.height/pixels.getSizeY(); while (k.hasNext()) { d = k.next(); j = d.getIndex(); split = new FigureComponent(this, renderer.getChannelColor(j), d.getChannelLabeling(), j); split.setSelected(true); lens.setPlaneImage( renderer.createSingleChannelImage(true, j, pDef)); img = lens.getZoomedImage(); if (img != null) { w = img.getWidth()*size.width/pixels.getSizeX(); h = img.getHeight()*size.height/pixels.getSizeY(); img = Factory.scaleBufferedImage(img, w, h); if (img != null) { w = img.getWidth(); h = img.getHeight(); split.setOriginalImage(img); split.setCanvasSize(w, h); } if (!active.contains(j)) split.resetImage(true); } components.put(j, split); } } /** * Initializes the plane. * * @param z The selected z-section. * @param t The selected time-point. */ private void initPlane(int z, int t) { pDef = new PlaneDef(); pDef.t = t; pDef.z = z; pDef.slice = omero.romio.XY.value; } /** * Initializes the components composing the display. * * @param name The default name of the file. */ private void initComponents(String name) { IconManager icons = IconManager.getInstance(); menuButton = new JButton(icons.getIcon(IconManager.BLACK_ARROW_DOWN)); menuButton.setText("Script"); menuButton.setHorizontalTextPosition(JButton.LEFT); menuButton.addMouseListener(new MouseAdapter() { public void mouseReleased(MouseEvent e) { Object src = e.getSource(); if (src instanceof Component) { Point p = e.getPoint(); createOptionMenu().show((Component) src, p.x, p.y); } } }); sorter = new ViewerSorter(); closeButton = new JButton("Cancel"); closeButton.setToolTipText(UIUtilities.formatToolTipText( "Close the window.")); closeButton.setActionCommand(""+CLOSE); closeButton.addActionListener(this); saveButton = new JButton("Create"); saveButton.setEnabled(false); saveButton.setToolTipText(UIUtilities.formatToolTipText( "Create a figure.")); saveButton.setActionCommand(""+SAVE); saveButton.addActionListener(this); nameField = new JTextField(); String s = UIUtilities.removeFileExtension(name); if (s != null) { nameField.setText(s); saveButton.setEnabled(true); checkBinaryAvailability(); } nameField.getDocument().addDocumentListener(this); Map<Integer, String> map = FigureParam.FORMATS; String[] f = new String[map.size()]; Entry<Integer, String> entry; Iterator<Entry<Integer, String>> i = map.entrySet().iterator(); int index = 0; int v; while (i.hasNext()) { entry = i.next(); v = entry.getKey(); f[v] = entry.getValue(); if (v == FigureParam.DEFAULT_FORMAT) index = v; } formats = new JComboBox(f); formats.setSelectedIndex(index); showScaleBar = new JCheckBox("Scale Bar"); showScaleBar.setFont(showScaleBar.getFont().deriveFont(Font.BOLD)); showScaleBar.setActionCommand(""+SCALE_BAR); showScaleBar.addActionListener(this); scaleBar = new NumericalTextField(); scaleBar.setText(""+EditorUtil.DEFAULT_SCALE); colorBox = new JComboBox(); Map<Color, String> colors = EditorUtil.COLORS_BAR; Object[][] cols = new Object[colors.size()][2]; int k = 0; Iterator<Entry<Color, String>> j = colors.entrySet().iterator(); Entry<Color, String> e; while (j.hasNext()) { e = j.next(); cols[k] = new Object[]{e.getKey(), e.getValue()}; k++; } colorBox.setModel(new DefaultComboBoxModel(cols)); colorBox.setSelectedIndex(cols.length-1); colorBox.setRenderer(new ColorListRenderer()); colorBox.setActionCommand(""+COLOR_SELECTION); colorBox.addActionListener(this); showScaleBar.setSelected(false); scaleBar.setEnabled(false); setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { close(); } }); rowName = new JComboBox(ROW_NAMES); ButtonGroup optionsGroups = new ButtonGroup(); displayedObjects = new JRadioButton("Displayed Images"); selectedObjects = new JRadioButton("Selected Images"); optionsGroups.add(displayedObjects); optionsGroups.add(selectedObjects); selectedObjects.setSelected(true); if (dialogType == THUMBNAILS) { includeUntagged = new JCheckBox("Include all thumbnails"); includeUntagged.setToolTipText("Include all remaining thumbnails " + "not selected by Tags."); includeUntagged.setHorizontalTextPosition(JCheckBox.LEFT); includeUntagged.setFont( includeUntagged.getFont().deriveFont(Font.BOLD)); arrangeByTags = new JCheckBox("Select by Tag"); arrangeByTags.setToolTipText("Arrange the thumbnails by Tags"); arrangeByTags.setHorizontalTextPosition(JCheckBox.LEFT); arrangeByTags.setFont( arrangeByTags.getFont().deriveFont(Font.BOLD)); arrangeByTags.addActionListener(this); arrangeByTags.setActionCommand(""+ARRANGE_BY_TAGS); sizeBox = new JComboBox(SIZE_OPTIONS); sizeBox.setSelectedIndex(SIZE_96); numberPerRow = new NumericalTextField(1, 100); numberPerRow.setColumns(3); numberPerRow.setText(""+ITEMS_PER_ROW); return; } numberPerRow = new NumericalTextField(1, 100); numberPerRow.setColumns(3); numberPerRow.setText(""+ITEMS_PER_ROW); projectionBox = new JRadioButton("Z-projection"); projectionBox.addChangeListener(this); planeSelection = new JRadioButton("Last-viewed Z-section"); planeSelection.addChangeListener(this); planeSelection.setSelected(true); ButtonGroup group = new ButtonGroup(); group.add(projectionBox); group.add(planeSelection); thumbnailHeight = Factory.THUMB_DEFAULT_HEIGHT; thumbnailWidth = Factory.THUMB_DEFAULT_WIDTH; int maxZ = pixels.getSizeZ(); zRange = new TextualTwoKnobsSlider(1, maxZ, 1, maxZ); zRange.layoutComponents(); zRange.setEnabled(maxZ > 1); String[] names = new String[ProjectionParam.PROJECTIONS.size()]; k = 0; i = ProjectionParam.PROJECTIONS.entrySet().iterator(); projectionTypes = new HashMap<Integer, Integer>(); while (i.hasNext()) { entry = i.next(); projectionTypes.put(k, entry.getKey()); names[k] = (String) entry.getValue(); k++; } projectionTypesBox = new JComboBox(names); projectionTypesBox.setToolTipText(PROJECTION_DESCRIPTION); projectionFrequency = new JSpinner(new SpinnerNumberModel(1, 1, maxZ+1, 1)); ButtonGroup g = new ButtonGroup(); splitPanelGrey = new JRadioButton("Grey"); splitPanelColor = new JRadioButton("Color"); splitPanelColor.addChangeListener(this); splitPanelGrey.addChangeListener(this); g.add(splitPanelGrey); g.add(splitPanelColor); splitPanelColor.setSelected(true); int maxT = pixels.getSizeT(); movieFrequency = new JSpinner(new SpinnerNumberModel(1, 1, maxT+1, 1)); movieFrequency.addChangeListener(this); widthField = new NumericalTextField(0, pixels.getSizeX()); widthField.setColumns(5); widthField.setText(""+pixels.getSizeX()); heightField = new NumericalTextField(0, pixels.getSizeY()); heightField.setColumns(5); heightField.setText(""+pixels.getSizeY()); widthField.getDocument().addDocumentListener(this); heightField.getDocument().addDocumentListener(this); movieSlider = new GridSlider(maxT, 1); movieSlider.addPropertyChangeListener( GridSlider.COLUMN_SELECTION_PROPERTY, this); setProjectionSelected(false); map = FigureParam.TIMES; f = new String[map.size()]; i = map.entrySet().iterator(); while (i.hasNext()) { entry = i.next(); f[entry.getKey()] = (String) entry.getValue(); } timesBox = new JComboBox(f); switch (dialogType) { case MOVIE: generalLabel = new JLabel(FRAMES_TEXT+maxT+"/"+maxT); break; case SPLIT_ROI: generalLabel = new JLabel(MAGNIFICATION_TEXT); break; default: generalLabel = new JLabel(); } } /** Builds and lays out the UI. */ private void buildGUI() { IconManager icons = IconManager.getInstance(); TitlePanel tp; String text = null; switch (dialogType) { case THUMBNAILS: text = "Create a thumbnail Figure."; break; case SPLIT: case SPLIT_ROI: text = "Create a Split View Figure."; break; case MOVIE: text = "Create a Movie Figure."; } tp = new TitlePanel("Create Figure", text, "The figure will be saved to the server.", icons.getIcon(IconManager.SPLIT_VIEW_48)); Container c = getContentPane(); c.setLayout(new BorderLayout(5, 5)); c.add(tp, BorderLayout.NORTH); c.add(buildBody(), BorderLayout.CENTER); c.add(buildToolBar(), BorderLayout.SOUTH); } /** * Builds and lays out the control. * * @return See above. */ private JPanel buildToolBar() { JPanel bar = new JPanel(); bar.add(closeButton); bar.add(Box.createHorizontalStrut(5)); bar.add(saveButton); bar.add(Box.createHorizontalStrut(20)); JPanel all = new JPanel(); all.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY)); all.setLayout(new BoxLayout(all, BoxLayout.X_AXIS)); all.add(UIUtilities.buildComponentPanel(menuButton)); all.add(UIUtilities.buildComponentPanelRight(bar)); return all; } /** * Builds and lays out the components displaying the dimensions. * * @return See above. */ private JPanel buildDimensionComponent() { JPanel p = new JPanel(); p.setLayout(new GridBagLayout()); GridBagConstraints c = new GridBagConstraints(); c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.WEST; c.gridy = 0; c.gridx = 0; c.weightx = 0.0; p.add(UIUtilities.setTextFont("Panel Width: "), c); c.gridx++; p.add(Box.createHorizontalStrut(5), c); c.gridx++; p.add(widthField, c); c.gridx++; p.add(new JLabel("pixels"), c); c.gridx = 0; c.gridy++; p.add(UIUtilities.setTextFont("Panel Height: "), c); c.gridx++; p.add(Box.createHorizontalStrut(5), c); c.gridx++; p.add(heightField, c); c.gridx++; p.add(new JLabel("pixels"), c); return UIUtilities.buildComponentPanel(p); } /** * Enables or not the projection controls. * * @param selected Pass <code>true</code> to enable the controls, * <code>false</code> otherwise. */ private void setProjectionSelected(boolean selected) { projectionTypesBox.setEnabled(selected); projectionFrequency.setEnabled(selected); zRange.setEnabled(selected); planeSelection.setEnabled(!selected); } /** * Builds the projection component. * * @return See above. */ private JPanel buildProjectionComponent() { JPanel p = new JPanel(); p.setLayout(new GridBagLayout()); GridBagConstraints c = new GridBagConstraints(); c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.WEST; c.insets = new Insets(0, 2, 2, 0); c.gridy = 0; c.gridx = 0; c.gridwidth = 2; JPanel content = new JPanel(); content.add(planeSelection); content.add(projectionBox); p.add(UIUtilities.buildComponentPanel(content, 0, 0), c); c.gridy++; c.gridx = 0; c.gridwidth = 1; p.add(UIUtilities.setTextFont("Intensity"), c); c.gridx++; p.add(projectionTypesBox, c); c.gridx = 0; c.gridy++; p.add(UIUtilities.setTextFont("Every n-th slice"), c); c.gridx++; p.add(UIUtilities.buildComponentPanel(projectionFrequency), c); c.gridy++; c.gridx = 0; p.add(UIUtilities.setTextFont("Z-sections Range"), c); c.gridx++; p.add(UIUtilities.buildComponentPanel(zRange), c); return UIUtilities.buildComponentPanel(p); } /** Invokes when the projection is selected or not. */ private void onProjectionSelectionChanged() { boolean b = projectionBox.isSelected(); if (projectionTypesBox != null) projectionTypesBox.setEnabled(b); if (projectionFrequency != null) projectionFrequency.setEnabled(b); if (zRange != null) zRange.setEnabled(b); } /** * Builds the component offering name and formats options. * * @return See above. */ private JPanel buildTypeComponent() { JPanel p = new JPanel(); double[][] tl = {{TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.FILL}, //columns {TableLayout.PREFERRED, 5, TableLayout.PREFERRED, 5, TableLayout.PREFERRED, 5, TableLayout.PREFERRED, 5, TableLayout.PREFERRED, 5, TableLayout.PREFERRED, 5, TableLayout.PREFERRED, 5, TableLayout.PREFERRED}}; //rows p.setLayout(new TableLayout(tl)); int i = 0; p.add(UIUtilities.setTextFont("Name"), "0, "+i+""); p.add(nameField, "1, "+i+", 4, "+i); i = i+2; p.add(UIUtilities.setTextFont("Format"), "0, "+i+""); p.add(formats, "1, "+i); if (dialogType == THUMBNAILS) { i = i+2; p.add(UIUtilities.setTextFont("Thumbnails Size"), "0, "+i+""); p.add(UIUtilities.buildComponentPanel(sizeBox), "1, "+i); i = i+2; p.add(UIUtilities.setTextFont(ITEMS_PER_ROW_TEXT), "0, "+i+""); p.add(UIUtilities.buildComponentPanel(numberPerRow), "1, "+i); } else { i = i+2; p.add(UIUtilities.setTextFont("Image Label"), "0, "+i+""); p.add(rowName, "1, "+i); i = i+2; p.add(showScaleBar, "0, "+i); p.add(scaleBar, "1, "+i); p.add(new JLabel("microns"), "2, "+i); i = i+2; p.add(UIUtilities.setTextFont("Overlay"), "0, "+i); p.add(UIUtilities.buildComponentPanel(colorBox), "1, "+i); } if (ImageData.class.equals(type)) { i = i+2; p.add(UIUtilities.setTextFont("Made of"), "0, "+i+"," + " LEFT, TOP"); JPanel controls = new JPanel(); controls.setLayout(new BoxLayout(controls, BoxLayout.Y_AXIS)); controls.add(displayedObjects); controls.add(selectedObjects); p.add(UIUtilities.buildComponentPanel(controls), "1, "+i); } switch (dialogType) { case MOVIE: if (pixels.getSizeT() > 1) { i++; p.add(new JSeparator(), "0, "+i+", 4, "+i); i++; p.add(buildMovieComponent(), "0, "+i+", 4, "+i); } } return p; } /** * Builds the components hosting the various images. * * @return See above. */ private JPanel buildComponents() { JPanel p = new JPanel(); double[] columns = new double[components.size()+1]; for (int i = 0; i < columns.length; i++) { columns[i] = TableLayout.PREFERRED; } double[] rows = {TableLayout.FILL}; p.setLayout(new TableLayout(columns, rows)); Entry<Integer, FigureComponent> entry; Iterator<Entry<Integer, FigureComponent>> i = components.entrySet().iterator(); int index = 0; while (i.hasNext()) { entry = i.next(); p.add(entry.getValue(), index+", 0, LEFT, TOP"); index++; } p.add(mergedComponent, index+", 0, LEFT, TOP"); p.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5)); return p; } /** * Builds and lays out the component displaying the channels. * * @return See above */ private JPanel buildChannelsComponent() { JPanel p = new JPanel(); Iterator<Integer> i = components.keySet().iterator(); while (i.hasNext()) { p.add(components.get(i.next())); } JPanel splitPanel = new JPanel(); splitPanel.add(UIUtilities.setTextFont("Split Panel")); splitPanel.add(splitPanelColor); splitPanel.add(splitPanelGrey); JPanel controls = new JPanel(); double size[][] = {{TableLayout.FILL}, {TableLayout.PREFERRED, 5, TableLayout.PREFERRED, 5, TableLayout.PREFERRED}}; controls.setLayout(new TableLayout(size)); controls.add(splitPanel, "0, 0, LEFT, CENTER"); controls.add(buildComponents(), "0, 2, LEFT, CENTER"); if (dialogType == SPLIT_ROI) { JPanel zoomPanel = new JPanel(); zoomPanel.setLayout(new BoxLayout(zoomPanel, BoxLayout.X_AXIS)); zoomPanel.add(UIUtilities.setTextFont("Zoom")); zoomPanel.add(zoomBox); JPanel pc = new JPanel(); pc.setLayout(new BoxLayout(pc, BoxLayout.Y_AXIS)); pc.add(zoomPanel); pc.add(UIUtilities.buildComponentPanel(generalLabel)); JPanel splitControls = new JPanel(); splitControls.setLayout(new BoxLayout(splitControls, BoxLayout.X_AXIS)); splitControls.add(pc); splitControls.add(buildDimensionComponent()); controls.add(UIUtilities.buildComponentPanel(splitControls), "0, 4"); } else { controls.add(buildDimensionComponent(), "0, 4"); } return controls; } /** * Builds and lays out the controls for the movie figure. * * @return See above. */ private JPanel buildMovieComponent() { JPanel controls = new JPanel(); controls.setLayout(new BoxLayout(controls, BoxLayout.Y_AXIS)); JPanel p = new JPanel(); p.setLayout(new GridBagLayout()); GridBagConstraints c = new GridBagConstraints(); c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.WEST; c.gridy = 0; c.gridx = 0; c.weightx = 0.0; p.add(UIUtilities.setTextFont(ITEMS_PER_ROW_TEXT), c); c.gridx++; p.add(Box.createHorizontalStrut(5), c); c.gridx++; p.add(UIUtilities.buildComponentPanel(numberPerRow), c); c.gridy++; c.gridx = 0; p.add(UIUtilities.setTextFont("Time-point frequency"), c); c.gridx++; p.add(Box.createHorizontalStrut(5), c); c.gridx++; JPanel pane = new JPanel(); pane.setLayout(new BoxLayout(pane, BoxLayout.X_AXIS)); pane.add(movieFrequency); pane.add(Box.createHorizontalStrut(5)); pane.add(generalLabel); p.add(UIUtilities.buildComponentPanel(pane), c); c.gridy++; c.gridx = 0; p.add(UIUtilities.setTextFont("Selected Time-points"), c); c.gridx++; p.add(Box.createHorizontalStrut(5), c); c.gridx++; if (pixels.getSizeT() <= MAX_CELLS) p.add(movieSlider, c); else { JScrollPane sp = new JScrollPane(movieSlider); Dimension ds = movieSlider.getPreferredSize(); sp.getViewport().setPreferredSize(new Dimension( MAX_CELLS*GridSlider.CELL_SIZE.width, ds.height)); p.add(sp, c); } c.weightx = 0.0; c.gridy++; c.gridx = 0; p.add(UIUtilities.setTextFont("Time units"), c); c.gridx++; p.add(Box.createHorizontalStrut(5), c); c.gridx++; p.add(UIUtilities.buildComponentPanel(timesBox), c); controls.add(UIUtilities.buildComponentPanel(p)); controls.add(buildDimensionComponent()); return controls; } /** * Builds the main component. * * @return See above. */ private JPanel buildBody() { if (dialogType == THUMBNAILS) return buildThumbnailsPane(); double[][] tl = {{TableLayout.FILL}, //columns {TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED}}; //rows JPanel p = new JPanel(); p.setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10)); p.setLayout(new TableLayout(tl)); JXTaskPane pane = EditorUtil.createTaskPane("General"); pane.setCollapsed(false); pane.add(buildTypeComponent()); int i = 0; p.add(pane, "0, "+i); if (pixels.getSizeZ() > 1 && dialogType != SPLIT_ROI) { pane = EditorUtil.createTaskPane("Z-section Selection"); pane.add(buildProjectionComponent()); i++; p.add(pane, "0, "+i); } if (dialogType != MOVIE) { i++; channelsPane = EditorUtil.createTaskPane("Channels selection"); channelsPane.setCollapsed(false); channelsPane.add(buildDefaultPane()); p.add(channelsPane, "0, "+i); } return p; } /** * Returns the components for the thumbnails script. * * @return See above. */ private JPanel buildThumbnailsPane() { thumbnailsPane = new JPanel(); thumbnailsPane.setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10)); double[][] tl = {{TableLayout.FILL}, //columns {TableLayout.PREFERRED, TableLayout.PREFERRED}}; //rows thumbnailsPane.setLayout(new TableLayout(tl)); thumbnailsPane.add(buildTypeComponent(), "0, 0"); return thumbnailsPane; } /** * Builds the default component. * * @return See above. */ private JPanel buildDefaultPane() { JPanel p = new JPanel(); JXBusyLabel label = new JXBusyLabel(); label.setBusy(true); p.add(label); return p; } /** Closes the dialog. */ private void close() { if (renderer != null) renderer.resetSettings(rndDef, false); option = CLOSE; firePropertyChange(CLOSE_FIGURE_PROPERTY, Boolean.valueOf(false), Boolean.valueOf(true)); setVisible(false); dispose(); } /** * Collects the parameters. * * @param p The value to fill. */ private void collectParam(FigureParam p) { if (mergedComponent != null) p.setMergedLabel(mergedComponent.isChannelsName()); p.setSelectedObjects(selectedObjects.isSelected()); p.setWidth((Integer) widthField.getValueAsNumber()); p.setHeight((Integer) heightField.getValueAsNumber()); p.setSplitGrey(splitPanelGrey.isSelected()); //scale bar int scale = -1; if (showScaleBar.isSelected()) { Number n = scaleBar.getValueAsNumber(); if (n != null) scale = n.intValue(); } p.setScaleBar(scale); p.setColor(getSelectedColor()); //projection if (projectionBox.isSelected()) { p.setZStart((int) zRange.getStartValue()-1); p.setZEnd((int) zRange.getEndValue()-1); p.setStepping((Integer) projectionFrequency.getValue()); p.setProjectionType( projectionTypes.get(projectionTypesBox.getSelectedIndex())); } else { p.setZStart(-1); p.setZEnd(-1); p.setStepping(1); p.setProjectionType(ProjectionParam.MAXIMUM_INTENSITY); } } /** * Collects the parameters to create a Split figure. * * @return See above. */ private FigureParam saveSplitFigure() { Map<Integer, String> split = new LinkedHashMap<Integer, String>(); FigureComponent comp; Entry<Integer, FigureComponent> entry; List<Integer> splitActive = new ArrayList<Integer>(); Iterator<Entry<Integer, FigureComponent>> i = components.entrySet().iterator(); while (i.hasNext()) { entry = i.next(); comp = entry.getValue(); split.put(entry.getKey(), comp.getLabel()); if (comp.isSelected()) { splitActive.add((Integer) entry.getKey()); } } Map<Integer, Color> merge = new LinkedHashMap<Integer, Color>(); List<Integer> active = renderer.getActiveChannels(); Iterator<Integer> j = active.iterator(); int index; while (j.hasNext()) { index = j.next(); merge.put(index, renderer.getChannelColor(index)); } String name = nameField.getText().trim(); int format = formats.getSelectedIndex(); int label = rowName.getSelectedIndex(); FigureParam p = new FigureParam(format, name, split, merge, label); p.setSplitActive(splitActive); collectParam(p); return p; } /** * Collects the parameters to create a ROI figure. * * @return See above. */ private FigureParam saveROIFigure() { Map<Integer, String> split = new LinkedHashMap<Integer, String>(); List<Integer> splitActive = new ArrayList<Integer>(); FigureComponent comp; Entry<Integer, FigureComponent> entry; Iterator<Entry<Integer, FigureComponent>> i = components.entrySet().iterator(); while (i.hasNext()) { entry = i.next(); comp = entry.getValue(); split.put(entry.getKey(), comp.getLabel()); if (comp.isSelected()) { splitActive.add((Integer) entry.getKey()); } } Map<Integer, Color> merge = new LinkedHashMap<Integer, Color>(); List<Integer> active = renderer.getActiveChannels(); Iterator<Integer> j = active.iterator(); int index; while (j.hasNext()) { index = j.next(); merge.put(index, renderer.getChannelColor(index)); } String name = nameField.getText().trim(); int format = formats.getSelectedIndex(); int label = rowName.getSelectedIndex(); FigureParam p = new FigureParam(format, name, split, merge, label); p.setSplitActive(splitActive); p.setIndex(FigureParam.SPLIT_VIEW_ROI); collectParam(p); double zoom = 0; switch (zoomBox.getSelectedIndex()) { case ZOOM_100: zoom = 1; break; case ZOOM_200: zoom = 2; break; case ZOOM_300: zoom = 3; break; case ZOOM_400: zoom = 4; break; case ZOOM_500: zoom = 5; } p.setMagnificationFactor(zoom); return p; } /** * Collects the parameters to create the movie figure. * * @return See above. */ private FigureParam saveMovieFigure() { String name = nameField.getText().trim(); int format = formats.getSelectedIndex(); int label = rowName.getSelectedIndex(); FigureParam p = new FigureParam(format, name, label); p.setIndex(FigureParam.MOVIE); p.setTime(timesBox.getSelectedIndex()); p.setTimepoints(sorter.sort(movieSlider.getSelectedCells())); collectParam(p); Number n = numberPerRow.getValueAsNumber(); if (n != null && n instanceof Integer) p.setMaxPerColumn((Integer) n); return p; } /** * Collects the parameters to create the thumbnail figure. * * @return See above. */ private FigureParam saveThumbnailsFigure() { String name = nameField.getText().trim(); int format = formats.getSelectedIndex(); FigureParam p = new FigureParam(format, name); p.setIndex(FigureParam.THUMBNAILS); int width = 96; switch (sizeBox.getSelectedIndex()) { case SIZE_24: width = 24; break; case SIZE_32: width = 32; break; case SIZE_48: width = 48; break; case SIZE_64: width = 64; break; case SIZE_96: width = 96; break; case SIZE_128: width = 128; break; case SIZE_160: width = 160; } p.setWidth(width); p.setSelectedObjects(selectedObjects.isSelected()); if (includeUntagged != null) p.setIncludeUntagged(includeUntagged.isSelected()); //retrieve the id of the selected tags if (arrangeByTags.isSelected() && selection != null && selection.size() > 0) { Iterator<JCheckBox> i = selection.iterator(); JCheckBox box; TagAnnotationData tag; List<Long> ids = new ArrayList<Long>(); while (i.hasNext()) { box = i.next(); tag = tagsSelection.get(box); ids.add(tag.getId()); } p.setTags(ids); } Number n = numberPerRow.getValueAsNumber(); if (n != null && n instanceof Integer) p.setMaxPerColumn((Integer) n); return p; } /** Collects the parameters to create a figure. */ private void save() { FigureParam p = null; switch (dialogType) { case SPLIT: p = saveSplitFigure(); break; case SPLIT_ROI: p = saveROIFigure(); break; case MOVIE: p = saveMovieFigure(); break; case THUMBNAILS: p = saveThumbnailsFigure(); } close(); if (p != null) firePropertyChange(CREATE_FIGURE_PROPERTY, null, p); } /** * Sets the enabled flag of the {@link #saveButton} depending on * the value to the name field. */ private void handleText() { String text = nameField.getText(); saveButton.setEnabled(!(text == null || text.trim().length() == 0)); switch (dialogType) { case SPLIT: case SPLIT_ROI: saveButton.setEnabled(renderer != null); } checkBinaryAvailability(); } /** * Handles the changes in the image dimension. * * @param field The modified numerical field. */ private void handleDimensionChange(NumericalTextField field) { Integer n = (Integer) field.getValueAsNumber(); if (n == null) return; Document doc; int v = (int) ((n*pixels.getSizeX())/pixels.getSizeY()); if (field == widthField) { doc = heightField.getDocument(); doc.removeDocumentListener(this); heightField.setText(""+v); doc.addDocumentListener(this); } else { doc = widthField.getDocument(); doc.removeDocumentListener(this); widthField.setText(""+v); doc.addDocumentListener(this); } setMergedImageForSplitROI(mergeUnscaled); } /** * Resets the image for the merged component. * * @param image The image to display. */ private void setMergedImageForSplitROI(BufferedImage image) { if (dialogType != SPLIT_ROI) return; int w = (Integer) widthField.getValueAsNumber(); if (w <= 0) return; int h = (Integer) heightField.getValueAsNumber(); if (h <= 0) return; int x = w*thumbnailWidth/pixels.getSizeX(); int y = w*thumbnailHeight/pixels.getSizeY(); if (x == 0 || y == 0) return; mergedComponent.setOriginalImage( Factory.scaleBufferedImage(image, x, y)); Dimension d = new Dimension(x, y); DrawingCanvasView canvasView = drawingComponent.getDrawingView(); double r = ((double) w)/pixels.getSizeX(); double f = scalingFactor*r; if (f != -1) canvasView.setScaleFactor(f, d); if (zoomBox.getSelectedIndex() == ZOOM_AUTO) setLensFactor(); mergedComponent.setCanvasSize(x, y); } /** * Returns the name of the script. * * @return See above. */ private String getScriptName() { switch (dialogType) { case SPLIT: return FigureParam.SPLIT_VIEW_SCRIPT; case SPLIT_ROI: return FigureParam.ROI_SCRIPT; case MOVIE: return FigureParam.MOVIE_SCRIPT; case THUMBNAILS: return FigureParam.THUMBNAIL_SCRIPT; } return ""; } /** * Returns <code>true</code> if the dialog required a set of pixels * <code>false</code> otherwise. * * @param index One of the constants identifying the dialog. * @return See above. */ public static boolean needPixels(int index) { return THUMBNAILS != index; } /** * Creates a new instance. * * @param owner The owner of the dialog. * @param name The default name for the file. * @param pixels The pixels object of reference. * @param index One of the constants defined by this class. * @param type The type of objects to handle. */ public FigureDialog(JFrame owner, String name, PixelsData pixels, int index, Class type) { super(owner, true); this.type = type; this.pixels = pixels; this.dialogType = index; initComponents(name); buildGUI(); setSize(500, 700); } /** * Creates and returns a greyScale image with only the selected channel * turned on. * * @param channel The index of the channel. * @return See above. */ BufferedImage createSingleGreyScaleImage(int channel) { return scaleImage(renderer.createSingleChannelImage(false, channel, pDef)); } /** * Sets the channel selection. * * @param channel The selected channel. * @param active Pass <code>true</code> to set the channel active, * <code>false</code> otherwise. * @param merged Pass <code>true</code> to indicate that the merged * channels have been modified, <code>false</code> * otherwise. */ void setChannelSelection(int channel, boolean active, boolean merged) { renderer.setActive(channel, active); if (dialogType == SPLIT_ROI) setMergedImageForSplitROI(getMergedImage()); else mergedComponent.setOriginalImage(getMergedImage()); List<Integer> actives = renderer.getActiveChannels(); int v; Iterator<ChannelButton> i = mergedComponent.getChannels().iterator(); ChannelButton cb; while (i.hasNext()) { cb = i.next(); v = cb.getChannelIndex(); cb.setSelected(actives.contains(v)); } FigureComponent comp = components.get(channel); switch (dialogType) { case SPLIT: case SPLIT_ROI: boolean grey = splitPanelGrey.isSelected(); if (active) { if (grey) comp.resetImage(grey); else comp.resetImage(!active); } else comp.resetImage(!active); if (!merged) comp.setSelected(active); break; } } /** * Returns the type of dialog. One of the constants defined by this class. * * @return See above. */ public int getDialogType() { return dialogType; } /** * Sets the renderer. * * @param renderer Reference to the renderer. Mustn't be <code>null</code>. */ public void setRenderer(Renderer renderer) { if (renderer == null) throw new IllegalArgumentException("No renderer."); this.renderer = renderer; rndDef = renderer.getRndSettingsCopy(); channelsPane.removeAll(); switch (dialogType) { case SPLIT: case SPLIT_ROI: initChannelComponents(); channelsPane.add(buildChannelsComponent()); saveButton.setEnabled(true); checkBinaryAvailability(); pack(); break; } } /** * Sets the collections of tags. * * @param tags The values to set. */ public void setTags(Collection tags) { if (tags == null || tags.size() == 0) return; if (thumbnailsPane == null) return; JPanel p = new JPanel(); double[][] tl = {{TableLayout.PREFERRED, TableLayout.FILL}, //columns {TableLayout.PREFERRED, TableLayout.PREFERRED}}; //rows p.setLayout(new TableLayout(tl)); tagsSelection = new LinkedHashMap<JCheckBox, TagAnnotationData>(); List<TagAnnotationData> l = sorter.sort(tags); Iterator<TagAnnotationData> i = l.iterator(); TagAnnotationData tag; JCheckBox box; JPanel tagPane = new JPanel(); tagPane.setLayout(new BoxLayout(tagPane, BoxLayout.Y_AXIS)); ActionListener listener = new ActionListener() { public void actionPerformed(ActionEvent e) { layoutSelectedTags((JCheckBox) e.getSource()); } }; while (i.hasNext()) { tag = i.next(); box = new JCheckBox(tag.getTagValue()); box.setEnabled(false); box.addActionListener(listener); tagsSelection.put(box, tag); tagPane.add(box); } selectedTags = new JPanel(); selectedTags.setLayout(new BoxLayout(selectedTags, BoxLayout.Y_AXIS)); JPanel controls = new JPanel(); controls.setLayout(new BoxLayout(controls, BoxLayout.Y_AXIS)); controls.add(UIUtilities.buildComponentPanel(arrangeByTags)); controls.add(UIUtilities.buildComponentPanel(includeUntagged)); p.add(controls, "0, 0, LEFT, TOP"); p.add(selectedTags, "0, 1, LEFT, TOP"); JScrollPane pane = new JScrollPane(tagPane); Dimension d = pane.getPreferredSize(); pane.setPreferredSize(new Dimension(d.width, MAX_HEIGHT)); p.add(pane, "1, 0, 1, 1"); thumbnailsPane.add(p, "0, 1"); thumbnailsPane.revalidate(); thumbnailsPane.repaint(); } /** * Sets the collection of ROIs related to the primary select. * * @param rois The value to set. */ public boolean setROIs(Collection rois) { if (rois == null) return false; drawingComponent = new DrawingComponent(); drawingComponent.getDrawingView().setScaleFactor(1.0); roiComponent = new ROIComponent(); Iterator<ROIResult> r = rois.iterator(); ROIResult result; int count = 0; try { long userID = MetadataViewerAgent.getUserDetails().getId(); Collection list; while (r.hasNext()) { result = (ROIResult) r.next(); list = result.getROIs(); if (list.size() > 0) count++; displayedROIs = roiComponent.loadROI(result.getFileID(), list, userID); modifyROIDisplay(); } } catch (Exception e) {} return count != 0; } /** * Sets the parent. * * @param parentRef The value to handle. */ public void setParentRef(Object parentRef) { if (parentRef instanceof DatasetData) nameField.setText(((DatasetData) parentRef).getName()); } /** * Sets the planes information to determine the time interval. * * @param planes The values to set. */ public void setPlaneInfo(Collection planes) { if (planes == null) return; Map<Integer, String> values = new HashMap<Integer, String>(); Iterator i = planes.iterator(); String value = ""; Map<String, Object> details; PlaneInfo pi; List<String> notSet; while (i.hasNext()) { pi = (PlaneInfo) i.next(); details = EditorUtil.transformPlaneInfo(pi); 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); value = "N/A"; } else { value = EditorUtil.formatTimeInSeconds( (Double) details.get(EditorUtil.DELTA_T)); } values.put(pi.getTheT().getValue(), value); } } movieSlider.setCellNames(values); } /** * Centers and shows the dialog. Returns the option selected by the user. * * @return The option selected by the user. */ public int centerDialog() { UIUtilities.centerAndShow(this); return option; } /** * Closes or creates a figure. * @see ActionListener#actionPerformed(ActionEvent) */ public void actionPerformed(ActionEvent e) { int index = Integer.parseInt(e.getActionCommand()); switch (index) { case CLOSE: close(); break; case SAVE: save(); break; case SCALE_BAR: scaleBar.setEnabled(showScaleBar.isSelected()); break; case ARRANGE_BY_TAGS: boolean b = arrangeByTags.isSelected(); Iterator<JCheckBox> i = tagsSelection.keySet().iterator(); while (i.hasNext()) i.next().setEnabled(b); break; case PROJECTION: setProjectionSelected(projectionBox.isSelected()); break; case ZOOM_FACTOR: setLensFactor(); break; case COLOR_SELECTION: modifyROIDisplay(); break; case DOWNLOAD: firePropertyChange( ScriptingDialog.DOWNLOAD_SELECTED_SCRIPT_PROPERTY, null, getScriptName()); break; case VIEW: firePropertyChange( ScriptingDialog.VIEW_SELECTED_SCRIPT_PROPERTY, null, getScriptName()); } } /** * Sets the <code>enabled</code> flag of the controls. * @see DocumentListener#insertUpdate(DocumentEvent) */ public void insertUpdate(DocumentEvent e) { Document doc = e.getDocument(); if (doc == nameField.getDocument()) handleText(); else if (doc == widthField.getDocument()) handleDimensionChange(widthField); else handleDimensionChange(heightField); } /** * Sets the <code>enabled</code> flag of the controls. * @see DocumentListener#removeUpdate(DocumentEvent) */ public void removeUpdate(DocumentEvent e) { Document doc = e.getDocument(); if (doc == nameField.getDocument()) handleText(); else if (doc == widthField.getDocument()) handleDimensionChange(widthField); else handleDimensionChange(heightField); } /** * Listens to channel button selection * @see PropertyChangeListener#propertyChange(PropertyChangeEvent) */ public void propertyChange(PropertyChangeEvent evt) { String name = evt.getPropertyName(); if (ChannelButton.CHANNEL_SELECTED_PROPERTY.equals(name)) { //mergeCanvas.setImage(getMergedImage()); Map<Integer, Boolean> map = (Map<Integer, Boolean>) evt.getNewValue(); if (map == null) return; if (map.size() != 1) return; Entry<Integer, Boolean> entry; Iterator<Entry<Integer, Boolean>> i = map.entrySet().iterator(); Integer index; while (i.hasNext()) { entry = i.next(); index = entry.getKey(); setChannelSelection(index.intValue(), entry.getValue(), true); } } else if (ChannelComponent.CHANNEL_SELECTION_PROPERTY.equals(name)) { ChannelComponent c = (ChannelComponent) evt.getNewValue(); setChannelSelection(c.getChannelIndex(), c.isActive(), true); } else if (GridSlider.COLUMN_SELECTION_PROPERTY.equals(name)) { int maxT = pixels.getSizeT(); generalLabel.setText( FRAMES_TEXT+movieSlider.getNumberOfSelectedCells()+"/"+maxT); generalLabel.repaint(); } } /** * Reacts to change in the type of split i.e. either grey or color. * @see ChangeListener#stateChanged(ChangeEvent) */ public void stateChanged(ChangeEvent e) { Object src = e.getSource(); if (src == projectionBox || src == planeSelection) { onProjectionSelectionChanged(); return; } switch (dialogType) { case SPLIT: case SPLIT_ROI: if (src == splitPanelGrey) { boolean grey = splitPanelGrey.isSelected(); if (components == null) return; Iterator<Integer> i = components.keySet().iterator(); FigureComponent comp; List<Integer> active = renderer.getActiveChannels(); Integer index; while (i.hasNext()) { index = i.next(); comp = components.get(index); if (grey) comp.resetImage(grey); else { if (active.contains(index)) comp.resetImage(grey); else comp.resetImage(!grey); } } } break; case MOVIE: if (src == movieFrequency) { Integer value = (Integer) movieFrequency.getValue(); movieSlider.selectCells(value); generalLabel.setText( FRAMES_TEXT+movieSlider.getNumberOfSelectedCells()+ "/"+pixels.getSizeT()); generalLabel.repaint(); } } } /** * Required by the {@link DocumentListener} I/F but no-operation * implementation in our case. * @see DocumentListener#changedUpdate(DocumentEvent) */ public void changedUpdate(DocumentEvent e) {} }