/* * org.openmicroscopy.shoola.agents.measurement.view.MeasurementResults * *------------------------------------------------------------------------------ * Copyright (C) 2006-2014 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.measurement.view; //Java imports import java.awt.BorderLayout; import java.awt.FlowLayout; import java.awt.Font; import java.awt.FontMetrics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.TreeMap; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JFileChooser; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.ListSelectionModel; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; //Third-party libraries //Application-internal dependencies import org.openmicroscopy.shoola.agents.measurement.IconManager; import org.openmicroscopy.shoola.agents.measurement.MeasurementAgent; import org.openmicroscopy.shoola.agents.measurement.util.TabPaneInterface; import org.openmicroscopy.shoola.agents.measurement.util.model.AnnotationDescription; import org.openmicroscopy.shoola.agents.measurement.util.model.AnnotationField; import org.openmicroscopy.shoola.agents.measurement.util.model.MeasurementObject; import org.openmicroscopy.shoola.agents.measurement.util.ui.KeyDescription; import org.openmicroscopy.shoola.agents.measurement.util.ui.ResultsCellRenderer; import org.openmicroscopy.shoola.env.config.Registry; import omero.log.Logger; import org.openmicroscopy.shoola.env.ui.UserNotifier; import org.openmicroscopy.shoola.util.file.ExcelWriter; import org.openmicroscopy.shoola.util.filter.file.ExcelFilter; import org.openmicroscopy.shoola.util.image.geom.Factory; 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.annotation.AnnotationKey; import org.openmicroscopy.shoola.util.roi.model.annotation.AnnotationKeys; import org.openmicroscopy.shoola.util.roi.model.annotation.MeasurementAttributes; import org.openmicroscopy.shoola.util.ui.UIUtilities; import org.openmicroscopy.shoola.util.ui.filechooser.FileChooser; /** * UI component displaying various value computed on a Region of Interest. * * @author Jean-Marie Burel      * <a href="mailto:j.burel@dundee.ac.uk">j.burel@dundee.ac.uk</a> * @author Donald MacDonald      * <a href="mailto:donald@lifesci.dundee.ac.uk">donald@lifesci.dundee.ac.uk</a> * @version 3.0 * <small> * (<b>Internal version:</b> $Revision: $Date: $) * </small> * @since OME3.0 */ class MeasurementResults extends JPanel implements ActionListener, TabPaneInterface { /** Index to identify tab */ public final static int INDEX = MeasurementViewerUI.RESULTS_INDEX; /** The default size of the column in a table. */ private static final int COLUMNWIDTH = 64; /** ROI ID Column no for the wizard. */ private static final int ROIID_COLUMN = 0; /** Time point Column no for the wizard. */ private static final int TIME_COLUMN = 2; /** Z-Section Column no for the wizard. */ private static final int Z_COLUMN = 1; /** Identifies the save action. */ private static final int SAVE = 0; /** Identifies the refresh action. */ private static final int REFRESH = 1; /** Identifies the wizard action. */ private static final int WIZARD = 2; /** The name of the panel. */ private static final String NAME = "Results"; /** Collection of column names. */ private List<KeyDescription> columnNames; /** Collection of column names. */ private List<AnnotationField> fields; /** Collection of column names for all possible fields. */ private List<AnnotationField> allFields; /** Button to save locally the results. */ private JButton saveButton; /** Button to save locally the results. */ private JButton refreshButton; /** Button to launch the results wizard. */ private JButton resultsWizardButton; /** The table displaying the results. */ private ResultsTable results; /** The scroll pane for the results. */ private JScrollPane scrollPane; /** Reference to the control. */ private MeasurementViewerControl controller; /** Reference to the model. */ private MeasurementViewerModel model; /** Reference to the View. */ private MeasurementViewerUI view; /** * The table selection listener attached to the table displaying the * objects. */ private ListSelectionListener listener; /** * Implemented as specified by the I/F {@link TabPaneInterface} * @see TabPaneInterface#getIndex() */ public int getIndex() {return INDEX; } /** * Shows the results wizard and updates the fields based on the users * selection. */ private void showResultsWizard() { ResultsWizard resultsWizard = new ResultsWizard(view, fields, allFields); resultsWizard.pack(); UIUtilities.setLocationRelativeToAndShow(this, resultsWizard); columnNames.clear(); populatesColumnNames(); AnnotationField field; for (int i = 0 ; i < fields.size(); i++) { field = fields.get(i); columnNames.add(new KeyDescription(field.getKey().toString(), field.getName())); } populate(); results.repaint(); } /** Populates column names.*/ private void populatesColumnNames() { columnNames.add(new KeyDescription( AnnotationDescription.ROIID_STRING, AnnotationDescription.ROIID_STRING)); columnNames.add(new KeyDescription( AnnotationDescription.ZSECTION_STRING, AnnotationDescription.ZSECTION_STRING)); columnNames.add(new KeyDescription(AnnotationDescription.TIME_STRING, AnnotationDescription.TIME_STRING)); columnNames.add(new KeyDescription(AnnotationDescription.SHAPE_STRING, AnnotationDescription.SHAPE_STRING)); } /** Initializes the components composing the display. */ private void initComponents() { saveButton = new JButton("Save To Excel..."); saveButton.setToolTipText("Save the results to Excel."); saveButton.setActionCommand(""+SAVE); saveButton.addActionListener(this); refreshButton = new JButton("Refresh"); refreshButton.setToolTipText("Refresh the results table."); refreshButton.setActionCommand(""+REFRESH); refreshButton.addActionListener(this); resultsWizardButton = new JButton("Results Wizard..."); resultsWizardButton.setToolTipText("Bring up the results wizard."); resultsWizardButton.setActionCommand(""+WIZARD); resultsWizardButton.addActionListener(this); refreshButton.setEnabled(false); saveButton.setEnabled(false); //Create table model. createAllFields(); createDefaultFields(); results = new ResultsTable(); results.getTableHeader().setReorderingAllowed(false); MeasurementTableModel tm = new MeasurementTableModel(columnNames, model.getMeasurementUnits()); results.setModel(tm); results.setSelectionMode( ListSelectionModel.SINGLE_SELECTION); results.setRowSelectionAllowed(true); results.setColumnSelectionAllowed(false); listener = new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { if (e.getValueIsAdjusting()) return; ListSelectionModel lsm = (ListSelectionModel) e.getSource(); if (lsm.isSelectionEmpty()) { } else { int index = lsm.getMinSelectionIndex(); if (index < 0) return; MeasurementTableModel m = (MeasurementTableModel) results.getModel(); int t, z; try { MeasurementObject object = m.getRow(index); ROIShape shape = object.getReference(); //roiShapeID = (Long) m.getValueAt(index, ROIID_COLUMN); long id = shape.getROI().getID(); t = (Integer) m.getValueAt(index, TIME_COLUMN)-1; z = (Integer) m.getValueAt(index, Z_COLUMN)-1; ROI roi = model.getROI(id); if (roi == null) return; view.selectFigure(id, t, z); } catch(Exception exception) { Registry reg = MeasurementAgent.getRegistry(); reg.getUserNotifier().notifyWarning("ROI does not exist", "ROI does not exist. Results may be out of date," + " try refreshing results."); } } } }; results.getSelectionModel().addListSelectionListener(listener); } /** Builds and lays out the GUI. */ private void buildGUI() { setLayout(new BorderLayout()); JPanel centrePanel = new JPanel(); centrePanel.setLayout(new BorderLayout()); scrollPane = new JScrollPane(results); centrePanel.add(scrollPane, BorderLayout.CENTER); JPanel bottomPanel = new JPanel(); bottomPanel.setLayout(new FlowLayout()); bottomPanel.add(resultsWizardButton); bottomPanel.add(refreshButton); bottomPanel.add(saveButton); JPanel containerPanel = new JPanel(); containerPanel.setLayout(new BorderLayout()); containerPanel.add(centrePanel, BorderLayout.CENTER); containerPanel.add(bottomPanel, BorderLayout.SOUTH); add(containerPanel, BorderLayout.CENTER); } /** * Create the fields which can be selected from. * */ private void createAllFields() { allFields = new ArrayList<AnnotationField>(); allFields.add(new AnnotationField(AnnotationKeys.CENTREX, AnnotationDescription.annotationDescription.get( AnnotationKeys.CENTREX), false)); allFields.add(new AnnotationField(AnnotationKeys.CENTREY, AnnotationDescription.annotationDescription.get( AnnotationKeys.CENTREY), false)); allFields.add(new AnnotationField(AnnotationKeys.AREA, AnnotationDescription.annotationDescription.get(AnnotationKeys.AREA) , false)); allFields.add(new AnnotationField(AnnotationKeys.PERIMETER, AnnotationDescription.annotationDescription.get( AnnotationKeys.PERIMETER),false)); allFields.add(new AnnotationField(AnnotationKeys.LENGTH, AnnotationDescription.annotationDescription.get( AnnotationKeys.LENGTH), false)); allFields.add(new AnnotationField(AnnotationKeys.WIDTH, AnnotationDescription.annotationDescription.get( AnnotationKeys.WIDTH), false)); allFields.add(new AnnotationField(AnnotationKeys.HEIGHT, AnnotationDescription.annotationDescription.get( AnnotationKeys.HEIGHT), false)); allFields.add(new AnnotationField(AnnotationKeys.ANGLE, AnnotationDescription.annotationDescription.get( AnnotationKeys.ANGLE), false)); allFields.add(new AnnotationField(AnnotationKeys.POINTARRAYX, AnnotationDescription.annotationDescription.get( AnnotationKeys.POINTARRAYX), false)); allFields.add(new AnnotationField(AnnotationKeys.POINTARRAYY, AnnotationDescription.annotationDescription.get( AnnotationKeys.POINTARRAYY), false)); allFields.add(new AnnotationField(AnnotationKeys.STARTPOINTX, AnnotationDescription.annotationDescription.get( AnnotationKeys.STARTPOINTX), false)); allFields.add(new AnnotationField(AnnotationKeys.STARTPOINTY, AnnotationDescription.annotationDescription.get( AnnotationKeys.STARTPOINTY), false)); allFields.add(new AnnotationField(AnnotationKeys.ENDPOINTX, AnnotationDescription.annotationDescription.get( AnnotationKeys.ENDPOINTX), false)); allFields.add(new AnnotationField(AnnotationKeys.ENDPOINTY, AnnotationDescription.annotationDescription.get( AnnotationKeys.ENDPOINTY), false)); } /** * Creates the default fields to show results of in the measurement tool. */ private void createDefaultFields() { fields = new ArrayList<AnnotationField>(); fields.add(new AnnotationField(AnnotationKeys.CENTREX, AnnotationDescription.annotationDescription.get( AnnotationKeys.CENTREX), false)); fields.add(new AnnotationField(AnnotationKeys.CENTREY, AnnotationDescription.annotationDescription.get( AnnotationKeys.CENTREY), false)); fields.add(new AnnotationField(AnnotationKeys.AREA, AnnotationDescription.annotationDescription.get(AnnotationKeys.AREA) , false)); fields.add(new AnnotationField(AnnotationKeys.LENGTH, AnnotationDescription.annotationDescription.get(AnnotationKeys.LENGTH), false)); fields.add(new AnnotationField(AnnotationKeys.WIDTH, AnnotationDescription.annotationDescription.get(AnnotationKeys.WIDTH), false)); fields.add(new AnnotationField(AnnotationKeys.HEIGHT, AnnotationDescription.annotationDescription.get(AnnotationKeys.HEIGHT), false)); fields.add(new AnnotationField(AnnotationKeys.ANGLE, AnnotationDescription.annotationDescription.get(AnnotationKeys.ANGLE), false)); columnNames = new ArrayList<KeyDescription>(); populatesColumnNames(); for (int i = 0 ; i < fields.size(); i++) columnNames.add(new KeyDescription( fields.get(i).getKey().toString(), fields.get(i).getName())); } /** * Creates a new instance. * * @param controller Reference to the Control. Mustn't be <code>null</code>. * @param model Reference to the Model. Mustn't be <code>null</code>. * @param view Reference to the View. Mustn't be <code>null</code>. */ MeasurementResults(MeasurementViewerControl controller, MeasurementViewerModel model, MeasurementViewerUI view) { if (controller == null) throw new IllegalArgumentException("No control."); if (model == null) throw new IllegalArgumentException("No model."); if (view == null) throw new IllegalArgumentException("No view."); this.controller = controller; this.model = model; this.view = view; initComponents(); buildGUI(); } /** Populate the table. */ void populate() { TreeMap map = model.getROI(); Iterator i = map.keySet().iterator(); ROI roi; TreeMap shapes; Iterator j; ROIShape shape; ROIFigure figure; MeasurementObject row; AnnotationKey key; MeasurementTableModel tm = new MeasurementTableModel(columnNames, model.getMeasurementUnits()); while (i.hasNext()) { roi = (ROI) map.get(i.next()); shapes = roi.getShapes(); j = shapes.keySet().iterator(); while (j.hasNext()) { shape = (ROIShape) shapes.get(j.next()); figure = shape.getFigure(); figure.calculateMeasurements(); row = new MeasurementObject(shape); //row.addElement(shape.getROI().getID()); if (shape.getROI().isClientSide()) row.addElement("--"); else row.addElement(shape.getROIShapeID()); row.addElement(shape.getCoord3D().getZSection()+1); row.addElement(shape.getCoord3D().getTimePoint()+1); row.addElement(shape.getFigure().getType()); for (int k = 0; k < fields.size(); k++) { key = fields.get(k).getKey(); Object value; if (AnnotationKeys.TEXT.equals(key)) value = key.get(shape.getFigure()); else value = key.get(shape); if (value instanceof List) { List valueArray = (List) value; row.addElement(new ArrayList(valueArray)); } else row.addElement(value); } tm.addRow(row); } } results.setModel(tm); resizeTableColumns(); int n = tm.getRowCount(); saveButton.setEnabled(n > 0); refreshButton.setEnabled(n > 0); } /** * Resize the columns so that they fit the column names better, the * column will be a minimum size of COLUMNWIDTH or the length of the * text whichever is greater. * */ private void resizeTableColumns() { int columnWidth = 0; Font font = getFont(); FontMetrics metrics = getFontMetrics( font ); MeasurementTableModel tm = (MeasurementTableModel)results.getModel(); for(int i = 0 ; i < results.getColumnCount(); i++) { TableColumn col = results.getColumnModel().getColumn(i); int w = metrics.stringWidth(tm.getColumnName(i)); columnWidth = Math.max(w, COLUMNWIDTH); col.setMinWidth(columnWidth); col.setPreferredWidth(columnWidth); } } /** * Returns the name of the component. * * @return See above. */ String getComponentName() { return NAME; } /** * Returns the icon of the component. * * @return See above. */ Icon getComponentIcon() { IconManager icons = IconManager.getInstance(); return icons.getIcon(IconManager.RESULTS); } /** * Save the results. * * @throws IOException Thrown if the data cannot be written. * @return true if results saved, false if users cancels save. */ private boolean saveResults() throws IOException { FileChooser chooser = view.createSaveToExcelChooser(); int choice = chooser.showDialog(); if (choice != JFileChooser.APPROVE_OPTION) return false; File file = chooser.getSelectedFile(); if (!file.getAbsolutePath().endsWith(ExcelFilter.EXCEL)) { String fileName = file.getAbsolutePath()+"."+ExcelFilter.EXCEL; file = new File(fileName); } String filename = file.getAbsolutePath(); MeasurementTableModel tm = (MeasurementTableModel) results.getModel(); tm = tm.copy(); tm.setShowUnits(true); ExcelWriter writer = new ExcelWriter(filename); writer.openFile(); writer.createSheet("Measurement Results"); writer.writeTableToSheet(0, 0, tm); BufferedImage originalImage = model.getRenderedImage(); if(originalImage != null) { BufferedImage image = Factory.copyBufferedImage(originalImage); // Add the ROI for the current plane to the image. //TODO: Need to check that. model.setAttributes(MeasurementAttributes.SHOWID, true); model.getDrawingView().print(image.getGraphics()); model.setAttributes(MeasurementAttributes.SHOWID, false); String imageName = "ROIImage"; try { writer.addImageToWorkbook(imageName, image); } catch (Exception e) { Logger logger = MeasurementAgent.getRegistry().getLogger(); logger.error(this, "Cannot Add the image to the sheet: " + ""+e.toString()); } int col = writer.getMaxColumn(0); writer.writeImage(0, col+1, 256, 256, imageName); } writer.close(); return true; } /** Refreshes the result table. */ public void refreshResults() { populate(); } /** * Reacts to controls selection. * @see ActionListener#actionPerformed(ActionEvent) */ public void actionPerformed(ActionEvent e) { int index = Integer.parseInt(e.getActionCommand()); switch (index) { case REFRESH: if (!model.isHCSData()) refreshResults(); break; case SAVE: Registry reg = MeasurementAgent.getRegistry(); UserNotifier un = reg.getUserNotifier(); boolean saved = false; try { saved = saveResults(); } catch (Exception ex) { reg.getLogger().error(this, "Cannot save the results "+ex.getMessage()); un.notifyInfo("Save ROI results", "Cannot save the ROI results"); } if (saved) un.notifyInfo("Save ROI results", "The ROI results have been " + "successfully saved."); break; case WIZARD: showResultsWizard(); } } /** Basic inner class use to set the cell renderer. */ class ResultsTable extends JTable { /** Creates a new instance. */ ResultsTable() { super(); } /** * Overridden to return a customized cell renderer. * @see JTable#getCellRenderer(int, int) */ public TableCellRenderer getCellRenderer(int row, int column) { return new ResultsCellRenderer(); } } }