Java tutorial
/* * Copyright (c) 2012 Diamond Light Source Ltd. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package org.dawnsci.plotting.tools.region; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import org.dawb.common.ui.util.EclipseUtils; import org.dawb.common.ui.wizard.persistence.PersistenceExportWizard; import org.dawb.common.ui.wizard.persistence.PersistenceImportWizard; import org.dawnsci.plotting.tools.Activator; import org.dawnsci.plotting.tools.preference.RegionEditorConstants; import org.dawnsci.plotting.tools.preference.RegionEditorPreferencePage; import org.dawnsci.plotting.tools.region.MeasurementLabelProvider.LabelType; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.dawnsci.analysis.api.dataset.IDataset; import org.eclipse.dawnsci.analysis.api.roi.IROI; import org.eclipse.dawnsci.analysis.dataset.impl.Dataset; import org.eclipse.dawnsci.analysis.dataset.impl.DatasetFactory; import org.eclipse.dawnsci.plotting.api.axis.ICoordinateSystem; import org.eclipse.dawnsci.plotting.api.region.IROIListener; import org.eclipse.dawnsci.plotting.api.region.IRegion; import org.eclipse.dawnsci.plotting.api.region.IRegionListener; import org.eclipse.dawnsci.plotting.api.region.ROIEvent; import org.eclipse.dawnsci.plotting.api.region.RegionEvent; import org.eclipse.dawnsci.plotting.api.region.RegionUtils; import org.eclipse.dawnsci.plotting.api.tool.AbstractToolPage; import org.eclipse.dawnsci.plotting.api.tool.IToolPage; import org.eclipse.dawnsci.plotting.api.trace.IImageTrace; import org.eclipse.dawnsci.plotting.api.trace.ITraceListener; import org.eclipse.dawnsci.plotting.api.trace.TraceEvent; import org.eclipse.draw2d.ColorConstants; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IContributionItem; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.preference.PreferenceDialog; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.viewers.ColumnViewerToolTipSupport; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TableViewerColumn; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.window.ToolTip; import org.eclipse.jface.wizard.IWizard; import org.eclipse.jface.wizard.WizardDialog; import org.eclipse.swt.SWT; import org.eclipse.swt.dnd.Clipboard; import org.eclipse.swt.dnd.TextTransfer; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.TableItem; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.dialogs.PreferencesUtil; import org.eclipse.ui.progress.UIJob; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This tool shows the measurements of selected regions. * * @author Matthew Gerring * */ public class MeasurementTool extends AbstractToolPage implements IRegionListener, IROIListener { protected IROI roi; private ITraceListener axesTraceListener; private double xCalibratedAxisFactor = Double.NaN; private double yCalibratedAxisFactor = Double.NaN; private String unitName; protected static final Logger logger = LoggerFactory.getLogger(MeasurementTool.class); private Composite composite; protected TableViewer viewer; private RegionColorListener viewUpdateListener; /** * A map to store dragBounds which are not the official bounds * of the selection until the user lets go. */ private Map<String, IROI> dragBounds; private ITraceListener traceListener; public MeasurementTool() { super(); dragBounds = new HashMap<String, IROI>(7); Activator.getPlottingPreferenceStore().addPropertyChangeListener(new IPropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent event) { if (isActive()) { if (isInterestedProperty(event)) viewer.refresh(); } } private boolean isInterestedProperty(PropertyChangeEvent event) { final String propName = event.getProperty(); return RegionEditorConstants.POINT_FORMAT.equals(propName) || RegionEditorConstants.INTENSITY_FORMAT.equals(propName) || RegionEditorConstants.SUM_FORMAT.equals(propName); } }); traceListener = new ITraceListener.Stub() { @Override public void traceUpdated(TraceEvent evt) { if (viewer != null && viewer.getControl().isDisposed()) return; viewer.refresh(); } @Override public void traceRemoved(TraceEvent evt) { if (viewer != null && viewer.getControl().isDisposed()) return; viewer.refresh(); } @Override public void traceCreated(TraceEvent evt) { if (viewer != null && viewer.getControl().isDisposed()) return; viewer.refresh(); } @Override public void traceAdded(TraceEvent evt) { if (viewer != null && viewer.getControl().isDisposed()) return; viewer.refresh(); } }; } @Override public void createControl(Composite parent) { this.composite = new Composite(parent, SWT.NONE); composite.setLayout(new FillLayout()); viewer = new TableViewer(composite, SWT.FULL_SELECTION | SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER); createColumns(viewer); viewer.getTable().setLinesVisible(true); viewer.getTable().setHeaderVisible(true); createActions(); getSite().setSelectionProvider(viewer); viewer.setContentProvider(new IStructuredContentProvider() { @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { // TODO Auto-generated method stub } @Override public void dispose() { // TODO Auto-generated method stub } @Override public Object[] getElements(Object inputElement) { final Collection<IRegion> regions = getPlottingSystem().getRegions(); if (regions == null || regions.isEmpty()) return new Object[] { "-" }; final List<IRegion> okRegions = new ArrayList<IRegion>(); for (IRegion iRegion : regions) { if (isRegionOk(iRegion)) okRegions.add(iRegion); } return okRegions.toArray(new IRegion[okRegions.size()]); } }); viewer.setInput(new Object()); this.viewUpdateListener = new RegionColorListener(); activate(); } protected boolean isRegionOk(IRegion iRegion) { return iRegion.isVisible() && iRegion.isUserRegion(); } protected IAction getReselectAction() { final Action reselect = new Action("Create new " + getRegionTypeName(), getImageDescriptor()) { public void run() { createNewRegion(true); } }; return reselect; } protected void createActions() { getSite().getActionBars().getToolBarManager().add(getReselectAction()); getSite().getActionBars().getToolBarManager().add(new Separator()); if (getToolPageRole() == ToolPageRole.ROLE_2D) { final Action calibrate = new Action( "Calibrate axes using a measurement and apply these axes to other plots.\nThese axes can then be applied to other plots by keeping the\nmeasurement tool open using 'open in a dedicated view'.", IAction.AS_PUSH_BUTTON) { public void run() { MeasurementCalibrationDialog dialog = new MeasurementCalibrationDialog(MeasurementTool.this); dialog.open(); } }; calibrate.setImageDescriptor(Activator.getImageDescriptor("icons/measurement_calibrate.png")); final Action applyCalibrated = new Action( "Apply calibrated axes to any images opened while this tool is active.", IAction.AS_CHECK_BOX) { public void run() { updateCalibrateTraceListener(isChecked()); } }; applyCalibrated.setChecked(true); applyCalibrated.setImageDescriptor(Activator.getImageDescriptor("icons/axis.png")); updateCalibrateTraceListener(true); getSite().getActionBars().getToolBarManager().add(calibrate); getSite().getActionBars().getToolBarManager().add(applyCalibrated); getSite().getActionBars().getToolBarManager().add(new Separator()); } final Action exportRegion = new Action("Export region to file", Activator.getImageDescriptor("icons/mask-export-wiz.png")) { public void run() { try { IWizard wiz = EclipseUtils.openWizard(PersistenceExportWizard.ID, false); WizardDialog wd = new WizardDialog(Display.getCurrent().getActiveShell(), wiz); wd.setTitle(wiz.getWindowTitle()); wd.open(); } catch (Exception e) { logger.error("Problem opening import!", e); } } }; final Action importRegion = new Action("Import region from file", Activator.getImageDescriptor("icons/mask-import-wiz.png")) { public void run() { try { IWizard wiz = EclipseUtils.openWizard(PersistenceImportWizard.ID, false); WizardDialog wd = new WizardDialog(Display.getCurrent().getActiveShell(), wiz); wd.setTitle(wiz.getWindowTitle()); wd.open(); } catch (Exception e) { logger.error("Problem opening import!", e); } } }; final Action copy = new Action("Copy region values to clipboard", Activator.getImageDescriptor("icons/plot-tool-measure-copy.png")) { public void run() { if (!isActive()) return; final IStructuredSelection sel = (IStructuredSelection) viewer.getSelection(); if (!(sel.getFirstElement() instanceof IRegion)) return; if (sel != null && sel.getFirstElement() != null) { final IRegion region = (IRegion) sel.getFirstElement(); if (region == null || region.getROI() == null) return; final IROI bounds = region.getROI(); if (bounds.getPointRef() == null) return; final Clipboard cb = new Clipboard(composite.getDisplay()); TextTransfer textTransfer = TextTransfer.getInstance(); cb.setContents(new Object[] { region.getName() + " " + bounds }, new Transfer[] { textTransfer }); } } }; copy.setToolTipText("Copies the region values as text to clipboard which can then be pasted externally."); final Action delete = new Action("Delete selected region", Activator.getImageDescriptor("icons/RegionDelete.png")) { public void run() { if (!isActive()) return; final IStructuredSelection sel = (IStructuredSelection) viewer.getSelection(); if (!(sel.getFirstElement() instanceof IRegion)) return; if (sel != null && sel.getFirstElement() != null) { final IRegion region = (IRegion) sel.getFirstElement(); getPlottingSystem().removeRegion(region); } } }; delete.setToolTipText("Delete selected region, if there is one."); final Action show = new Action("Show all vertex values", Activator.getImageDescriptor("icons/plot-tool-measure-vertices.png")) { public void run() { if (!isActive()) return; final Object[] oa = ((IStructuredContentProvider) viewer.getContentProvider()).getElements(null); for (Object object : oa) { if (object instanceof IRegion) ((IRegion) object).setShowPosition(true); } } }; show.setToolTipText("Show vertices in all visible regions"); final Action clear = new Action("Show no vertex values", Activator.getImageDescriptor("icons/plot-tool-measure-clear.png")) { public void run() { if (!isActive()) return; final Object[] oa = ((IStructuredContentProvider) viewer.getContentProvider()).getElements(null); for (Object object : oa) { if (object instanceof IRegion) ((IRegion) object).setShowPosition(false); } } }; clear.setToolTipText("Clear all vertices shown in the plotting"); final Action preferences = new Action("Preferences...") { public void run() { if (!isActive()) return; PreferenceDialog pref = PreferencesUtil.createPreferenceDialogOn( PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), RegionEditorPreferencePage.ID, null, null); if (pref != null) pref.open(); } }; preferences.setToolTipText("Open Region Editor preferences"); getSite().getActionBars().getToolBarManager().add(importRegion); getSite().getActionBars().getToolBarManager().add(exportRegion); getSite().getActionBars().getToolBarManager().add(new Separator()); getSite().getActionBars().getToolBarManager().add(copy); getSite().getActionBars().getMenuManager().add(copy); getSite().getActionBars().getToolBarManager().add(delete); getSite().getActionBars().getMenuManager().add(delete); final Separator sep = new Separator(getClass().getName() + ".separator1"); getSite().getActionBars().getToolBarManager().add(sep); getSite().getActionBars().getMenuManager().add(sep); getSite().getActionBars().getToolBarManager().add(show); getSite().getActionBars().getMenuManager().add(show); getSite().getActionBars().getToolBarManager().add(clear); getSite().getActionBars().getMenuManager().add(clear); getSite().getActionBars().getMenuManager().add(preferences); createRightClickMenu(); } /** * Add or remove a trace listener which applies the calibrated images * @param b */ private void updateCalibrateTraceListener(boolean addListener) { if (addListener) { axesTraceListener = new ITraceListener.Stub() { @Override public void tracesUpdated(TraceEvent evt) { updateAxes(evt); } public void traceAdded(TraceEvent evt) { updateAxes(evt); } protected void updateAxes(TraceEvent evt) { applyCalibration(); } }; getPlottingSystem().addTraceListener(axesTraceListener); applyCalibration(); } else { getPlottingSystem().removeTraceListener(axesTraceListener); axesTraceListener = null; final IImageTrace image = getImageTrace(); if (image != null) image.setAxes(null, true); } getPlottingSystem().repaint(); } private void applyCalibration() { final IImageTrace trace = getImageTrace(); if (trace != null && !Double.isNaN(xCalibratedAxisFactor) && !Double.isNaN(yCalibratedAxisFactor) && xCalibratedAxisFactor > 0 && yCalibratedAxisFactor > 0) { final IDataset data = trace.getData(); trace.setAxes(Arrays.asList(getCalibratedAxis(xCalibratedAxisFactor, data.getShape()[1]), getCalibratedAxis(yCalibratedAxisFactor, data.getShape()[0])), true); } } private IDataset getCalibratedAxis(double factor, int size) { Dataset axis = DatasetFactory.createRange(size, Dataset.FLOAT64); axis.imultiply(factor); axis.setName(unitName); return axis; } private void createRightClickMenu() { final MenuManager menuManager = new MenuManager(); for (IContributionItem item : getSite().getActionBars().getMenuManager().getItems()) menuManager.add(item); viewer.getControl().setMenu(menuManager.createContextMenu(viewer.getControl())); } private void createColumns(final TableViewer viewer) { ColumnViewerToolTipSupport.enableFor(viewer, ToolTip.NO_RECREATE); TableViewerColumn var = new TableViewerColumn(viewer, SWT.LEFT, 0); var.getColumn().setText("Name"); var.getColumn().setWidth(120); var.setLabelProvider(new MeasurementLabelProvider(this, LabelType.ROINAME)); var = new TableViewerColumn(viewer, SWT.CENTER, 1); var.getColumn().setText("Region Type"); var.getColumn().setWidth(100); var.setLabelProvider(new MeasurementLabelProvider(this, LabelType.ROITYPE)); var = new TableViewerColumn(viewer, SWT.LEFT, 2); var.getColumn().setText("dx"); var.getColumn().setWidth(80); var.setLabelProvider(new MeasurementLabelProvider(this, LabelType.DX)); var = new TableViewerColumn(viewer, SWT.LEFT, 3); var.getColumn().setText("dy"); var.getColumn().setWidth(80); var.setLabelProvider(new MeasurementLabelProvider(this, LabelType.DY)); var = new TableViewerColumn(viewer, SWT.LEFT, 4); var.getColumn().setText("length"); var.getColumn().setWidth(80); var.setLabelProvider(new MeasurementLabelProvider(this, LabelType.LENGTH)); var = new TableViewerColumn(viewer, SWT.LEFT, 5); var.getColumn().setText("Coordinates"); var.getColumn().setWidth(500); var.setLabelProvider(new MeasurementLabelProvider(this, LabelType.ROISTRING)); } @Override public void activate() { super.activate(); if (viewer != null && viewer.getControl().isDisposed()) return; getPlottingSystem().addTraceListener(traceListener); if (viewUpdateListener != null) viewer.addSelectionChangedListener(viewUpdateListener); try { try { getPlottingSystem().addRegionListener(this); final Collection<IRegion> regions = getPlottingSystem().getRegions(); for (IRegion iRegion : regions) iRegion.addROIListener(this); if (!isDedicatedView()) { createNewRegion(false); } } catch (Exception e) { logger.error("Cannot add region listeners!", e); } if (viewer != null) { try { viewer.refresh(); } catch (Throwable ignored) { // Can happen when model invalid. } } } catch (Exception e) { logger.error("Cannot put the selection into fitting region mode!", e); } if (getPlottingSystem() != null && axesTraceListener != null) try { getPlottingSystem().addTraceListener(axesTraceListener); } catch (Exception e) { logger.error("Cannot add trace listener!", e); } } @Override public void deactivate() { super.deactivate(); if (viewer != null && !viewer.getControl().isDisposed() && viewUpdateListener != null) { viewer.removeSelectionChangedListener(viewUpdateListener); viewUpdateListener.resetSelectionColor(); } if (dragBounds != null) dragBounds.clear(); if (getPlottingSystem() != null) try { getPlottingSystem().removeTraceListener(traceListener); getPlottingSystem().removeRegionListener(this); final Collection<IRegion> regions = getPlottingSystem().getRegions(); if (regions != null) for (IRegion iRegion : regions) iRegion.removeROIListener(this); } catch (Exception e) { logger.error("Cannot remove region listeners!", e); } if (getPlottingSystem() != null && axesTraceListener != null) try { getPlottingSystem().removeTraceListener(axesTraceListener); } catch (Exception e) { logger.error("Cannot remove trace listener!", e); } } private void createNewRegion(boolean force) { try { if (!force) { // We check to see if the region type preferred is already there final Collection<IRegion> regions = getPlottingSystem().getRegions(); for (IRegion iRegion : regions) { if (iRegion.isUserRegion() && iRegion.isVisible()) { // We have one already, do not go into create mode :) if (iRegion.getRegionType() == IRegion.RegionType.LINE) return; } } } getPlottingSystem().createRegion(RegionUtils.getUniqueName("Measurement", getPlottingSystem()), IRegion.RegionType.LINE); } catch (Exception e) { logger.error("Cannot create line region for selecting in measurement tool!", e); } } @Override public void setFocus() { if (viewer != null && !viewer.getControl().isDisposed()) viewer.getControl().setFocus(); } public void dispose() { super.dispose(); } @Override public Control getControl() { return composite; } @Override public void regionCreated(RegionEvent evt) { IRegion region = evt.getRegion(); region.setAlpha(51); // 20% } @Override public void regionCancelled(RegionEvent evt) { } @Override public void regionNameChanged(RegionEvent evt, String oldName) { // TODO Auto-generated method stub } @Override public void regionAdded(RegionEvent evt) { if (!isActive()) return; IRegion region = evt.getRegion(); if (region != null && region.getROI() != null) { region.addROIListener(this); region.getROI().setPlot(true); // set the Region isActive flag region.setActive(true); } if (viewer != null) viewer.refresh(); } @Override public void regionRemoved(RegionEvent evt) { if (!isActive()) return; if (viewer != null) viewer.refresh(); if (evt.getRegion() != null) { evt.getRegion().removeROIListener(this); } } @Override public void regionsRemoved(RegionEvent evt) { if (!isActive()) return; if (viewer != null) viewer.refresh(); } @Override public void roiDragged(ROIEvent evt) { viewer.cancelEditing(); if (!isActive()) return; updateRegion(evt); } @Override public void roiChanged(ROIEvent evt) { if (!isActive()) return; updateRegion(evt); if ((IRegion) evt.getSource() == null) return; updateColorSelection((IRegion) evt.getSource()); } @Override public void roiSelected(ROIEvent evt) { } private void updateColorSelection(IRegion region) { Collection<IRegion> regions = getPlottingSystem().getRegions(); for (IRegion iRegion : regions) { if (region.getName().equals(iRegion.getName())) { iRegion.setRegionColor(ColorConstants.red); } else { if (iRegion.isActive()) iRegion.setRegionColor(ColorConstants.green); else if (!iRegion.isActive()) iRegion.setRegionColor(ColorConstants.gray); } } TableItem[] regionItems = viewer.getTable().getItems(); for (TableItem tableItem : regionItems) { IRegion myRegion = (IRegion) tableItem.getData(); if (region.getName().equals(myRegion.getName())) { viewer.getTable().setSelection(tableItem); break; } } } private RegionBoundsUIJob updateJob; /** * Uses cancellable UIJob * * @param evt */ private void updateRegion(final ROIEvent evt) { if (viewer == null) return; if (viewer.isCellEditorActive()) return; if (updateJob == null) { updateJob = new RegionBoundsUIJob(); updateJob.setPriority(UIJob.INTERACTIVE); //updateJob.setUser(false); } updateJob.setEvent(evt); updateJob.cancel(); updateJob.schedule(); } private final class RegionBoundsUIJob extends UIJob { private ROIEvent evt; RegionBoundsUIJob() { super("Measurement update"); } @Override public IStatus runInUIThread(IProgressMonitor monitor) { if (viewer != null) { if (monitor.isCanceled()) return Status.CANCEL_STATUS; IRegion region = (IRegion) evt.getSource(); IROI rb = evt.getROI(); if (monitor.isCanceled()) return Status.CANCEL_STATUS; dragBounds.put(region.getName(), rb); if (monitor.isCanceled()) return Status.CANCEL_STATUS; viewer.refresh(region); } return Status.OK_STATUS; } void setEvent(ROIEvent evt) { this.evt = evt; } }; public IROI getROI(IRegion region) { if (dragBounds != null && dragBounds.containsKey(region.getName())) return dragBounds.get(region.getName()); return region.getROI(); } /** * get point in axis coords * @param coords * @return */ public double[] getAxisPoint(ICoordinateSystem coords, double... vals) { if (coords == null) return vals; try { return coords.getValueAxisLocation(vals); } catch (Exception e) { return vals; } } /** * get point in image coords * @param coords * @return */ public double[] getImagePoint(ICoordinateSystem coords, double... vals) { if (coords == null) return vals; try { return coords.getAxisLocationValue(vals); } catch (Exception e) { return vals; } } public IROI getRoi() { return roi; } public void setRoi(IROI roi) { this.roi = roi; } @Override public ToolPageRole getToolPageRole() { if (getToolId() != null) { if (getToolId().endsWith("1d")) return ToolPageRole.ROLE_1D; if (getToolId().endsWith("2d")) return ToolPageRole.ROLE_2D; } return ToolPageRole.ROLE_1D; } @Override public boolean isStaticTool() { return getToolPageRole() == ToolPageRole.ROLE_2D; } private String getRegionTypeName() { return "measurement"; } public IToolPage cloneTool() throws Exception { IToolPage tp = super.cloneTool(); ((MeasurementTool) tp).xCalibratedAxisFactor = xCalibratedAxisFactor; ((MeasurementTool) tp).yCalibratedAxisFactor = yCalibratedAxisFactor; return tp; } /** * must be two axes in array. * @param axes */ public void setCalibratedAxes(String unitName, double... axes) { this.unitName = unitName; if (axes == null || axes.length != 2) { xCalibratedAxisFactor = Double.NaN; yCalibratedAxisFactor = Double.NaN; return; } xCalibratedAxisFactor = axes[0]; yCalibratedAxisFactor = axes[1]; viewer.refresh(); } public double getxCalibratedAxisFactor() { return xCalibratedAxisFactor; } public void setxCalibratedAxisFactor(double xCalibratedAxisFactor) { this.xCalibratedAxisFactor = xCalibratedAxisFactor; } public double getyCalibratedAxisFactor() { return yCalibratedAxisFactor; } public void setyCalibratedAxisFactor(double yCalibratedAxisFactor) { this.yCalibratedAxisFactor = yCalibratedAxisFactor; } public String getUnitName() { return unitName; } public void setUnitName(String unitName) { this.unitName = unitName; } }