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

/**
 * 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());
	}

	/**
	 * 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));
	}
	
	private static Handle 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 GtkStockItem
	 */
	public Button(GtkStockItem stockItem) {
		super(gtk_button_new_from_stock(stockItem.getString()));
	}

	/**
	 * 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 GtkStockItem
	 */
	public Button(String stockItem) {
		super(gtk_button_new_from_stock(stockItem));
	}

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

	/**
	 * 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());
	}

	public void setAlignment(double xalign, double yalign) {
		gtk_button_set_alignment(getHandle(), xalign, yalign);
	}
	
	public double getXAlignment() {
		double[] xalign = new double[1];
		double[] yalign = new double[1];
		gtk_button_get_alignment(getHandle(), xalign, yalign);
		return xalign[0];
	}
	
	public double getYAlignment() {
		double[] xalign = new double[1];
		double[] yalign = new double[1];
		gtk_button_get_alignment(getHandle(), xalign, yalign);
		return yalign[0];
	}
	
	public void setImage(Widget image) {
		gtk_button_set_image(getHandle(), image.getHandle());
	}
	
	public Widget getImage() {
		return new Widget(gtk_button_get_image(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) {
				evtMap.initialize(this, ButtonEvent.Type.ACTIVATE);
				evtMap.initialize(this, ButtonEvent.Type.CLICK);
				evtMap.initialize(this, ButtonEvent.Type.ENTER);
				evtMap.initialize(this, ButtonEvent.Type.LEAVE);
				evtMap.initialize(this, ButtonEvent.Type.PRESS);
				evtMap.initialize(this, ButtonEvent.Type.RELEASE);
				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()) {
			evtMap.uninitialize(this, ButtonEvent.Type.ACTIVATE);
			evtMap.uninitialize(this, ButtonEvent.Type.CLICK);
			evtMap.uninitialize(this, ButtonEvent.Type.ENTER);
			evtMap.uninitialize(this, ButtonEvent.Type.LEAVE);
			evtMap.uninitialize(this, ButtonEvent.Type.PRESS);
			evtMap.uninitialize(this, ButtonEvent.Type.RELEASE);
			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));
	}

	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("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());
	}


	native static final protected int gtk_button_get_type();
	native static final protected Handle gtk_button_new();
	native static final protected Handle gtk_button_new_with_label(String label);
	native static final protected Handle gtk_button_new_from_stock(String stock_id);
	native static final protected Handle gtk_button_new_with_mnemonic(String label);
	native static final protected void gtk_button_pressed(Handle button);
	native static final protected void gtk_button_released(Handle button);
	native static final protected void gtk_button_clicked(Handle button);
	native static final protected void gtk_button_enter(Handle button);
	native static final protected void gtk_button_leave(Handle button);
	native static final protected void gtk_button_set_relief(Handle button, int relief);
	native static final protected int gtk_button_get_relief(Handle button);
	native static final protected void gtk_button_set_label(Handle button, String label);
	native static final protected String gtk_button_get_label(Handle button);
	native static final protected void gtk_button_set_use_underline(Handle button, boolean useUnderline);
	native static final protected boolean gtk_button_get_use_underline(Handle button);
	native static final protected void gtk_button_set_use_stock(Handle button, boolean useStock);
	native static final protected boolean gtk_button_get_use_stock(Handle button);
	native static final protected void gtk_button_set_focus_on_click(Handle button, boolean focus);
	native static final protected boolean gtk_button_get_focus_on_click(Handle button);
	native static final protected void gtk_button_set_alignment(Handle button, double xalign, double yalign);
	native static final protected void gtk_button_get_alignment(Handle button, double[] xalign, double[] yalign);
	native static final protected void gtk_button_set_image(Handle button, Handle image);
	native static final protected Handle gtk_button_get_image(Handle button);

}
