/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is NetBeans. The Initial Developer of the Original
* Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun
* Microsystems, Inc. All Rights Reserved.
*/
package org.openide.util;
import java.awt.AWTEvent;
import java.awt.Component;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import javax.swing.SwingUtilities;
/** Performance helper class, allows to run post-init task for given component.
* Can also handle cancel logic if contained in AsyncGUIJob.
* Class is designed for one time use, can't be used to perform async init
* more then once.
* Restrictions: Note that for correct functionality given component must not
* be showing at construction time of this class, however shouldn't stay hidden
* forever as memory leak may occur.
*
* @author Dafe Simonek
*/
final class AsyncInitSupport implements AWTEventListener,
HierarchyListener,
Runnable {
/** lock for access to wasCancelled flag */
private static final Object CANCELLED_LOCK = new Object();
/** task in which post init code from AsyncJob is executed */
private Task initTask;
/** true after cancel request came, false otherwise */
private boolean wasCancelled;
/** Component requesting asynchronous initialization */
private Component comp4Init;
/** Job that performs async init task */
private AsyncGUIJob initJob;
/** Creates a new instance of AsyncInitComponent
* @param comp4Init Component to be initialized. Mustn't be showing at this
* time. IllegalStateException is thrown if component is already showing.
* @param initJob Instance of initialization job.
*/
public AsyncInitSupport(Component comp4Init, AsyncGUIJob initJob) {
this.comp4Init = comp4Init;
this.initJob = initJob;
if (comp4Init.isShowing()) {
throw new IllegalStateException(
"Component already shown, can't be inited: " + comp4Init
);
}
Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.PAINT_EVENT_MASK);
comp4Init.addHierarchyListener(this);
}
/** Invokes execution of init code in non-ED thread.
* @param evt ignored
*/
public void eventDispatched (AWTEvent event) {
if ((event.getSource() instanceof Component) &&
SwingUtilities.isDescendingFrom(comp4Init, (Component)(event.getSource()))) {
Toolkit.getDefaultToolkit().removeAWTEventListener(this);
initTask = RequestProcessor.getDefault().post(this);
}
}
/** Stops listening to asociated component it isn't showing anymore,
* calls cancel if desirable.
* @param evt hierarchy event
*/
public void hierarchyChanged(HierarchyEvent evt) {
if (((evt.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0) &&
!comp4Init.isShowing()) {
comp4Init.removeHierarchyListener(this);
cancel();
}
}
/** Body of task executed in RequestProcessor. Runs AsyncGUIJob's worker
* method and after its completion posts AsyncJob's UI update method
* to AWT thread.
*/
public void run() {
if (!SwingUtilities.isEventDispatchThread()) {
// first pass, executed in some of RP threads
initJob.construct();
comp4Init.removeHierarchyListener(this);
// continue to invoke finished method only if hasn't been cancelled
boolean localCancel;
synchronized (CANCELLED_LOCK) {
localCancel = wasCancelled;
}
if (!localCancel) {
SwingUtilities.invokeLater(this);
}
} else {
// second pass, executed in event dispatch thread
initJob.finished();
}
}
/** Delegates valid cancel requests to asociated AsyncGUIJob, in the case
* job supports cancelling. */
private void cancel () {
if ((initTask != null) && !initTask.isFinished() &&
(initJob instanceof Cancellable)) {
synchronized (CANCELLED_LOCK) {
wasCancelled = true;
}
((Cancellable)initJob).cancel();
}
}
}