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

/**
 * The TreeViewColumn object is a visible column in a {@link TreeView} widget,
 * which is the base widget for all Tree, list and table widgets.
 */
public class TreeViewColumn extends GObject {
	/**
	 * Creates a new Column
	 */
	public TreeViewColumn() {
		super(gtk_tree_view_column_new());
		initializeEventHandlers();
	}

	/**
	 */
	protected TreeViewColumn(int handle) {
		super(handle);
		initializeEventHandlers();
	}

	/**
	 * Packs the cell into the beginning column. If expand is TRUE, then 
	 * the cell is allocated a share of all available space that the 
	 * column has.
	 * @param cell The CellRenderer. 
	 * @param expand TRUE if cell is to be given extra space allocated to box.
	 */
	public void packStart(CellRenderer cell, boolean expand) {
		gtk_tree_view_column_pack_start(getHandle(), cell.getHandle(), expand);
	}

	/**
	 * Packs the cell into the column. If expand is TRUE, then the cell is 
	 * allocated a share of all available space that the column has.
	 * @param cell The CellRenderer. 
	 * @param expand TRUE if cell is to be given extra space allocated to box.
	 */
	public void packEnd(CellRenderer cell, boolean expand) {
		gtk_tree_view_column_pack_end(getHandle(), cell.getHandle(), expand);
	}

	/**
	 * Removes all the renderers from the column.
	 */
	public void clear() {
		gtk_tree_view_column_clear(getHandle());
	}

	/**
	 * Returns an array of CellRenderers in the column in no particular
	 * order.
	 * @return
	 */
	public CellRenderer[] getCellRenderers() {
		int[] hndls = gtk_tree_view_column_get_cell_renderers(getHandle());
		if (null == hndls)
			return null;
		CellRenderer[] cr = new CellRenderer[hndls.length];
		for (int i = 0; i < hndls.length; i++) {
			GObject obj = retrieveGObject(hndls[i]);
			if (null != obj)
				cr[i] = (CellRenderer)obj;
			else
				cr[i] = new CellRenderer(hndls[i]);
		}
		return cr;
	}

	/**
	 * Sets the spacing field of the column, which is the number of pixels to 
	 * place between cell renderers packed into it.
	 * @param spacing Distance between cell renderers in pixels.
	 */
	public void setSpacing(int spacing) {
		gtk_tree_view_column_set_spacing(getHandle(), spacing);
	}
	
	public int getSpacing() {
		return gtk_tree_view_column_get_spacing(getHandle());
	}

	/**
	 * Sets the visibility of the column
	 * @param visible If true, the column s visible.
	 */
	public void setVisible(boolean visible) {
		gtk_tree_view_column_set_visible(getHandle(), visible);
	}
	
	public boolean getVisible() {
		return gtk_tree_view_column_get_visible(getHandle());
	}

	/**
	 * If resizable is TRUE, then the user can explicitly resize the column by 
	 * grabbing the outer edge of the column button. 
	 * @param resizable TRUE, if the column can be resized.
	 */
	public void setResizable(boolean resizable) {
		gtk_tree_view_column_set_resizable(getHandle(), resizable);
	}
	
	public boolean getResizable() {
		return gtk_tree_view_column_get_resizable(getHandle());
	}

	/**
	 * Sets the growth behavior of the column
	 * @param type The TreeViewColumnSizing.
	 */
	public void setSizing(TreeViewColumnSizing type) {
		gtk_tree_view_column_set_sizing(getHandle(), type.getValue());
	}
	
	public TreeViewColumnSizing getSizing() {
		return TreeViewColumnSizing.intern(gtk_tree_view_column_get_sizing(getHandle()));
	}

	/**
	 * Returns the current size of the column in pixels
	 * @return The current width, in pizels.
	 */
	public int getWidth() {
		return gtk_tree_view_column_get_width(getHandle());
	}

	/**
	 * Sets the size of the column in pixels. This is meaningful only if the 
	 * sizing type is {@link TreeViewColumnSizing#FIXED}. The size of the column
	 * is clamped to the min/max width for the column. Please note that the 
	 * min/max width of the column doesn't actually affect the "fixedWidth" 
	 * property of the widget, just the actual size when displayed.
	 * @param fixedWidth The size to set the column  to. Must be greater than 0.
	 */
	public void setFixedWidth(int fixedWidth) {
		gtk_tree_view_column_set_fixed_width(getHandle(), fixedWidth);
	}
	
	public int getFixedWidth() {
		return gtk_tree_view_column_get_fixed_width(getHandle());
	}

