/* * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI for * visualizing and manipulating spatial features with geometry and attributes. * * Copyright (C) 2003 Vivid Solutions * * 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., 59 Temple * Place - Suite 330, Boston, MA 02111-1307, USA. * * For more information, contact: * * Vivid Solutions Suite #1A 2328 Government Street Victoria BC V8T 5G5 Canada * * (250)385-6040 www.vividsolutions.com */ package com.vividsolutions.jump.workbench.ui.task; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.Date; import javax.swing.JOptionPane; import javax.swing.Timer; import com.vividsolutions.jump.util.StringUtil; import com.vividsolutions.jump.workbench.plugin.PlugInContext; import com.vividsolutions.jump.workbench.plugin.ThreadedPlugIn; import com.vividsolutions.jump.workbench.ui.GUIUtil; import com.vividsolutions.jump.workbench.ui.WorkbenchFrame; /** * * TODO : I18N */ public class TaskMonitorManager { public TaskMonitorManager() { } /** * Executes the task in a separate thread, reporting progress in a dialog. */ public void execute(ThreadedPlugIn plugIn, PlugInContext context) { final TaskMonitorDialog progressDialog = new TaskMonitorDialog(context .getWorkbenchFrame(), context.getErrorHandler()); progressDialog.setTitle(plugIn.getName()); //Do not refer to context inside the anonymous class, otherwise it (and //the Task it refers to) will not be garbage collected. [Jon Aquino] //<<TODO>> Eliminate TaskWrapper. The Task no longer needs to be //garbage-collectable for the data to be garbage-collected. [Jon // Aquino] final TaskWrapper taskWrapper = new TaskWrapper(plugIn, context, progressDialog); final Thread thread = new Thread(taskWrapper); progressDialog.addWindowListener(new WindowAdapter() { private int attempts = 0; public void windowClosing(WindowEvent e) { if (JOptionPane.NO_OPTION == JOptionPane .showConfirmDialog( progressDialog, StringUtil .split( "Warning: Killing the process may result in data corruption or data loss. " + "Are you sure you want to kill the process?", 80), "Kill Process", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE)) { return; } attempts++; if (attempts > 1) { // Sometimes the thread seems to take a while to die. // So force the dialog to close if the user has pressed // the close button for the second time. // [Jon Aquino 2005-03-14] progressDialog.setVisible(false); progressDialog.dispose(); } thread.stop(); } }); progressDialog.addComponentListener(new ComponentAdapter() { public void componentShown(ComponentEvent e) { //Wait for the dialog to appear before starting the task. // Otherwise the task might possibly finish before the dialog // appeared and the dialog would never close. [Jon Aquino] thread.start(); } }); GUIUtil.centreOnWindow(progressDialog); Timer timer = timer(new Date(), plugIn, context.getWorkbenchFrame()); timer.start(); try { progressDialog.setVisible(true); } finally { timer.stop(); progressDialog.dispose(); } } private Timer timer(final Date start, final ThreadedPlugIn plugIn, final WorkbenchFrame workbenchFrame) { return new Timer(1000, new ActionListener() { public void actionPerformed(ActionEvent e) { String message = ""; message += StringUtil.toTimeString(new Date().getTime() - start.getTime()); message += (" (" + plugIn.getName() + ")"); workbenchFrame.setTimeMessage(message); } }); } private class TaskWrapper implements Runnable { private ThreadedPlugIn plugIn; private PlugInContext context; private TaskMonitorDialog dialog; public TaskWrapper(ThreadedPlugIn plugIn, PlugInContext context, TaskMonitorDialog dialog) { this.plugIn = plugIn; this.context = context; this.dialog = dialog; } public void run() { Throwable throwable = null; try { plugIn.run(dialog, context); } catch (Throwable t) { throwable = t; } finally { // Hmm - race conditions because we are doing a GUI action // (#setVisible) outside the AWT event thread? Case in point: // AutoConflatePlugIn displays a dialog using #invokeLater, // but timer keeps on running until dialog is closed . . . // [Jon Aquino 2004-09-07] dialog.setVisible( false ); dialog.dispose(); if (throwable != null) { context.getErrorHandler().handleThrowable(throwable); } // Releases references to the data, to facilitate garbage // collection. [Jon Aquino] context = null; } } } }