/*
 * 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.gtk.event.ButtonEvent;
import org.gnu.gtk.event.ButtonListener;
import org.gnu.gtk.event.GtkEventType;

/**
 * A widget that creates a signal when clicked on. This is generally 
 * used to attach a function to that is called when the button is pressed. 
 * <p>The gtk.Button widget can hold any valid child widget. That is it can 
 * hold most any other standard gtk.Widget. The most commonly used child 
 * is the gtk.Label.
 */
public class Button extends Bin {

	/**
	 * Creates a new Button widget
	 */
	public Button() {
		super(gtk_button_new());
		initializeEventHandlers();
	}

	/**
	 * Creates a button widget with a gtk.Label child containing the given text. 
	 * <p>If <code>hasMnemonic</code> is true, the label will be interpreted as 
	 * containing <i>Mnemonic</i> characters (keyboard accelerators). If 
	 * characters in label are proceeded by an underscore character, they will 
	 * be underlined. The first underlined character will be taken as the 
	 * mnemonic - pressing <code>Alt</code> and that character will activate 
	 * the button.
	 * @param label Text to appear on the button
	 * @param hasMnemonic See above description
	 */
	public Button(String label, boolean hasMnemonic) {
		super(init(label, hasMnemonic));
		initializeEventHandlers();
	}
	
	private static int init(String label, boolean hasMnemonic) {
		if (hasMnemonic)
			return gtk_button_new_with_mnemonic(label);
		else
			return gtk_button_new_with_label(label);
	}

	/**
	 * Constructs a button using a stock item. Stock items are standard icons
	 * and text strings. The use of these is highly encouraged as they allow gtk
	 * themes to have greater control over applications and so give a more
	 * consistant interface to the user.
	 * <br>Example: <code>Button myButton = new Button( new StockItem( StockItem.NO );
	 * )</code>
	 * @param stockItem A gtk stock item
	 * @see StockItem
	 */
	public Button(GtkStockItem stockItem) {
		super(gtk_button_new_from_stock(stockItem.getString()));
		initializeEventHandlers();
	}

	/**
	 * Constructs a button using a String that represents a stock item. Stock items are standard icons
	 * and text strings. The use of these is highly encouraged as they allow gtk
	 * themes to have greater control over applications and so give a more
	 * consistant interface to the user.
	 * <br>Example: <code>Button myButton = new Button( StockItem.NO;
	 * )</code>
	 * @param StockItem A String representing a stock item
	 * @see StockItem
	 */
	public Button(String StockItem) {
		super(gtk_button_new_from_stock(StockItem));
		initializeEventHandlers();
	}

	/**
	 * Construct a button using a handle to a native resource.
	 */
	public Button(int handle) {
		super(handle);
		initializeEventHandlers();
	}

	/**
	 * Sends a <i>pressed</i> signal to the button. If handlers have been set 
	 * up for this event then they will be called
	 */
	public void press() {
		gtk_button_pressed(getHandle());
	}

	/**
	 * Sends a <i>released</i> signal to the button. If handlers have been set
	 * up for this event, they will be called.
	 */
	public void release() {
		gtk_button_released(getHandle());
	}

	/**
	 * Sends a <i>clicked</i> signal to the button. If handlers have been set up
	 * for this event, they will be called
	 */
	public void click() {
		gtk_button_clicked(getHandle());
	}

	/**
	 * Sends an <i>enter</i> signal to the button. If handlers have been set up
	 * for this event, they will be called.
	 */
	public void enter() {
		gtk_button_enter(getHandle());
	}

	/**
	 * Sends a <i>leave</i> signal to the button. If handlers have been set up
	 * for this event, they will be called.
	 */
	public void leave() {
		gtk_button_leave(getHandle());
	}

	/**
	 * Sets the relief style of the edges of the Button widget. 
	 */
	public void setRelief(ReliefStyle newRelief) {
		gtk_button_set_relief(getHandle(), newRelief.getValue());
	}

	/**
	 * Returns the current relief style of the button
	 */
	public ReliefStyle getRelief() {
		return ReliefStyle.intern(gtk_button_get_relief(getHandle()));
	}

	/**
	 * Sets the text of the label of the button to newLabel. 
	 * If setUseStock has been called or this object was created using stock
	 * buttons, then newLabel should be the name of the stock item to be used.
	 */
	public void setLabel(String newLabel) {
		gtk_button_set_label(getHandle(), newLabel);
	}

	/**
	 * Returns the label which is being used on the button.
	 */
	public String getLabel() {
		return gtk_button_get_label(getHandle());
	}

	/**
	 * If true, an underline in the text of the button label indicates the next 
	 * character should be used for the mnemonic accelerator key.
	 */
	public void setUseUnderline(boolean useUnderLine) {
		gtk_button_set_use_underline(getHandle(), useUnderLine);
	}

	/**
	 * Returns whether an embedded underline in the button label indicates a 
	 * mnemonic.
	 */
	public boolean getUseUnderline() {
		return gtk_button_get_use_underline(getHandle());
	}