	/**
	 * Sets the minimum width of the column. If minWidth is -1, then the 
	 * minimum width is unset.
	 * @param minWidth The minimum width of the column in pixels, or -1.
	 */
	public void setMinWidth(int minWidth) {
		gtk_tree_view_column_set_min_width(getHandle(), minWidth);
	}
	
	public int getMinWidth() {
		return gtk_tree_view_column_get_min_width(getHandle());
	}

	/**
	 * Sets the maximum width of the column. If maxWidth is -1, then the 
	 * maximum width is unset. Note, the column can actually be wider than 
	 * max width if it's the last column in a view. In this case, the 
	 * column expands to fill any extra space.
	 * @param maxWidth The maximum width of the column in pixels, or -1.
	 */
	public void setMaxWidth(int maxWidth) {
		gtk_tree_view_column_set_max_width(getHandle(), maxWidth);
	}
	
	public int getMaxWidth() {
		return gtk_tree_view_column_get_max_width(getHandle());
	}

	/**
	 * Creates a Clicked event. This function will only work if tree_column 
	 * is clickable.
	 */
	public void click() {
		gtk_tree_view_column_clicked(getHandle());
	}

	/**
	 * Sets the title of the column. If a custom widget has been set, then this 
	 * value is ignored.
	 * @param title The title of the column
	 */
	public void setTitle(String title) {
		gtk_tree_view_column_set_title(getHandle(), title);
	}
	
	public String getTitle() {
		return gtk_tree_view_column_get_title(getHandle());
	}

	/**
	 * Sets the header to be active if <code>active</code> is TRUE. When the 
	 * header is active, then it can take keyboard focus, and can be clicked.
	 * @param clickable TRUE if the header is active.
	 */
	public void setClickable(boolean clickable) {
		gtk_tree_view_column_set_clickable(getHandle(), clickable);
	}
	
	public boolean getClickable() {
		return gtk_tree_view_column_get_clickable(getHandle());
	}

	/**
	 * Sets the widget in the header to be <code>widget<code>. If widget is 
	 * <code>null</code>, then the header button is set with a {@link Label}
	 * set to the title of column.
	 * @param widget : A child {@link Widget}, or null.
	 */
	public void setWidget(Widget widget) {
		gtk_tree_view_column_set_widget(getHandle(), widget.getHandle());
	}
	
	public Widget getWidget() {
		int hndl = gtk_tree_view_column_get_widget(getHandle());
		if (0 == hndl)
			return null;
		GObject obj = retrieveGObject(hndl);
		if (null != obj)
			return (Widget)obj;
		return new Widget(hndl);
	}

	/**
	 * Sets the alignment of the title or custom widget inside the column 
	 * header. The alignment determines its location inside the button -- 
	 * 0.0 for left, 0.5 for center, 1.0 for right.
	 * @param align : The alignment, which is between [0.0 and 1.0] inclusive.
	 */
	public void setAlignment(double align) {
		gtk_tree_view_column_set_alignment(getHandle(), align);
	}
	
	public double getAlignment() {
		return gtk_tree_view_column_get_alignment(getHandle());
	}

	/**
	 * If <code>reorderable</code> is TRUE, then the column can be reordered by 
	 * the end user dragging the header. By using this method, the developer
	 * does not have to deal with the drag events.
	 * @param reorderable TRUE, if the column can be reordered.
	 */
	public void setReorderable(boolean reorderable) {
		gtk_tree_view_column_set_reorderable(getHandle(), reorderable);
	}
	
	public boolean getReorderable() {
		return gtk_tree_view_column_get_reorderable(getHandle());
	}

	/**
	 * Sets the logical sortColumnId that this column sorts on when this column 
	 * is selected for sorting. Doing so makes the column header clickable.
	 * @param sortColumnId The sortColumnId of the model to sort on.
	 */
	public void setSortColumn( DataColumn column ) {
		gtk_tree_view_column_set_sort_column_id(getHandle(), column.getColumn() );
	}

	/**
	 * Call this function with a setting of <code>TRUE</code> to display an arrow 
	 * in the header button indicating the column is sorted. Call 
	 * {@link #setSortOrder(SortType)} to change the direction of the arrow.
	 * @param setting TRUE to display an indicator that the column is sorted
	 */
	public void setSortIndicator(boolean setting) {
		gtk_tree_view_column_set_sort_indicator(getHandle(), setting);
	}
	
	public boolean getSortIndicator() {
		return gtk_tree_view_column_get_sort_indicator(getHandle());
	}

