/* *------------------------------------------------------------------------------ * 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; import java.awt.Component; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Font; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.JSeparator; import javax.swing.JToggleButton; import javax.swing.JToolBar; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.jhotdraw.draw.AttributeKey; import org.jhotdraw.draw.DrawingEditor; import org.openmicroscopy.shoola.agents.measurement.IconManager; import org.openmicroscopy.shoola.agents.measurement.actions.DrawingAction; import org.openmicroscopy.shoola.agents.util.ui.PermissionMenu; import org.openmicroscopy.shoola.util.roi.figures.MeasureBezierFigure; import org.openmicroscopy.shoola.util.roi.figures.MeasureEllipseFigure; import org.openmicroscopy.shoola.util.roi.figures.MeasureLineConnectionFigure; import org.openmicroscopy.shoola.util.roi.figures.MeasureLineFigure; import org.openmicroscopy.shoola.util.roi.figures.MeasurePointFigure; import org.openmicroscopy.shoola.util.roi.figures.MeasureRectangleFigure; import org.openmicroscopy.shoola.util.roi.figures.MeasureTextFigure; import org.openmicroscopy.shoola.util.roi.figures.ROIFigure; import org.openmicroscopy.shoola.util.roi.model.annotation.MeasurementAttributes; import org.openmicroscopy.shoola.util.ui.UIUtilities; import org.openmicroscopy.shoola.util.ui.drawingtools.attributes.DrawingAttributes; import org.openmicroscopy.shoola.util.ui.drawingtools.attributes.FigureProperties; import org.openmicroscopy.shoola.util.ui.drawingtools.creationtools.DrawingBezierTool; import org.openmicroscopy.shoola.util.ui.drawingtools.creationtools.DrawingConnectionTool; import org.openmicroscopy.shoola.util.ui.drawingtools.creationtools.DrawingObjectCreationTool; import org.openmicroscopy.shoola.util.ui.drawingtools.creationtools.DrawingPointCreationTool; import org.openmicroscopy.shoola.util.ui.drawingtools.creationtools.DrawingToolBarButtonFactory; import org.openmicroscopy.shoola.util.ui.drawingtools.figures.FigureUtil; import omero.gateway.model.ShapeSettingsData; /** * UI component acting as toolbar. Used to create 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 * @since OME3.0 */ class ToolBar extends JPanel implements MouseListener { /** The defaults attributes of the line connection figure. */ private final static Map<AttributeKey, Object> defaultConnectionAttributes; /** Add the polyline tool to the toolbar. */ private final static boolean addPolyline = false; /** Add the polygon tool to the toolbar. */ private final static boolean addPolygon = true; /** Add the connection tool to the toolbar. */ private final static boolean addConnection = false; static { defaultConnectionAttributes = new HashMap<AttributeKey, Object>(); defaultConnectionAttributes.put(MeasurementAttributes.FILL_COLOR, ShapeSettingsData.DEFAULT_FILL_COLOUR); defaultConnectionAttributes.put(MeasurementAttributes.STROKE_COLOR, ShapeSettingsData.DEFAULT_STROKE_COLOUR); defaultConnectionAttributes.put(MeasurementAttributes.TEXT_COLOR, ShapeSettingsData.DEFAULT_STROKE_COLOUR); defaultConnectionAttributes.put(MeasurementAttributes.FONT_SIZE, new Double(ShapeSettingsData.DEFAULT_FONT_SIZE)); defaultConnectionAttributes.put(MeasurementAttributes.FONT_BOLD, Boolean.valueOf(false)); defaultConnectionAttributes.put(MeasurementAttributes.STROKE_WIDTH, ShapeSettingsData.DEFAULT_STROKE_WIDTH); defaultConnectionAttributes.put(MeasurementAttributes.TEXT, ROIFigure.DEFAULT_TEXT); defaultConnectionAttributes.put( MeasurementAttributes.MEASUREMENTTEXT_COLOUR, ShapeSettingsData.DEFAULT_STROKE_COLOUR); defaultConnectionAttributes.put(MeasurementAttributes.SHOWMEASUREMENT, Boolean.valueOf(false)); defaultConnectionAttributes.put(DrawingAttributes.SHOWTEXT, Boolean.valueOf(false)); } /** The default string added to the type of Figure to create. */ private static final String CREATE_KEY = "create"; /** Size of the horizontal box. */ private static final Dimension HGLUE = new Dimension(5, 5); /** The max plane size.*/ private static final int MAX_SIZE = 1024; /** The properties figure for a line connection object. */ private FigureProperties lineConnectionProperties; /** Tool bar hosting the control defined by <code>JHotDraw</code>. */ private JToolBar toolBar; /** Reference to the Control. */ private MeasurementViewerControl controller; /** Reference to the Control. */ private MeasurementViewerUI view; /** Reference to the Model. */ private MeasurementViewerModel model; /** Reference to the Component. */ private MeasurementViewer measurementcomponent; /** The ellipse creation tool. */ private DrawingObjectCreationTool ellipseTool; /** The rectangle creation tool. */ private DrawingObjectCreationTool rectTool; /** The line creation tool. */ private DrawingObjectCreationTool lineTool; /** The text creation tool. */ private DrawingObjectCreationTool textTool; /** The point creation tool. */ private DrawingObjectCreationTool pointTool; /** The polygon creation tool. */ private DrawingBezierTool polygonTool; /** The polyline creation tool. */ private DrawingBezierTool polylineTool; /** The connection creation tool. */ private DrawingConnectionTool connectionTool; /** The button to bring up the assistant. */ private JButton assistantButton; /** The component to show/hide the text. */ private JCheckBox showTextButton; /** Menu offering the delete option for Admin/group owner.*/ private PermissionMenu deleteMenu; /** * Sets the property of the toggle button. * * @param button The button to handle. */ private void setUpToggleButton(JToggleButton button) { button.setAction(new DrawingAction(measurementcomponent, button)); button.addMouseListener(this); } /** * Determines the font size according to the image size. * * @return See above. */ private double getDefaultFontSize() { Dimension d = model.getDrawingView().getSize(); int sizeX = d.width; double r1 = 1; if (sizeX == 0) { sizeX = model.getSizeX(); } r1 = model.getSizeX()/sizeX; int sizeY = d.height; if (sizeY == 0) { sizeY = model.getSizeY(); } double r2 = 1; r2 = model.getSizeX()/sizeX; double f = ShapeSettingsData.DEFAULT_FONT_SIZE; double sx = model.getSizeX(); double sy = model.getSizeY(); if (sx > MAX_SIZE || sy > MAX_SIZE){ f = 2*f; } double rx = f*r1; double ry = f*r2; f = Math.floor(Math.max(ry, rx)); if (f < ShapeSettingsData.DEFAULT_FONT_SIZE) return ShapeSettingsData.DEFAULT_FONT_SIZE; return f; } /** Initializes the component composing the display. */ private void initComponents() { showTextButton = new JCheckBox("Show Comment"); lineConnectionProperties = new FigureProperties( defaultConnectionAttributes); Map<AttributeKey, Object> p = new HashMap<AttributeKey, Object>(); double value = getDefaultFontSize(); Font font = ROIFigure.DEFAULT_FONT; font = font.deriveFont((float) value); p.put(MeasurementAttributes.FONT_SIZE, value); p.put(MeasurementAttributes.FONT_FACE, font); ellipseTool = new DrawingObjectCreationTool( new MeasureEllipseFigure(false, true, true, true, true), p); rectTool = new DrawingObjectCreationTool( new MeasureRectangleFigure(false, true, true, true, true), p); textTool = new DrawingObjectCreationTool( new MeasureTextFigure(false, true), p); lineTool = new DrawingObjectCreationTool( new MeasureLineFigure(false, true, true, true, true), p); Map<AttributeKey, Object> m = lineConnectionProperties.getProperties(); m.put(MeasurementAttributes.FONT_SIZE, value); connectionTool = new DrawingConnectionTool( new MeasureLineConnectionFigure(), m); pointTool = new DrawingObjectCreationTool( new MeasurePointFigure(false, true, true, true, true), p); polygonTool = new DrawingBezierTool( new MeasureBezierFigure(true, false, true, true, true, true), p); polylineTool = new DrawingBezierTool( new MeasureBezierFigure(false, false, true, true, true, true), p); Component component; toolBar = DrawingToolBarButtonFactory.createDefaultBar(); DrawingEditor editor = model.getDrawingEditor(); DrawingToolBarButtonFactory.addSelectionToolTo(toolBar, editor, true); component = toolBar.getComponent(toolBar.getComponentCount()-1); if (component instanceof JToggleButton) setUpToggleButton((JToggleButton) component); toolBar.add(new JSeparator()); toolBar.add(Box.createRigidArea(HGLUE)); DrawingToolBarButtonFactory.addToolTo(toolBar, editor, rectTool, CREATE_KEY+FigureUtil.RECTANGLE_TYPE); component = toolBar.getComponent(toolBar.getComponentCount()-1); if (component instanceof JToggleButton) setUpToggleButton((JToggleButton) component); DrawingToolBarButtonFactory.addToolTo(toolBar, editor, ellipseTool, CREATE_KEY+FigureUtil.ELLIPSE_TYPE); component = toolBar.getComponent(toolBar.getComponentCount()-1); if (component instanceof JToggleButton) setUpToggleButton((JToggleButton) component); DrawingToolBarButtonFactory.addToolTo(toolBar, editor, pointTool, CREATE_KEY+FigureUtil.ELLIPSE_TYPE); component = toolBar.getComponent( toolBar.getComponentCount()-1); if (component instanceof JToggleButton) { JToggleButton button = (JToggleButton) component; IconManager icons = IconManager.getInstance(); button.setIcon(icons.getIcon(IconManager.POINTICON_22)); button.setToolTipText(FigureUtil.POINT_TYPE); setUpToggleButton(button); } DrawingToolBarButtonFactory.addToolTo(toolBar, editor, lineTool, CREATE_KEY+FigureUtil.LINE_TYPE); component = toolBar.getComponent(toolBar.getComponentCount()-1); if (component instanceof JToggleButton) setUpToggleButton((JToggleButton) component); if (addPolyline) { DrawingToolBarButtonFactory.addToolTo(toolBar, editor, polylineTool, CREATE_KEY+FigureUtil.SCRIBBLE_TYPE); component = toolBar.getComponent(toolBar.getComponentCount()-1); if (component instanceof JToggleButton) setUpToggleButton((JToggleButton) component); } if (addPolygon) { DrawingToolBarButtonFactory.addToolTo(toolBar, editor, polygonTool, CREATE_KEY+FigureUtil.POLYGON_TYPE); component = toolBar.getComponent(toolBar.getComponentCount()-1); if (component instanceof JToggleButton) setUpToggleButton((JToggleButton) component); } DrawingToolBarButtonFactory.addToolTo(toolBar, editor, textTool, CREATE_KEY+FigureUtil.TEXT_TYPE); component = toolBar.getComponent(toolBar.getComponentCount()-1); if (component instanceof JToggleButton) setUpToggleButton((JToggleButton) component); if (addConnection) { DrawingToolBarButtonFactory.addToolTo(toolBar, editor, connectionTool, CREATE_KEY+FigureUtil.LINE_CONNECTION_TYPE); component = toolBar.getComponent( toolBar.getComponentCount()-1); if (component instanceof JToggleButton) { JToggleButton button = (JToggleButton) component; button.setToolTipText("Connector"); setUpToggleButton(button); } } } /** * Builds the tool bar hosting the controls. * * @return See above. */ private JToolBar buildControlsBar() { JToolBar bar = new JToolBar(); bar.setFloatable(false); bar.setRollover(true); bar.setBorder(null); JButton button = new JButton( controller.getAction(MeasurementViewerControl.SAVE)); UIUtilities.unifiedButtonLookAndFeel(button); bar.add(button); button = new JButton(controller.getAction( MeasurementViewerControl.LOAD)); UIUtilities.unifiedButtonLookAndFeel(button); bar.add(button); assistantButton = new JButton(controller.getAction( MeasurementViewerControl.ROI_ASSISTANT)); UIUtilities.unifiedButtonLookAndFeel(assistantButton); bar.add(assistantButton); button = new JButton(controller.getAction( MeasurementViewerControl.DELETE)); if (!model.isMember()) { button.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { if (deleteMenu == null) { deleteMenu = new PermissionMenu(PermissionMenu.DELETE, "ROIs"); deleteMenu.addPropertyChangeListener(controller); } deleteMenu.show((JComponent) e.getSource(), e.getX(), e.getY()); } }); } UIUtilities.unifiedButtonLookAndFeel(button); bar.add(button); bar.add(new JSeparator()); return bar; } /** Builds and lays out the UI. */ private void buildGUI() { JPanel j = new JPanel(); JPanel p = new JPanel(); p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS)); p.add(buildControlsBar()); p.add(Box.createHorizontalStrut(5)); p.add(toolBar); p.add(Box.createHorizontalStrut(5)); p.add(showTextButton); setLayout(new FlowLayout(FlowLayout.LEFT)); j.setLayout(new BoxLayout(j, BoxLayout.Y_AXIS)); j.add(p); add(j); } /** * Creates a new instance. * * @param component Reference to the component. * Mustn't be <code>null</code>. * @param view Reference to the view. * Mustn't be <code>null</code>. * @param controller Reference to the controller. * Mustn't be <code>null</code>. * @param model Reference to the View. Mustn't be <code>null</code>. */ ToolBar(MeasurementViewer component, MeasurementViewerUI view, MeasurementViewerControl controller, MeasurementViewerModel model) { if (component == null) throw new IllegalArgumentException("No component."); if (view == null) throw new IllegalArgumentException("No view."); if (controller == null) throw new IllegalArgumentException("No control."); if (model == null) throw new IllegalArgumentException("No model."); measurementcomponent = component; this.view = view; this.controller = controller; this.model = model; initComponents(); buildGUI(); } /** * Return true if the right button was clicked or left button was clicked * with control held down. * @param e mouse event. * @return see above. */ protected boolean rightClick(MouseEvent e) { if (e.getButton() == MouseEvent.BUTTON3 || (e.getButton() == MouseEvent.BUTTON1 && e.isControlDown())) return true; return false; } /** * Creates a single figure and moves the tool in the menu back to the * selection tool, if the passed parameter is <code>true</code>. * * @param option see above. */ void createSingleFigure(boolean option) { ellipseTool.setResetToSelect(option); rectTool.setResetToSelect(option); textTool.setResetToSelect(option); lineTool.setResetToSelect(option); // TODO : connectionTool.setResetToSelect(option); pointTool.setResetToSelect(option); if (addPolygon) polygonTool.setResetToSelect(option); if (addPolyline) polylineTool.setResetToSelect(option); } /** Sets the value in the tool bar.*/ void refreshToolBar() { Collection<ROIFigure> figures = model.getAllFigures(); if (figures.size() > 0) { Iterator<ROIFigure> i = figures.iterator(); ROIFigure figure; boolean b = false; Boolean value; while (i.hasNext()) { figure = i.next(); //if (!figure.isReadOnly()) { value = MeasurementAttributes.SHOWTEXT.get(figure); if (value != null && value.booleanValue()) { b = value.booleanValue(); break; } //} } showTextButton.setSelected(b); } showTextButton.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { view.showText(showTextButton.isSelected()); } }); } /** Invokes when figures are selected. */ void onFigureSelected() { int size = view.getDrawingView().getSelectedFigures().size(); assistantButton.getAction().setEnabled(size == 1); } /** * Indicates any on-going analysis. * * @param analyse Passes <code>true</code> when analyzing, * <code>false</code> otherwise. */ void onAnalysed(boolean analyse) { assistantButton.setEnabled(!analyse); } /** Modifies the creation tools when changing the magnification.*/ void onMagnificationChanged() { if (!model.isBigImage()) return; Map<AttributeKey, Object> p = new HashMap<AttributeKey, Object>(); double value = getDefaultFontSize(); Font font = ROIFigure.DEFAULT_FONT; font = font.deriveFont((float) value); p.put(MeasurementAttributes.FONT_SIZE, value); p.put(MeasurementAttributes.FONT_FACE, font); rectTool.setAttributes(p); ellipseTool.setAttributes(p); pointTool.setAttributes(p); lineTool.setAttributes(p); textTool.setAttributes(p); polygonTool.setAttributes(p); polylineTool.setAttributes(p); Map<AttributeKey, Object> m = lineConnectionProperties.getProperties(); m.put(MeasurementAttributes.FONT_SIZE, value); connectionTool = new DrawingConnectionTool( new MeasureLineConnectionFigure(), m); } /** * Sets the selected flag of the source of the event to * <code>true</code> when a right click event occurs. * @see MouseListener#mouseClicked(MouseEvent) */ public void mouseClicked(MouseEvent e) { if (rightClick(e)) { createSingleFigure(false); JToggleButton button = (JToggleButton)e.getSource(); button.setSelected(true); } else createSingleFigure(view.isCreateSingleFigure()); } /** * Required by the {@link MouseListener} I/F but no-op implementation * in our case. * @see MouseListener#mouseEntered(MouseEvent) */ public void mouseEntered(MouseEvent e) {} /** * Required by the {@link MouseListener} I/F but no-op implementation * in our case. * @see MouseListener#mouseExited(MouseEvent) */ public void mouseExited(MouseEvent e) {} /** * Required by the {@link MouseListener} I/F but no-op implementation * in our case. * @see MouseListener#mousePressed(MouseEvent) */ public void mousePressed(MouseEvent e) {} /** * Required by the {@link MouseListener} I/F but no-op implementation * in our case. * @see MouseListener#mouseReleased(MouseEvent) */ public void mouseReleased(MouseEvent e) {} }