	// TODO: give a doc link to list of stock items. an example application,
	// perhaps.
	/**
	 * Setting this will true will make the widget try to interpret the label as
	 * a stock item. If the stock id is unknown, it will be treated as a normal
	 * label.
	 * <p>Stock items are standard icons and strings. These are included in Gtk
	 * themes, so that the appearance of all applications follows their theme.
	 * The use of stock items is highly recommended.
	 * @param useStock true if this button should use stock items
	 */
	public void setUseStock(boolean useStock) {
		gtk_button_set_use_stock(getHandle(), useStock);
	}

	/**
	 * Returns true if this button is using stock items
	 */
	public boolean getUseStock() {
		return gtk_button_get_use_stock(getHandle());
	}
	
	public void setFocusOnClick(boolean focusOnClick) {
		gtk_button_set_focus_on_click(getHandle(), focusOnClick);
	}
	
	public boolean getFocusOnClick() {
		return gtk_button_get_focus_on_click(getHandle());
	}

	/* **************************************
	 * EVENT LISTENERS
	 ****************************************/

	/**
	 * Listeners for handling button events
	 */
	private Vector buttonListeners = null;

	/**
	 * Register an object to handle button events.
	 * @see org.gnu.gtk.event.ButtonListener
	 */
	public void addListener(ButtonListener listener) {
		// Don't add the listener a second time if it is in the Vector.
		int i = findListener(buttonListeners, listener);
		if (i == -1) {
			if (null == buttonListeners) {
				buttonListeners = new Vector();
			}
			buttonListeners.addElement(listener);
		}
	}
	/**
	 * Removes a listener
	 * @see #addListener(ButtonListener)
	 */
	public void removeListener(ButtonListener listener) {
		int i = findListener(buttonListeners, listener);
		if (i > -1) {
			buttonListeners.remove(i);
		}
		if (0 == buttonListeners.size()) {
			buttonListeners = null;
		}
	}

	protected void fireButtonEvent(ButtonEvent event) {
		if (null == buttonListeners) {
			return;
		}
		int size = buttonListeners.size();
		int i = 0;
		while (i < size) {
			ButtonListener bl = (ButtonListener)buttonListeners.elementAt(i);
			bl.buttonEvent(event);
			i++;
		}
	}

	private void handleActivate() {
		fireButtonEvent(new ButtonEvent(this, ButtonEvent.Type.ACTIVATE));
	}

	private void handleClick() {
		fireButtonEvent(new ButtonEvent(this, ButtonEvent.Type.CLICK));
	}

	private void handleEnter() {
		fireButtonEvent(new ButtonEvent(this, ButtonEvent.Type.ENTER));
	}

	private void handleLeave() {
		fireButtonEvent(new ButtonEvent(this, ButtonEvent.Type.LEAVE));
	}

	private void handlePress() {
		fireButtonEvent(new ButtonEvent(this, ButtonEvent.Type.PRESS));
	}

	private void handleRelease() {
		fireButtonEvent(new ButtonEvent(this, ButtonEvent.Type.RELEASE));
	}

	protected void initializeEventHandlers() {
		if (!eventsInitialized) {
			super.initializeEventHandlers();
			evtMap.initialize(this);
			eventsInitialized = true;
		}
	}

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

	public GtkEventType getEventType(String signal) {
		GtkEventType 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("activate", "handleActivate", ButtonEvent.Type.ACTIVATE, ButtonListener.class);
		anEvtMap.addEvent("clicked", "handleClick", ButtonEvent.Type.CLICK, ButtonListener.class);
		anEvtMap.addEvent("enter", "handleEnter", ButtonEvent.Type.ENTER, ButtonListener.class);
		anEvtMap.addEvent("leave", "handleLeave", ButtonEvent.Type.LEAVE, ButtonListener.class);
		anEvtMap.addEvent("pressed", "handlePress", ButtonEvent.Type.PRESS, ButtonListener.class);
		anEvtMap.addEvent("released", "handleRelease", ButtonEvent.Type.RELEASE, ButtonListener.class);
	}

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

	/****************************************
	 * BEGINNING OF JNI CODE
	 ****************************************/
	native static final protected int gtk_button_get_type();
	native static final protected int gtk_button_new();
	native static final protected int gtk_button_new_with_label(String label);
	native static final protected int gtk_button_new_from_stock(String stock_id);
	native static final protected int gtk_button_new_with_mnemonic(String label);
	native static final protected void gtk_button_pressed(int button);
	native static final protected void gtk_button_released(int button);
	native static final protected void gtk_button_clicked(int button);
	native static final protected void gtk_button_enter(int button);
	native static final protected void gtk_button_leave(int button);
	native static final protected void gtk_button_set_relief(int button, int relief);
	native static final protected int gtk_button_get_relief(int button);
	native static final protected void gtk_button_set_label(int button, String label);
	native static final protected String gtk_button_get_label(int button);
	native static final protected void gtk_button_set_use_underline(int button, boolean useUnderline);
	native static final protected boolean gtk_button_get_use_underline(int button);
	native static final protected void gtk_button_set_use_stock(int button, boolean useStock);
	native static final protected boolean gtk_button_get_use_stock(int button);
	native static final protected void gtk_button_set_focus_on_click(int button, boolean focus);
	native static final protected boolean gtk_button_get_focus_on_click(int button);
	/****************************************
	 * END OF JNI CODE
	 ****************************************/
}