	/**
	 * Changes the appearance of the sort indicator.
	 *
	 * <p>This does not actually sort the model. Use {@link #setSortColumnID(int)}
	 * if you want automatic sorting support. This function is primarily for 
	 * custom sorting behavior, and should be used in conjunction with 
	 * {@link #setSortColumnID(int)} to do that. For custom models, the mechanism will 
	 * vary.
	 * 
	 * <p>The sort indicator changes direction to indicate normal sort or 
	 * reverse sort. Note that you must have the sort indicator enabled to see 
	 * anything when calling this function; 
	 * @see #setSortIndicator(boolean)
	 * @param order Sort order that the sort indicator should indicate
	 */
	public void setSortOrder(SortType order) {
		gtk_tree_view_column_set_sort_order(getHandle(), order.getValue());
	}

	public SortType getSortOrder() {
		return SortType.intern(gtk_tree_view_column_get_sort_order(getHandle()));
	}
	
	/**
	 * Returns TRUE if any of the cells packed into the column are visible. 
	 */
	public boolean getIsVisible() {
		return gtk_tree_view_column_cell_is_visible(getHandle());
	}

	/**
	 * {@link TreeView} widgets contain {@link TreeViewColumn} objects. These
	 * contain {@link CellRenderer}s to display data on the screen. This data is
	 * stored in a {@link ListStore} or {@link TreeStore}. In order for data to
	 * be displayed, a mapping has to be made between the data in the data store
	 * and the attributes of the CellRenderers which determine what they render.
	 * This method creates those mappings.
	 * @param renderer The cell renderer to add the mapping to. This must have
	 * been addded to this column.
	 * @param attribute The attribute to be mapped. This must be one of the
	 * attributes for the given renderer.
	 * @param dataBlock the dataBlock in the store in which the data is
	 * contained. This should be of the type required by the renderer attribute.
	 */
	public void addAttributeMapping(CellRenderer renderer, CellRendererAttribute attribute, DataColumn dataBlock) {
		gtk_tree_view_column_add_attribute(getHandle(), renderer.getHandle(), attribute.toString(), dataBlock.getColumn());
	}

	/**
	 * Clears all attribute mappings
	 * @see #addAttributeMapping(CellRenderer, CellRendererAttribute, DataColumn)
	 */
	public void clearAttributeMappings(CellRenderer renderer) {
		gtk_tree_view_column_clear_attributes(getHandle(), renderer.getHandle());
	}

	/**
	 * Sets the column to take available extra space. This space is shared
	 * equally amongst all columns that have the expand set to TRUE. If no
	 * column has this option set, then the last column gets all extra space. By
	 * default, every column is created with this FALSE.
	 * 
	 * @since 2.4
	 *
	 * @param expand
	 */
	public void setExpand( boolean expand ){
		gtk_tree_view_column_set_expand(getHandle(), expand);
	}

	/**
	 * Return TRUE if the column expands to take any available space.
	 * 
	 * @since 2.4
	 *
	 * @return true, if the column expands
	 */
	public boolean getExpand( ){
		return gtk_tree_view_column_get_expand(getHandle());
	}

	/**
	 * Sets the current keyboard focus to be at cell, if the column contains 2
	 * or more editable and activatable cells.
	 *
	 * @since 2.2
	 */
	public void focusCell( CellRenderer cell ){
			gtk_tree_view_column_focus_cell (getHandle(), cell.getHandle());
	}
	

	//////////////////////////////////////////////
	// CLICKED EVENT HANDLER

	/** listeners for selection changing */
	private Vector columnClickedListeners = null;

	/** 
	 * Register an object to handle Selection change events which are emitted
	 * whenever the selection has (possibly) changed
	 * @see org.gnu.gtk.event.TreeViewColumnListener
	 */
	public void addListener(TreeViewColumnListener listener) {
		// Don't add the listener a second time if it is in the Vector.
		int i = Widget.findListener(columnClickedListeners, listener);
		if (i == -1) {
			if (null == columnClickedListeners) {
				columnClickedListeners = new Vector();
			}
			columnClickedListeners.addElement(listener);
		}
	}

	/**
	 * Removes a listener
	 * @see #addListener(TreeViewColumnListener)
	 */
	public void removeListener(TreeViewColumnListener listener) {
		int i = Widget.findListener(columnClickedListeners, listener);
		if (i > -1) {
			columnClickedListeners.remove(i);
		}
		if (0 == columnClickedListeners.size()) {
			columnClickedListeners = null;
		}
	}

	protected void fireSelectionEvent(TreeViewColumnEvent event) {
		if (null == columnClickedListeners) {
			return;
		}
		int size = columnClickedListeners.size();
		int i = 0;
		while (i < size) {
			TreeViewColumnListener bl = (TreeViewColumnListener)columnClickedListeners.elementAt(i);
			bl.columnClickedEvent(event);
			i++;
		}
	}
	private void handleClicked() {
		fireSelectionEvent(new TreeViewColumnEvent(this));
	}

