001: /* uDig - User Friendly Desktop Internet GIS client
002: * http://udig.refractions.net
003: * (C) 2004, Refractions Research Inc.
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation;
008: * version 2.1 of the License.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: */
015: package net.refractions.udig.ui;
016:
017: import java.lang.reflect.InvocationTargetException;
018: import java.util.Collection;
019: import java.util.LinkedList;
020:
021: import net.refractions.udig.internal.ui.UiPlugin;
022: import net.refractions.udig.ui.internal.Messages;
023:
024: import org.eclipse.core.runtime.IProgressMonitor;
025: import org.eclipse.jface.dialogs.ProgressMonitorDialog;
026: import org.eclipse.jface.operation.IRunnableWithProgress;
027: import org.eclipse.swt.widgets.Display;
028: import org.eclipse.swt.widgets.Shell;
029: import org.eclipse.ui.IWorkbench;
030: import org.eclipse.ui.IWorkbenchListener;
031: import org.eclipse.ui.PlatformUI;
032:
033: /**
034: * This class allows a plugin to add an {@link IShutdownTask} object that will be run when uDig
035: * shuts down. It allows a single place for shutdown tasks such as saving the catalog or projects or
036: * anything else.
037: *
038: * @author Jesse
039: * @since 1.1.0
040: */
041: public class ShutdownTaskList implements IWorkbenchListener {
042:
043: private final static ShutdownTaskList INSTANCE = new ShutdownTaskList();
044: private Collection<PostTask> postShutdownTasks = new LinkedList<PostTask>();
045: private Collection<PreTask> preShutdownTasks = new LinkedList<PreTask>();
046:
047: public void postShutdown(final IWorkbench workbench) {
048:
049: try {
050: final ProgressMonitorDialog dialog = getDialog(workbench);
051: dialog.run(true, false, new IRunnableWithProgress() {
052:
053: public void run(IProgressMonitor monitor2)
054: throws InvocationTargetException,
055: InterruptedException {
056: OffThreadProgressMonitor monitor = new OffThreadProgressMonitor(
057: monitor2, dialog.getShell().getDisplay());
058:
059: int totalsteps = 0;
060: for (PostTask task : postShutdownTasks) {
061: try {
062: task.steps = task.task
063: .getProgressMonitorSteps();
064: totalsteps += task.steps;
065: } catch (Throwable e) {
066: UiPlugin
067: .log(
068: "error calling getProgressMonitorSteps() on " + task.task, e); //$NON-NLS-1$
069: }
070: }
071:
072: monitor.beginTask(
073: Messages.ShutdownTaskList_shutDown,
074: totalsteps);
075:
076: for (PostTask task : postShutdownTasks) {
077: IProgressMonitor subMonitor = new ProgressMonitorTaskNamer(
078: monitor, task.steps);
079: try {
080: task.task.postShutdown(subMonitor,
081: workbench);
082: } catch (Throwable t) {
083: task.task.handlePostShutdownException(t);
084: } finally {
085: subMonitor.done();
086: }
087: }
088: }
089:
090: });
091: } catch (InvocationTargetException e) {
092: throw (RuntimeException) new RuntimeException()
093: .initCause(e);
094: } catch (InterruptedException e) {
095: throw (RuntimeException) new RuntimeException()
096: .initCause(e);
097: }
098:
099: }
100:
101: public boolean preShutdown(final IWorkbench workbench,
102: final boolean forced) {
103: final ProgressMonitorDialog dialog = getDialog(workbench);
104:
105: final boolean[] allowShutdown = new boolean[1];
106: allowShutdown[0] = true;
107:
108: workbench.getActiveWorkbenchWindow().getShell().setVisible(
109: false);
110:
111: final Display display = Display.getCurrent();
112: try {
113: dialog.run(true, forced, new IRunnableWithProgress() {
114:
115: public void run(IProgressMonitor monitor2)
116: throws InvocationTargetException,
117: InterruptedException {
118:
119: IProgressMonitor monitor = new OffThreadProgressMonitor(
120: monitor2, display);
121:
122: int totalsteps = 0;
123: for (PreTask task : preShutdownTasks) {
124: try {
125: task.steps = task.task
126: .getProgressMonitorSteps();
127: totalsteps += task.steps;
128: } catch (Throwable e) {
129: UiPlugin
130: .log(
131: "error calling getProgressMonitorSteps() on " + task.task, e); //$NON-NLS-1$
132: }
133: }
134: monitor.beginTask(
135: Messages.ShutdownTaskList_shutDown,
136: totalsteps);
137:
138: for (PreTask task : preShutdownTasks) {
139: IProgressMonitor subMonitor = new ProgressMonitorTaskNamer(
140: monitor, task.steps);
141: boolean result;
142: try {
143: result = task.task.preShutdown(subMonitor,
144: workbench, forced);
145: } catch (Throwable t) {
146: result = task.task
147: .handlePreShutdownException(t,
148: forced);
149: } finally {
150: subMonitor.done();
151: }
152: if (!forced) {
153: if (monitor.isCanceled() || !result)
154: allowShutdown[0] = false;
155: if (monitor.isCanceled())
156: return;
157: }
158: }
159: }
160:
161: });
162: } catch (InvocationTargetException e) {
163: throw (RuntimeException) new RuntimeException()
164: .initCause(e);
165: } catch (InterruptedException e) {
166: throw (RuntimeException) new RuntimeException()
167: .initCause(e);
168: }
169:
170: if (!allowShutdown[0])
171: workbench.getActiveWorkbenchWindow().getShell().setVisible(
172: true);
173:
174: return allowShutdown[0];
175: }
176:
177: private ProgressMonitorDialog getDialog(IWorkbench workbench) {
178: Shell shell = new Shell(Display.getCurrent());
179:
180: ProgressMonitorDialog dialog = new ProgressMonitorDialog(shell);
181: dialog.open();
182: return dialog;
183: }
184:
185: public static ShutdownTaskList instance() {
186: return INSTANCE;
187: }
188:
189: /**
190: * Adds a task to the list of tasks to be run post shutdown.
191: *
192: * @see #postShutdown(IWorkbench)
193: * @param task the task to be ran. The ordering or the tasks ran is random so make sure there
194: * are no order dependencies between tasks
195: */
196: public synchronized void addPostShutdownTask(PostShutdownTask task) {
197: postShutdownTasks.add(new PostTask(task));
198: }
199:
200: /**
201: * Adds a task to the list of tasks to be run post shutdown.
202: *
203: * @see #postShutdown(IWorkbench)
204: * @param task the task to be ran. The ordering or the tasks ran is random so make sure there
205: * are no order dependencies between tasks
206: */
207: public synchronized void addPreShutdownTask(PreShutdownTask task) {
208: preShutdownTasks.add(new PreTask(task));
209: }
210:
211: public synchronized void removePreShutdownTask(
212: PreShutdownTask shutdownTask) {
213: preShutdownTasks.remove(new PreTask(shutdownTask));
214: }
215:
216: public synchronized void removePostShutdownTask(
217: PostShutdownTask shutdownTask) {
218: postShutdownTasks.remove(new PostTask(shutdownTask));
219: }
220:
221: public static class PostTask {
222:
223: int steps;
224: final PostShutdownTask task;
225:
226: public PostTask(PostShutdownTask task) {
227: this .task = task;
228: }
229:
230: @Override
231: public int hashCode() {
232: final int PRIME = 31;
233: int result = 1;
234: result = PRIME * result
235: + ((task == null) ? 0 : task.hashCode());
236: return result;
237: }
238:
239: @Override
240: public boolean equals(Object obj) {
241: if (this == obj)
242: return true;
243: if (obj == null)
244: return false;
245: if (getClass() != obj.getClass())
246: return false;
247: final PostTask other = (PostTask) obj;
248: if (task == null) {
249: if (other.task != null)
250: return false;
251: } else if (!task.equals(other.task))
252: return false;
253: return true;
254: }
255:
256: }
257:
258: public static class PreTask {
259:
260: int steps;
261: final PreShutdownTask task;
262:
263: public PreTask(PreShutdownTask task) {
264: this .task = task;
265: }
266:
267: @Override
268: public int hashCode() {
269: final int PRIME = 31;
270: int result = 1;
271: result = PRIME * result
272: + ((task == null) ? 0 : task.hashCode());
273: return result;
274: }
275:
276: @Override
277: public boolean equals(Object obj) {
278: if (this == obj)
279: return true;
280: if (obj == null)
281: return false;
282: if (getClass() != obj.getClass())
283: return false;
284: final PreTask other = (PreTask) obj;
285: if (task == null) {
286: if (other.task != null)
287: return false;
288: } else if (!task.equals(other.task))
289: return false;
290: return true;
291: }
292:
293: }
294: }
|