/* *------------------------------------------------------------------------------ * 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.measurement.view; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Cursor; import java.awt.Dimension; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.TreeMap; import javax.swing.ButtonGroup; import javax.swing.ImageIcon; import javax.swing.JCheckBoxMenuItem; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JTabbedPane; import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.filechooser.FileFilter; import omero.gateway.model.ROIData; import omero.gateway.model.ROIResult; import org.jhotdraw.draw.AttributeKey; import org.jhotdraw.draw.DelegationSelectionTool; import org.jhotdraw.draw.Drawing; import org.jhotdraw.draw.Figure; import org.openmicroscopy.shoola.agents.events.iviewer.ImageViewport; import org.openmicroscopy.shoola.agents.events.measurement.SelectPlane; import org.openmicroscopy.shoola.agents.measurement.IconManager; import org.openmicroscopy.shoola.agents.measurement.MeasurementAgent; import org.openmicroscopy.shoola.agents.measurement.actions.MeasurementViewerAction; import omero.gateway.model.ChannelData; import org.openmicroscopy.shoola.env.config.Registry; import org.openmicroscopy.shoola.env.data.model.DeletableObject; import org.openmicroscopy.shoola.env.event.EventBus; import org.openmicroscopy.shoola.env.ui.TaskBar; import org.openmicroscopy.shoola.env.ui.TopWindow; import org.openmicroscopy.shoola.env.ui.UserNotifier; import org.openmicroscopy.shoola.util.filter.file.ExcelFilter; import org.openmicroscopy.shoola.util.filter.file.JPEGFilter; import org.openmicroscopy.shoola.util.filter.file.PNGFilter; import org.openmicroscopy.shoola.util.roi.exception.NoSuchROIException; import org.openmicroscopy.shoola.util.roi.exception.ROICreationException; import org.openmicroscopy.shoola.util.roi.model.annotation.MeasurementAttributes; import org.openmicroscopy.shoola.util.roi.model.util.Coord3D; import org.openmicroscopy.shoola.util.roi.figures.MeasureMaskFigure; 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.ShapeList; import org.openmicroscopy.shoola.util.ui.LoadingWindow; import org.openmicroscopy.shoola.util.ui.UIUtilities; import org.openmicroscopy.shoola.util.ui.drawingtools.canvas.DrawingCanvasView; import org.openmicroscopy.shoola.util.ui.filechooser.FileChooser; import org.openmicroscopy.shoola.util.ui.graphutils.ChartObject; /** * The {@link MeasurementViewer} view. * * @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 MeasurementViewerUI extends TopWindow { /** The message displayed when a ROI cannot be retrieved. */ static final String RETRIEVE_MSG = "Cannot retrieve the ROI"; /** The message displayed when a ROI cannot be created. */ static final String CREATE_MSG = "Cannot create the ROI"; /** The message displayed when a ROI cannot be deleted. */ static final String DELETE_MSG = "Cannot delete the ROI"; /** * The message displayed when a an ROI exception occurred but cause * is unknown. */ static final String UNKNOWN_MSG = "An unknown error occurred in "; /** The default message. */ static final String DEFAULT_MSG = ""; /** The default size of the window. */ private static final Dimension DEFAULT_SIZE = new Dimension(400, 300); /** The title for the measurement tool main window. */ private static final String WINDOW_TITLE = ""; /** index to identify inspector tab. */ public static final int INSPECTOR_INDEX = 0; /** index to identify manager tab. */ public static final int MANAGER_INDEX = 1; /** index to identify results tab. */ public static final int RESULTS_INDEX = 2; /** index to identify graph tab. */ public static final int GRAPH_INDEX = 3; /** index to identify intensity tab. */ public static final int INTENSITY_INDEX = 4; /** index to identify calculation tab. */ public static final int CALCWIZARD_INDEX = 5; /** index to identify intensity results view tab. */ public static final int INTENSITYRESULTVIEW_INDEX = 6; /** Reference to the Model. */ private MeasurementViewerModel model; /** Reference to the Control. */ private MeasurementViewerControl controller; /** Reference to the Component. */ private MeasurementViewer component; /** The loading window. */ private LoadingWindow loadingWindow; /** The tool bar. */ private ToolBar toolBar; /** The ROI inspector. */ private ObjectInspector roiInspector; /** The ROI manager. */ private ObjectManager roiManager; /** The Results component. */ private MeasurementResults roiResults; /** The graphing component. */ private GraphPane graphPane; /** The graphing component. */ private IntensityView intensityView; /** The graphing component. */ private IntensityResultsView intensityResultsView; /** The calculation Wizard component. */ private CalculationWizard calcWizard; /** Tab pane hosting the various panel. */ private JTabbedPane tabs; /** The status bar. */ private StatusBar statusBar; /** the creation option to create multiple figures in the UI. */ private JCheckBoxMenuItem createMultipleFigure; /** the creation option to create single figures in the UI. */ private JCheckBoxMenuItem createSingleFigure; /** The collection of components displaying the tables. */ private List<ServerROITable> roiTables; /** The main menu bar. */ private JMenuBar mainMenu; /** Flag if the graph and intensity panels are shown */ private boolean showGraph = true; /** * Scrolls to the passed figure. * * @param figure The figure to handle. */ private void scrollToFigure(ROIFigure figure) { EventBus bus = MeasurementAgent.getRegistry().getEventBus(); bus.post(new ImageViewport(model.getImageID(), model.getPixelsID(), figure.getBounds().getBounds())); } /** * Creates the menu bar. * * @return The menu bar. */ private JMenuBar createMenuBar() { JMenuBar menuBar = new JMenuBar(); menuBar.add(createControlsMenu()); menuBar.add(createOptionsMenu()); TaskBar tb = MeasurementAgent.getRegistry().getTaskBar(); menuBar.add(tb.getMenu(TaskBar.WINDOW_MENU)); menuBar.add(tb.getMenu(TaskBar.HELP_MENU)); return menuBar; } /** * Helper method to create the controls menu. * * @return The controls sub-menu. */ private JMenu createControlsMenu() { JMenu menu = new JMenu("Controls"); menu.setMnemonic(KeyEvent.VK_C); MeasurementViewerAction a = controller.getAction(MeasurementViewerControl.LOAD); JMenuItem item = new JMenuItem(a); item.setText(a.getName()); menu.add(item); a = controller.getAction(MeasurementViewerControl.SAVE); item = new JMenuItem(a); item.setText(a.getName()); menu.add(item); a = controller.getAction(MeasurementViewerControl.ROI_ASSISTANT); item = new JMenuItem(a); item.setText(a.getName()); menu.add(item); return menu; } /** * Helper method to create the Options menu. * * @return The options sub-menu. */ private JMenu createOptionsMenu() { JMenu menu = new JMenu("Options"); ButtonGroup displayUnits = new ButtonGroup(); menu.setMnemonic(KeyEvent.VK_O); JMenu subMenu = new JMenu("Units"); JCheckBoxMenuItem item; MeasurementViewerAction a; if (model.sizeInMicrons()) { a = controller.getAction(MeasurementViewerControl.IN_MICRONS); item = new JCheckBoxMenuItem(a); item.setText(a.getName()); displayUnits.add(item); subMenu.add(item); item.setSelected(true); } model.showMeasurementsInMicrons(model.sizeInMicrons()); a = controller.getAction(MeasurementViewerControl.IN_PIXELS); item = new JCheckBoxMenuItem(a); item.setText(a.getName()); displayUnits.add(item); subMenu.add(item); if (!model.sizeInMicrons()) item.setSelected(true); menu.add(subMenu); ButtonGroup createFigureGroup = new ButtonGroup(); JMenu creationMenu = new JMenu("ROI Creation"); a = controller.getAction( MeasurementViewerControl.CREATE_SINGLE_FIGURE); createSingleFigure = new JCheckBoxMenuItem(a); createSingleFigure.setText(a.getName()); createFigureGroup.add(createSingleFigure); creationMenu.add(createSingleFigure); a = controller.getAction( MeasurementViewerControl.CREATE_MULTIPLE_FIGURES); createMultipleFigure = new JCheckBoxMenuItem(a); createMultipleFigure.setText(a.getName()); createFigureGroup.add(createMultipleFigure); creationMenu.add(createMultipleFigure); createMultipleFigure.setSelected(true); //TODO: retrieve info menu.add(creationMenu); return menu; } /** /** Initializes the components composing the display. */ private void initComponents() { showGraph = !model.isBigImage() && hasStatsInfo(); roiTables = new ArrayList<ServerROITable>(); statusBar = new StatusBar(); toolBar = new ToolBar(component, this, controller, model); roiManager = new ObjectManager(this, controller, model); roiInspector = new ObjectInspector(controller, model); roiResults = new MeasurementResults(controller, model, this); if (showGraph) { graphPane = new GraphPane(this, controller, model); intensityView = new IntensityView(this, model, controller); intensityResultsView = new IntensityResultsView(this, model); } calcWizard = new CalculationWizard(controller, model); tabs = new JTabbedPane(JTabbedPane.TOP, JTabbedPane.WRAP_TAB_LAYOUT); DrawingCanvasView canvasView = model.getDrawingView(); canvasView.addMouseListener(new MouseAdapter() { /** * Sets the cursor. * @see MouseListener#mouseEntered(MouseEvent) */ public void mouseEntered(MouseEvent e) { Cursor cursor; if (model.getDrawingEditor().getTool() instanceof DelegationSelectionTool) cursor = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR); else cursor = Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR); getDrawingView().setCursor(cursor); } }); tabs.setAlignmentX(LEFT_ALIGNMENT); tabs.addChangeListener(new ChangeListener() { // This method is called whenever the selected tab changes public void stateChanged(ChangeEvent evt) { if (model.isHCSData()) { updateDrawingArea(); } else { if (inDataView()) controller.analyseSelectedFigures(); } } }); } /** * Creates a new instance. * The {@link #initialize(MeasurementViewer, MeasurementViewerControl, * MeasurementViewerModel) initialize} method should be called straight * after to link this View to the Controller. * * @param title The window title. */ MeasurementViewerUI(String title) { super(WINDOW_TITLE+title); loadingWindow = new LoadingWindow(this); } /** * Links this View to its Controller and Model. * * @param component Reference to the Component. Mustn't be <code>null</code>. * @param controller Reference to the Control. Mustn't be <code>null</code>. * @param model Reference to the Model. Mustn't be <code>null</code>. */ void initialize(MeasurementViewer component, MeasurementViewerControl controller, MeasurementViewerModel model) { if (component == null) throw new NullPointerException("No component."); if (controller == null) throw new NullPointerException("No control."); if (model == null) throw new NullPointerException("No model."); this.component = component; this.model = model; this.controller = controller; controller.attachListeners(); ImageIcon icon = IconManager.getInstance().getImageIcon( IconManager.MEASUREMENT_TOOL); if (icon != null) setIconImage(icon.getImage()); initComponents(); controller.getAction(MeasurementViewerControl.IN_MICRONS); setName("measurement viewer window"); } /** Builds and lays out the GUI. */ void buildGUI() { mainMenu = createMenuBar(); setJMenuBar(mainMenu); tabs.addTab(roiManager.getComponentName(), roiManager.getComponentIcon(), roiManager); tabs.addTab(roiInspector.getComponentName(), roiInspector.getComponentIcon(), roiInspector); tabs.addTab(roiResults.getComponentName(), roiResults.getComponentIcon(), roiResults); if (showGraph) { tabs.addTab(graphPane.getComponentName(), graphPane.getComponentIcon(), graphPane); tabs.addTab(intensityView.getComponentName(), intensityView.getComponentIcon(), intensityView); tabs.addTab(intensityResultsView.getComponentName(), intensityResultsView.getComponentIcon(), intensityResultsView); } Container container = getContentPane(); container.setLayout(new BorderLayout(0, 0)); container.add(toolBar, BorderLayout.NORTH); container.add(tabs, BorderLayout.CENTER); container.add(statusBar, BorderLayout.SOUTH); } /** * Checks if all channels have stats * @return */ private boolean hasStatsInfo() { List<ChannelData> channels = model.getMetadata(); for(ChannelData channel : channels) { if(!channel.hasStats()) return false; } return true; } /** * Displays the menu at the specified location if not already visible. * * @param x The x-coordinate of the mouse click. * @param y The y-coordinate of the mouse click. */ void showROIManagementMenu(int x, int y) { roiManager.showROIManagementMenu(x, y); } /** * Merge the ROIShapes with identifiers in the idList and the ROIShapes * selected in the shapeList from those ROI. * * @param idList see above. * @param shapeList see above. */ void mergeROI(List<Long> idList, List<ROIShape> shapeList) { try { model.notifyDataChanged(true); ROI newROI = model.cloneROI(idList.get(0)); ROIShape newShape; ROIFigure roi; for (ROIShape shape : shapeList) { roi = shape.getFigure(); if (!roi.isReadOnly() && roi.canEdit()) { newShape = new ROIShape(newROI, shape.getCoord3D(), shape); if (getDrawing().contains(roi)) { if (roi.canAnnotate()) roi.removeFigureListener(controller); getDrawing().removeDrawingListener(controller); getDrawing().remove(shape.getFigure()); getDrawing().addDrawingListener(controller); } model.deleteShape(shape.getID(), shape.getCoord3D()); if (newShape.getCoord3D().equals(model.getCurrentView())) { getDrawing().removeDrawingListener(controller); getDrawing().add(newShape.getFigure()); if (roi.canAnnotate()) newShape.getFigure().addFigureListener( controller); getDrawing().addDrawingListener(controller); } model.addShape(newROI.getID(), newShape.getCoord3D(), newShape); } } } catch (Exception e) { if (e instanceof ROICreationException) handleROIException(e, CREATE_MSG); else if (e instanceof NoSuchROIException) handleROIException(e, RETRIEVE_MSG); else handleROIException(e, UNKNOWN_MSG+"Merging ROI"); } } /** * Splits the ROIShapes from the ROI with id and the ROIShapes selected in * the shapeList from that ROI. * * @param id see above. * @param shapeList see above. */ void splitROI(long id, List<ROIShape> shapeList) { try { model.notifyDataChanged(true); ROI newROI = model.cloneROI(id); ROIShape newShape; ROIFigure roi; for (ROIShape shape : shapeList) { roi = shape.getFigure(); if (!roi.isReadOnly() && roi.canEdit()) { newShape = new ROIShape(newROI, shape.getCoord3D(), shape); if (getDrawing().contains(roi)) { if (roi.canAnnotate()) roi.removeFigureListener(controller); getDrawing().removeDrawingListener(controller); getDrawing().remove(shape.getFigure()); getDrawing().addDrawingListener(controller); } model.deleteShape(shape.getID(), shape.getCoord3D()); if (newShape.getCoord3D().equals(model.getCurrentView())) { getDrawing().removeDrawingListener(controller); this.getDrawing().add(newShape.getFigure()); if (roi.canAnnotate()) newShape.getFigure().addFigureListener(controller); getDrawing().addDrawingListener(controller); } model.addShape(newROI.getID(), newShape.getCoord3D(), newShape); } } } catch (Exception e) { if(e instanceof ROICreationException) handleROIException(e, CREATE_MSG); else if(e instanceof NoSuchROIException) handleROIException(e, RETRIEVE_MSG); else handleROIException(e, UNKNOWN_MSG+"Splitting ROI."); } } /** * Duplicate the ROI with id and the ROIShapes selected in the shapeList * from that ROI. * @param id see above. * @param shapeList see above. */ void duplicateROI(long id, List<ROIShape> shapeList) { try { model.notifyDataChanged(true); ROI newROI = model.cloneROI(id); ROIShape newShape; Drawing drawing = model.getDrawing(); ROIFigure roi; for (ROIShape shape : shapeList) { roi = shape.getFigure(); if (!roi.isReadOnly()) { newShape = new ROIShape(newROI, shape.getCoord3D(), shape); if (newShape.getCoord3D().equals(model.getCurrentView())) { drawing.removeDrawingListener(controller); drawing.add(newShape.getFigure()); newShape.getFigure().addFigureListener(controller); drawing.addDrawingListener(controller); } model.addShape(newROI.getID(), newShape.getCoord3D(), newShape); } } updateDrawingArea(); } catch (Exception e) { handleROIException(e, CREATE_MSG); } } /** * Marks the specified ROI to be deleted. * * @param roi The roi to handle. */ void markROIForDelete(ROIFigure roi) { if (roi == null) return; long id = roi.getROIShape().getID(); if (id < 0) return; model.markROIForDelete(id, roi.getROI(), true); } /** * Deletes the ROI with id and the ROIShapes selected in the shapeList. * * @param shapeList see above. */ void deleteROIShapes(List<ROIShape> shapeList) { try { ROIFigure roi; ROI r; List<DeletableObject> deobs = new ArrayList<DeletableObject>(); for (ROIShape shape : shapeList) { roi = shape.getFigure(); if (roi.canDelete()) { r = roi.getROI(); if (r.getID() >= 0 && !r.isClientSide()) { ROIData rd = new ROIData(); rd.setId(r.getID()); rd.setImage(model.getImage().asImage()); DeletableObject d = new DeletableObject(rd); d.setSecurityContext(model.getSecurityContext()); deobs.add(d); } if (getDrawing().contains(roi)) { shape.getFigure().removeFigureListener(controller); getDrawing().removeDrawingListener(controller); getDrawing().remove(roi); getDrawing().addDrawingListener(controller); } model.deleteShape(shape.getID(), shape.getCoord3D()); } } model.deleteAllROIs(deobs); TreeMap<Long, ROI> rois = model.getROIComponent().getROIMap(); boolean allsaved = true; for (ROI tmp : rois.values()) { if (tmp.isClientSide()) { allsaved = false; break; } } if (allsaved) { model.notifyDataChanged(false); } } catch (Exception e) { handleROIException(e, DELETE_MSG); } } /** * Returns <code>true</code> if in the graph or intensity view, * <code>false</code> otherwise. * * @return See above. */ boolean inDataView() { return (inIntensityView() || inGraphView() || inCalcWizardView()); } /** * Returns <code>true</code> if in the calcWizard view, * <code>false</code> otherwise. * * @return See above. */ boolean inCalcWizardView() { int index = tabs.getSelectedIndex(); if (index < 0) return false; int n = tabs.getTabCount(); if (index >= n) return false; return (tabs.getTitleAt(index).equals(calcWizard.getComponentName())); } /** * Returns <code>true</code> if in the graph view, * <code>false</code> otherwise. * * @return See above. */ boolean inGraphView() { if (!showGraph) return false; int index = tabs.getSelectedIndex(); if (index < 0) return false; int n = tabs.getTabCount(); if (index >= n) return false; return (tabs.getTitleAt(index).equals(graphPane.getComponentName())); } /** * Returns <code>true</code> if in the intensity view, * <code>false</code> otherwise. * * @return See above. */ boolean inIntensityView() { if (!showGraph) return false; int index = tabs.getSelectedIndex(); if (index < 0) return false; int n = tabs.getTabCount(); if (index >= n) return false; return (tabs.getTitleAt(index).equals( intensityView.getComponentName())); } /** * Returns <code>true</code> if in the intensity Results view, * <code>false</code> otherwise. * * @return See above. */ boolean inIntensityResultsView() { if (!showGraph) return false; return (tabs.getTitleAt(tabs.getSelectedIndex()). equals(intensityResultsView.getComponentName())); } /** * Returns the {@link #loadingWindow}. * * @return See above. */ LoadingWindow getLoadingWindow() { return loadingWindow; } /** * Sets the passed color to the currently selected cell. * * @param color The color to set. */ void setCellColor(Color color) { int row = -1; if (roiInspector != null) row = roiInspector.setCellColor(color); Collection<Figure> l = model.getSelectedFigures(); if (l == null || l.size() == 0) return; Iterator<Figure> i = l.iterator(); AttributeKey attKey = roiInspector.getAttributeKey(row); attKey.set(i.next(), color); model.getDrawingView().repaint(); } /** * Selects the current figure based on ROIid, t and z sections. * * @param ROIid The id of the selected ROI. * @param t The corresponding time-point. * @param z The corresponding z-section. */ void selectFigure(long ROIid, int t, int z) { try { ROI roi = model.getROI(ROIid); ROIFigure fig = roi.getFigure(new Coord3D(z, t)); selectFigure(fig); } catch (Exception e) { handleROIException(e, RETRIEVE_MSG); } } /** Displays the ROI assistant. */ void showROIAssistant() { Registry reg = MeasurementAgent.getRegistry(); UserNotifier un = reg.getUserNotifier(); if (inDataView()) { un.notifyInfo("ROI Assistant", "ROI Assistant cannot be used" + " in graph pane or intensity view."); return; } Collection<ROI> roiList = model.getSelectedROI(); if (roiList.size() == 0) { un.notifyInfo("ROI Assistant", "Select a Figure to modify " + "using the ROI Assistant."); return; } if (roiList.size() > 1) { un.notifyInfo("ROI Assistant", "The ROI Assistant can" + "only be used on one ROI at a time."); return; } ROI currentROI = roiList.iterator().next(); ROIAssistant assistant = new ROIAssistant(model.getNumTimePoints(), model.getNumZSections(), model.getCurrentView(), currentROI, this); UIUtilities.setLocationRelativeToAndShow(this, assistant); updateDrawingArea(); } /** * Displays the {@link ROIAssistant} for the passed ROI. * * @param roi The ROI to handle. */ void showROIAssistant(ROI roi) { Registry reg = MeasurementAgent.getRegistry(); UserNotifier un = reg.getUserNotifier(); if (inDataView()) { un.notifyInfo("ROI Assistant", "ROI Assistant cannot be used" + " in graph pane or intensity view"); return; } ROIAssistant assistant = new ROIAssistant(model.getNumTimePoints(), model.getNumZSections(), model.getCurrentView(), roi, this); UIUtilities.setLocationRelativeToAndShow(this, assistant); updateDrawingArea(); } /** * Selects the passed figure. * * @param figure The figure to select. */ void selectFigure(ROIFigure figure) { if (figure == null) { model.getDrawingView().setToolTipText(""); return; } Coord3D coord3D = figure.getROIShape().getCoord3D(); if (coord3D == null) return; if (!coord3D.equals(model.getCurrentView()) || model.isBigImage()) { model.setPlane(coord3D.getZSection(), coord3D.getTimePoint()); SelectPlane request = new SelectPlane(model.getPixelsID(), coord3D.getZSection(), coord3D.getTimePoint()); if (model.isBigImage()) { request.setBounds(figure.getBounds().getBounds()); } EventBus bus = MeasurementAgent.getRegistry().getEventBus(); bus.post(request); updateDrawingArea(); } DrawingCanvasView dv = model.getDrawingView(); dv.setToolTipText(""+figure.getAttribute(MeasurementAttributes.TEXT)); dv.clearSelection(); dv.addToSelection(figure); List<ROIShape> roiShapeList = new ArrayList<ROIShape>(); roiShapeList.add(figure.getROIShape()); dv.grabFocus(); if (model.isHCSData()) { List<Long> ids = new ArrayList<Long>(); Iterator<ROIShape> j = roiShapeList.iterator(); ROIShape roiShape; while (j.hasNext()) { roiShape = (ROIShape) j.next(); ids.add(roiShape.getROI().getID()); } Component c = tabs.getSelectedComponent(); if (c instanceof ServerROITable) { ((ServerROITable) c).selectROI(ids); } } else { roiInspector.setSelectedFigures(roiShapeList); roiManager.setSelectedFigures(roiShapeList, false); if (showGraph) { intensityResultsView.onFigureSelected(); intensityView.onFigureSelected(); } toolBar.onFigureSelected(); displayAnalysisResults(); } } /** * Sets the selected figures. * * @param figures Collection of selected figures. */ void setSelectedFigures(Collection figures) { if (model.getState() != MeasurementViewer.READY) return; if (figures == null) return; Iterator i = figures.iterator(); ROIFigure figure; List<ROIShape> shapeList = new ArrayList<ROIShape>(); ROI roi; ROIShape shape; try { while (i.hasNext()) { figure = (ROIFigure) i.next(); shape = figure.getROIShape(); if (shape != null) shapeList.add(shape); } } catch (Exception e) { handleROIException(e, RETRIEVE_MSG); } if (model.isHCSData()) { List<Long> ids = new ArrayList<Long>(); Iterator<ROIShape> j = shapeList.iterator(); while (j.hasNext()) { shape = (ROIShape) j.next(); ids.add(shape.getROI().getID()); } Component c = tabs.getSelectedComponent(); if (c instanceof ServerROITable) { ((ServerROITable) c).selectROI(ids); } } else { roiInspector.setSelectedFigures(shapeList); roiManager.setSelectedFigures(shapeList, true); if (showGraph) { intensityResultsView.onFigureSelected(); intensityView.onFigureSelected(); } toolBar.onFigureSelected(); } } /** * Sets the figures selected from the table. * * @param figures */ void setTableSelectedFigure(List<ROIFigure> figures) { if (figures == null) return; DrawingCanvasView dv = model.getDrawingView(); Iterator<ROIFigure> k = figures.iterator(); ROIFigure figure; dv.clearSelection(); if (figures == null || figures.size() == 0) return; dv.removeFigureSelectionListener(controller); int n = figures.size()-1; int index = 0; while (k.hasNext()) { figure = k.next(); dv.addToSelection(figure); if (index == n) scrollToFigure(figure); index++; } dv.addFigureSelectionListener(controller); dv.grabFocus(); } /** * Removes the specified figure from the display. * * @param figure The figure to remove. */ void removeROI(ROIFigure figure) { if (figure == null) return; try { model.removeROIShape(figure.getROI().getID()); if (!model.isHCSData()) { roiManager.removeFigure(figure); roiResults.refreshResults(); roiInspector.removeROIFigure(figure); } } catch (Exception e) { handleROIException(e, DELETE_MSG); } } /** * Deletes the ROI from Display. * * @param figures The figure to remove. */ void deleteROIs(List<ROIFigure> figures) { if (figures == null || figures.size() == 0) return; try { roiManager.removeFigures(figures); roiResults.refreshResults(); roiInspector.removeROIFigures(figures); if (showGraph) { intensityView.onFigureRemoved(); intensityResultsView.removeAllResults(); graphPane.clearData(); } } catch (Exception e) { handleROIException(e, DELETE_MSG); } } /** * Adds the specified figure to the display. * * @param figure The figure to add. */ void addROI(ROIFigure figure) { if (figure == null) return; ROI roi = null; try { boolean isDuplicate = getDrawingView().isDuplicate(); roi = model.createROI(figure, !isDuplicate); if (!isDuplicate) { MeasurementAttributes.SHOWTEXT.set(figure, roiInspector.isShowText()); MeasurementAttributes.SHOWMEASUREMENT.set(figure, true); } getDrawingView().unsetDuplicate(); } catch (Exception e) { handleROIException(e, CREATE_MSG); } if (roi == null) return; List<ROI> roiList = new ArrayList<ROI>(); roiList.add(roi); if (!model.isHCSData()) { roiManager.addFigures(roiList); roiResults.refreshResults(); } } /** * Reacts to the changes of attributes for the specified figure. * * @param figure The figure to handle. */ void onAttributeChanged(ROIFigure figure) { if (model.getState() != MeasurementViewer.READY) return; if (figure == null) return; if (!model.isHCSData()) { roiInspector.setModelData(figure); roiResults.refreshResults(); } } /** * Returns the drawing. * * @return See above. */ Drawing getDrawing() { return model.getDrawing(); } /** * Returns the drawing view. * * @return See above. */ DrawingCanvasView getDrawingView() { return model.getDrawingView(); } /** Rebuilds the ROI table. */ void rebuildManagerTable() { if (!model.isHCSData()) roiManager.rebuildTable(); } /** Sets the value in the tool bar.*/ void refreshToolBar() { toolBar.refreshToolBar(); } /** Rebuilds the results table. */ void refreshResultsTable() { if (!model.isHCSData()) roiResults.refreshResults(); } /** Rebuild the inspector table. */ void refreshInspectorTable() { if (!model.isHCSData()) roiInspector.repaint(); } /** Clear the inspector after saving the data. */ void clearInspector() { roiInspector.clearData(); } /** * Handles the exception thrown by the <code>ROIComponent</code>. * * @param e The exception to handle. * @param text The message displayed in the status bar. */ void handleROIException(Exception e, String text) { Registry reg = MeasurementAgent.getRegistry(); if (e instanceof ROICreationException || e instanceof NoSuchROIException) { reg.getLogger().error(this, "Problem while handling ROI "+e.getMessage()); statusBar.setStatus(text); } else { String s = "An unexpected error occurred while handling ROI "; reg.getLogger().error(this, s+e.getMessage()); reg.getUserNotifier().notifyError("ROI", s, e); } } /** Lays out the UI. */ void layoutUI() { if (model.isHCSData()) { tabs.removeAll(); Collection l = model.getMeasurementResults(); Iterator i = l.iterator(); ROIResult result; ServerROITable comp; while (i.hasNext()) { result = (ROIResult) i.next(); comp = new ServerROITable(this, model); comp.setResult(result); roiTables.add(comp); tabs.addTab(comp.getComponentName(), comp.getComponentIcon(), comp); } if (l.size() > 0) tabs.setSelectedIndex(0); getContentPane().remove(toolBar); setJMenuBar(null); } } /** Updates the drawing area. */ void updateDrawingArea() { Drawing drawing = model.getDrawing(); drawing.removeDrawingListener(controller); drawing.clear(); ShapeList list = null; ROIFigure figure; Iterator<ROIFigure> f; List<ROIFigure> first = new ArrayList<ROIFigure>(); List<ROIFigure> second = new ArrayList<ROIFigure>(); if (model.isHCSData()) { Component comp = tabs.getSelectedComponent(); if (comp instanceof ServerROITable) { ServerROITable table = (ServerROITable) comp; try { long fileID = table.getFileID(); List<ROI> rois; if (fileID >= 0) { rois = model.getROIList(fileID); if (rois != null) { Iterator<ROI> k = rois.iterator(); ROI roi; TreeMap<Coord3D, ROIShape> shapes; Iterator<ROIShape> j; ROIShape shape; while (k.hasNext()) { roi = k.next(); shapes = roi.getShapes(); j = shapes.values().iterator(); while (j.hasNext()) { shape = j.next(); figure = shape.getFigure(); if (!(figure instanceof MeasureMaskFigure)) second.add(figure); else first.add(figure); } } f = first.iterator(); while (f.hasNext()) { figure = f.next(); drawing.add(figure); if (figure.canAnnotate()) figure.addFigureListener(controller); } f = second.iterator(); while (f.hasNext()) { figure = f.next(); drawing.add(figure); if (figure.canAnnotate()) figure.addFigureListener(controller); } } } else { try { list = model.getShapeList(); } catch (Exception e) { handleROIException(e, RETRIEVE_MSG); } if (list != null) { TreeMap<?, ROIShape> map = list.getList(); Iterator<ROIShape> i = map.values().iterator(); ROIShape shape; while (i.hasNext()) { shape = i.next(); if (shape != null) { figure = shape.getFigure(); drawing.add(figure); if (figure.canAnnotate()) figure.addFigureListener(controller); } } } } } catch (Exception e) { handleROIException(e, RETRIEVE_MSG); } } DrawingCanvasView canvas = model.getDrawingView(); KeyListener[] l = canvas.getKeyListeners(); if (l != null) { for (int i = 0; i < l.length; i++) canvas.removeKeyListener(l[i]); } } else { //non HCS data try { list = model.getShapeList(); } catch (Exception e) { handleROIException(e, RETRIEVE_MSG); } if (list != null) { TreeMap<Long, ROIShape> map = list.getList(); Iterator<ROIShape> i = map.values().iterator(); ROIShape shape; //mask while (i.hasNext()) { shape = i.next(); if (shape != null) { figure = shape.getFigure(); if (!(figure instanceof MeasureMaskFigure)) second.add(figure); else first.add(figure); } } f = first.iterator(); while (f.hasNext()) { figure = f.next(); drawing.add(figure); if (figure.canAnnotate()) figure.addFigureListener(controller); } f = second.iterator(); while (f.hasNext()) { figure = f.next(); drawing.add(figure); if (figure.canAnnotate()) figure.addFigureListener(controller); } } } setStatus(DEFAULT_MSG); model.getDrawingView().setDrawing(drawing); drawing.addDrawingListener(controller); } /** * Propagates the selected shape in the roi model. * * @param shape The ROIShape to propagate. * @param timePoint The timepoint to propagate to. * @param zSection The z-section to propagate to. */ void propagateShape(ROIShape shape, int timePoint, int zSection) { List<ROIShape> addedShapes = new ArrayList<ROIShape>(); try { ROIFigure roi = shape.getFigure(); if (!roi.isReadOnly() && roi.canEdit()) addedShapes = model.propagateShape(shape, timePoint, zSection); ROIFigure figToDelete = null; ROIFigure roiFig; for (ROIShape newShape : addedShapes) { roi = newShape.getFigure(); if (!roi.isReadOnly() && roi.canEdit()) { if (newShape.getCoord3D().equals(model.getCurrentView())) { getDrawing().removeDrawingListener(controller); figToDelete = null; for (Figure f : getDrawing().getFigures()) { roiFig = (ROIFigure) f; if (roiFig.getROI().getID() == newShape.getID()) figToDelete = roiFig; } if (figToDelete!=null) getDrawing().remove(figToDelete); this.getDrawing().add(newShape.getFigure()); if (roi.canAnnotate()) newShape.getFigure().addFigureListener(controller); getDrawing().addDrawingListener(controller); } newShape.getFigure().calculateMeasurements(); } } if (!model.isHCSData()) roiManager.addROIShapes(addedShapes); } catch (ROICreationException e) { handleROIException(e, CREATE_MSG); } catch (NoSuchROIException e) { handleROIException(e, RETRIEVE_MSG); } setStatus(DEFAULT_MSG); } /** * Deletes the selected shape from current coordinate to timepoint * and z-section. * * @param shape The initial shape to delete. * @param timePoint The timepoint to delete to. * @param zSection The z-section to delete to. */ void deleteShape(ROIShape shape, int timePoint, int zSection) { try { model.deleteShape(shape, timePoint, zSection); } catch (Exception e) { handleROIException(e, RETRIEVE_MSG); } setStatus(DEFAULT_MSG); rebuildManagerTable(); } /** * Sets a message in the status bar. * * @param text The text to display. */ void setStatus(String text) { statusBar.setStatus(text); } /** * Sets a message in the status bar. * * @param text The text to display. */ void setPlaneStatus(String text) { statusBar.setPlaneStatus(text); } /** * Sets ready message in the status bar. */ void setReadyStatus() { setStatus(DEFAULT_MSG); } /** Builds the graphs and displays them in the results pane. */ void displayAnalysisResults() { if (inGraphView()) graphPane.displayAnalysisResults(); else if (inIntensityView()) intensityView.displayAnalysisResults(); else if (inIntensityResultsView()) intensityResultsView.displayAnalysisResults(); } /** * Creates a single figure and returns to the selection tool. * * @param createSingleFig See above. */ void createSingleFigure(boolean createSingleFig) { createSingleFigure.setSelected(createSingleFig); createMultipleFigure.setSelected(!createSingleFig); toolBar.createSingleFigure(createSingleFig); } /** * is the user menu set to create single figures * * @return see above. */ boolean isCreateSingleFigure() { return createSingleFigure.isSelected(); } /** * Returns the id of the pixels set this tool is for. * * @return See above. */ long getPixelsID() { return model.getPixelsID(); } /** * Calculate the stats for the Rois in the shapelist. This method * will call the graphView. * * @param shapeList see above. */ void calculateStats(List<ROIShape> shapeList) { if (model.getState() != MeasurementViewer.READY) return; model.calculateStats(shapeList); } /** Invokes when the figures are selected. */ void onSelectedFigures() { Collection<Figure> figures = model.getSelectedFigures(); if (figures != null) { boolean show = roiInspector.isShowMeasurement(); Iterator<Figure> i = figures.iterator(); Figure f; while (i.hasNext()) { f = i.next(); MeasurementAttributes.SHOWMEASUREMENT.set(f, show); } } roiManager.onSelectedFigures(); } /** * Returns the selected figures from the table. If a ROI is selected, * all the shapes hosted by that ROI * * @return See above. */ Collection<Figure> getSelectedFiguresFromTables() { return roiManager.getSelectedFiguresFromTables(); } /** * Creates a file chooser used to select where to save the results * as an Excel file. * * @return See above. */ FileChooser createSaveToExcelChooser() { List<FileFilter> filterList = new ArrayList<FileFilter>(); FileFilter filter = new ExcelFilter(); filterList.add(filter); FileChooser chooser = new FileChooser(this, FileChooser.SAVE, "Save Results to Excel", "Save the Results data to a file which can be loaded by " + "a spreadsheet.", filterList); try { File f = UIUtilities.getDefaultFolder(); if (f != null) chooser.setCurrentDirectory(f); } catch (Exception ex) {} return chooser; } /** * Shows or hides the Text of all shapes. * * @param show Pass <code>true</code> to show the text, <code>false</code> * otherwise. */ void showText(boolean show) { Collection<ROIFigure> figures = model.getAllFigures(); if (figures.size() == 0) return; Iterator<ROIFigure> i = figures.iterator(); ROIFigure figure; while (i.hasNext()) { figure = i.next(); MeasurementAttributes.SHOWTEXT.set(figure, show); if (roiInspector != null) roiInspector.showText(show, figure); } model.getDrawingView().repaint(); } /** * Returns <code>true</code> if the channel is active, <code>false</code> * otherwise. * * @param channel The channel to handle * @return See above. */ boolean isChannelActive(int channel) { return model.isChannelActive(channel); } /** * Indicates any on-going analysis. * * @param analyse Passes <code>true</code> when analyzing, * <code>false</code> otherwise. */ void onAnalysed(boolean analyse) { if (!showGraph) return; graphPane.onAnalysed(analyse); intensityView.onAnalysed(analyse); toolBar.onAnalysed(analyse); } /** Updates view when the zoom factor is modified.*/ void onMagnificationChanged() { toolBar.onMagnificationChanged(); } /** * Overridden to the set the location of the {@link MeasurementViewer}. * @see TopWindow#setOnScreen() */ public void setOnScreen() { setSize(DEFAULT_SIZE); UIUtilities.incrementRelativeToAndShow(null, this); } /** * Opens a file chooser dialog and exports the graph as JPEG or PNG. */ public void exportGraph() { if (!showGraph) return; List<FileFilter> filterList = new ArrayList<FileFilter>(); filterList.add(new JPEGFilter()); filterList.add(new PNGFilter()); FileChooser chooser = new FileChooser( (JFrame) SwingUtilities.windowForComponent(this), FileChooser.SAVE, "Save Graph", "Save the graph as JPEG or PNG", filterList); try { File f = UIUtilities.getDefaultFolder(); if (f != null) chooser.setCurrentDirectory(f); } catch (Exception ex) { } if (chooser.showDialog() != JFileChooser.APPROVE_OPTION) return; File file = chooser.getFormattedSelectedFile(); FileFilter filter = chooser.getSelectedFilter(); int type = (filter instanceof JPEGFilter) ? ChartObject.SAVE_AS_JPEG : ChartObject.SAVE_AS_PNG; graphPane.saveGraph(file, type); } void displayAnnotations(List<ROIShape> shapes) { roiInspector.setSelectedFigures(shapes); } }