/*
* org.openmicroscopy.shoola.agents.measurement.view.ROIAssistant
*
*------------------------------------------------------------------------------
* Copyright (C) 2006-2007 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.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.AbstractListModel;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.JViewport;
import javax.swing.ListCellRenderer;
import javax.swing.UIManager;
import javax.swing.table.JTableHeader;
//Third-party libraries
//Application-internal dependencies
import org.openmicroscopy.shoola.agents.measurement.IconManager;
import org.openmicroscopy.shoola.util.roi.model.ROI;
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.TitlePanel;
import org.openmicroscopy.shoola.util.ui.UIUtilities;
/**
* Dialog uses to propagate ROIs
*
* @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 ROIAssistant
extends JDialog
implements ActionListener
{
/** Action command ID to accept the current ROI assistant results.*/
private static final int CLOSE = 0;
/**
* The table showing the ROI and allowing the user to propagate the selected
* ROI through time and Z-section.
*/
private ROIAssistantTable table;
/**
* The model which will define the ROI's displayed in the table.
*/
private ROIAssistantModel model;
/** Text field showing the current type of the selected shape. */
private JTextField shapeType;
/** Text field showing the x coordinate of the selected shape. */
private JTextField xCoord;
/** Text field showing the y coordinate of the selected shape. */
private JTextField yCoord;
/** Text field showing the width of the selected shape. */
private JTextField width;
/** Text field showing the height of the selected shape. */
private JTextField height;
/** Text field showing the description of the selected shape. */
private JTextField description;
/** Checkbox which is selected if the user has selected to add an ROI. */
private JRadioButton addButton;
/** Checkbox which is selected if the user has selected to remove an ROI. */
private JRadioButton removeButton;
/** The scroll pane of the Table. */
private JScrollPane scrollPane;
/** button closes windows. */
private JButton closeButton;
/** Model for the measurement tool. */
private MeasurementViewerUI view;
/** The initial shape selected when launching the ROIAssistant. */
private ROIShape initialShape;
/** The panel showing the corner z\t graphic. */
private JPanel cornerPane;
/**
* Maps the coordinate to a cell in the table.
*
* @param coord see above.
* @return see above.
*/
private Point mapCoordToCell(Coord3D coord)
{
int w = table.getColumnWidth();
int h = table.getRowHeight();
int x = coord.getTimePoint()*w;
int y = (table.getRowCount()-coord.getZSection())*h;
return new Point(x, y);
}
/** Create the UI for the Assistant. */
private void buildUI()
{
JPanel panel = new JPanel();
JPanel infoPanel = createInfoPanel();
JPanel shapePanel = createShapePanel();
createAcceptButton();
createCornerPane();
scrollPane = new JScrollPane(table);
scrollPane.setVerticalScrollBar(scrollPane.createVerticalScrollBar());
scrollPane.setHorizontalScrollBar(
scrollPane.createHorizontalScrollBar());
JPanel scrollPanel = new JPanel();
scrollPanel.setLayout(new BoxLayout(scrollPanel, BoxLayout.X_AXIS));
scrollPanel.add(Box.createHorizontalStrut(10));
scrollPanel.add(scrollPane);
scrollPanel.add(Box.createHorizontalStrut(10));
scrollPanel.add(createActionPanel());
scrollPanel.add(Box.createHorizontalStrut(10));
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
panel.add(Box.createVerticalStrut(10));
panel.add(scrollPanel);
panel.add(Box.createVerticalStrut(10));
panel.add(shapePanel);
panel.add(Box.createVerticalStrut(10));
panel.add(closeButton);
panel.add(Box.createVerticalStrut(10));
Container c = getContentPane();
c.setLayout(new BorderLayout());
c.add(infoPanel, BorderLayout.NORTH);
c.add(panel, BorderLayout.CENTER);
setSize(550,530);
}
/**
* Create the table and model.
*
* @param numRow The number of z sections in the image.
* @param numCol The number of time points in the image.
* @param currentPlane the current plane of the image.
* @param selectedROI The ROI which will be propagated.
*/
private void createTable(int numRow, int numCol, Coord3D currentPlane,
ROI selectedROI)
{
model = new ROIAssistantModel(numRow, numCol, currentPlane,
selectedROI);
table = new ROIAssistantTable(model);
table.addMouseListener(new java.awt.event.MouseAdapter()
{
public void mousePressed(java.awt.event.MouseEvent e)
{
int col = table.getSelectedColumn();
int row = table.getSelectedRow();
if(row < 0 || row >= table.getRowCount() ||
col < 0 || col > table.getColumnCount())
return;
ROIShape shape = table.getShapeAt(row, col);
if (shape != null)
{
initialShape = shape;
shapeType.setText(shape.getFigure().getType());
description.setText(
(String) shape.getFigure().getAttribute(
MeasurementAttributes.TEXT));
xCoord.setText(shape.getFigure().getStartPoint().getX()+"");
yCoord.setText(shape.getFigure().getStartPoint().getY()+"");
width.setText(Math.abs(
shape.getFigure().getEndPoint().getX()-
shape.getFigure().getStartPoint().getX())+"");
height.setText(Math.abs(
shape.getFigure().getEndPoint().getY()-
shape.getFigure().getStartPoint().getY())+"");
}
}
public void mouseReleased(java.awt.event.MouseEvent e)
{
if (initialShape == null) return;
int[] col = table.getSelectedColumns();
int[] row = table.getSelectedRows();
for (int i = 0 ; i < row.length ; i++)
row[i] = (table.getRowCount()-row[i])-1;
int mincol = col[0];
int maxcol = col[0];
int minrow = row[0];
int maxrow = row[0];
for (int i = 0 ; i < col.length; i++)
{
mincol = Math.min(mincol, col[i]);
maxcol = Math.max(maxcol, col[i]);
}
for (int i = 0 ; i < row.length; i++)
{
minrow = Math.min(minrow, row[i]);
maxrow = Math.max(maxrow, row[i]);
}
if(minrow < 0 || maxrow > table.getRowCount() ||
mincol < 0 || maxcol > table.getColumnCount())
return;
int boundrow;
int boundcol;
if (maxcol != initialShape.getT()) boundcol = maxcol;
else boundcol = mincol;
if (maxrow != initialShape.getZ()) boundrow = maxrow;
else boundrow = minrow;
if (addButton.isSelected())
view.propagateShape(initialShape, boundcol, boundrow);
if (removeButton.isSelected())
view.deleteShape(initialShape, boundcol, boundrow);
initialShape=null;
table.repaint();
}
});
}
/**
* Create the corner pane.
*/
private void createCornerPane()
{
cornerPane = new JPanel();
cornerPane.setLayout(new BorderLayout());
JLabel icon = new JLabel();
icon.setIcon(IconManager.getInstance().getIcon(IconManager.CORNERICON));
cornerPane.add(icon, BorderLayout.CENTER);
}
/**
* Creates the action panel is the panel which holds the buttons to choose
* the action to perform on the ROI.
*
* @return See above.
*/
private JPanel createActionPanel()
{
JPanel actionPanel = new JPanel();
addButton = new JRadioButton("Add ROI");
removeButton = new JRadioButton("Remove ROI");
ButtonGroup group = new ButtonGroup();
addButton.setSelected(true);
group.add(addButton);
group.add(removeButton);
actionPanel.setLayout(new BorderLayout());
JPanel subPanel = new JPanel();
subPanel.setLayout(new BoxLayout(subPanel, BoxLayout.Y_AXIS));
subPanel.add(addButton);
subPanel.add(removeButton);
actionPanel.add(subPanel, BorderLayout.NORTH);
return actionPanel;
}
/**
* Creates the info panel at the top the the dialog,
* showing a little text about the ROI Assistant.
*
* @return See above.
*/
private JPanel createInfoPanel()
{
JPanel infoPanel = new TitlePanel("ROI Assistant",
"The ROI Assistant allows you to create an ROI " +
"which extends \n" +
"through time and z-sections.",
IconManager.getInstance().getIcon(IconManager.WIZARD_48));
return infoPanel;
}
/**
* Creates the shape panel which shows the parameters of the initial shape.
*
* @return See above.
*/
private JPanel createShapePanel()
{
JPanel shapePanel = new JPanel();
shapeType = new JTextField();
description = new JTextField();
xCoord = new JTextField();
yCoord = new JTextField();
width = new JTextField();
height = new JTextField();
JLabel shapeTypeLabel = new JLabel("Shape Type ");
JLabel xCoordLabel = new JLabel("X Coord");
JLabel yCoordLabel = new JLabel("Y Coord");
JLabel widthLabel = new JLabel("Width");
JLabel heightLabel = new JLabel("Height");
JLabel descriptionLabel = new JLabel("Description");
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
panel.add(createLabelText(shapeTypeLabel, shapeType));
panel.add(Box.createVerticalStrut(5));
panel.add(createLabelText(descriptionLabel, description));
JPanel panel2 = new JPanel();
panel2.setLayout(new BoxLayout(panel2, BoxLayout.Y_AXIS));
panel2.add(createLabelText(xCoordLabel, xCoord));
panel2.add(Box.createVerticalStrut(5));
panel2.add(createLabelText(yCoordLabel, yCoord));
JPanel panel3 = new JPanel();
panel3.setLayout(new BoxLayout(panel3, BoxLayout.Y_AXIS));
panel3.add(createLabelText(widthLabel, width));
panel3.add(Box.createVerticalStrut(5));
panel3.add(createLabelText(heightLabel, height));
shapePanel.setLayout(new BoxLayout(shapePanel, BoxLayout.X_AXIS));
shapePanel.add(panel);
shapePanel.add(Box.createHorizontalStrut(10));
shapePanel.add(panel2);
shapePanel.add(Box.createHorizontalStrut(10));
shapePanel.add(panel3);
return shapePanel;
}
/**
* Creates a panel with label and textfield.
*
* @param l label The label to layout.
* @param t textfield The field to layout.
* @return see above.
*/
private JPanel createLabelText(JLabel l, JTextField t)
{
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
panel.add(l);
panel.add(t);
UIUtilities.setDefaultSize(l, new Dimension(80,22));
UIUtilities.setDefaultSize(t, new Dimension(80,22));
return panel;
}
/** Creates the accept button to close on click. */
private void createAcceptButton()
{
closeButton = new JButton("Close");
closeButton.setActionCommand(""+CLOSE);
closeButton.addActionListener(this);
}
/** Closes the ROIAssistant window. */
private void closeAssistant()
{
setVisible(false);
this.dispose();
}
/**
* Creates a new instance.
*
* @param numRow The number of z-sections in the image.
* @param numCol The numer of time points in the image.
* @param currentPlane The current plane of the image.
* @param selectedROI The ROI which will be propagated.
* @param view a reference to the view.
*/
ROIAssistant(int numRow, int numCol, Coord3D currentPlane,
ROI selectedROI, MeasurementViewerUI view)
{
super(view);
this.view = view;
initialShape = null;
//this.setAlwaysOnTop(true);
this.setModal(true);
createTable(numRow, numCol,currentPlane, selectedROI);
buildUI();
JList rowHeader = new JList(new HeaderListModel(table.getRowCount()));
//table.setDefaultRenderer(JComponent.class, new TableComponentCellRenderer());
rowHeader.setFixedCellHeight(table.getRowHeight());
rowHeader.setFixedCellWidth(table.getColumnWidth());
rowHeader.setCellRenderer(new RowHeaderRenderer(table));
scrollPane.setRowHeaderView(rowHeader);
scrollPane.setCorner(JScrollPane.UPPER_LEFT_CORNER, cornerPane);
JViewport viewPort = scrollPane.getViewport();
Point point = mapCoordToCell(currentPlane);
int x = (int) Math.max((point.getX()-6*table.getColumnWidth()), 0);
int y = (int) Math.max((point.getY()-6*table.getColumnWidth()), 0);
viewPort.setViewPosition(new Point(x, y));
}
/**
* Reacts to event fired by the various controls.
* @see ActionListener#actionPerformed(ActionEvent)
*/
public void actionPerformed(ActionEvent evt)
{
int id = -1;
try
{
id = Integer.parseInt(evt.getActionCommand());
switch (id)
{
case CLOSE:
closeAssistant();
break;
}
}
catch (Exception e)
{
// TODO: handle exception
}
}
/**
* Class to define the row header data, this is the Z section
* count in the ROIAssistant.
*/
class HeaderListModel
extends AbstractListModel
{
/** The header values. */
private String[] headers;
/**
* Instantiate the header values with a count from n to 1.
* @param n see above.
*/
public HeaderListModel(int n)
{
headers = new String[n];
for (int i = 0; i<n; i++)
headers[i] = ""+(n-i);
}
/**
* Get the size of the header.
* @return see above.
*/
public int getSize(){ return headers.length; }
/**
* Get the header object at index.
* @param index see above.
* @return see above.
*/
public Object getElementAt(int index) { return headers[index]; }
}
/**
* The renderer for the row header.
*/
class RowHeaderRenderer
extends JLabel
implements ListCellRenderer
{
/**
* Instantiate row renderer for table.
* @param table see above.
*/
public RowHeaderRenderer(JTable table)
{
if (table != null)
{
JTableHeader header = table.getTableHeader();
setOpaque(true);
setBorder(UIManager.getBorder("TableHeader.cellBorder"));
setHorizontalAlignment(CENTER);
setHorizontalTextPosition(CENTER);
setForeground(header.getForeground());
setBackground(header.getBackground());
setFont(header.getFont());
}
}
/**
* Return the component for the renderer.
* @param list the list containing the headers render context.
* @param value the value to be rendered.
* @param index the index of the rendered object.
* @param isSelected is the current header selected.
* @param cellHasFocus has the cell focus.
* @return the render component.
*/
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus)
{
setText((value == null) ? "" : value.toString());
return this;
}
}
}