package com.plectix.simulator.gui.lib; import java.awt.AWTEvent; import java.awt.Component; import java.awt.Cursor; import java.awt.EventQueue; import java.awt.MenuComponent; import java.awt.MenuContainer; import java.awt.event.InvocationEvent; import java.awt.event.MouseEvent; import java.awt.event.WindowEvent; import java.util.Timer; import java.util.TimerTask; import javax.swing.SwingUtilities; /** * Event queue implementation that uses a timer thread to show a watch cursor if the * processing of any event takes longer than the specified time. To use this class, * call Toolkit.getDefaultToolkit().getSystemEventQueue().push(new WaitingEventQueue()); * * Based on code from http://www.javaworld.com/javaworld/javatips/jw-javatip87.html * * @author ecemis */ class WaitingEventQueue extends EventQueue { private static final String TIMEOUT_PROPERTY_STRING = "timeout.waitcursor.millis"; private Timer timer = new Timer(); private int delay; private Component rootComponent; private Object lock = new Object(); public WaitingEventQueue(Component rootComponent) { this.rootComponent = rootComponent; this.delay = UIProperties.getInt(TIMEOUT_PROPERTY_STRING); } public void disable() { timer.cancel(); timer = null; } @Override protected void dispatchEvent(AWTEvent event) { // Skip some event types that may cause re-entrancy problems, or that we // just don't care about String classname = event.getClass().getName(); if (timer == null || // we've been disabled classname.equals("java.awt.SequencedEvent") || classname.equals("java.awt.SentEvent") || event instanceof WindowEvent || event instanceof InvocationEvent || // These seem to be generated by repaint() among other things (event instanceof MouseEvent && event.getID() == MouseEvent.MOUSE_MOVED)) { super.dispatchEvent(event); return; } final AWTEvent timedEvent = event; TimerTask timerTask = new TimerTask() { @Override public void run() { Component c = findRootComponent(rootComponent, timedEvent); // log.debug("Showing wait cursor on " + c + " for " + timedEvent); c.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); } }; synchronized (lock) { timer.schedule(timerTask, delay); try { super.dispatchEvent(event); } finally { timerTask.cancel(); Component c = findRootComponent(rootComponent, timedEvent); // log.debug("Clearing wait cursor on " + c + " for " + timedEvent); if (c != null) c.setCursor(null); } } } /** * This logic seems to be necessary to use the right root component for * when modal dialogs are being displayed. If we can get a root component * from the event (either the dialog or the main window), use it. For some * events (for whatever reason) we can't find a valid root (or the event's * root is no longer visible), so use the global root (the main window). */ private Component findRootComponent(Component rootComponent, AWTEvent event) { if (event == null) return rootComponent; Object eventSource = event.getSource(); if (eventSource instanceof Component) { Component c = SwingUtilities.getRoot((Component) eventSource); if (c != null && c.isVisible()) return c; else return rootComponent; } if (eventSource instanceof MenuComponent) { MenuContainer menuParent = ((MenuComponent) eventSource).getParent(); if (menuParent instanceof Component) { Component c = SwingUtilities.getRoot((Component) menuParent); if (c != null && c.isVisible()) return c; else return rootComponent; } } return null; } }