gt: 				Task task= taskOnReset(p);
context: /*******************************************************************************
   * Copyright (c) 2000, 2008 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
   * http://www.eclipse.org/legal/epl-v10.html
   *
   * Contributors:
   *     IBM Corporation - initial API and implementation
   *******************************************************************************/
  package org.eclipse.jface.text.contentassist;
  
  import org.eclipse.swt.events.SelectionEvent;
  import org.eclipse.swt.events.SelectionListener;
  import org.eclipse.swt.graphics.Point;
  import org.eclipse.swt.graphics.Rectangle;
  import org.eclipse.swt.widgets.Control;
  import org.eclipse.swt.widgets.Display;
  import org.eclipse.swt.widgets.Shell;
  import org.eclipse.swt.widgets.Table;
  import org.eclipse.swt.widgets.TableItem;
  
  import org.eclipse.core.runtime.Assert;
  import org.eclipse.core.runtime.IProgressMonitor;
  import org.eclipse.core.runtime.IStatus;
  import org.eclipse.core.runtime.Status;
  import org.eclipse.core.runtime.jobs.Job;
  
  import org.eclipse.jface.internal.text.InformationControlReplacer;
  
  import org.eclipse.jface.text.AbstractInformationControlManager;
  import org.eclipse.jface.text.AbstractReusableInformationControlCreator;
  import org.eclipse.jface.text.DefaultInformationControl;
  import org.eclipse.jface.text.IInformationControl;
  import org.eclipse.jface.text.IInformationControlCreator;
  import org.eclipse.jface.text.IInformationControlExtension3;
  
  
  /**
   * Displays the additional information available for a completion proposal.
   *
   * @since 2.0
   */
  class AdditionalInfoController extends AbstractInformationControlManager {
  
  	/**
  	 * A timer thread.
  	 *
  	 * @since 3.2
  	 */
  	private static abstract class Timer {
  		private static final int DELAY_UNTIL_JOB_IS_SCHEDULED= 50;
  
  		/**
  		 * A <code>Task</code> is {@link Task#run() run} when {@link #delay()} milliseconds have
  		 * elapsed after it was scheduled without a {@link #reset(ICompletionProposal) reset}
  		 * to occur.
  		 */
  		private abstract class Task implements Runnable {
  			/**
  			 * @return the delay in milliseconds before this task should be run
  			 */
  	        public abstract long delay();
  	        /**
  	         * Runs this task.
  	         */
  	        public abstract void run();
  	        /**
  	         * @return the task to be scheduled after this task has been run
  	         */
  	        public abstract Task nextTask();
  		}
  
  		/**
  		 * IDLE: the initial task, and active whenever the info has been shown. It cannot be run,
  		 * but specifies an infinite delay.
  		 */
  		private final Task IDLE= new Task() {
  			public void run() {
  				Assert.isTrue(false);
  			}
  
  			public Task nextTask() {
  				Assert.isTrue(false);
  			    return null;
  			}
  
  			public long delay() {
  				return Long.MAX_VALUE;
  			}
  
  			public String toString() {
  				return "IDLE"; //$NON-NLS-1$
  			}
  		};
  		/**
  		 * FIRST_WAIT: Schedules a platform {@link Job} to fetch additional info from an {@link ICompletionProposalExtension5}.
  		 */
  		private final Task FIRST_WAIT= new Task() {
  			public void run() {
  				final ICompletionProposalExtension5 proposal= getCurrentProposalEx();
  				Job job= new Job(JFaceTextMessages.getString("AdditionalInfoController.job_name")) { //$NON-NLS-1$
  					protected IStatus run(IProgressMonitor monitor) {
  						Object info;
                          try {
  	                        info= proposal.getAdditionalProposalInfo(monitor);
                          } catch (RuntimeException x) {
                          	/*
  							 * XXX: This is the safest fix at this point so close to end of 3.2.
  							 *		Will be revisited when fixing https://bugs.eclipse.org/bugs/show_bug.cgi?id=101033
                          	 */
                          	return new Status(IStatus.WARNING, "org.eclipse.jface.text", IStatus.OK, "", x); //$NON-NLS-1$ //$NON-NLS-2$
                          }
  						setInfo((ICompletionProposal) proposal, info);
  					    return new Status(IStatus.OK, "org.eclipse.jface.text", IStatus.OK, "", null); //$NON-NLS-1$ //$NON-NLS-2$
  					}
  				};
  				job.schedule();
  			}
  
  			public Task nextTask() {
  				return SECOND_WAIT;
  			}
  
  			public long delay() {
  				return DELAY_UNTIL_JOB_IS_SCHEDULED;
  			}
  
  			public String toString() {
  				return "FIRST_WAIT"; //$NON-NLS-1$
  			}
  		};
  		/**
  		 * SECOND_WAIT: Allows display of additional info obtained from an
  		 * {@link ICompletionProposalExtension5}.
  		 */
  		private final Task SECOND_WAIT= new Task() {
  			public void run() {
  				// show the info
  				allowShowing();
  			}
  
  			public Task nextTask() {
  				return IDLE;
  			}
  
  			public long delay() {
  				return fDelay - DELAY_UNTIL_JOB_IS_SCHEDULED;
  			}
  
  			public String toString() {
  				return "SECOND_WAIT"; //$NON-NLS-1$
  			}
  		};
  		/**
  		 * LEGACY_WAIT: Posts a runnable into the display thread to fetch additional info from non-{@link ICompletionProposalExtension5}s.
  		 */
  		private final Task LEGACY_WAIT= new Task() {
  			public void run() {
  				final ICompletionProposal proposal= getCurrentProposal();
  				if (!fDisplay.isDisposed()) {
  					fDisplay.asyncExec(new Runnable() {
  						public void run() {
  							synchronized (Timer.this) {
  								if (proposal == getCurrentProposal()) {
  									Object info= proposal.getAdditionalProposalInfo();
  									showInformation(proposal, info);
  								}
  							}
  						}
  					});
  				}
  			}
  
  			public Task nextTask() {
  				return IDLE;
  			}
  
  			public long delay() {
  				return fDelay;
  			}
  
  			public String toString() {
  			    return "LEGACY_WAIT"; //$NON-NLS-1$
  			}
  		};
  		/**
  		 * EXIT: The task that triggers termination of the timer thread.
  		 */
  		private final Task EXIT= new Task() {
  			public long delay() {
  		        return 1;
  	        }
  
  			public Task nextTask() {
  				Assert.isTrue(false);
  		        return EXIT;
  	        }
  
  			public void run() {
  				Assert.isTrue(false);
  	        }
  
  			public String toString() {
  				return "EXIT"; //$NON-NLS-1$
  			}
  		};
  
  		/** The timer thread. */
  		private final Thread fThread;
  
  		/** The currently waiting / active task. */
  		private Task fTask;
  		/** The next wake up time. */
  		private long fNextWakeup;
  
  		private ICompletionProposal fCurrentProposal= null;
  		private Object fCurrentInfo= null;
  		private boolean fAllowShowing= false;
  
  		private final Display fDisplay;
  		private final int fDelay;
  
  		/**
  		 * Creates a new timer.
  		 *
  		 * @param display the display to use for display thread posting.
  		 * @param delay the delay until to show additional info
  		 */
  		public Timer(Display display, int delay) {
      		fDisplay= display;
  			fDelay= delay;
  			long current= System.currentTimeMillis();
      		schedule(IDLE, current);
  
      		fThread= new Thread(new Runnable() {
      			public void run() {
      				try {
  	                    loop();
                      } catch (InterruptedException x) {
                      }
      			}
      		}, JFaceTextMessages.getString("InfoPopup.info_delay_timer_name")); //$NON-NLS-1$
  			fThread.start();
  		}
  
  		/**
  		 * Terminates the timer thread.
  		 */
  		public synchronized final void terminate() {
  			schedule(EXIT, System.currentTimeMillis());
  			notifyAll();
  		}
  
  		/**
  		 * Resets the timer thread as the selection has changed to a new proposal.
  		 *
  		 * @param p the new proposal
  		 */
  		public final synchronized void reset(ICompletionProposal p) {
  			if (fCurrentProposal != p) {
  				fCurrentProposal= p;
  				fCurrentInfo= null;
  				fAllowShowing= false;
  
  				long oldWakeup= fNextWakeup;
  