/* * Copyright 2010-2015 Institut Pasteur. * * This file is part of Icy. * * Icy 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 3 of the License, or * (at your option) any later version. * * Icy 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 Icy. If not, see <http://www.gnu.org/licenses/>. */ package icy.gui.dialog; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.Timer; import java.util.TimerTask; import javax.swing.Box; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.ScrollPaneConstants; import icy.common.exception.UnsupportedFormatException; import icy.file.Loader; import icy.file.SequenceFileImporter; import icy.gui.component.ThumbnailComponent; import icy.gui.util.ComponentUtil; import icy.image.IcyBufferedImage; import icy.image.IcyBufferedImageUtil; import icy.main.Icy; import icy.resource.ResourceUtil; import icy.sequence.MetaDataUtil; import icy.util.OMEUtil; import loci.formats.IFormatReader; import loci.formats.meta.IMetadata; import loci.formats.ome.OMEXMLMetadata; import loci.formats.ome.OMEXMLMetadataImpl; /** * Dialog used to select which serie to open for multi serie image. * * @author Stephane */ public class SeriesSelectionDialog extends ActionDialog implements Runnable { /** * */ private static final long serialVersionUID = -2133845128887305016L; protected static final int NUM_COL = 4; protected static final int THUMB_X = 160; protected static final int THUMB_Y = 140; // GUI protected JScrollPane scrollPane; protected JPanel gridPanel; protected ThumbnailComponent[] serieComponents; protected JButton selectAllBtn; protected JButton unselectAllBtn; // internal protected IFormatReader reader; protected SequenceFileImporter importer; protected String id; protected OMEXMLMetadata metadata; protected int[] selectedSeries; protected final MouseAdapter serieDoubleClickAction; protected final Thread loadingThread; /** * @deprecated Use {@link #SeriesSelectionDialog(SequenceFileImporter, String)} instead. */ @Deprecated public SeriesSelectionDialog(IFormatReader reader) { super("Series selection", null, Icy.getMainInterface().getMainFrame()); this.reader = reader; // default is empty selectedSeries = new int[] {}; initialize(); // double cick action = direct selection serieDoubleClickAction = new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { if (e.getClickCount() == 2) { final ThumbnailComponent thumb = (ThumbnailComponent) e.getSource(); for (int i = 0; i < serieComponents.length; i++) { if (serieComponents[i] == thumb) { selectedSeries = new int[] {i}; dispose(); } } } } }; final int series; if (reader != null) { metadata = OMEUtil.getOMEMetadata((IMetadata) reader.getMetadataStore()); series = reader.getSeriesCount(); } else { metadata = null; series = 0; } serieComponents = new ThumbnailComponent[series]; // adjust number of row int numRow = series / NUM_COL; if (series > (NUM_COL * numRow)) numRow++; ((GridLayout) gridPanel.getLayout()).setRows(numRow); for (int i = 0; i < numRow; i++) { for (int j = 0; j < NUM_COL; j++) { final int index = (i * NUM_COL) + j; if (index < series) { final ThumbnailComponent thumb = new ThumbnailComponent(true); // add mouse listener (double click action) thumb.addMouseListener(serieDoubleClickAction); // remove mouse listener (double click action) if (serieComponents[index] != null) serieComponents[index].removeMouseListener(serieDoubleClickAction); serieComponents[index] = thumb; thumb.setEnabled(true); thumb.setTitle("loading..."); thumb.setInfos(""); thumb.setInfos2(""); gridPanel.add(thumb); } else gridPanel.add(Box.createGlue()); } } // load thumbnails... loadingThread = new Thread(this, "Series thumbnail loading"); loadingThread.start(); // action on "OK" setOkAction(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { int numSelected = 0; for (int i = 0; i < serieComponents.length; i++) if (serieComponents[i].isSelected()) numSelected++; selectedSeries = new int[numSelected]; int ind = 0; for (int i = 0; i < serieComponents.length; i++) if (serieComponents[i].isSelected()) selectedSeries[ind++] = i; } }); // action on "Select All" selectAllBtn.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { for (ThumbnailComponent thumb : serieComponents) thumb.setSelected(true); } }); // action on "Unselect All" unselectAllBtn.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { for (ThumbnailComponent thumb : serieComponents) thumb.setSelected(false); } }); setPreferredSize(new Dimension(740, 520)); pack(); ComponentUtil.center(this); setVisible(true); } /** * Create a new dialog to select the series to open from an image. * * @throws IOException * @throws UnsupportedFormatException */ public SeriesSelectionDialog(SequenceFileImporter importer, String id, OMEXMLMetadata metadata) throws UnsupportedFormatException, IOException { super("Series selection", null, Icy.getMainInterface().getMainFrame()); this.importer = importer; this.id = id; this.metadata = metadata; // default is empty selectedSeries = new int[] {}; initialize(); final int series = MetaDataUtil.getNumSerie(metadata); // double cick action = direct selection serieDoubleClickAction = new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { if (e.getClickCount() == 2) { final ThumbnailComponent thumb = (ThumbnailComponent) e.getSource(); for (int i = 0; i < serieComponents.length; i++) { if (serieComponents[i] == thumb) { selectedSeries = new int[] {i}; dispose(); } } } } }; serieComponents = new ThumbnailComponent[series]; // adjust number of row int numRow = series / NUM_COL; if (series > (NUM_COL * numRow)) numRow++; ((GridLayout) gridPanel.getLayout()).setRows(numRow); for (int i = 0; i < numRow; i++) { for (int j = 0; j < NUM_COL; j++) { final int index = (i * NUM_COL) + j; if (index < series) { final ThumbnailComponent thumb = new ThumbnailComponent(true); // add mouse listener (double click action) thumb.addMouseListener(serieDoubleClickAction); // remove mouse listener (double click action) if (serieComponents[index] != null) serieComponents[index].removeMouseListener(serieDoubleClickAction); serieComponents[index] = thumb; thumb.setEnabled(true); thumb.setTitle("loading..."); thumb.setInfos(""); thumb.setInfos2(""); gridPanel.add(thumb); } else gridPanel.add(Box.createGlue()); } } // load thumbnails... loadingThread = new Thread(this, "Series thumbnail loading"); loadingThread.start(); // action on "OK" setOkAction(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { int numSelected = 0; for (int i = 0; i < serieComponents.length; i++) if (serieComponents[i].isSelected()) numSelected++; selectedSeries = new int[numSelected]; int ind = 0; for (int i = 0; i < serieComponents.length; i++) if (serieComponents[i].isSelected()) selectedSeries[ind++] = i; } }); // action on "Select All" selectAllBtn.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { for (ThumbnailComponent thumb : serieComponents) thumb.setSelected(true); } }); // action on "Unselect All" unselectAllBtn.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { for (ThumbnailComponent thumb : serieComponents) thumb.setSelected(false); } }); setPreferredSize(new Dimension(740, 520)); pack(); ComponentUtil.center(SeriesSelectionDialog.this); setVisible(true); } /** * @deprecated Use {@link #SeriesSelectionDialog(SequenceFileImporter, String, OMEXMLMetadata)} instead. */ @Deprecated public SeriesSelectionDialog(SequenceFileImporter importer, String id, OMEXMLMetadataImpl metadata) throws UnsupportedFormatException, IOException { this(importer, id, (OMEXMLMetadata) metadata); } /** * Create a new dialog to select the series to open from an image. * * @throws IOException * @throws UnsupportedFormatException */ public SeriesSelectionDialog(SequenceFileImporter importer, String id) throws UnsupportedFormatException, IOException { this(importer, id, Loader.getMetaData(importer, id)); } /** * @return the selectedSeries */ public int[] getSelectedSeries() { return selectedSeries; } void initialize() { JPanel panel = new JPanel(); getContentPane().add(panel, BorderLayout.NORTH); panel.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5)); JLabel lblSelect = new JLabel("Click on a serie to select / unselect it or double click to directly open it."); ComponentUtil.setFontBold(lblSelect); ComponentUtil.setFontSize(lblSelect, 12); panel.add(lblSelect); scrollPane = new JScrollPane(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); mainPanel.add(scrollPane, BorderLayout.CENTER); gridPanel = new JPanel(); scrollPane.setViewportView(gridPanel); gridPanel.setLayout(new GridLayout(2, NUM_COL, 0, 0)); buttonPanel.removeAll(); selectAllBtn = new JButton("Select all"); unselectAllBtn = new JButton("Unselect all"); buttonPanel.add(Box.createHorizontalStrut(4)); buttonPanel.add(selectAllBtn); buttonPanel.add(Box.createHorizontalStrut(8)); buttonPanel.add(unselectAllBtn); buttonPanel.add(Box.createHorizontalStrut(8)); buttonPanel.add(Box.createHorizontalGlue()); buttonPanel.add(Box.createHorizontalStrut(8)); buttonPanel.add(okBtn); buttonPanel.add(Box.createHorizontalStrut(8)); buttonPanel.add(cancelBtn); buttonPanel.add(Box.createHorizontalStrut(4)); } @Override protected void onClosed() { super.onClosed(); // kill loading task in 2 seconds new Timer().schedule(new TimerTask() { @SuppressWarnings("deprecation") @Override public void run() { if ((loadingThread != null) && loadingThread.isAlive()) { try { loadingThread.stop(); } catch (Throwable t) { // ignore } } } }, 2000); } @Override public void run() { try { // start by filling metadata only... for (int i = 0; i < serieComponents.length; i++) { // interrupt if (isClosed()) return; try { final int sizeC = MetaDataUtil.getSizeC(metadata, i); serieComponents[i].setTitle(metadata.getImageName(i)); serieComponents[i].setInfos(MetaDataUtil.getSizeX(metadata, i) + " x " + MetaDataUtil.getSizeY(metadata, i) + " - " + MetaDataUtil.getSizeZ(metadata, i) + "Z x " + MetaDataUtil.getSizeT(metadata, i) + "T"); serieComponents[i].setInfos2(sizeC + ((sizeC > 1) ? " channels (" : " channel (") + MetaDataUtil.getDataType(metadata, i) + ")"); } catch (Exception e) { serieComponents[i].setTitle("Cannot read file"); serieComponents[i].setInfos(""); serieComponents[i].setInfos2(""); } try { // why does this sometime fails ??? serieComponents[i].setImage(ResourceUtil.ICON_PICTURE); } catch (Exception e) { // ignore } } // then try to load thumbnail for (int i = 0; i < serieComponents.length; i++) { // interrupt if (isClosed()) return; try { if (importer.open(id, 0)) { try { final IcyBufferedImage img = importer.getThumbnail(i); serieComponents[i] .setImage(IcyBufferedImageUtil.toBufferedImage(img, BufferedImage.TYPE_INT_ARGB)); } finally { importer.close(); } } else serieComponents[i].setImage(ResourceUtil.ICON_DELETE); } catch (OutOfMemoryError e) { // error image, we just totally ignore error here... serieComponents[i].setImage(ResourceUtil.ICON_DELETE); } catch (Exception e) { // error image, we just totally ignore error here... serieComponents[i].setImage(ResourceUtil.ICON_DELETE); } } } catch (ThreadDeath t) { // just stop process... } } }