/*
 * 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.Type;
import org.gnu.gtk.event.CheckMenuItemEvent;
import org.gnu.gtk.event.CheckMenuItemListener;
import org.gnu.gtk.event.GtkEventType;

/**
 * The CheckMenuItem is a menu item that maintains the state of a boolean
 * value in addition to the MenuItem's usual role of activating applicaiton
 * code.
 * <p>
 * A check box indicating the state of boolean value is displayed on the
 * left side of the MenuItem.  Activating the MenuItem toggles this value.
 */
public class CheckMenuItem extends MenuItem {
	
	/**
	 * Create a new CheckMenuItem
	 */
	public CheckMenuItem() {
		super(CheckMenuItem.gtk_check_menu_item_new());
		initializeEventHandlers();
	}
	
	/**
	 * Construct a CheckMenuItem using a handle to a native resource.
	 */
	public CheckMenuItem(int handle) {
	    super(handle);
	    initializeEventHandlers();
	}

	/**
	 * Create a new CheckMenuItem with the given label.
	 * 
	 * @param label The label to display for this CheckMenuItem.
	 */
	public CheckMenuItem(String label, boolean hasMnemonic) {
		super(init(label, hasMnemonic));
		initializeEventHandlers();
	}
	
	private static int init(String label, boolean hasMnemonic) {
		if (hasMnemonic)
			return gtk_check_menu_item_new_with_mnemonic(label);
		else
			return gtk_check_menu_item_new_with_label(label);
	}
	
	/**
	 * Sets the active state of the CheckMenuItem's check box.
	 * 
	 * @param isActive true if the check box is checked.
	 */
	public void setActive(boolean isActive) {
		CheckMenuItem.gtk_check_menu_item_set_active(getHandle(), isActive);
	}
	
	/**
	 * Returns whether the CheckMenuItem is active.
	 * 
	 * @return true if the check box is active.
	 */
	public boolean getActive() {
		return CheckMenuItem.gtk_check_menu_item_get_active(getHandle());
	}
	
	/**
	 * This method will turn on a third state that indicates that the
	 * widget is in an inconsistent state.
	 * 
	 * @param isInconsistent true to display an "inconsistent" third state.
	 */
	public void setInconsistent(boolean isInconsistent) {
		gtk_check_menu_item_set_inconsistent(getHandle(), isInconsistent);
	}
	
	/**
	 * Returns whether the CheckMenuItem is in the "inconsistent" state.
	 * 
	 * @return true if the check box is inconsistent.
	 */
	public boolean getInconsistent() {
		return gtk_check_menu_item_get_inconsistent(getHandle());
	}
	
	/**
	 * Sets whether the CheckMenuItem should be drawn as a radio control
	 * @param drawAsRadio
	 */
	public void setDrawAsRadio(boolean drawAsRadio) {
		gtk_check_menu_item_set_draw_as_radio(getHandle(), drawAsRadio);
	}
	
	/**
	 * Gets whether the CheckMenuItem will be drawn as a radio control.
	 * @return
	 */
	public boolean getDrawAsRadio() {
		return gtk_check_menu_item_get_draw_as_radio(getHandle());
	}
	
	/**
	 * Retrieve the runtime type used by the GLib library.
	 */
	public static Type getType() {
		return new Type(gtk_check_menu_item_get_type());
	}

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

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

	/**
	 * Register an object to handle dialog events.
	 * @see CheckMenuItemListener
	 */
	public void addListener(CheckMenuItemListener 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(CheckMenuItemListener)
	 */
	public void removeListener(CheckMenuItemListener listener) {
		int i = findListener(listeners, listener);
		if (i > -1) {
			listeners.remove(i);
		}
		if (0 == listeners.size()) {
			listeners = null;
		}
	}

	protected void fireCheckMenuItemEvent(CheckMenuItemEvent event) {
		if (null == listeners) {
			return;
		}
		int size = listeners.size();
		int i = 0;
		while (i < size) {
			CheckMenuItemListener cbl = (CheckMenuItemListener)listeners.elementAt(i);
			cbl.checkMenuItemEvent(event);
			i++;
		}
	}

	private void handleToggled() {
		fireCheckMenuItemEvent(new CheckMenuItemEvent(this, CheckMenuItemEvent.Type.TOGGLED));
	}

	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("toggled", "handleToggled", CheckMenuItemEvent.Type.TOGGLED, CheckMenuItemListener.class);
	}

	/****************************************
	 * BEGINNING OF JNI CODE
	 ****************************************/
	native static final protected int gtk_check_menu_item_get_type();
	native static final protected int gtk_check_menu_item_new();
	native static final protected int gtk_check_menu_item_new_with_label(String label);
	native static final protected int gtk_check_menu_item_new_with_mnemonic(String label);
	native static final protected void gtk_check_menu_item_set_active(int check_menu_item, boolean isActive);
	native static final protected boolean gtk_check_menu_item_get_active(int check_menu_item);
	native static final protected void gtk_check_menu_item_toggled(int check_menu_item);
	native static final protected void gtk_check_menu_item_set_inconsistent(int check_menu_item, boolean setting);
	native static final protected boolean gtk_check_menu_item_get_inconsistent(int check_menu_item);
	native static final protected void gtk_check_menu_item_set_draw_as_radio(int cmenu, boolean asRadio);
	native static final protected boolean gtk_check_menu_item_get_draw_as_radio(int cmenu);
	/****************************************
	 * END OF JNI CODE
	 ****************************************/
}
