Java tutorial
/* * uDig - User Friendly Desktop Internet GIS client * (C) MangoSystem - www.mangosystem.com * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). */ package org.locationtech.udig.processingtoolbox.tools; import java.awt.Font; import java.awt.geom.Ellipse2D; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.swt.SWT; import org.eclipse.swt.browser.Browser; import org.eclipse.swt.custom.CTabFolder; import org.eclipse.swt.custom.CTabItem; import org.eclipse.swt.custom.ScrolledComposite; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.PlatformUI; import org.geotools.data.simple.SimpleFeatureCollection; import org.geotools.data.simple.SimpleFeatureIterator; import org.geotools.factory.CommonFactoryFinder; import org.geotools.process.Process; import org.geotools.process.spatialstatistics.GlobalMoransIProcess; import org.geotools.process.spatialstatistics.GlobalMoransIProcess.MoransIProcessResult; import org.geotools.process.spatialstatistics.GlobalMoransIProcessFactory; import org.geotools.process.spatialstatistics.autocorrelation.LocalMoranIStatisticOperation; import org.geotools.process.spatialstatistics.core.SpatialEvent; import org.geotools.process.spatialstatistics.core.WeightMatrixBuilder; import org.geotools.process.spatialstatistics.enumeration.DistanceMethod; import org.geotools.process.spatialstatistics.enumeration.SpatialConcept; import org.geotools.process.spatialstatistics.enumeration.StandardizationMethod; import org.geotools.process.spatialstatistics.styler.SSStyleBuilder; import org.geotools.styling.Style; import org.geotools.util.Converters; import org.geotools.util.logging.Logging; import org.jfree.chart.ChartMouseEvent; import org.jfree.chart.ChartMouseListener; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.entity.ChartEntity; import org.jfree.chart.entity.XYItemEntity; import org.jfree.chart.labels.StandardXYToolTipGenerator; import org.jfree.chart.labels.XYToolTipGenerator; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.plot.SeriesRenderingOrder; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.xy.XYItemRenderer; import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; import org.jfree.data.xy.XYDataset; import org.jfree.data.xy.XYSeries; import org.jfree.data.xy.XYSeriesCollection; import org.locationtech.udig.catalog.util.GeoToolsAdapters; import org.locationtech.udig.processingtoolbox.ToolboxPlugin; import org.locationtech.udig.processingtoolbox.internal.Messages; import org.locationtech.udig.processingtoolbox.styler.MapUtils; import org.locationtech.udig.processingtoolbox.styler.MapUtils.FieldType; import org.locationtech.udig.processingtoolbox.styler.MapUtils.VectorLayerType; import org.locationtech.udig.project.ILayer; import org.locationtech.udig.project.IMap; import org.opengis.feature.simple.SimpleFeature; import org.opengis.filter.Filter; import org.opengis.filter.FilterFactory2; import org.opengis.util.ProgressListener; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Geometry; /** * Moran Scatter Plot Dialog * * @author Minpa Lee, MangoSystem * * @source $URL$ */ public class MoranScatterPlotDialog extends AbstractGeoProcessingDialog implements IRunnableWithProgress { protected static final Logger LOGGER = Logging.getLogger(MoranScatterPlotDialog.class); protected final FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(null); private ChartComposite2 chartComposite; private Map<String, Object> params = new HashMap<String, Object>(); private ILayer inputLayer, outputLayer; private Combo cboLayer, cboField, cboConcept, cboDistance, cboStandard; private Browser browser; private CTabItem inputTab, plotTab, outputTab; private boolean crossCenter = true; private WeightMatrixBuilder swMatrix; private double[] zScore; private SpatialConcept spatialConcept = SpatialConcept.InverseDistance; private DistanceMethod distanceMethod = DistanceMethod.Euclidean; private StandardizationMethod standardization = StandardizationMethod.None; private Double searchDistance = Double.valueOf(0d); private XYMinMaxVisitor minMaxVisitor = new XYMinMaxVisitor(); public MoranScatterPlotDialog(Shell parentShell, IMap map) { super(parentShell, map); setShellStyle(SWT.CLOSE | SWT.MIN | SWT.TITLE | SWT.BORDER | SWT.MODELESS | SWT.RESIZE); this.windowTitle = Messages.MoranScatterPlotDialog_title; this.windowDesc = Messages.MoranScatterPlotDialog_description; this.windowSize = new Point(650, 520); } @Override protected Control createDialogArea(final Composite parent) { Composite area = (Composite) super.createDialogArea(parent); // 0. Tab Folder final CTabFolder parentTabFolder = new CTabFolder(area, SWT.BOTTOM); parentTabFolder.setUnselectedCloseVisible(false); parentTabFolder.setLayout(new FillLayout()); parentTabFolder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); // 1. Input Tab createInputTab(parentTabFolder); parentTabFolder.setSelection(inputTab); parentTabFolder.pack(); area.pack(true); return area; } private void createInputTab(final CTabFolder parentTabFolder) { inputTab = new CTabItem(parentTabFolder, SWT.NONE); inputTab.setText(Messages.ProcessExecutionDialog_tabparameters); ScrolledComposite scroller = new ScrolledComposite(parentTabFolder, SWT.NONE | SWT.V_SCROLL | SWT.H_SCROLL); scroller.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); Composite container = new Composite(scroller, SWT.NONE); container.setLayout(new GridLayout(1, false)); container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); // local moran's i Image image = ToolboxPlugin.getImageDescriptor("icons/public_co.gif").createImage(); //$NON-NLS-1$ uiBuilder.createLabel(container, Messages.MoranScatterPlotDialog_InputLayer, EMPTY, image, 1); cboLayer = uiBuilder.createCombo(container, 1, true); fillLayers(map, cboLayer, VectorLayerType.ALL); uiBuilder.createLabel(container, Messages.MoranScatterPlotDialog_InputField, EMPTY, image, 1); cboField = uiBuilder.createCombo(container, 1, true); uiBuilder.createLabel(container, Messages.MoranScatterPlotDialog_Conceptualization, EMPTY, 1); cboConcept = uiBuilder.createCombo(container, 1, true); cboConcept.addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent e) { for (Object enumVal : SpatialConcept.class.getEnumConstants()) { if (enumVal.toString().equalsIgnoreCase(cboConcept.getText())) { params.put(GlobalMoransIProcessFactory.spatialConcept.key, enumVal); break; } } } }); fillEnum(cboConcept, SpatialConcept.class); uiBuilder.createLabel(container, Messages.MoranScatterPlotDialog_DistanceMethod, EMPTY, 1); cboDistance = uiBuilder.createCombo(container, 1, true); cboDistance.addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent e) { for (Object enumVal : DistanceMethod.class.getEnumConstants()) { if (enumVal.toString().equalsIgnoreCase(cboDistance.getText())) { params.put(GlobalMoransIProcessFactory.distanceMethod.key, enumVal); break; } } } }); fillEnum(cboDistance, DistanceMethod.class); uiBuilder.createLabel(container, Messages.MoranScatterPlotDialog_Standardization, EMPTY, 1); cboStandard = uiBuilder.createCombo(container, 1, true); cboStandard.addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent e) { for (Object enumVal : StandardizationMethod.class.getEnumConstants()) { if (enumVal.toString().equalsIgnoreCase(cboStandard.getText())) { params.put(GlobalMoransIProcessFactory.standardization.key, enumVal); break; } } } }); fillEnum(cboStandard, StandardizationMethod.class); uiBuilder.createLabel(container, Messages.MoranScatterPlotDialog_DistanceBand, EMPTY, 1); final Text txtDistance = uiBuilder.createText(container, EMPTY, 1, true); txtDistance.addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent e) { Object obj = Converters.convert(txtDistance.getText(), Double.class); if (obj == null) { params.put(GlobalMoransIProcessFactory.searchDistance.key, Double.valueOf(0d)); } else { params.put(GlobalMoransIProcessFactory.searchDistance.key, obj); } } }); // register events cboLayer.addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent e) { inputLayer = MapUtils.getLayer(map, cboLayer.getText()); if (inputLayer == null) { return; } SimpleFeatureCollection features = MapUtils.getFeatures(inputLayer); params.put(GlobalMoransIProcessFactory.inputFeatures.key, features); fillFields(cboField, inputLayer.getSchema(), FieldType.Number); } }); cboField.addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent e) { params.put(GlobalMoransIProcessFactory.inputField.key, cboField.getText()); } }); // finally scroller.setContent(container); inputTab.setControl(scroller); scroller.setMinSize(450, container.getSize().y - 2); scroller.setExpandVertical(true); scroller.setExpandHorizontal(true); scroller.pack(); container.pack(); } private void createOutputTab(final CTabFolder parentTabFolder) { outputTab = new CTabItem(parentTabFolder, SWT.NONE); outputTab.setText(Messages.ScatterPlotDialog_Summary); try { browser = new Browser(parentTabFolder, SWT.NONE); GridData layoutData = new GridData(GridData.FILL_BOTH); browser.setLayoutData(layoutData); outputTab.setControl(browser); } catch (Exception e) { LOGGER.log(Level.WARNING, e.getMessage(), e); } } private void createGraphTab(final CTabFolder parentTabFolder) { plotTab = new CTabItem(parentTabFolder, SWT.NONE); plotTab.setText(Messages.MoranScatterPlotDialog_Graph); XYPlot plot = new XYPlot(); plot.setOrientation(PlotOrientation.VERTICAL); plot.setBackgroundPaint(java.awt.Color.WHITE); plot.setDomainPannable(false); plot.setRangePannable(false); plot.setSeriesRenderingOrder(SeriesRenderingOrder.FORWARD); JFreeChart chart = new JFreeChart(EMPTY, JFreeChart.DEFAULT_TITLE_FONT, plot, false); chart.setBackgroundPaint(java.awt.Color.WHITE); chart.setBorderVisible(false); chartComposite = new ChartComposite2(parentTabFolder, SWT.NONE | SWT.EMBEDDED, chart, true); chartComposite.setLayout(new FillLayout()); chartComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); chartComposite.setDomainZoomable(false); chartComposite.setRangeZoomable(false); chartComposite.setMap(map); chartComposite.addChartMouseListener(new PlotMouseListener()); plotTab.setControl(chartComposite); chartComposite.pack(); } class PlotMouseListener implements ChartMouseListener { @Override public void chartMouseMoved(ChartMouseEvent event) { } @Override public void chartMouseClicked(ChartMouseEvent event) { ChartEntity entity = event.getEntity(); if (entity != null && (entity instanceof XYItemEntity)) { XYItemEntity item = (XYItemEntity) entity; XYSeriesCollection dataSet = (XYSeriesCollection) item.getDataset(); XYSeries xySeries = dataSet.getSeries(item.getSeriesIndex()); XYDataItem2 dataItem = (XYDataItem2) xySeries.getDataItem(item.getItem()); Filter selectionFilter = ff.id(ff.featureId(dataItem.getFeature().getID())); map.select(selectionFilter, outputLayer); } else { map.select(Filter.EXCLUDE, outputLayer); } } } private void updateChart(SimpleFeatureCollection features, String propertyName, String morani) { // 1. Create a single plot containing both the scatter and line XYPlot plot = new XYPlot(); plot.setOrientation(PlotOrientation.VERTICAL); plot.setBackgroundPaint(java.awt.Color.WHITE); plot.setDomainPannable(false); plot.setRangePannable(false); plot.setSeriesRenderingOrder(SeriesRenderingOrder.FORWARD); plot.setDomainCrosshairVisible(false); plot.setRangeCrosshairVisible(false); plot.setDomainCrosshairLockedOnData(true); plot.setRangeCrosshairLockedOnData(true); plot.setDomainCrosshairPaint(java.awt.Color.CYAN); plot.setRangeCrosshairPaint(java.awt.Color.CYAN); plot.setDomainGridlinePaint(java.awt.Color.LIGHT_GRAY); plot.setRangeGridlinePaint(java.awt.Color.LIGHT_GRAY); // 2. Setup Scatter plot // Create the scatter data, renderer, and axis int fontStyle = java.awt.Font.BOLD; FontData fontData = getShell().getDisplay().getSystemFont().getFontData()[0]; NumberAxis xPlotAxis = new NumberAxis(propertyName); // ZScore xPlotAxis.setLabelFont(new Font(fontData.getName(), fontStyle, 12)); xPlotAxis.setTickLabelFont(new Font(fontData.getName(), fontStyle, 10)); NumberAxis yPlotAxis = new NumberAxis("lagged " + propertyName); //$NON-NLS-1$ yPlotAxis.setLabelFont(new Font(fontData.getName(), fontStyle, 12)); yPlotAxis.setTickLabelFont(new Font(fontData.getName(), fontStyle, 10)); XYToolTipGenerator plotToolTip = new StandardXYToolTipGenerator(); XYItemRenderer plotRenderer = new XYLineAndShapeRenderer(false, true); // Shapes only plotRenderer.setSeriesShape(0, new Ellipse2D.Double(0, 0, 3, 3)); plotRenderer.setSeriesPaint(0, java.awt.Color.BLUE); // dot plotRenderer.setBaseToolTipGenerator(plotToolTip); // Set the scatter data, renderer, and axis into plot plot.setDataset(0, getScatterPlotData(features)); plot.setRenderer(0, plotRenderer); plot.setDomainAxis(0, xPlotAxis); plot.setRangeAxis(0, yPlotAxis); // Map the scatter to the first Domain and first Range plot.mapDatasetToDomainAxis(0, 0); plot.mapDatasetToRangeAxis(0, 0); // 3. Setup line // Create the line data, renderer, and axis XYItemRenderer lineRenderer = new XYLineAndShapeRenderer(true, false); // Lines only lineRenderer.setSeriesPaint(0, java.awt.Color.GRAY); // dot // Set the line data, renderer, and axis into plot NumberAxis xLineAxis = new NumberAxis(EMPTY); xLineAxis.setTickMarksVisible(false); xLineAxis.setTickLabelsVisible(false); NumberAxis yLineAxis = new NumberAxis(EMPTY); yLineAxis.setTickMarksVisible(false); yLineAxis.setTickLabelsVisible(false); plot.setDataset(1, getLinePlotData(crossCenter)); plot.setRenderer(1, lineRenderer); plot.setDomainAxis(1, xLineAxis); plot.setRangeAxis(1, yLineAxis); // Map the line to the second Domain and second Range plot.mapDatasetToDomainAxis(1, 0); plot.mapDatasetToRangeAxis(1, 0); // 4. Setup Selection NumberAxis xSelectionAxis = new NumberAxis(EMPTY); xSelectionAxis.setTickMarksVisible(false); xSelectionAxis.setTickLabelsVisible(false); NumberAxis ySelectionAxis = new NumberAxis(EMPTY); ySelectionAxis.setTickMarksVisible(false); ySelectionAxis.setTickLabelsVisible(false); XYItemRenderer selectionRenderer = new XYLineAndShapeRenderer(false, true); // Shapes only selectionRenderer.setSeriesShape(0, new Ellipse2D.Double(0, 0, 6, 6)); selectionRenderer.setSeriesPaint(0, java.awt.Color.RED); // dot plot.setDataset(2, new XYSeriesCollection(new XYSeries(EMPTY))); plot.setRenderer(2, selectionRenderer); plot.setDomainAxis(2, xSelectionAxis); plot.setRangeAxis(2, ySelectionAxis); // Map the scatter to the second Domain and second Range plot.mapDatasetToDomainAxis(2, 0); plot.mapDatasetToRangeAxis(2, 0); // 5. Finally, Create the chart with the plot and a legend String title = "Moran's I = " + morani; //$NON-NLS-1$ java.awt.Font titleFont = new Font(fontData.getName(), fontStyle, 20); JFreeChart chart = new JFreeChart(title, titleFont, plot, false); chart.setBackgroundPaint(java.awt.Color.WHITE); chart.setBorderVisible(false); chartComposite.setChart(chart); chartComposite.forceRedraw(); } private XYDataset getLinePlotData(boolean center) { XYSeriesCollection dataset = new XYSeriesCollection(); // Horizontal XYSeries horizontal = new XYSeries("Horizontal"); //$NON-NLS-1$ if (center) { horizontal.add(-minMaxVisitor.getAbsMaxX(), 0); horizontal.add(minMaxVisitor.getAbsMaxX(), 0); } else { horizontal.add(minMaxVisitor.getMinX(), 0); horizontal.add(minMaxVisitor.getMaxX(), 0); } dataset.addSeries(horizontal); // Vertical XYSeries vertical = new XYSeries("Vertical"); //$NON-NLS-1$ if (center) { vertical.add(0, -minMaxVisitor.getAbsMaxY()); vertical.add(0, minMaxVisitor.getAbsMaxY()); } else { vertical.add(0, minMaxVisitor.getMinY()); vertical.add(0, minMaxVisitor.getMaxY()); } dataset.addSeries(vertical); return dataset; } @SuppressWarnings("nls") private XYDataset getScatterPlotData(SimpleFeatureCollection features) { // "LMiIndex", "LMiZScore", "LMiPValue", "COType" XYSeries xySeries = new XYSeries(features.getSchema().getTypeName()); minMaxVisitor.reset(); String typeName = features.getSchema().getTypeName(); SimpleFeatureIterator featureIter = features.features(); try { int i = 0; while (featureIter.hasNext()) { SimpleFeature feature = featureIter.next(); Geometry geometry = (Geometry) feature.getDefaultGeometry(); Coordinate coordinate = geometry.getCentroid().getCoordinate(); // The X axis of the scatter plot represents the standardised Z values of your // variable (that is, theyve been standardised to their Z scores, with a mean of // zero, and a standard deviation of 1.) Double x = Converters.convert(feature.getAttribute("LMiZScore"), Double.class); if (x == null || x.isInfinite() || x.isNaN()) { continue; } // The Y axis represents the standardised values of the neighbouring values around // your point of interest, that is the lagged values. These are calculated according // to the spatial weights matrix that you specify. So, for instance, if you specify // a contiguous spatial weights matrix, with a first order queen contiguity, the // value of the y axis represents the mean value of the variable for all of the // areas that share a border with the area of interest. SpatialEvent source = new SpatialEvent(typeName + "." + ++i, coordinate); int neighbors = 0; double zSum = 0d; for (int j = 0; j < swMatrix.getEvents().size(); j++) { SpatialEvent target = swMatrix.getEvents().get(j); if (source.id == target.id) { continue; } double wij = swMatrix.getWeight(source, target); if (wij > 0) { neighbors++; zSum += zScore[j]; } } double y = neighbors == 0 ? 0d : zSum / neighbors; minMaxVisitor.visit(x, y); xySeries.add(new XYDataItem2(feature, x, y)); } } finally { featureIter.close(); } return new XYSeriesCollection(xySeries); } @Override protected void okPressed() { if (invalidWidgetValue(cboLayer, cboField)) { openInformation(getShell(), Messages.Task_ParameterRequired); return; } spatialConcept = (SpatialConcept) params.get(GlobalMoransIProcessFactory.spatialConcept.key); distanceMethod = (DistanceMethod) params.get(GlobalMoransIProcessFactory.distanceMethod.key); standardization = (StandardizationMethod) params.get(GlobalMoransIProcessFactory.standardization.key); searchDistance = (Double) params.get(GlobalMoransIProcessFactory.searchDistance.key); if (spatialConcept == SpatialConcept.FixedDistance && (searchDistance == null || searchDistance == 0)) { openInformation(getShell(), "FIXEDDISTANCEBAND option requires Distance Band"); //$NON-NLS-1$ return; } if (inputLayer.getFilter() != Filter.EXCLUDE) { map.select(Filter.EXCLUDE, inputLayer); } try { PlatformUI.getWorkbench().getProgressService().run(false, true, this); } catch (InvocationTargetException e) { MessageDialog.openError(getShell(), Messages.General_Error, e.getMessage()); } catch (InterruptedException e) { MessageDialog.openInformation(getShell(), Messages.General_Cancelled, e.getMessage()); } } @SuppressWarnings("nls") @Override public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { monitor.beginTask(String.format(Messages.Task_Executing, windowTitle), 100); try { if (plotTab == null) { monitor.subTask("Preparing scatter plot..."); createGraphTab(inputTab.getParent()); } if (outputTab == null) { createOutputTab(inputTab.getParent()); } monitor.worked(increment); monitor.subTask("Analyzing global moran..."); ProgressListener subMonitor = GeoToolsAdapters .progress(SubMonitor.convert(monitor, Messages.Task_Internal, increment)); Process process = new GlobalMoransIProcess(null); Map<String, Object> result = process.execute(params, subMonitor); MoransIProcessResult moran = (MoransIProcessResult) result.get(GlobalMoransIProcessFactory.RESULT.key); // write html HtmlWriter writer = new HtmlWriter(inputLayer.getName()); writer.writeMoransI(moran); browser.setText(writer.getHTML()); monitor.subTask("Analyzing local moran..."); subMonitor = GeoToolsAdapters.progress(SubMonitor.convert(monitor, Messages.Task_Internal, increment)); LocalMoranIStatisticOperation opertor = new LocalMoranIStatisticOperation(); opertor.setSpatialConceptType(spatialConcept); opertor.setDistanceType(distanceMethod); opertor.setStandardizationType(standardization); if (searchDistance != null && searchDistance > 0 && !Double.isNaN(searchDistance)) { spatialConcept = SpatialConcept.FixedDistance; opertor.setDistanceBand(searchDistance); opertor.setSpatialConceptType(spatialConcept); } SimpleFeatureCollection features = opertor.execute( (SimpleFeatureCollection) params.get(GlobalMoransIProcessFactory.inputFeatures.key), (String) params.get(GlobalMoransIProcessFactory.inputField.key)); swMatrix = opertor.getSpatialWeightMatrix(); zScore = opertor.getZScore(); subMonitor.complete(); monitor.subTask(Messages.Task_AddingLayer); SSStyleBuilder ssBuilder = new SSStyleBuilder(features.getSchema()); ssBuilder.setOpacity(0.95f); Style style = ssBuilder.getLISAStyle("COType"); //$NON-NLS-1$ outputLayer = MapUtils.addFeaturesToMap(map, features, "Local Moran's I", style); features = MapUtils.getFeatures(outputLayer); monitor.worked(increment); monitor.subTask("Updating scatter plot..."); chartComposite.setLayer(outputLayer); updateChart(features, moran.getPropertyName(), moran.getObserved_Index()); plotTab.getParent().setSelection(plotTab); monitor.worked(increment); } catch (Exception e) { ToolboxPlugin.log(e.getMessage()); throw new InvocationTargetException(e.getCause(), e.getMessage()); } finally { ToolboxPlugin.log(String.format(Messages.Task_Completed, windowTitle)); monitor.done(); } } }