/*
 * 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.GObject;
import org.gnu.glib.Type;
import org.gnu.gtk.event.ExpanderEvent;
import org.gnu.gtk.event.ExpanderListener;
import org.gnu.gtk.event.GtkEventType;

/** 
 * A container which can hide its child.
 * 
 * <p>An Expander allows the user to hide or show its child by clicking on an expander 
 * triangle similar to the triangles used in a {@link org.gnu.gtk.TreeView}.
 */
public class Expander extends Bin {
	
	/**
	 * Creates a new Expander using label as the text of the label.
	 *
	 * <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 preceded by an underscore, they are underlined. 
	 * If you need a literal underscore character in a label, use '__' (two underscores). 
	 * The first underlined character represents a keyboard accelerator called a mnemonic.
	 * Pressing Alt and that key activates the button.
	 * @param label the text of the label
	 * @param hasMnemonic see above description
	 */
	public Expander(String label, boolean hasMnemonic) {
		super(init(label, hasMnemonic));
		initializeEventHandlers();
	}
	
	private static int init(String label, boolean hasMnemonic) {
		if (hasMnemonic)
			return gtk_expander_new_with_mnemonic(label);
		else
			return gtk_expander_new(label);
	}
	
	/**
	 * Sets the state of the expander. Set to <code>TRUE</code>, if you want the 
	 * child widget to be revealed, and <code>FALSE</code> if you want the child 
	 * widget to be hidden.
	 * @param expanded whether the child widget is revealed
	 */
	public void setExpanded(boolean expanded) {
		gtk_expander_set_expanded(getHandle(), expanded);
	}
	
	/**
	 * Queries an Expander and returns its current state. Returns <code>TRUE</code> 
	 * if the child widget is revealed.
	 * @see Expander#getExpanded()
	 * @return the current state of the expander
	 */
	public boolean getExpanded() {
		return gtk_expander_get_expanded(getHandle());
	}
	
	/**
	 * Sets the spacing field of Expander, which is the number of pixels to place 
	 * between Expander and the child.
	 * @param spacing  distance between the Expander and child in pixels
	 */
	public void setSpacing(int spacing) {
		gtk_expander_set_spacing(getHandle(), spacing);
	}
	
	/**
	 * Gets the value set by {@link Expander#setSpacing(int)}.
	 * @return spacing between the expander and child in pixels
	 */
	public int getSpacing() {
		return gtk_expander_get_spacing(getHandle());
	}
	
	/**
	 * Sets the text of the label of the expander to <code>label</code>.
	 * This will also clear any previously set labels.
	 * @param label a string
	 */
	public void setLabel(String label) {
		gtk_expander_set_label(getHandle(), label);
	}
	
	/**
	 * Fetches the text from the label of the Expander, as set by {@link Expander#setLabel(String)}. 
	 * If the label text has not been set the return value will be <code>NULL</code>. 
	 * This will be the case if you create an empty button with {@link Button#Button()} 
	 * to use as a container. 
	 * @return  the text of the label widget
	 */
	public String getLabel() {
		return gtk_expander_get_label(getHandle());
	}
	
	/**
	 * If true, an underline in the text of the Expander label indicates the next
	 * character should be used for the mnemonic accelerator key.
	 * @param useUnderline TRUE if underlines in the text indicate mnemonics
	 */
	public void setUseUnderline(boolean useUnderline) {
		gtk_expander_set_use_underline(getHandle(), useUnderline);
	}
	
	/**
	 * Returns whether an embedded underline in the Expander label indicates a mnemonic.
	 * @see Expander#setUseUnderline(boolean)
	 * @return <code>TRUE</code> if an embedded underline in the Expander label indicates the mnemonic accelerator keys. 
	 */
	public boolean getUseUnderline() {
		return gtk_expander_get_use_underline(getHandle());
	}
	
	/**
	 * Sets whether the text of the label contains markup in Pango's text markup 
	 * language. 
	 * @see Label#setMarkup(String)
	 * @param useMarkup <code>TRUE</code> if the label's text should be parsed for markup
	 */
	public void setUseMarkup(boolean useMarkup) {
		gtk_expander_set_use_markup(getHandle(), useMarkup);
	}
	
	/**
	 * Returns whether the label's text is interpreted as marked up with the Pango
	 * text markup language. 
	 * @see Expander#setUseMarkup(boolean) 
	 * @return <code>TRUE</code> if the label's text will be parsed for markup
	 */
	public boolean getUseMarkup() {
		return gtk_expander_get_use_markup(getHandle());
	}
	
	/**
	 * Set the label widget for the Expander. This is the widget that will appear 
	 * embedded alongside the Expander arrow.
	 * @param label the new label widget
	 */
	public void setLabelWidget(Widget label) {
		gtk_expander_set_label_widget(getHandle(), label.getHandle());
	}
	
	/**
	 * Retrieves the label widget for the frame. 
	 * @see Expander#setLabelWidget(Widget)
	 * @return the label widget, or <code>NULL</code> if there is none 
	 */
	public Widget getLabelWidget() {
		int hndl = gtk_expander_get_label_widget(getHandle());
		if (0 == hndl)
			return null;
		GObject obj = retrieveGObject(hndl);
		if (null != obj)
			return (Widget)obj;
		return new Widget(hndl);
	}
	
	/**
	 * Retrieve the runtime type used by the GLib library.
	 */
	public static Type getType() {
		return new Type(gtk_expander_get_type());
	}

	/* **************************************
	 * EVENT LISTENERS
	 ****************************************/
	/**
	 * Listeners for handling dialog events
	 */
	private Vector listeners = null;

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

	protected void fireExpanderEvent(ExpanderEvent event) {
		if (null == listeners) {
			return;
		}
		int size = listeners.size();
		int i = 0;
		while (i < size) {
			ExpanderListener el = (ExpanderListener)listeners.elementAt(i);
			el.expanderEvent(event);
			i++;
		}
	}

	private void handleActivate() {
		fireExpanderEvent(new ExpanderEvent(this, ExpanderEvent.Type.ACTIVATE));
	}

	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", ExpanderEvent.Type.ACTIVATE, ExpanderListener.class);
	}

	/****************************************
	 * BEGINNING OF JNI CODE
	 ****************************************/
	native static final protected int gtk_expander_get_type ();
	native static final protected int gtk_expander_new(String label);
	native static final protected int gtk_expander_new_with_mnemonic(String label);
	native static final protected void gtk_expander_set_expanded(int expander, boolean expanded);
	native static final protected boolean gtk_expander_get_expanded(int expander);
	native static final protected void gtk_expander_set_spacing(int expander, int spacing);
	native static final protected int gtk_expander_get_spacing(int expander);
	native static final protected void gtk_expander_set_label(int expander, String label);
	native static final protected String gtk_expander_get_label(int expander);
	native static final protected void gtk_expander_set_use_underline(int expander, boolean useUnderline);
	native static final protected boolean gtk_expander_get_use_underline(int expander);
	native static final protected void gtk_expander_set_use_markup(int expander, boolean useMarkup);
	native static final protected boolean gtk_expander_get_use_markup(int expander);
	native static final protected void gtk_expander_set_label_widget(int expander, int label);
	native static final protected int gtk_expander_get_label_widget(int expander);
	/****************************************
	 * END OF JNI CODE
	 ****************************************/
}