	protected void initializeEventHandlers() {
		if (!eventsInitialized) {
			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);
	}

	private static void addEvents(EventMap evtMap) {
	    evtMap.addEvent("clicked", "handleClicked",
			    TreeViewColumnEvent.Type.CLICKED,
			    TreeViewColumnListener.class);
	}

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

	/****************************************
	 * BEGINNING OF JNI CODE
	 ****************************************/
	native static final protected int gtk_tree_view_column_get_type();
	native static final protected int gtk_tree_view_column_new();
	native static final protected void gtk_tree_view_column_pack_start(int treeColumn, int cell, boolean expand);
	native static final protected void gtk_tree_view_column_pack_end(int treeColumn, int cell, boolean expand);
	native static final protected void gtk_tree_view_column_clear(int treeColumn);
	native static final protected int[] gtk_tree_view_column_get_cell_renderers(int treeColumn);
	native static final protected void gtk_tree_view_column_add_attribute(int treeColumn, int cellRenderer, String attribute, int column);
	native static final protected void gtk_tree_view_column_clear_attributes(int treeColumn, int cellRenderer);
	native static final protected void gtk_tree_view_column_set_spacing(int treeColumn, int spacing);
	native static final protected int gtk_tree_view_column_get_spacing(int treeColumn);
	native static final protected void gtk_tree_view_column_set_visible(int treeColumn, boolean visible);
	native static final protected boolean gtk_tree_view_column_get_visible(int treeColumn);
	native static final protected void gtk_tree_view_column_set_resizable(int treeColumn, boolean resizable);
	native static final protected boolean gtk_tree_view_column_get_resizable(int treeColumn);
	native static final protected void gtk_tree_view_column_set_sizing(int treeColumn, int type);
	native static final protected int gtk_tree_view_column_get_sizing(int treeColumn);
	native static final protected int gtk_tree_view_column_get_width(int treeColumn);
	native static final protected int gtk_tree_view_column_get_fixed_width(int treeColumn);
	native static final protected void gtk_tree_view_column_set_fixed_width(int treeColumn, int fixedWidth);
	native static final protected void gtk_tree_view_column_set_min_width(int treeColumn, int minWidth);
	native static final protected int gtk_tree_view_column_get_min_width(int treeColumn);
	native static final protected void gtk_tree_view_column_set_max_width(int treeColumn, int maxWidth);
	native static final protected int gtk_tree_view_column_get_max_width(int treeColumn);
	native static final protected void gtk_tree_view_column_clicked(int treeColumn);
	native static final protected void gtk_tree_view_column_set_title(int treeColumn, String title);
	native static final protected String gtk_tree_view_column_get_title(int treeColumn);
	native static final protected void gtk_tree_view_column_set_expand(int treeColumn, boolean expand);
	native static final protected boolean gtk_tree_view_column_get_expand(int treeColumn);
	native static final protected void gtk_tree_view_column_set_clickable(int treeColumn, boolean clickable);
	native static final protected boolean gtk_tree_view_column_get_clickable(int treeColumn);
	native static final protected void gtk_tree_view_column_set_widget(int treeColumn, int widget);
	native static final protected int gtk_tree_view_column_get_widget(int treeColumn);
	native static final protected void gtk_tree_view_column_set_alignment(int treeColumn, double xalign);
	native static final protected double gtk_tree_view_column_get_alignment(int treeColumn);
	native static final protected void gtk_tree_view_column_set_reorderable(int treeColumn, boolean reorderable);
	native static final protected boolean gtk_tree_view_column_get_reorderable(int treeColumn);
	native static final protected void gtk_tree_view_column_set_sort_column_id(int treeColumn, int sortColumnID);
	native static final protected int gtk_tree_view_column_get_sort_column_id(int treeColumn);
	native static final protected void gtk_tree_view_column_set_sort_indicator(int treeColumn, boolean setting);
	native static final protected boolean gtk_tree_view_column_get_sort_indicator(int treeColumn);
	native static final protected void gtk_tree_view_column_set_sort_order(int treeColumn, int order);
	native static final protected int gtk_tree_view_column_get_sort_order(int treeColumn);
	native static final protected void gtk_tree_view_column_cell_set_cell_data(int treeColumn, int treeModel, int iter, boolean isExpander, boolean isExpanded);
	native static final protected void gtk_tree_view_column_cell_get_size(int treeColumn, int[] cellArea, int[] xOffset, int[] yOffset, int[] width, int[] height);
	native static final protected boolean gtk_tree_view_column_cell_is_visible(int treeColumn);
	native static final protected void gtk_tree_view_column_focus_cell(int treeColumn, int cell);
	/****************************************
	 * END OF JNI CODE
	 ****************************************/
}
