Mercurial > projects > dwt-addons
diff dwtx/jface/operation/ModalContext.d @ 70:46a6e0e6ccd4
Merge with d-fied sources of 3.4M7
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Thu, 22 May 2008 01:36:46 +0200 |
parents | 84ce9636d109 |
children | 4878bef4a38e |
line wrap: on
line diff
--- a/dwtx/jface/operation/ModalContext.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/operation/ModalContext.d Thu May 22 01:36:46 2008 +0200 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2007 IBM Corporation and others. * 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 @@ -15,8 +15,11 @@ import dwt.widgets.Display; import dwtx.core.runtime.Assert; import dwtx.core.runtime.IProgressMonitor; +import dwtx.core.runtime.IStatus; import dwtx.core.runtime.OperationCanceledException; import dwtx.core.runtime.ProgressMonitorWrapper; +import dwtx.core.runtime.Status; +import dwtx.jface.util.Policy; import dwtx.jface.operation.IThreadListener; import dwtx.jface.operation.IRunnableWithProgress; @@ -28,12 +31,12 @@ import tango.io.Stdout; /** - * Utility class for supporting modal operations. - * The runnable passed to the <code>run</code> method is executed in a - * separate thread, depending on the value of the passed fork argument. - * If the runnable is executed in a separate thread then the current thread - * either waits until the new thread ends or, if the current thread is the - * UI thread, it polls the DWT event queue and dispatches each event. + * Utility class for supporting modal operations. The runnable passed to the + * <code>run</code> method is executed in a separate thread, depending on the + * value of the passed fork argument. If the runnable is executed in a separate + * thread then the current thread either waits until the new thread ends or, if + * the current thread is the UI thread, it polls the DWT event queue and + * dispatches each event. * <p> * This class is not intended to be subclassed. * </p> @@ -41,21 +44,21 @@ public class ModalContext { /** - * Indicated whether ModalContext is in debug mode; - * <code>false</code> by default. + * Indicated whether ModalContext is in debug mode; <code>false</code> by + * default. */ private static bool debug_ = true; /** - * The number of nested modal runs, or 0 if not inside a modal run. - * This is global state. + * The number of nested modal runs, or 0 if not inside a modal run. This is + * global state. */ private static int modalLevel = 0; /** - * Indicates whether operations should be run in a separate thread. - * Defaults to true. - * For internal debugging use, set to false to run operations in the calling thread. + * Indicates whether operations should be run in a separate thread. Defaults + * to true. For internal debugging use, set to false to run operations in + * the calling thread. */ private static bool runInSeparateThread = true; @@ -98,10 +101,13 @@ /** * Creates a new modal context. * - * @param operation the runnable to run - * @param monitor the progress monitor to use to display progress and receive - * requests for cancelation - * @param display the display to be used to read and dispatch events + * @param operation + * the runnable to run + * @param monitor + * the progress monitor to use to display progress and + * receive requests for cancelation + * @param display + * the display to be used to read and dispatch events */ private this(IRunnableWithProgress operation, IProgressMonitor monitor, Display display) { @@ -113,8 +119,8 @@ this.callingThread = Thread.getThis(); } - /* (non-Javadoc) - * Method declared on Thread. + /* + * (non-Javadoc) Method declared on Thread. */ public /+override+/ void run2() { try { @@ -129,15 +135,21 @@ } catch (RuntimeException e) { throwable = e; } catch (ThreadDeath e) { - // Make sure to propagate ThreadDeath, or threads will never fully terminate + // Make sure to propagate ThreadDeath, or threads will never + // fully terminate throw e; +/ } catch (/+Error+/Exception e) { throwable = e; } finally { - //notify the operation of change of thread of control + // notify the operation of change of thread of control if ( auto tl = cast(IThreadListener)runnable ) { - tl.threadChange(callingThread); + auto exception = + invokeThreadListener(tl, callingThread); + + //Forward it if we don't already have one + if(exception !is null && throwable is null) + throwable = exception; } // Make sure that all events in the asynchronous event queue @@ -163,7 +175,7 @@ public void block() { if (display is Display.getCurrent()) { while (continueEventDispatching) { - // Run the event loop. Handle any uncaught exceptions caused + // Run the event loop. Handle any uncaught exceptions caused // by UI events. try { if (!display.readAndDispatch()) { @@ -171,7 +183,8 @@ } } /+ - // ThreadDeath is a normal error when the thread is dying. We must + // ThreadDeath is a normal error when the thread is dying. + // We must // propagate it in order for it to properly terminate. catch (ThreadDeath e) { throw (e); @@ -179,8 +192,14 @@ +/ // For all other exceptions, log the problem. catch (Exception e) { - Stderr.formatln("Unhandled event loop exception during blocked modal context."); //$NON-NLS-1$ - ExceptionPrintStackTrace(e); + Policy + .getLog() + .log( + new Status( + IStatus.ERROR, + Policy.JFACE, + "Unhandled event loop exception during blocked modal context.",//$NON-NLS-1$ + e)); } } } else { @@ -194,13 +213,15 @@ } /** - * Returns whether the first progress monitor is the same as, or - * a wrapper around, the second progress monitor. - * - * @param monitor1 the first progress monitor - * @param monitor2 the second progress monitor - * @return <code>true</code> if the first is the same as, or - * a wrapper around, the second + * Returns whether the first progress monitor is the same as, or a wrapper + * around, the second progress monitor. + * + * @param monitor1 + * the first progress monitor + * @param monitor2 + * the second progress monitor + * @return <code>true</code> if the first is the same as, or a wrapper + * around, the second * @see ProgressMonitorWrapper */ public static bool canProgressMonitorBeUsed(IProgressMonitor monitor1, @@ -223,19 +244,23 @@ * Checks with the given progress monitor and throws * <code>InterruptedException</code> if it has been canceled. * <p> - * Code in a long-running operation should call this method - * regularly so that a request to cancel will be honored. + * Code in a long-running operation should call this method regularly so + * that a request to cancel will be honored. * </p> * <p> * Convenience for: + * * <pre> * if (monitor.isCanceled()) - * throw new InterruptedException(); + * throw new InterruptedException(); * </pre> + * * </p> - * - * @param monitor the progress monitor - * @exception InterruptedException if cancelling the operation has been requested + * + * @param monitor + * the progress monitor + * @exception InterruptedException + * if cancelling the operation has been requested * @see IProgressMonitor#isCanceled() */ public static void checkCanceled(IProgressMonitor monitor) { @@ -245,7 +270,8 @@ } /** - * Returns the currently active modal context thread, or null if no modal context is active. + * Returns the currently active modal context thread, or null if no modal + * context is active. */ private static ModalContextThread getCurrentModalContextThread() { Thread t = Thread.getThis(); @@ -259,13 +285,13 @@ * Returns the modal nesting level. * <p> * The modal nesting level increases by one each time the - * <code>ModalContext.run</code> method is called within the - * dynamic scope of another call to <code>ModalContext.run</code>. + * <code>ModalContext.run</code> method is called within the dynamic scope + * of another call to <code>ModalContext.run</code>. * </p> - * - * @return the modal nesting level, or <code>0</code> if - * this method is called outside the dynamic scope of any - * invocation of <code>ModalContext.run</code> + * + * @return the modal nesting level, or <code>0</code> if this method is + * called outside the dynamic scope of any invocation of + * <code>ModalContext.run</code> */ public static int getModalLevel() { return modalLevel; @@ -274,41 +300,54 @@ /** * Returns whether the given thread is running a modal context. * - * @param thread The thread to be checked - * @return <code>true</code> if the given thread is running a modal context, <code>false</code> if not + * @param thread + * The thread to be checked + * @return <code>true</code> if the given thread is running a modal + * context, <code>false</code> if not */ public static bool isModalContextThread(Thread thread) { return (cast(ModalContextThread)thread) !is null; } /** - * Runs the given runnable in a modal context, passing it a progress monitor. + * Runs the given runnable in a modal context, passing it a progress + * monitor. * <p> - * The modal nesting level is increased by one from the perspective - * of the given runnable. + * The modal nesting level is increased by one from the perspective of the + * given runnable. * </p> - *<p> + * <p> * If the supplied operation implements <code>IThreadListener</code>, it * will be notified of any thread changes required to execute the operation. - * Specifically, the operation will be notified of the thread that will call its - * <code>run</code> method before it is called, and will be notified of the - * change of control back to the thread calling this method when the operation - * completes. These thread change notifications give the operation an - * opportunity to transfer any thread-local state to the execution thread before - * control is transferred to the new thread. - *</p> - * @param operation the runnable to run - * @param fork <code>true</code> if the runnable should run in a separate thread, - * and <code>false</code> if in the same thread - * @param monitor the progress monitor to use to display progress and receive - * requests for cancelation - * @param display the display to be used to read and dispatch events - * @exception InvocationTargetException if the run method must propagate a checked exception, - * it should wrap it inside an <code>InvocationTargetException</code>; runtime exceptions and errors are automatically - * wrapped in an <code>InvocationTargetException</code> by this method - * @exception InterruptedException if the operation detects a request to cancel, - * using <code>IProgressMonitor.isCanceled()</code>, it should exit by throwing - * <code>InterruptedException</code>; this method propagates the exception + * Specifically, the operation will be notified of the thread that will call + * its <code>run</code> method before it is called, and will be notified + * of the change of control back to the thread calling this method when the + * operation completes. These thread change notifications give the operation + * an opportunity to transfer any thread-local state to the execution thread + * before control is transferred to the new thread. + * </p> + * + * @param operation + * the runnable to run + * @param fork + * <code>true</code> if the runnable should run in a separate + * thread, and <code>false</code> if in the same thread + * @param monitor + * the progress monitor to use to display progress and receive + * requests for cancelation + * @param display + * the display to be used to read and dispatch events + * @exception InvocationTargetException + * if the run method must propagate a checked exception, it + * should wrap it inside an + * <code>InvocationTargetException</code>; runtime + * exceptions and errors are automatically wrapped in an + * <code>InvocationTargetException</code> by this method + * @exception InterruptedException + * if the operation detects a request to cancel, using + * <code>IProgressMonitor.isCanceled()</code>, it should + * exit by throwing <code>InterruptedException</code>; + * this method propagates the exception */ public static void run(IRunnableWithProgress operation, bool fork, IProgressMonitor monitor, Display display) { @@ -330,11 +369,19 @@ runInCurrentThread(operation, monitor); } else { t = new ModalContextThread(operation, monitor, display); + Exception listenerException = null; if ( auto tl = cast(IThreadListener)operation ) { - tl.threadChange(t); + listenerException = invokeThreadListener(tl, t); } - t.start(); - t.block(); + + if(listenerException is null){ + t.start(); + t.block(); + } + else { + if(t.throwable is null) + t.throwable = listenerException; + } Exception throwable = t.throwable; if (throwable !is null) { if (debug_ @@ -343,8 +390,10 @@ Stderr.formatln("Exception in modal context operation:"); //$NON-NLS-1$ ExceptionPrintStackTrace(throwable); Stderr.formatln("Called from:"); //$NON-NLS-1$ - // Don't create the InvocationTargetException on the throwable, - // otherwise it will print its stack trace (from the other thread). + // Don't create the InvocationTargetException on the + // throwable, + // otherwise it will print its stack trace (from the + // other thread). ExceptionPrintStackTrace( new InvocationTargetException(null)); } if (cast(InvocationTargetException)throwable ) { @@ -352,7 +401,9 @@ } else if (cast(InterruptedException)throwable ) { throw cast(InterruptedException) throwable; } else if (cast(OperationCanceledException)throwable ) { - // See 1GAN3L5: ITPUI:WIN2000 - ModalContext converts OperationCancelException into InvocationTargetException + // See 1GAN3L5: ITPUI:WIN2000 - ModalContext + // converts OperationCancelException into + // InvocationTargetException throw new InterruptedException(throwable .msg); } else { @@ -367,8 +418,32 @@ } /** - * Run a runnable. Convert all thrown exceptions to - * either InterruptedException or InvocationTargetException + * Invoke the ThreadListener if there are any errors or RuntimeExceptions + * return them. + * + * @param listener + * @param switchingThread + * the {@link Thread} being switched to + */ + static Throwable invokeThreadListener(IThreadListener listener, + Thread switchingThread) { + try { + listener.threadChange(switchingThread); + } catch (ThreadDeath e) { + // Make sure to propagate ThreadDeath, or threads will never + // fully terminate + throw e; + } catch (Error e) { + return e; + }catch (RuntimeException e) { + return e; + } + return null; + } + + /** + * Run a runnable. Convert all thrown exceptions to either + * InterruptedException or InvocationTargetException */ private static void runInCurrentThread(IRunnableWithProgress runnable, IProgressMonitor progressMonitor) { @@ -384,7 +459,8 @@ throw new InterruptedException(); /+ } catch (ThreadDeath e) { - // Make sure to propagate ThreadDeath, or threads will never fully terminate + // Make sure to propagate ThreadDeath, or threads will never fully + // terminate throw e; +/ } catch (RuntimeException e) { @@ -396,21 +472,26 @@ /** * Sets whether ModalContext is running in debug mode. - * - * @param debugMode <code>true</code> for debug mode, - * and <code>false</code> for normal mode (the default) + * + * @param debugMode + * <code>true</code> for debug mode, and <code>false</code> + * for normal mode (the default) */ public static void setDebugMode(bool debugMode) { debug_ = debugMode; } /** - * Sets whether ModalContext may process events (by calling <code>Display.readAndDispatch()</code>) - * while running operations. By default, ModalContext will process events while running operations. - * Use this method to disallow event processing temporarily. - * @param allowReadAndDispatch <code>true</code> (the default) if events may be processed while - * running an operation, <code>false</code> if Display.readAndDispatch() should not be called - * from ModalContext. + * Sets whether ModalContext may process events (by calling + * <code>Display.readAndDispatch()</code>) while running operations. By + * default, ModalContext will process events while running operations. Use + * this method to disallow event processing temporarily. + * + * @param allowReadAndDispatch + * <code>true</code> (the default) if events may be processed + * while running an operation, <code>false</code> if + * Display.readAndDispatch() should not be called from + * ModalContext. * @since 3.2 */ public static void setAllowReadAndDispatch(bool allowReadAndDispatch) {