package org.jcon.ui;

import java.awt.Container;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.Window;
import java.util.Enumeration;
import java.util.Hashtable;

/**
* This class changes the cursor for a component and all
* its contained components. It is designed to allow easily
* changing a window from normal to wait to normal cursor,
* for all the window's components. However it may be used 
* for other uses as well.
* <p>
* Typically you will use beginWaitCursor(...), do the
* task, and then call endWaitCursor().
*
* @author Jack Harich
*/
public class CursorChanger {

//---------- Private Fields ------------------------------
// Internal
private Component component;

// Key = Component, Object = original Cursor to restore
private Hashtable components = new Hashtable();

//---------- Public Methods ------------------------------
/**
* A convenience method that calls setComponentCursor()
* with a wait cursor.
*/
public void beginWaitCursor(Component component) {
    this.component = component;
    setComponentCursor(component, new Cursor(Cursor.WAIT_CURSOR));
    
    // Reveal modified cursor 
    // FAILS TO WORK immediately, about a 1 second delay
    Toolkit.getDefaultToolkit().sync();
}
/**
* An appropriately named method that is the same as
* restoreComponentCursor().
* Call this after beginWaitCursor().
*/
public void endWaitCursor() {
    restoreComponentCursor();
    if (component != null) component.setEnabled(true);
}
/**
* Sets the cursor for the component and all its children,
* if any. 
*/
public void setComponentCursor(Component component, Cursor cursor) {
    components.clear(); 
    setTheCursor(component, cursor);
}
/**
* Restores the previously set component's cursor, including
* its children. This must be called after setComponentCursor()
* to return to the normal cursor state.
*/
public void restoreComponentCursor() {
    Enumeration enum = components.keys();
    while (enum.hasMoreElements()) {
        Component comp = (Component)enum.nextElement();
        Cursor oldCursor = (Cursor)components.get(comp);
        comp.setCursor(oldCursor);
    }
}
//---------- Private Methods -----------------------------
// RECURSIVE
private void setTheCursor(Component component, Cursor cursor) {
    // First the top component
    components.put(component, component.getCursor());
    component.setCursor(cursor);
    
    // Then all its children
    if (component instanceof Container) {
        Component[] comps = ((Container)component).getComponents();
        for (int i = 0; i < comps.length; i++) {
            Component comp2 = (Component)comps[i];
            if (comp2 instanceof Container) {
                // RECURSE
                setTheCursor(comp2, cursor);
            } else {
                components.put(comp2, comp2.getCursor());
                comp2.setCursor(cursor);
            }
        }
    }    
}
//--- Std
private static void print(String text) {
    System.out.println("CursorChanger" + text);
}

} // End class

    /*
    // Sleep to let sync take effect immediately NO EFFECT
    try {
        Thread.currentThread().sleep(200);
    } catch(InterruptedException ex) {
        print(".beginWaitCursor() - Interrupted"); // Should never happen
    }
    
    // THIS CAUSES THE CURSOR TO NEVER CHANGE
    //component.setEnabled(false);
    
    // Wiggle window to fix awt bug, otherwise user must
    // move cursor to reveal wait cursor.
    // THIS FAILS TO REPAINT UNTIL LATER
    if (component instanceof Window) {
        Point currentLocation = component.getLocation();
        Point wiggleLocation = new Point(
            currentLocation.x + 1, currentLocation.y + 1);
            
        component.setLocation(wiggleLocation);
        component.setLocation(currentLocation);
    }
    component.repaint(0);
    
    */
    
