/* BEGIN_HEADER                                              Java TreeView
 *
 * $Author: alokito $
 * $RCSfile: ContainerFocusTracker.java,v $
 * $Revision: 1.5 $
 * $Date: 2004-12-21 03:28:13 $
 * $Name:  $
 *
 * This file is part of Java TreeView
 * Copyright (C) 2001-2014 Alok Saldanha, All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * END_HEADER 
 */
package edu.stanford.genetics.treeview;


import java.awt.*;
import java.awt.event.*;

/**
 * Note: I, Alok, didn't write this class.
 *
 * Class for Containers which won't take the keyboard focus.
 * Because of what appears to be a bug in Java 1.1, when you move the
 * focus on to a Frame, or other Container, it keeps the focus, rather
 * than handing it on to an appropriate tabstop inside it.
 * This class collects all focus events for the Container and its contents, 
 * and will correct the problem. It also monitors the Container, and keeps
 * track if the focussed component is removed from the container.
 * To use, just create a tracker, passing it the Container you want to
 * deal with. 
 */
public class ContainerFocusTracker implements FocusListener, ContainerListener {
	static RCSVersion version = new RCSVersion("$Id: ContainerFocusTracker.java,v 1.5 2004-12-21 03:28:13 alokito Exp $");
	//****************************
	// Constructors
	//****************************
	public ContainerFocusTracker(Container c) {
		if(debug)
			System.out.println("FocusTracker(" + c.getName() + ")");
		container = c;
		addComponent(c);
	}

	//****************************
	// Event handling
	//****************************

	public void componentAdded(ContainerEvent e) {
		if(debug)
			System.out.println(container.getName() + " - Adding...");
		addComponent(e.getChild());
	}

	public void componentRemoved(ContainerEvent e) {
		if(debug)
			System.out.println(container.getName() + " - Removing...");
		removeComponent(e.getChild());
	}

	public void focusGained(FocusEvent e) {
		Component c = e.getComponent();

		if(c == container) {
			if(debug)
				System.out.println("Container " + container.getName() + " got focus");
			if(focus != null) {
				if(debug)
					System.out.println("Returning focus to " + focus.getName());
				focus.requestFocus();
			} else {
				switchFocus(container);
			}
		} else if(c.isVisible() && c.isEnabled() && c.isFocusable()) {
			if(debug)
				System.out.println(container.getName() + " - Tracking focus to " + e.getComponent().getName());
			focus = c;
		}
	}

	public void focusLost(FocusEvent e) {
	}

	//****************************
	// Package and private methods
	//****************************

	private boolean switchFocus(Container container) {
		synchronized (container.getTreeLock()) {
			for (int i = 0; i < container.getComponentCount(); i++) {
				Component c = container.getComponent(i);

				if(c == null)
					break;
				if (c.isVisible() && c.isEnabled() 
						&& c.isFocusable()) {
					if(debug)
						System.out.println(this.container.getName() + " - Giving focus to " + c.getName());
					c.requestFocus();
					return true;
				} else if(c instanceof Container) {
					if(switchFocus((Container)c))
						return true;
				} else if(debug) {
					System.out.println("Not giving focus to " + c.getName()
						+ " vis:" + c.isVisible()
						+ " ena:" + c.isEnabled()
						+ " tab:" + c.isFocusable());
				}
			}
		}
		return false;
	}

	private void addComponent(Component c) {
		if(debug)
			System.out.println(" " + c.getName());
		c.addFocusListener(this);
		if(c instanceof Container)
			addContainer((Container)c);
	}

	private void addContainer(Container container) {
		container.addContainerListener(this);
		synchronized (container.getTreeLock()) {
			for (int i = 0; i < container.getComponentCount(); i++) {
				Component c = container.getComponent(i);
				addComponent(c);
			}
		}
	}

	private void removeComponent(Component c) {
		if(debug)
			System.out.println(" " + c.getName());
		if(c == focus)
			focus = null;
		c.removeFocusListener(this);
		if(c instanceof Container)
			removeContainer((Container)c);
	}

	private void removeContainer(Container container) {
		container.removeContainerListener(this);
		synchronized (container.getTreeLock()) {
			for (int i = 0; i < container.getComponentCount(); i++) {
				Component c = container.getComponent(i);
				removeComponent(c);
			}
		}
	}

	//****************************
	// Variables
	//****************************

	Container container;
	Component focus;
	final static boolean debug = false;
}

