/*
 * Java-Gnome Bindings Library
 *
 * Copyright 1998-2004 the Java-Gnome Team, all rights reserved.
 *
 * The Java-Gnome bindings library is free software distributed under
 * the terms of the GNU Library General Public License version 2.
 */

package org.gnu.gtk;

import java.util.Vector;

import org.gnu.glib.EventMap;
import org.gnu.glib.EventType;
import org.gnu.glib.Handle;
import org.gnu.glib.Type;
import org.gnu.gtk.event.ToggleEvent;
import org.gnu.gtk.event.ToggleListener;

/**
 * A ToggleButton is a button that changes and retains its on or off
 * state each time it is selected with the mouse. When in the on state, it will
 * appear to be pressed in. 
 * @see CheckButton
 * @see RadioButton
 * @see Button
 */
public class ToggleButton extends Button {
	/**
	 * Creates a new toggle button.
	 */
	public ToggleButton() {
		super(gtk_toggle_button_new());
	}

	/**
	 * Construct a toggle button using a handle to a native resource.
	 */
	public ToggleButton(Handle handle) {
		super(handle);
	}

	/**
	 * Creates a new toggle button with a text label. If the hasMnemonic Label
	 * is set, the button is assumes to contain mnemonic characters; that is
	 * characters which are preceeded by an underscore. These will appear
	 * underlined and will be used as keyboard accelerators.
	 * @param label The text to be displayed on the button
	 * @param hasMnemonic If true, keyboeard accelerators will be interpreted.
	 */
	public ToggleButton(String label, boolean hasMnemonic) {
		super(init(label, hasMnemonic));
	}
	
	private static Handle init(String label, boolean hasMnemonic) {
		if (hasMnemonic) {
			return gtk_toggle_button_new_with_mnemonic(label);
		} else {
			return gtk_toggle_button_new_with_label(label);
		}
	}

	/**
	 * Modifies the state of the toggle button
	 * @param state If true, the button is in the 'on', or 'pressed in' state.
	 */
	public void setState(boolean state) {
		gtk_toggle_button_set_active(getHandle(), state);
	}

	/**
	 * Returns the state of the toggle button
	 * @return True if the button is on or 'pressed in'.
	 */
	public boolean getState() {
		return gtk_toggle_button_get_active(getHandle());
	}

	/**
	 * Determines whether the toggle button should be in the half-on, or
	 * inconsistent state. This is envirely a visual setting  - changes to this
	 * will not affect the state of the button as returned by {@link
	 * #getState()}. 
	 * @param isInconsistent If true, the button will appear in the in-between
	 * state.
	 */
	public void setInconsistent(boolean isInconsistent) {
		gtk_toggle_button_set_inconsistent(getHandle(), isInconsistent);
	}

	/**
	 * Return whether this is in the inconsistent state
	 * @see #setInconsistent(boolean)
	 * @return True if the 'inbetween' state is in use
	 */
	public boolean getInconsistent() {
		return gtk_toggle_button_get_inconsistent(getHandle());
	}

	/* **************************************
	 * Event Handler Related code
	 ****************************************/

	/**
	 * Listeners for handling toggle events
	 */
	private Vector toggleListeners = null;
	/**
	 * Register an object to handle button events.
	 * @see org.gnu.gtk.event.ToggleListener
	 */
	public void addListener(ToggleListener listener) {
		// Don't add the listener a second time if it is in the Vector.
		int i = findListener(toggleListeners, listener);
		if (i == -1) {
			if (null == toggleListeners) {
				evtMap.initialize(this, ToggleEvent.Type.TOGGLED);
				toggleListeners = new Vector();
			}
			toggleListeners.addElement(listener);
		}
	}
	/**
	 * Removes a listener
	 * @see #addListener(ToggleListener)
	 */
	public void removeListener(ToggleListener listener) {
		int i = findListener(toggleListeners, listener);
		if (i > -1) {
			toggleListeners.remove(i);
		}
		if (0 == toggleListeners.size()) {
			evtMap.uninitialize(this, ToggleEvent.Type.TOGGLED);
			toggleListeners = null;
		}
	}

	protected void fireToggleEvent(ToggleEvent event) {
		if (null == toggleListeners) {
			return;
		}
		int size = toggleListeners.size();
		int i = 0;
		while (i < size) {
			ToggleListener tl = (ToggleListener)toggleListeners.elementAt(i);
			tl.toggleEvent(event);
			i++;
		}
	}

	private void handleToggled() {
		fireToggleEvent(new ToggleEvent(this));
	}

	public Class getEventListenerClass(String signal) {
		Class cls = evtMap.getEventListenerClass(signal);
		if (cls == null) cls = super.getEventListenerClass(signal);
		return cls;
	}

	public EventType getEventType(String signal) {
		EventType et = evtMap.getEventType(signal);
		if (et == null) et = super.getEventType(signal);
		return et;
	}

	private static EventMap evtMap = new EventMap();
	static {
		addEvents(evtMap);
	}

	/**
	* Implementation method to build an EventMap for this widget class.
	* Not useful (or supported) for application use.
	*/
	private static void addEvents(EventMap anEvtMap) {
		anEvtMap.addEvent("toggled", "handleToggled", ToggleEvent.Type.TOGGLED, ToggleListener.class);
	}

	/**
	 * Retrieve the runtime type used by the GLib library.
	 */
	public static Type getType() {
		return new Type(gtk_toggle_button_get_type());
	}

	native static final protected int gtk_toggle_button_get_type();
	native static final protected Handle gtk_toggle_button_new();
	native static final protected Handle gtk_toggle_button_new_with_label(String label);
	native static final protected Handle gtk_toggle_button_new_with_mnemonic(String label);
	native static final protected void gtk_toggle_button_set_mode(Handle toggle_button, boolean drawIndicator);
	native static final protected boolean gtk_toggle_button_get_mode(Handle toggle_button);
	native static final protected void gtk_toggle_button_set_active(Handle toggle_button, boolean isActive);
	native static final protected boolean gtk_toggle_button_get_active(Handle toggle_button);
	native static final protected void gtk_toggle_button_toggled(Handle toggle_button);
	native static final protected void gtk_toggle_button_set_inconsistent(Handle toggle_button, boolean setting);
	native static final protected boolean gtk_toggle_button_get_inconsistent(Handle toggle_button);
}
