001: /*
002: * Beryl - A web platform based on XML, XSLT and Java
003: * This file is part of the Beryl XML GUI
004: *
005: * Copyright (C) 2004 Wenzel Jakob <wazlaf@tigris.org>
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or (at your option) any later version.
011:
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-3107 USA
020: */
021:
022: package org.beryl.gui;
023:
024: import java.awt.AWTEvent;
025: import java.awt.Component;
026: import java.awt.Cursor;
027: import java.awt.EventQueue;
028: import java.awt.MenuComponent;
029: import java.awt.MenuContainer;
030: import java.util.ArrayList;
031:
032: import javax.swing.SwingUtilities;
033:
034: /**
035: * Change the cursor to an hour glass when necessary
036: *
037: * Usage:
038: * EventQueue waitQueue = new WaitCursorEventQueue(500);
039: * Toolkit.getDefaultToolkit().getSystemEventQueue().push(waitQueue);
040: *
041: * Part of the trick to this tip is choosing the duration after which the hourglass should appear.
042: * The delay should be long enough that the hourglass will not appear for most events processed
043: * within the UI thread, but it should be short enough so that the user perceives near-immediate
044: * feedback when a more intensive task begins processing. In moderate usability testing,
045: * a delay in the range of about 500 milliseconds appears to work quite well.
046: *
047: * Taken from JavaWorld
048: * Race condition fixed by Wenzel Jakob
049: */
050: public class WaitCursorEventQueue extends EventQueue {
051: private int delay = 0;
052: private ArrayList waitTimers = null;
053:
054: public WaitCursorEventQueue(int delay) {
055: this .delay = delay;
056: waitTimers = new ArrayList();
057: addWaitTimer();
058: }
059:
060: private WaitCursorTimer addWaitTimer() {
061: WaitCursorTimer waitTimer = new WaitCursorTimer();
062: waitTimer.setDaemon(true);
063: waitTimer.start();
064: waitTimers.add(waitTimer);
065: return waitTimer;
066: }
067:
068: private WaitCursorTimer getWaitTimer() {
069: synchronized (waitTimers) {
070: for (int i = 0; i < waitTimers.size(); i++) {
071: WaitCursorTimer timer = (WaitCursorTimer) waitTimers
072: .get(i);
073: if (!timer.isUsed())
074: return timer;
075: }
076: return addWaitTimer();
077: }
078: }
079:
080: protected void dispatchEvent(AWTEvent event) {
081: WaitCursorTimer timer = getWaitTimer();
082: timer.startTimer(event.getSource());
083: try {
084: super .dispatchEvent(event);
085: } finally {
086: timer.stopTimer();
087: }
088: }
089:
090: private class WaitCursorTimer extends Thread {
091: private Object source = null;
092: private Component parent = null;
093:
094: synchronized void startTimer(Object source) {
095: this .source = source;
096: notify();
097: }
098:
099: synchronized boolean isUsed() {
100: return source != null;
101: }
102:
103: synchronized void stopTimer() {
104: if (parent == null)
105: interrupt();
106: else {
107: parent.setCursor(null);
108: parent = null;
109: }
110: source = null;
111: }
112:
113: public synchronized void run() {
114: while (true) {
115: try {
116: /* wait for notification from startTimer() */
117: wait();
118:
119: /* wait for event processing to reach the threshold,
120: * or interruption from stopTimer() */
121: wait(delay);
122:
123: if (source instanceof Component)
124: parent = SwingUtilities
125: .getRoot((Component) source);
126: else if (source instanceof MenuComponent) {
127: MenuContainer mParent = ((MenuComponent) source)
128: .getParent();
129: if (mParent instanceof Component)
130: parent = SwingUtilities
131: .getRoot((Component) mParent);
132: }
133:
134: if (parent != null && parent.isShowing())
135: parent
136: .setCursor(Cursor
137: .getPredefinedCursor(Cursor.WAIT_CURSOR));
138: } catch (InterruptedException ie) {
139: /* Ignore */
140: }
141: }
142: }
143: }
144: }
|