/*
*------------------------------------------------------------------------------
* Copyright (C) 2006-2016 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;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
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.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.Vector;
import java.util.Map.Entry;
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.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;
import org.apache.commons.collections.CollectionUtils;
import org.jhotdraw.draw.Figure;
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.AnalysisStatsWrapper;
import org.openmicroscopy.shoola.agents.measurement.util.model.AnnotationDescription;
import org.openmicroscopy.shoola.agents.measurement.util.model.AnalysisStatsWrapper.StatsType;
import org.openmicroscopy.shoola.env.config.Registry;
import omero.log.Logger;
import org.openmicroscopy.shoola.env.rnd.roi.ROIShapeStats;
import org.openmicroscopy.shoola.env.ui.UserNotifier;
import org.openmicroscopy.shoola.util.file.ExcelWriter;
import org.openmicroscopy.shoola.util.image.geom.Factory;
import org.openmicroscopy.shoola.util.roi.figures.MeasureTextFigure;
import org.openmicroscopy.shoola.util.roi.figures.ROIFigure;
import org.openmicroscopy.shoola.util.roi.model.ROIShape;
import org.openmicroscopy.shoola.util.roi.model.annotation.MeasurementAttributes;
import org.openmicroscopy.shoola.util.roi.model.util.Coord3D;
import org.openmicroscopy.shoola.util.ui.UIUtilities;
import org.openmicroscopy.shoola.util.ui.filechooser.FileChooser;
import omero.gateway.model.ChannelData;
/**
* Displays the intensity results.
*
* @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 OME3.0
*/
class IntensityResultsView
extends JPanel
implements ActionListener, TabPaneInterface
{
/** Index to identify tab */
public final static int INDEX =
MeasurementViewerUI.INTENSITYRESULTVIEW_INDEX;
/** The add button name. */
private final static String ADD_NAME = "Add";
/** Tooltip for the add button. */
private final static String ADD_DESCRIPTION = "Add Intensities for " +
"the selected ROIs to results table.";
/** The addAll button name. */
private final static String ADDALL_NAME = "Add Selected";
/** Tooltip for the add button. */
private final static String ADDALL_DESCRIPTION = "Add Intensities for " +
"all the shapes of the selected ROIs to results table.";
/** The remove button name. */
private final static String REMOVE_NAME = "Remove";
/** Tooltip for the remove button. */
private final static String REMOVE_DESCRIPTION = "Remove Results in " +
"selected row from table.";
/** The remove button name. */
private final static String REMOVE_ALL_NAME = "Remove All";
/** Tooltip for the remove button. */
private final static String REMOVE_ALL_DESCRIPTION =
"Remove all the Results from table.";
/** The save button name. */
private final static String SAVE_NAME = "Export to Excel...";
/** Tooltip for the save button. */
private final static String SAVE_DESCRIPTION = "Save Intensities " +
"to Excel File.";
/** Reference to the view. */
private MeasurementViewerUI view;
/** The results table. */
private JTable results;
/** The results model for the results table. */
private ResultsTableModel resultsModel;
/** The remove button. */
private JButton removeButton;
/** The save button. */
private JButton saveButton;
/** The add button. */
private JButton addButton;
/** The addAll button. */
private JButton addAllButton;
/** The add button. */
private JButton removeAllButton;
/** The state of the Intensity View. */
static enum State
{
/** Analysing data. */
ANALYSING,
/** Ready to analyse. */
READY
}
/**
* Intensity view state, if Analysing we should not all the user to
* change combobox or save.
*/
private State state = State.READY;
/** The name of the panel. */
private static final String NAME = "Intensity Results View";
/** Action command id indicating to remove the selected rows. */
private static final int REMOVE = 0;
/** Action command id indicating to add new row. */
private static final int ADD = 1;
/** Action command id indicating to add new row. */
private static final int ADDALL = 4;
/** Action command id indicating to remove all the rows. */
private static final int REMOVE_ALL = 2;
/** Action command id indicating to save the results. */
private static final int SAVE = 3;
/** Reference to the model. */
private MeasurementViewerModel model;
/** The map of <ROIShape, ROIStats> .*/
private Map<ROIShape, Map<Integer, ROIShapeStats>> ROIStats;
/** list of the channel names. */
private Map<Integer, String> channelName = new TreeMap<Integer, String>();
/** List of the channel colours. */
private Map<Integer, Color> channelColour = new TreeMap<Integer, Color>();
/** Map of the channel sums, for each selected channel. */
private Map<Integer, Double> channelSum = new TreeMap<Integer, Double>();
/** Map of the channel mins, for each selected channel. */
private Map<Integer, Double> channelMin = new TreeMap<Integer, Double>();
/** Map of the channel Max, for each selected channel. */
private Map<Integer, Double> channelMax = new TreeMap<Integer, Double>();
/** Map of the channel Mean, for each selected channel. */
private Map<Integer, Double> channelMean = new TreeMap<Integer, Double>();
/** Map of the channel std. dev., for each selected channel. */
private Map<Integer, Double> channelStdDev = new TreeMap<Integer, Double>();
/** Map of the channel name to channel number .*/
private Map<String, Integer> nameMap = new HashMap<String, Integer>();
/** Map of the min channel intensity values to coord. */
private Map<Coord3D, Map<Integer, Double>> minStats;
/** Map of the max channel intensity values to coord. */
private Map<Coord3D, Map<Integer, Double>> maxStats;
/** Map of the mean channel intensity values to coord. */
private Map<Coord3D, Map<Integer, Double>> meanStats;
/** Map of the std dev channel intensity values to coord. */
private Map<Coord3D, Map<Integer, Double>> stdDevStats;
/** Map of the sum channel intensity values to coord. */
private Map<Coord3D, Map<Integer, Double>> sumStats;
/** Map of the coordinate to a shape. */
private Map<Coord3D, ROIShape> shapeMap;
/** The current coordinate of the ROI being depicted in the slider. */
private Coord3D coord;
/** Current ROIShape. */
private ROIShape shape;
/**
* Wraps an ROI shape such that its string representation shows its ID,
* or <q>--</q> if it a client-side shape. This is used for the shape IDs
* in the first column of the results model table so that it is easy to
* query any row to discover to which ROI shape it pertains.
*/
private static class ShapeAsID {
private final ROIShape shape;
private final String id;
/**
* Construct a new ShapeAsID instance.
* @param shape the ROI shape that the instance is to wrap, may not be null
*/
private ShapeAsID(ROIShape shape) {
if (shape == null)
throw new IllegalArgumentException(new NullPointerException());
this.shape = shape;
/* how the shape ID should display in the results model table */
if (shape.getROI().isClientSide())
this.id = "--";
else
this.id = Long.toString(shape.getROIShapeID());
}
/* a string suited for the ID column of the results model table */
@Override
public String toString() {
return this.id;
}
/**
* @return the wrapped ROI shape
*/
private ROIShape getShape() {
return this.shape;
}
}
/**
* Implemented as specified by the I/F {@link TabPaneInterface}
* @see TabPaneInterface#getIndex()
*/
public int getIndex() { return INDEX; }
/** Initializes the component composing the display. */
private void initComponents()
{
state = State.READY;
removeButton = new JButton(REMOVE_NAME);
removeButton.setToolTipText(
UIUtilities.formatToolTipText(REMOVE_DESCRIPTION));
removeButton.setActionCommand(""+REMOVE);
removeButton.addActionListener(this);
saveButton = new JButton(SAVE_NAME);
saveButton.setToolTipText(
UIUtilities.formatToolTipText(SAVE_DESCRIPTION));
saveButton.setActionCommand(""+SAVE);
saveButton.addActionListener(this);
setButtonsEnabled(false);
addButton = new JButton(ADD_NAME);
addButton.setToolTipText(
UIUtilities.formatToolTipText(ADD_DESCRIPTION));
addButton.setActionCommand(""+ADD);
addButton.addActionListener(this);
addAllButton = new JButton(ADDALL_NAME);
addAllButton.setToolTipText(
UIUtilities.formatToolTipText(ADDALL_DESCRIPTION));
addAllButton.setActionCommand(""+ADDALL);
addAllButton.addActionListener(this);
removeAllButton = new JButton(REMOVE_ALL_NAME);
removeAllButton.setToolTipText(
UIUtilities.formatToolTipText(REMOVE_ALL_DESCRIPTION));
removeAllButton.setActionCommand(""+REMOVE_ALL);
removeAllButton.addActionListener(this);
addAllButton.setEnabled(false);
removeAllButton.setEnabled(false);
removeButton.setEnabled(false);
}
/**
* Sets the <code>enabled</code> flag of the {@link #saveButton}.
*
* @param enabled The value to set.
*/
private void setButtonsEnabled(boolean enabled)
{
saveButton.setEnabled(enabled);
}
/** Builds and lays out the UI. */
private void buildGUI()
{
resultsModel = new ResultsTableModel();
resultsModel.addColumn(AnnotationDescription.ROIID_STRING);
resultsModel.addColumn("Z");
resultsModel.addColumn("T");
resultsModel.addColumn("Channel");
resultsModel.addColumn("Text");
resultsModel.addColumn("Min");
resultsModel.addColumn("Max");
resultsModel.addColumn("Sum");
resultsModel.addColumn("Mean");
resultsModel.addColumn("stdDev");
results = new JTable(resultsModel);
results.getSelectionModel().addListSelectionListener(
new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
onFigureSelected();
}
});
JPanel centrePanel = new JPanel();
centrePanel.setLayout(new BorderLayout());
JScrollPane scrollPane = new JScrollPane(results);
centrePanel.add(scrollPane, BorderLayout.CENTER);
JPanel bottomPanel = new JPanel();
bottomPanel.setLayout(new FlowLayout());
//bottomPanel.add(addButton);
bottomPanel.add(addAllButton);
bottomPanel.add(removeButton);
bottomPanel.add(removeAllButton);
bottomPanel.add(saveButton);
JPanel containerPanel = new JPanel();
containerPanel.setLayout(new BorderLayout());
containerPanel.add(centrePanel, BorderLayout.CENTER);
containerPanel.add(bottomPanel, BorderLayout.SOUTH);
setLayout(new BorderLayout());
add(containerPanel, BorderLayout.CENTER);
}
/**
* Returns <code>true</code> if the shape is already displayed for
* the specified channel, <code>false</code> otherwise.
*
* @param shape The shape to add.
* @param channelName The name of channel to display.
*/
private boolean isValueDisplayed(ROIShape shape, String channelName)
{
long id = shape.getID();
int z = shape.getCoord3D().getZSection();
int t = shape.getCoord3D().getTimePoint();
for (int i = 0; i < resultsModel.getRowCount(); i++) {
ROIShape s = ((ShapeAsID) resultsModel.getValueAt(i, 0)).getShape();
if (s.getID() == id && s.getCoord3D().getZSection() == z &&
s.getCoord3D().getTimePoint() == t) {
//check channel
String v = (String) resultsModel.getValueAt(i, 3);
if (v.equals(channelName))
return true;
}
}
return false;
}
/**
* Populates the table with the data.
*
* @param shape The analyzed shape.
*/
private void getResults(ROIShape shape)
{
Vector<Vector<Object>> rows = new Vector<Vector<Object>>();
final ShapeAsID shapeID = new ShapeAsID(shape);
Iterator<String> channelIterator = channelName.values().iterator();
if (minStats.get(coord) == null)
return;
channelMin = minStats.get(coord);
channelMax = maxStats.get(coord);
channelMean = meanStats.get(coord);
channelStdDev = stdDevStats.get(coord);
channelSum = sumStats.get(coord);
String cName;
int channel;
Vector<Object> rowData;
while (channelIterator.hasNext())
{
cName = channelIterator.next();
channel = nameMap.get(cName);
if (!isValueDisplayed(shape, cName)) {
rowData = new Vector<Object>();
rowData.add(shapeID);
rowData.add(shape.getCoord3D().getZSection()+1);
rowData.add(shape.getCoord3D().getTimePoint()+1);
rowData.add(cName);
rowData.add(MeasurementAttributes.TEXT.get(shape.getFigure()));
rowData.add(channelMin.get(channel));
rowData.add(channelMax.get(channel));
rowData.add(channelSum.get(channel));
rowData.add(channelMean.get(channel));
rowData.add(channelStdDev.get(channel));
rows.add(rowData);
}
}
for (Vector<Object> data : rows) {
resultsModel.addRow(data);
}
results.repaint();
}
/** Saves the results of the table to an Excel file. */
private void saveResults()
{
FileChooser chooser = view.createSaveToExcelChooser();
if (chooser.showDialog() != JFileChooser.APPROVE_OPTION) return;
File file = chooser.getFormattedSelectedFile();
ExcelWriter writer = null;
try
{
String filename = file.getAbsolutePath();
writer = new ExcelWriter(filename);
writer.openFile();
writer.createSheet("Intensity Results");
writer.writeTableToSheet(0, 0, resultsModel);
BufferedImage originalImage = model.getRenderedImage();
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.setAttributes(MeasurementAttributes.SHOWID, false);
try {
if (image != null) {
model.getDrawingView().print(image.getGraphics());
writer.addImageToWorkbook("ThumbnailImage", image);
int col = writer.getMaxColumn(0);
writer.writeImage(0, col+1, 256, 256, "ThumbnailImage");
}
} catch (Exception e) {
Logger logger = MeasurementAgent.getRegistry().getLogger();
logger.error(this, "Cannot write Image: "+e.toString());
}
writer.close();
} catch (IOException e) {
Logger logger = MeasurementAgent.getRegistry().getLogger();
logger.error(this, "Cannot save ROI results: "+e.toString());
UserNotifier un = MeasurementAgent.getRegistry().getUserNotifier();
un.notifyInfo("Save Results", "An error occurred while trying to" +
" save the data.\nPlease try again.");
file.delete();
try {
writer.close();
} catch (Exception e2) {
//ignore: cannot close the writer.
}
return;
}
Registry reg = MeasurementAgent.getRegistry();
UserNotifier un = reg.getUserNotifier();
un.notifyInfo("Save ROI results", "The ROI results have been " +
"successfully saved.");
}
/** Removes the selected results from the table. */
private void removeResults()
{
int[] rows = results.getSelectedRows();
for (int i = 0;i < rows.length; i++){
resultsModel.removeRow(rows[i]-i);
}
results.clearSelection();
setButtonsEnabled(results.getRowCount() > 0);
}
/**
* @return the ROI shapes currently in the results table rows, never null
*/
private Set<ROIShape> getShapesInRows() {
final Set<ROIShape> shapes = new HashSet<ROIShape>();
for (int i = 0; i < resultsModel.getRowCount(); i++)
shapes.add(((ShapeAsID) resultsModel.getValueAt(i, 0)).getShape());
return shapes;
}
/**
* Check to see if the selected figure contains textFigure
* @param selectedFigures see above.
* @return see above.
*/
private boolean validFigures(Set<Figure> selectedFigures)
{
if (CollectionUtils.isEmpty(selectedFigures))
return false;
for (Figure figure : selectedFigures)
if (figure instanceof MeasureTextFigure)
return false;
return true;
}
/**
* Adds the statistics from the selected ROI to the table.
*/
private void addResults()
{
Set<Figure> selectedFigures =
view.getDrawingView().getSelectedFigures();
if (!validFigures(selectedFigures))
return;
if (CollectionUtils.isEmpty(selectedFigures) ||
state == State.ANALYSING) return;
state = State.ANALYSING;
List<ROIShape> shapeList = new ArrayList<ROIShape>();
final Set<ROIShape> alreadyInTable = getShapesInRows();
Iterator<Figure> iterator = selectedFigures.iterator();
ROIFigure fig;
Map<ROIShape, Map<Integer, ROIShapeStats>> analysisResults = model.getAnalysisResults();
if (analysisResults == null)
analysisResults = Collections.emptyMap();
ROIShape shape;
while (iterator.hasNext()) {
fig = (ROIFigure) iterator.next();
shape = fig.getROIShape();
if (alreadyInTable.contains(shape))
removeShape(shape);
final Map<Integer, ROIShapeStats> shapeStatsByChannel = analysisResults.get(shape);
if (shapeStatsByChannel == null || shapeStatsByChannel.isEmpty())
/* if empty, they were probably wiped out by AnalysisStatsWrapper.convertStats */
shapeList.add(shape);
}
if (shapeList.size() > 0) {
view.calculateStats(shapeList);
onFigureSelected();
}
state = State.READY;
}
/**
* Removes the shape from the table.
*
* @param shapeID The identifier of the shape.
*/
private void removeShape(ROIShape shape)
{
List<Integer> indexes = new ArrayList<Integer>();
for (int i = 0; i < resultsModel.getRowCount(); i++)
if (((ShapeAsID) resultsModel.getValueAt(i, 0)).getShape().equals(shape))
indexes.add(i);
Iterator<Integer> j = indexes.iterator();
while (j.hasNext()) {
resultsModel.removeRow(j.next());
}
}
/**
* Sets the enabled flag of the various buttons.
*
* @param value The value to set.
*/
private void setControls(boolean value)
{
addAllButton.setEnabled(value);
removeAllButton.setEnabled(value);
removeButton.setEnabled(value);
saveButton.setEnabled(value);
}
/**
* Adds the statistics from the ROIShapes of the select ROI to the table.
*/
private void addAllResults()
{
Set<Figure> selectedFigures =
view.getDrawingView().getSelectedFigures();
if (CollectionUtils.isEmpty(selectedFigures) ||
state == State.ANALYSING) return;
state = State.ANALYSING;
setControls(false);
List<ROIShape> shapeList = new ArrayList<ROIShape>();
final Set<ROIShape> alreadyInTable = getShapesInRows();
Iterator<Figure> i = selectedFigures.iterator();
ROIFigure fig;
TreeMap<Coord3D, ROIShape> treeMap;
Iterator<Coord3D> j;
ROIShape shape;
Map<ROIShape, Map<Integer, ROIShapeStats>> analysisResults = model.getAnalysisResults();
if (analysisResults == null)
analysisResults = Collections.emptyMap();
while (i.hasNext()) {
fig = (ROIFigure) i.next();
if (!(fig instanceof MeasureTextFigure)) {
treeMap = fig.getROI().getShapes();
j = treeMap.keySet().iterator();
while (j.hasNext()) {
shape = treeMap.get(j.next());
if (!alreadyInTable.contains(shape)) {
final Map<Integer, ROIShapeStats> shapeStatsByChannel = analysisResults.get(shape);
if (shapeStatsByChannel == null || shapeStatsByChannel.isEmpty())
/* if empty, they were probably wiped out by AnalysisStatsWrapper.convertStats */
shapeList.add(shape);
}
}
}
}
if (shapeList.isEmpty()) {
if (!analysisResults.isEmpty()) {
displayAnalysisResults();
}
} else {
view.calculateStats(shapeList);
}
}
/**
* Creates a new instance.
*
* @param view Reference to the View. Mustn't be <code>null</code>.
* @param model Reference to the Model. Mustn't be <code>null</code>.
*/
IntensityResultsView(MeasurementViewerUI view, MeasurementViewerModel model)
{
if (view == null)
throw new IllegalArgumentException("No view.");
if (model == null)
throw new IllegalArgumentException("No model.");
this.view = view;
this.model = model;
initComponents();
buildGUI();
}
/**
* 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.INTENSITYVIEW);
}
/**
* Get the analysis results from the model and convert to the
* necessary array. data types using the ROIStats wrapper then
* create the appropriate table data and summary statistics.
*/
void displayAnalysisResults()
{
this.ROIStats = model.getAnalysisResults();
onFigureSelected();
if (ROIStats == null || ROIStats.size() == 0) {
state = State.READY;
return;
}
shapeMap = new TreeMap<Coord3D, ROIShape>(new Coord3D());
minStats = new TreeMap<Coord3D, Map<Integer, Double>>(new Coord3D());
maxStats = new TreeMap<Coord3D, Map<Integer, Double>>(new Coord3D());
meanStats = new TreeMap<Coord3D, Map<Integer, Double>>(new Coord3D());
sumStats = new TreeMap<Coord3D, Map<Integer, Double>>(new Coord3D());
stdDevStats = new TreeMap<Coord3D, Map<Integer, Double>>(new Coord3D());
Entry entry;
Iterator j = ROIStats.entrySet().iterator();
channelName = new TreeMap<Integer, String>();
nameMap = new HashMap<String, Integer>();
Map<StatsType, Map> shapeStats;
Coord3D c3D;
ChannelData channelData;
int channel;
List<ChannelData> metadata = model.getMetadata();
Iterator<ChannelData> i;
while (j.hasNext())
{
entry = (Entry) j.next();
shape = (ROIShape) entry.getKey();
//shapeMap.put(shape.getCoord3D(), shape);
if (shape.getFigure() instanceof MeasureTextFigure)
{
state = State.READY;
return;
}
c3D = shape.getCoord3D();
shapeStats = AnalysisStatsWrapper.convertStats(
(Map) entry.getValue());
if (shapeStats != null) {
minStats.put(c3D, shapeStats.get(StatsType.MIN));
maxStats.put(c3D, shapeStats.get(StatsType.MAX));
meanStats.put(c3D, shapeStats.get(StatsType.MEAN));
sumStats.put(c3D, shapeStats.get(StatsType.SUM));
stdDevStats.put(c3D, shapeStats.get(StatsType.STDDEV));
}
channelName.clear();
nameMap.clear();
channelColour.clear();
i = metadata.iterator();
while (i.hasNext()) {
channelData = i.next();
channel = channelData.getIndex();
if (model.isChannelActive(channel))
{
channelName.put(channel, channelData.getChannelLabeling());
nameMap.put(channelName.get(channel), channel);
channelColour.put(channel,
(Color) model.getActiveChannels().get(channel));
}
}
if (channelName.size() == 0 || nameMap.size() == 0 ||
channelColour.size() == 0)
{
state = State.READY;
return;
}
coord = c3D;
getResults(shape);
}
setButtonsEnabled(true);
onFigureSelected();
state = State.READY;
}
/** Invokes when figures are selected. */
void onFigureSelected()
{
Set<Figure> selectedFigures =
view.getDrawingView().getSelectedFigures();
boolean valid = validFigures(selectedFigures);
addButton.setEnabled(valid);
addAllButton.setEnabled(valid);
if (results != null) {
int count = results.getRowCount();
int[] rows = results.getSelectedRows();
removeButton.setEnabled(rows != null && rows.length > 0);
removeAllButton.setEnabled(count > 0);
} else {
removeButton.setEnabled(false);
removeAllButton.setEnabled(false);
}
}
/** Removes the results from the table. */
void removeAllResults()
{
int count = results.getRowCount();
for (int i = count-1 ; i >= 0 ; i--)
resultsModel.removeRow(i);
model.setAnalysisResults(null);
setButtonsEnabled(false);
onFigureSelected();
}
/**
* Listens to the controls.
* @see ActionListener#actionPerformed(ActionEvent)
*
*/
public void actionPerformed(ActionEvent e)
{
int index = Integer.parseInt(e.getActionCommand());
switch (index) {
case ADD:
addResults();
break;
case ADDALL:
addAllResults();
break;
case SAVE:
saveResults();
break;
case REMOVE:
removeResults();
break;
case REMOVE_ALL:
removeAllResults();
}
}
/**
* The table model for the results table, only overridden to make it read
* only.
*/
class ResultsTableModel
extends DefaultTableModel
{
/**
* Overridden to make sure that the cell cannot be edited.
* @see DefaultTableModel#isCellEditable(int, int)
*/
public boolean isCellEditable(int row, int col) { return false; }
}
}