org.devzendo.commonapp.gui.DefaultCursorManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of CommonGui Show documentation
Show all versions of CommonGui Show documentation
Common application GUI code
(Apache License v2) 2008-2013 Matt Gumbley, DevZendo.org
The newest version!
/**
* Copyright (C) 2008-2010 Matt Gumbley, DevZendo.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.devzendo.commonapp.gui;
import java.awt.Component;
import java.awt.Cursor;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import javax.swing.JFrame;
import javax.swing.JRootPane;
import org.apache.log4j.Logger;
import org.devzendo.commoncode.string.StringUtils;
/**
* Handlings make benefit great user interaction of hourglass/normal cursor.
* @author borat
*
* Allows applications to easily set/remove the hourglass cursor, and detect
* when an app is 'stuck' with the hourglass.
*/
public final class DefaultCursorManager implements CursorManager {
private static final Logger LOGGER = Logger.getLogger(DefaultCursorManager.class);
private static final Cursor HOURGLASS = new Cursor(Cursor.WAIT_CURSOR);
private static final Cursor NORMAL = new Cursor(Cursor.DEFAULT_CURSOR);
private JFrame mMainFrame = null;
private final AtomicBoolean mHourglassCursorActive = new AtomicBoolean(false);
private final AtomicLong mHourglassSetTime = new AtomicLong(0);
private Thread mStuckDetectorThread;
private Object mLock;
private List mHourglassCallers;
private boolean mAlive = true;
/**
* Instantiate the CursorManager, which won't be able to effect change
* of the cursor until a main component has been set.
*/
public DefaultCursorManager() {
startStuckDetector();
}
private void startStuckDetector() {
mLock = new Object();
mHourglassCallers = new ArrayList();
mStuckDetectorThread = new Thread(new StuckHourGlassDetector());
mStuckDetectorThread.setDaemon(true);
mStuckDetectorThread.setName("Stuck Hourglass Detector");
mStuckDetectorThread.start();
}
/**
* {@inheritDoc}
*/
public JFrame getMainFrame() {
return mMainFrame;
}
/**
* {@inheritDoc}
*/
public void setMainFrame(final JFrame mainFrame) {
mMainFrame = mainFrame;
LOGGER.debug("CursorManager's main frame has been set to " + mainFrame);
}
/**
* {@inheritDoc}
*/
public void shutdown() {
mAlive = false;
mStuckDetectorThread.interrupt();
}
/**
* {@inheritDoc}
*/
public void hourglass(final String caller) {
LOGGER.debug("Setting hourglass cursor");
if (mMainFrame != null) {
mMainFrame.setCursor(HOURGLASS);
mHourglassCallers.add(caller);
mHourglassCursorActive.set(true);
mHourglassSetTime.set(System.currentTimeMillis());
synchronized (mLock) {
mLock.notify();
}
}
final Component glassPane = getGlassPane();
if (glassPane != null) {
glassPane.setEnabled(false);
glassPane.setVisible(true);
}
}
/**
* {@inheritDoc}
*/
public void hourglassViaEventThread(final String caller) {
final Runnable r = new Runnable() {
public void run() {
hourglass(caller);
}
};
GUIUtils.runOnEventThread(r);
}
/**
* {@inheritDoc}
*/
public void normal(final String caller) {
LOGGER.debug("Setting normal cursor");
if (mMainFrame != null) {
mMainFrame.setCursor(NORMAL);
mHourglassCursorActive.set(false);
mHourglassSetTime.set(0);
if (mHourglassCallers.size() > 0) {
final int lastIndex = mHourglassCallers.size() - 1;
if (mHourglassCallers.get(lastIndex).equals(caller)) {
mHourglassCallers.remove(lastIndex);
}
}
synchronized (mLock) {
mLock.notify();
}
}
final Component glassPane = getGlassPane();
if (glassPane != null) {
glassPane.setVisible(false);
glassPane.setEnabled(true);
glassPane.setCursor(NORMAL);
}
}
/**
* {@inheritDoc}
*/
public void normalViaEventThread(final String caller) {
final Runnable r = new Runnable() {
public void run() {
normal(caller);
}
};
GUIUtils.runOnEventThread(r);
}
private Component getGlassPane() {
if (mMainFrame == null) {
LOGGER.warn("Frame is null");
return null;
}
final JRootPane rootPane = mMainFrame.getRootPane();
if (rootPane == null) {
LOGGER.warn("JRootPane is null");
return null;
}
final Component glassPane = rootPane.getGlassPane();
if (glassPane == null) {
LOGGER.warn("GlassPane is null");
}
return glassPane;
}
/**
* If the hourglass is present for more than 30s, it's most likely a
* problem.
* @author matt
*
*/
private class StuckHourGlassDetector implements Runnable {
public void run() {
while (mAlive && Thread.currentThread().isAlive()) {
if (mHourglassCursorActive.get()) {
// hourglass
try {
LOGGER.debug("waiting a while for hourglass to get stuck");
synchronized (mLock) {
mLock.wait(30000);
}
if (mHourglassCursorActive.get()) {
LOGGER.debug("in hourglass state");
if (mHourglassSetTime.get() != 0) {
final long stuckFor = System.currentTimeMillis() - mHourglassSetTime.get();
if (stuckFor > 28000) {
LOGGER.warn("The hourglass cursor appears to have been stuck for " + StringUtils.translateTimeDuration(stuckFor));
for (final String caller : mHourglassCallers) {
LOGGER.warn(" " + caller);
}
} else {
LOGGER.debug("Only been in hourglass for " + StringUtils.translateTimeDuration(stuckFor));
}
} else {
LOGGER.debug("hourglass set time if zero");
}
} else {
LOGGER.debug("in normal state");
}
} catch (final InterruptedException e) {
LOGGER.debug("interrupted in hourglass state");
// nothing
}
} else {
// normal
try {
LOGGER.debug("waiting for hourglass...");
synchronized (mLock) {
mLock.wait();
}
LOGGER.debug("out of wait for hourglass");
} catch (final InterruptedException e) {
LOGGER.debug("interrupted in normal state, perhaps in hourglass now?");
// nothing
}
}
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy