/*
 * 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.GObject;
import org.gnu.glib.Handle;
import org.gnu.glib.Type;
import org.gnu.gtk.event.HandleBoxEvent;
import org.gnu.gtk.event.HandleBoxListener;

/**
 * The HandleBox widget allows a portion of the window to be "torn-off".
 * It is a bin widget which displays its children and a handle that the
 * user can drag to tear off a separate window containing the child widget.
 * A thin <i>ghost</i> is drawn in the original location of the handlebox.
 * By dragging the separate window back to its original location it can
 * be reattached.
 */
public class HandleBox extends Bin 
{
	/**
	 * Create a new HandleBox object.
	 */
	public HandleBox() {
		super(gtk_handle_box_new());
	}
	
	/**
	 * Construct a HandleBox using a handle to a native resource.
	 */
	public HandleBox(Handle handle) {
	    super(handle);
	}

	/**
	 * Set the shadow type to be drawn around the border of the
	 * handle box.
	 * @param type The ShadowType to use for the shadow.
	 */
	public void setShadowType(ShadowType type) {
		gtk_handle_box_set_shadow_type(getHandle(), type.getValue());
	}
	
	/**
	 * Retrieves the shadow type used by this widget.
	 */
	public ShadowType getShadowType() {
		return ShadowType.intern(gtk_handle_box_get_shadow_type(getHandle()));
	}
	
	/**
	 * Sets the side of the handle box where the handle is drawn.
	 * @param position Defines the position of the handle.
	 */
	public void setHandlePosition(PositionType position) {
		gtk_handle_box_set_handle_position(getHandle(), position.getValue());
	}
	
	/**
	 * Retrieves the handle position.
	 */
	public PositionType getHandlePosition() {
		return PositionType.intern(gtk_handle_box_get_handle_position(getHandle()));
	}
	
	/**
	 * Sets the snap edge of the handle box.  The snap edge is the edge
	 * of the detached child that must be aligned with the corresponding
	 * edge of the ghost left behind when the child was detached to 
	 * reattach the torn-off window.
	 * @param edge The side for the snap edge.
	 */
	public void setShapEdge(PositionType edge) {
		gtk_handle_box_set_snap_edge(getHandle(), edge.getValue());
	}
	
	/**
	 * Retrieves the snap edge of the widget.
	 */
	public PositionType getShapEdge() {
		return PositionType.intern(gtk_handle_box_get_snap_edge(getHandle()));
	}
	
	/***************************************
	 * EVENT LISTENERS
	 ****************************************/

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

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

	protected void fireHandleBoxEvent(HandleBoxEvent event) {
		if (null == hbListeners) {
			return;
		}
		int size = hbListeners.size();
		int i = 0;
		while (i < size) {
			HandleBoxListener hbl = (HandleBoxListener)hbListeners.elementAt(i);
			hbl.handleBoxEvent(event);
			i++;
		}
	}

	private void handleChildAttached(Handle widget) {
		HandleBoxEvent evt = new HandleBoxEvent(this, HandleBoxEvent.Type.CHILD_ATTACHED);
		GObject obj = getGObjectFromHandle(widget);
		if (null != obj)
			evt.setWidget((Widget)obj);
		else
			evt.setWidget(new Widget(widget));
		fireHandleBoxEvent(evt);
	}

	private void handleChildDetached(Handle widget) {
		HandleBoxEvent evt =new HandleBoxEvent(this, HandleBoxEvent.Type.CHILD_DETACHED);
		GObject obj = getGObjectFromHandle(widget);
		if (null != obj)
			evt.setWidget((Widget)obj);
		else
			evt.setWidget(new Widget(widget));
		fireHandleBoxEvent(evt);
	}

	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("child_attached", "handleChildAttached", HandleBoxEvent.Type.CHILD_ATTACHED, HandleBoxListener.class);
		anEvtMap.addEvent("child_detached", "handleChildDetached", HandleBoxEvent.Type.CHILD_DETACHED, HandleBoxListener.class);
	}
	
	/**
	 * Retrieve the runtime type used by the GLib library.
	 */
	public static Type getType() {
		return new Type(gtk_handle_box_get_type());
	}

    native static final protected int gtk_handle_box_get_type ();
    native static final protected Handle gtk_handle_box_new ();
    native static final protected void gtk_handle_box_set_shadow_type (Handle handle_box, int type);
    native static final protected int gtk_handle_box_get_shadow_type (Handle handle_box);
    native static final protected void gtk_handle_box_set_handle_position (Handle handle_box, int position);
    native static final protected int gtk_handle_box_get_handle_position (Handle handle_box);
    native static final protected void gtk_handle_box_set_snap_edge (Handle handle_box, int edge);
    native static final protected int gtk_handle_box_get_snap_edge (Handle handle_box);
}

