/*
 * 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.ArrayList;
import java.util.List;

import org.gnu.gdk.Pixbuf;
import org.gnu.glib.Type;
import org.gnu.glib.Value;
import org.gnu.glib.Handle;

/**
 * The TreeStore is a Model used for storing data which will be displayed in any
 * number of {@link TreeView} widgets. For an overview of how the tree and list
 * objects fit together, see the {@link TreeView} description.
 * 
 * <p>
 * Data is stored within this object in {@link DataColumn}s. This data is
 * displayed in the widgets via {@link CellRenderer}'s; the mapping between
 * this data and the cell renderers of each treeview column is done in the
 * {@link TreeViewColumn} class.
 * 
 * @author Mark Howard &lt;mh@debian.org&gt;
 */
public class TreeStore extends TreeModel implements TreeSortable, TreeDragDest,
        TreeDragSource {

    private List columnTypes = new ArrayList();

    /**
     * Constructs a new TreeStore, defining the types for each datablock.
     * Subsequent setting of data to any of the datablocks must follow the types
     * you set out here.
     * 
     * @param dataColumns
     *            Types for the data to be stored in the TreeStore.
     */
    public TreeStore(DataColumn[] dataColumns) {
        super(initTreeStore(dataColumns));

        for (int i = 0; i < dataColumns.length; i++) {
            columnTypes.add(dataColumns[i]);
        }
    }

    private static Handle initTreeStore(DataColumn[] dataColumns) {
        int[] intTypes = new int[dataColumns.length];
        for (int i = 0; i < intTypes.length; i++) {
            intTypes[i] = dataColumns[i].getType().getTypeHandle();
            dataColumns[i].setColumn(i);
        }
        return gtk_tree_store_newv(dataColumns.length, intTypes);
    }

    public void setColumnTypes(DataColumn[] dataColumns) {
        int[] intTypes = new int[dataColumns.length];
        for (int i = 0; i < intTypes.length; i++) {
            intTypes[i] = dataColumns[i].getType().getTypeHandle();
            dataColumns[i].setColumn(i);
            columnTypes.add(dataColumns[i]);
        }

        gtk_tree_store_set_column_types(getHandle(), dataColumns.length,
                intTypes);
    }

    /**
     * Returns the type of the column <code>aCol</code> as a
     * <code>DataColumn</code>. This is similar to calling
     * <code>getType(int)</code>; the difference is that this method returns
     * the type as a DataColumn, which is a more high-level structure.
     * 
     * @param aCol
     *            the column index
     * @return the corresponding DataColumn
     */
    public DataColumn getDataColumn(int aCol) {
        return (DataColumn) columnTypes.get(aCol);
    }

    /**
     * Returns a <code>List</code> with the types for every column as a
     * <code>DataColumn</code> object.
     * 
     * @return the list of <code>DataColumn</code>'s
     */
    public List getAllDataColumns() {
        return columnTypes;
    }

    /**
     * Sets a value in the dataStore. The type of the value <em>must</em>
     * match the type set for that dataBlock in the constructor.
     * <p>
     * This does not make the data visible in any of the widgets which use the
     * class - to do that, you have to construct a {@link TreeViewColumn} and
     * add it to the {@link TreeView}; construct and add a {@link CellRenderer}
     * to that; and finally associate the properties of the CellRenderer with
     * the dataBlocks, using the
     * {@link TreeViewColumn#addAttributeMapping(CellRenderer, CellRendererAttribute,
     * DataColumn)} method.
     * 
     * @param dataBlock
     *            The datablock in which the data should be stored.
     * @param iter
     *            Valid iterator for the data row in which the value is to be
     *            set. These can be gotten using methods such as
     *            {@link #appendRow(TreeIter)}.
     * @param value
     *            The value to be set.
     */
    public void setValue(TreeIter iter, DataColumnString dataBlock, String value) {
        Value val = new Value(Type.STRING());
        val.setString(value);
        gtk_tree_store_set_value(getHandle(), iter.getHandle(), dataBlock
                .getColumn(), val.getHandle());
    }

    /**
     * Sets a value in the dataStore. The type of the value <em>must</em>
     * match the type set for that dataBlock in the constructor.
     * <p>
     * This does not make the data visible in any of the widgets which use the
     * class - to do that, you have to construct a {@link TreeViewColumn} and
     * add it to the {@link TreeView}; construct and add a {@link CellRenderer}
     * to that; and finally associate the properties of the CellRenderer with
     * the dataBlocks, using the
     * {@link TreeViewColumn#addAttributeMapping(CellRenderer, CellRendererAttribute,
     * DataColumn)} method.
     * 
     * @param dataBlock
     *            The datablock in which the data should be stored.
     * @param iter
     *            Valid iterator for the data row in which the value is to be
     *            set. These can be gotten using methods such as
     *            {@link #appendRow(TreeIter)}.
     * @param value
     *            The value to be set.
     */
    public void setValue(TreeIter iter, DataColumnStockItem dataBlock,
            GtkStockItem value) {
        Value val = new Value(Type.STRING());
        val.setString(value.getString());
        gtk_tree_store_set_value(getHandle(), iter.getHandle(), dataBlock
                .getColumn(), val.getHandle());
    }

    /**
     * Sets a value in the dataStore. The type of the value <em>must</em>
     * match the type set for that dataBlock in the constructor.
     * <p>
     * This does not make the data visible in any of the widgets which use the
     * class - to do that, you have to construct a {@link TreeViewColumn} and
     * add it to the {@link TreeView}; construct and add a {@link CellRenderer}
     * to that; and finally associate the properties of the CellRenderer with
     * the dataBlocks, using the
     * {@link TreeViewColumn#addAttributeMapping(CellRenderer, CellRendererAttribute,
     * DataColumn)} method.
     * 
     * @param dataBlock
     *            The datablock in which the data should be stored.
     * @param iter
     *            Valid iterator for the data row in which the value is to be
     *            set. These can be gotten using methods such as
     *            {@link #appendRow(TreeIter)}.
     * @param value
     *            The value to be set.
     */
    public void setValue(TreeIter iter, DataColumnIconSize dataBlock,
            IconSize value) {
        Value val = new Value(Type.INT());
        val.setInteger(value.getValue());
        gtk_tree_store_set_value(getHandle(), iter.getHandle(), dataBlock
                .getColumn(), val.getHandle());
    }

    /**
     * Sets a value in the dataStore. The type of the value <em>must</em>
     * match the type set for that dataBlock in the constructor.
     * <p>
     * This does not make the data visible in any of the widgets which use the
     * class - to do that, you have to construct a {@link TreeViewColumn} and
     * add it to the {@link TreeView}; construct and add a {@link CellRenderer}
     * to that; and finally associate the properties of the CellRenderer with
     * the dataBlocks, using the
     * {@link TreeViewColumn#addAttributeMapping(CellRenderer, CellRendererAttribute,
     * DataColumn)} method.
     * 
     * @param dataBlock
     *            The datablock in which the data should be stored.
     * @param iter
     *            Valid iterator for the data row in which the value is to be
     *            set. These can be gotten using methods such as
     *            {@link #appendRow(TreeIter)}.
     * @param value
     *            The value to be set.
     * @since 2.8.5
     */
    public void setValue(TreeIter iter, DataColumnInt dataBlock, int value) {
        Value val = new Value(Type.INT());
        val.setInteger(value);
        gtk_tree_store_set_value(getHandle(), iter.getHandle(), dataBlock
                .getColumn(), val.getHandle());
    }

    /**
     * Sets a value in the dataStore. The type of the value <em>must</em>
     * match the type set for that dataBlock in the constructor.
     * <p>
     * This does not make the data visible in any of the widgets which use the
     * class - to do that, you have to construct a {@link TreeViewColumn} and
     * add it to the {@link TreeView}; construct and add a {@link CellRenderer}
     * to that; and finally associate the properties of the CellRenderer with
     * the dataBlocks, using the
     * {@link TreeViewColumn#addAttributeMapping(CellRenderer, CellRendererAttribute,
     * DataColumn)} method.
     * 
     * @param dataBlock
     *            The datablock in which the data should be stored.
     * @param iter
     *            Valid iterator for the data row in which the value is to be
     *            set. These can be gotten using methods such as
     *            {@link #appendRow(TreeIter)}.
     * @param value
     *            The <code>long</code> value to set into this row.
     */
    public void setValue(TreeIter iter, DataColumnLong dataBlock, long value) {
        Value val = new Value(Type.LONG());
        val.setLong(value);
        gtk_tree_store_set_value(getHandle(), iter.getHandle(), dataBlock
                .getColumn(), val.getHandle());
    }

    /**
     * Sets a value in the dataStore. The type of the value <em>must</em>
     * match the type set for that dataBlock in the constructor.
     * <p>
     * This does not make the data visible in any of the widgets which use the
     * class - to do that, you have to construct a {@link TreeViewColumn} and
     * add it to the {@link TreeView}; construct and add a {@link CellRenderer}
     * to that; and finally associate the properties of the CellRenderer with
     * the dataBlocks, using the
     * {@link TreeViewColumn#addAttributeMapping(CellRenderer, CellRendererAttribute,
     * DataColumn)} method.
     * 
     * @param dataBlock
     *            The datablock in which the data should be stored.
     * @param iter
     *            Valid iterator for the data row in which the value is to be
     *            set. These can be gotten using methods such as
     *            {@link #appendRow(TreeIter)}.
     * @param value
     *            The value to be set.
     */
    public void setValue(TreeIter iter, DataColumnBoolean dataBlock,
            boolean value) {
        Value val = new Value(Type.BOOLEAN());
        val.setBoolean(value);
        gtk_tree_store_set_value(getHandle(), iter.getHandle(), dataBlock
                .getColumn(), val.getHandle());
    }

    /**
     * Sets a value in the dataStore. The type of the value <em>must</em>
     * match the type set for that dataBlock in the constructor.
     * <p>
     * This does not make the data visible in any of the widgets which use the
     * class - to do that, you have to construct a {@link TreeViewColumn} and
     * add it to the {@link TreeView}; construct and add a {@link CellRenderer}
     * to that; and finally associate the properties of the CellRenderer with
     * the dataBlocks, using the
     * {@link TreeViewColumn#addAttributeMapping(CellRenderer, CellRendererAttribute,
     * DataColumn)} method.
     * 
     * @param dataBlock
     *            The datablock in which the data should be stored.
     * @param iter
     *            Valid iterator for the data row in which the value is to be
     *            set. These can be gotten using methods such as
     *            {@link #appendRow(TreeIter)}.
     * @param value
     *            The value to be set.
     */
    public void setValue(TreeIter iter, DataColumnDouble dataBlock, double value) {
        Value val = new Value(Type.DOUBLE());
        val.setDouble(value);
        gtk_tree_store_set_value(getHandle(), iter.getHandle(), dataBlock
                .getColumn(), val.getHandle());
    }

    /**
     * Sets a value in the dataStore. The type of the value <em>must</em>
     * match the type set for that dataBlock in the constructor.
     * <p>
     * This does not make the data visible in any of the widgets which use the
     * class - to do that, you have to construct a {@link TreeViewColumn} and
     * add it to the {@link TreeView}; construct and add a {@link CellRenderer}
     * to that; and finally associate the properties of the CellRenderer with
     * the dataBlocks, using the
     * {@link TreeViewColumn#addAttributeMapping(CellRenderer, CellRendererAttribute,
     * DataColumn)} method.
     * 
     * @param dataBlock
     *            The data block in which to store the data, starting at 0.
     * @param iter
     *            Valid iterator for the data row in which the value is to be
     *            set. These can be gotten using methods such as
     *            {@link #appendRow(TreeIter)}.
     * @param value
     *            The value to be set. This <em>must</em> match the type for
     *            that dataBlock, as set in the constructor.
     */
    public void setValue(TreeIter iter, DataColumnObject dataBlock, Object value) {
        Value val = new Value(Type.JAVA_OBJECT());
        val.setJavaObject(value);
        gtk_tree_store_set_value(getHandle(), iter.getHandle(), dataBlock
                .getColumn(), val.getHandle());
    }

    /**
     * Sets a value in the dataStore. The type of the value <em>must</em>
     * match the type set for that dataBlock in the constructor.
     * <p>
     * This does not make the data visible in any of the widgets which use the
     * class - to do that, you have to construct a {@link TreeViewColumn} and
     * add it to the {@link TreeView}; construct and add a {@link CellRenderer}
     * to that; and finally associate the properties of the CellRenderer with
     * the dataBlocks, using the
     * {@link TreeViewColumn#addAttributeMapping(CellRenderer, CellRendererAttribute,
     * DataColumn)} method.
     * 
     * @param dataBlock
     *            The data block in which to store the data, starting at 0.
     * @param iter
     *            Valid iterator for the data row in which the value is to be
     *            set. These can be gotten using methods such as
     *            {@link #appendRow(TreeIter)}.
     * @param value
     *            The value to be set.
     */
    public void setValue(TreeIter iter, DataColumnPixbuf dataBlock,
            org.gnu.gdk.Pixbuf value) {
        Value val = new Value(Type.PIXBUF());
        val.setPixbuf(value);
        gtk_tree_store_set_value(getHandle(), iter.getHandle(), dataBlock
                .getColumn(), val.getHandle());
    }

    /**
     * @param rowIter
     * @param dataCol
     * @param rowItem
     */
    private void trySetValue(TreeIter rowIter, DataColumn dataCol,
            Object rowItem) {

        // TODO: this method shouldn't exist; method should be using
        // gtk_tree_store_set_valist () instead

        if (dataCol instanceof DataColumnBoolean) {
            setValue(rowIter, (DataColumnBoolean) dataCol, ((Boolean) rowItem)
                    .booleanValue());

        } else if (dataCol instanceof DataColumnDouble) {
            setValue(rowIter, (DataColumnDouble) dataCol, ((Double) rowItem)
                    .doubleValue());

        } else if (dataCol instanceof DataColumnIconSize) {
            setValue(rowIter, (DataColumnIconSize) dataCol,
                    ((IconSize) rowItem));

        } else if (dataCol instanceof DataColumnInt) {
            setValue(rowIter, (DataColumnInt) dataCol, ((Integer) rowItem)
                    .intValue());

        } else if (dataCol instanceof DataColumnObject) {
            setValue(rowIter, (DataColumnObject) dataCol, rowItem);

        } else if (dataCol instanceof DataColumnPixbuf) {
            setValue(rowIter, (DataColumnPixbuf) dataCol, ((Pixbuf) rowItem));

        } else if (dataCol instanceof DataColumnStockItem) {
            setValue(rowIter, (DataColumnStockItem) dataCol,
                    ((GtkStockItem) rowItem));

        } else if (dataCol instanceof DataColumnString) {
            setValue(rowIter, (DataColumnString) dataCol, ((String) rowItem));
        }
    }

    /**
     * Adds a row to the tree. This method can be used to easily add data to the
     * tree. Each item in the DataRow must match the {@link DataColumn} type
     * specified in the constructor of TreeStore. For example, if it was passed
     * <code>{new DataColumnBoolean(), new DataColumnString()}</code> to the
     * constructor, then the DataRow must contain a Boolean and a String object,
     * respectively.
     * 
     * @param aRow
     *            a row to be added to the list
     */
    public void addRow(DataRow aRow) {

        TreeIter rowIter = this.appendRow(null);
        int size = columnTypes.size();

        for (int i = 0; i < size; i++) {

            DataColumn dataCol = getDataColumn(i);
            Object rowItem = aRow.get(i);

            // TODO: should use gtk_tree_store_set_valist instead

            trySetValue(rowIter, dataCol, rowItem);
        }
    }

    /**
     * Adds a row to the tree, at the specified position. This method can be
     * used to easily add data to the tree. Each item in the DataRow must match
     * the {@link DataColumn} type specified in the constructor of TreeStore.
     * For example, if it was passed
     * <code>{new DataColumnBoolean(), new DataColumnString()}</code> to the
     * constructor, then the DataRow must contain a Boolean and a String object,
     * respectively.
     * 
     * @param aRow
     *            a row to be added to the list
     */
    public void addRowAt(DataRow aRow, int aPosition) {

        TreeIter rowIter = this.insertRow(null, aPosition);
        int size = columnTypes.size();

        for (int i = 0; i < size; i++) {

            DataColumn dataCol = getDataColumn(i);
            Object rowItem = aRow.get(i);

            // TODO: should use gtk_tree_store_set_valist instead

            trySetValue(rowIter, dataCol, rowItem);
        }
    }

    /**
     * Adds a row to the tree. This method can be used to easily add data to the
     * tree. Each item in the DataRow must match the {@link DataColumn} type
     * specified in the constructor of TreeStore. For example, if it was passed
     * <code>{new DataColumnBoolean(), new DataColumnString()}</code> to the
     * constructor, then the DataRow must contain a Boolean and a String object,
     * respectively.
     * 
     * @param aRow
     *            a row to be added to the list
     * @param aParent
     *            a <code>TreeIter</code> pointing to a parent row.
     */
    public void addRow(DataRow aRow, TreeIter aParent) {

        TreeIter rowIter = this.appendRow(aParent);
        int size = columnTypes.size();

        for (int i = 0; i < size; i++) {

            DataColumn dataCol = getDataColumn(i);
            Object rowItem = aRow.get(i);

            // TODO: should use gtk_tree_store_set_valist instead

            trySetValue(rowIter, dataCol, rowItem);
        }
    }

    /**
     * Adds a row to the tree, at the specified position. This method can be
     * used to easily add data to the tree. Each item in the DataRow must match
     * the {@link DataColumn} type specified in the constructor of TreeStore.
     * For example, if it was passed
     * <code>{new DataColumnBoolean(), new DataColumnString()}</code> to the
     * constructor, then the DataRow must contain a Boolean and a String object,
     * respectively.
     * 
     * @param aRow
     *            a row to be added to the list
     * @param aParent
     *            a <code>TreeIter</code> pointing to a parent row.
     */
    public void addRowAt(DataRow aRow, TreeIter aParent, int aPosition) {

        TreeIter rowIter = this.insertRow(aParent, aPosition);
        int size = columnTypes.size();

        for (int i = 0; i < size; i++) {

            DataColumn dataCol = getDataColumn(i);
            Object rowItem = aRow.get(i);

            // TODO: should use gtk_tree_store_set_valist instead

            trySetValue(rowIter, dataCol, rowItem);
        }
    }

    /**
     * Gets all the values in the row indicated by <code>aIter</code>. There
     * are several ways you can get a <code>TreeIter</code> to pass; for
     * example: using methods like <code>getIter</code> and
     * <code>getFirstIter()</code>, or from a <code>TreeSelection</code>.
     * 
     * @param aIter
     *            the iter pointing to the row
     * @return a <code>DataRow</code> filled with the values of the row.
     * @see TreeModel#getIter(String)
     * @see TreeModel#getIter(TreePath)
     * @see TreeModel#getFirstIter()
     * @see TreeSelection
     */
    public DataRow getRowAt(TreeIter aIter) {

        DataRow row = new DataRow();
        int size = columnTypes.size();

        for (int i = 0; i < size; i++) {

            // TODO: should use gtk_tree_model_get_valist ()
            // instead of calling getValue for each column

            DataColumn dataCol = getDataColumn(i);

            if (dataCol instanceof DataColumnBoolean) {
                row.add(Boolean.valueOf(getValue(aIter,
                        (DataColumnBoolean) dataCol)));

            } else if (dataCol instanceof DataColumnDouble) {
                row
                        .add(new Double(getValue(aIter,
                                (DataColumnDouble) dataCol)));

            } else if (dataCol instanceof DataColumnIconSize) {
                row.add(new Integer(getValue(aIter,
                        (DataColumnIconSize) dataCol)));

            } else if (dataCol instanceof DataColumnInt) {
                row.add(new Integer(getValue(aIter, (DataColumnInt) dataCol)));

            } else if (dataCol instanceof DataColumnObject) {
                row.add(getValue(aIter, (DataColumnObject) dataCol));

            } else if (dataCol instanceof DataColumnPixbuf) {
                row.add(getValue(aIter, (DataColumnPixbuf) dataCol));

            } else if (dataCol instanceof DataColumnStockItem) {
                row.add(getValue(aIter, (DataColumnStockItem) dataCol));

            } else if (dataCol instanceof DataColumnString) {
                row.add(getValue(aIter, (DataColumnString) dataCol));
            }
        }

        return row;
    }

    /**
     * Sets all columns pointed by <code>aIter</code> to the values stored in
     * <code>aRow</code>.
     * 
     * @param aRow
     *            a row with items
     * @param aIter
     *            a <code>TreeIter</code> pointing to a row in the tree.
     * @see #getRowAt(TreeIter)
     */
    public void setRowAt(DataRow aRow, TreeIter aIter) {

        // TODO: should use gtk_tree_store_set_valist instead

        int size = columnTypes.size();

        for (int i = 0; i < size; i++) {
            trySetValue(aIter, getDataColumn(i), aRow.get(i));
        }
    }

    /**
     * Removes a row from the tree store. After being removed, iter is set to
     * the next valid row at that level, or invalidated if it previously pointed
     * to the last one.
     * 
     * @param iter
     *            TreeIter representing the row.
     */
    public void removeRow(TreeIter iter) {
        gtk_tree_store_remove(getHandle(), iter.getHandle());
    }

    /**
     * Creates a new row at position. If parent is non-NULL, then the row will
     * be made a child of parent. Otherwise, the row will be created at the
     * toplevel. If position is larger than the number of rows at that level,
     * then the new row will be inserted to the end of the list.
     * 
     * @param parent
     *            A valid TreeIter, or NULL
     * @param position
     *            Position to insert the new row
     * @return Iterator for the new row
     */
    public TreeIter insertRow(TreeIter parent, int position) {
        Handle hndl = (null == parent) ? null : parent.getHandle();
        return TreeIter.getTreeIter(gtk_tree_store_insert(getHandle(), hndl,
                position), this);
    }

    /**
     * Inserts a new row before sibling. If sibling is NULL, then the row will
     * be appended to parent 's children. If parent and sibling are NULL, then
     * the row will be appended to the toplevel. If both sibling and parent are
     * set, then parent must be the parent of sibling. When sibling is set,
     * parent is optional
     * 
     * @param parent
     *            A valid TreeIter, or NULL
     * @param sibling
     *            A valid TreeIter, or NULL
     * @return Iterator for the new row.
     */
    public TreeIter insertRowBefore(TreeIter sibling, TreeIter parent) {
        Handle s = null;
        Handle p = null;
        if (null != parent)
            p = parent.getHandle();
        if (null != sibling)
            s = sibling.getHandle();
        return TreeIter.getTreeIter(gtk_tree_store_insert_before(getHandle(),
                p, s), this);
    }

    /**
     * Inserts a new row after sibling. If sibling is NULL, then the row will be
     * prepended to the beginning of the parent 's children. If parent and
     * sibling are NULL, then the row will be prepended to the toplevel. If both
     * sibling and parent are set, then parent must be the parent of sibling.
     * When sibling is set, parent is optional.
     * 
     * @param parent
     *            A valid TreeIter, or NULL
     * @param sibling
     *            A valid GtkTreeIter, or NULL
     * @return Iterator for the new row.
     */
    public TreeIter insertRowAfter(TreeIter sibling, TreeIter parent) {
        Handle s = null;
        Handle p = null;
        if (null != parent)
            p = parent.getHandle();
        if (null != sibling)
            s = sibling.getHandle();
        return TreeIter.getTreeIter(gtk_tree_store_insert_after(getHandle(), p,
                s), this);
    }

    /**
     * Prepends a new row to the store. If parent is non-NULL, then it will
     * prepend the new row before the first child of parent, otherwise it will
     * prepend a row to the top level.
     * 
     * @param parent
     *            A valid TreeIter, or NULL
     * @return Iterator for the new row.
     */
    public TreeIter prependRow(TreeIter parent) {
        Handle hndl = (null == parent) ? null : parent.getHandle();
        return TreeIter.getTreeIter(gtk_tree_store_prepend(getHandle(), hndl),
                this);
    }

    /**
     * Appends a new row to tree_store. If parent is non-NULL, then it will
     * append the new row after the last child of parent, otherwise it will
     * append a row to the top level.
     * 
     * @param parent
     *            A valid TreeIter, or NULL
     * @return Iterator for the new row.
     */
    public TreeIter appendRow(TreeIter parent) {
        Handle hndl = (null == parent) ? null : parent.getHandle();
        return TreeIter.getTreeIter(gtk_tree_store_append(getHandle(), hndl),
                this);
    }

    /**
     * Returns TRUE if iter is an ancestor of descendant. That is, iter is the
     * parent (or grandparent or great-grandparent) of descendant.
     * 
     * @param iter
     *            Row to be tested.
     * @param descendant
     *            Descendant row for testing
     * @return True of iter is an ancestor of descendant
     */
    public boolean isAncestor(TreeIter iter, TreeIter descendant) {
        return gtk_tree_store_is_ancestor(getHandle(), iter.getHandle(),
                descendant.getHandle());
    }

    /**
     * Returns the depth of the iterator. This will be 0 for anything on the
     * root level, 1 for anything down a level, etc.
     * 
     * @param iter
     *            The iterator to test the depth of
     * @return Depth of the iterator.
     */
    public int getIteratorDepth(TreeIter iter) {
        return gtk_tree_store_iter_depth(getHandle(), iter.getHandle());
    }

    /**
     * Removes all items from the treestore.
     */
    public void clear() {
        gtk_tree_store_clear(getHandle());
    }

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

    // 
    // TreeSortable interface.
    //

    /**
     * Set the column in the list to sort on.
     */
    public void setSortColumn(DataColumn column, SortType order) {
        TreeSortableHelper.setSortColumn(this, column, order);
    }

    /**
     * Get a DataColumn object representing the currently sorted column. This is
     * not the same DataColumn used to create the store. It is only of type
     * DataColumn (not DataColumnString, etc). It can be compared with another
     * DataColumn object using the <tt>{@link DataColumn#equals}</tt> method.
     * 
     * @return A DataColumn object representing the currently sorted column or
     *         <tt>null</tt> if there is no column currently sorted.
     */
    public DataColumn getSortColumn() {
        return TreeSortableHelper.getSortColumn(this);
    }

    /**
     * Get the current sorting order of the store.
     * 
     * @return A SortType object defining the current sorting order of the store
     *         or <tt>null</tt> if there is no current sort order.
     */
    public SortType getSortOrder() {
        return TreeSortableHelper.getSortOrder(this);
    }

    /**
     * Set the class used to sort the list according to the values stored in the
     * given DataColumn.
     */
    public void setSortMethod(TreeIterComparison method, DataColumn column) {
        TreeSortableHelper.setSortMethod(this, method, column);
    }

    /**
     * Call-back method invoked by the JNI code when sorting is required. This
     * is for internal use only.
     */
    public int handleCompareFunc(Handle model, Handle aIter, Handle bIter,
            int col) {
        TreeIterComparison method = TreeSortableHelper.getMethod(this, col);
        if (method != null) {
            TreeModel mdl = (TreeModel) getGObjectFromHandle(model);
            TreeIter a = TreeIter.getTreeIter(aIter, mdl);
            TreeIter b = TreeIter.getTreeIter(bIter, mdl);
            return method.compareTreeIters(mdl, a, b);
        } else {
            return 0;
        }
    }

    public void setDragDestListener(TreeDragDestListener listener) {
        // TODO
        throw new RuntimeException("Not yet implemented");
    }

    public void setDragSourceListener(TreeDragSourceListener listener) {
        // TODO
        throw new RuntimeException("Not yet implemented");
    }

    /**
     * Swaps a and b in the same level of tree_store. Note that this function
     * only works with unsorted stores.
     * 
     * @since 2.2
     */
    public void swapRows(TreeIter a, TreeIter b) {
        gtk_tree_store_swap(getHandle(), a.getHandle(), b.getHandle());
    }

    /**
     * Moves iter to the end of the model
     * 
     * @since 2.2
     */
    public void moveRowToEnd(TreeIter iter) {
        gtk_tree_store_move_before(getHandle(), iter.getHandle(), null);
    }

    /**
     * Moves iter in this store to the position after position. <tt>iter</tt>
     * and <tt>position</tt> should be in the same level. Note that this
     * function only works with unsorted stores.
     * 
     * @since 2.2
     */
    public void moveRowAfter(TreeIter iter, TreeIter position) {
        gtk_tree_store_move_after(getHandle(), iter.getHandle(), position
                .getHandle());
    }

    /**
     * Moves iter in this store to the start of the store.
     * 
     * @since 2.2
     */
    public void moveRowToStart(TreeIter iter) {
        gtk_tree_store_move_after(getHandle(), iter.getHandle(), null);
    }

    /**
     * Moves iter in tree_store to the position before position. <tt>iter</tt>
     * and <tt>position</tt> should be in the same level. Note that this
     * function only works with unsorted stores.
     * 
     * @since 2.2
     */
    public void moveRowBefore(TreeIter iter, TreeIter position) {
        gtk_tree_store_move_before(getHandle(), iter.getHandle(), position
                .getHandle());
    }

    public boolean isIterValid(TreeIter iter) {
        if (iter == null)
            return false;

        return gtk_tree_store_iter_is_valid(getHandle(), iter.getHandle());
    }

    public void reorder(TreeIter iter, int[] newOrder) {
        gtk_tree_store_reorder(getHandle(), iter.getHandle(), newOrder);
    }

    // native static final protected int getRoot(int cptr);
    // native final protected void setRoot(int cptr, int root);
    // native static final protected int getLast(int cptr);
    // native final protected void setLast(int cptr, int last);
    // native static final protected int getNColumns(int cptr);
    // native final protected void setNColumns(int cptr, int n_columns);
    // native static final protected int getColumnHeaders(int cptr);
    // native final protected void setColumnHeaders(int cptr, int
    // column_headers);
    // native static final protected boolean getColumnsDirty(int cptr);
    // native final protected void setColumnsDirty(int cptr, boolean
    // columns_dirty);

    native static final protected int gtk_tree_store_get_type();

    native static final protected Handle gtk_tree_store_newv(int numColumns,
            int[] types);

    native static final protected void gtk_tree_store_set_column_types(
            Handle treeStore, int numColumns, int[] types);

    native static final protected void gtk_tree_store_set_value(
            Handle treeStore, Handle iter, int columnt, Handle value);

    native static final protected void gtk_tree_store_remove(Handle treeStore,
            Handle iter);

    native static final protected Handle gtk_tree_store_insert(
            Handle treeStore, Handle parent, int position);

    native static final protected Handle gtk_tree_store_insert_before(
            Handle treeStore, Handle parent, Handle sibling);

    native static final protected Handle gtk_tree_store_insert_after(
            Handle treeStore, Handle parent, Handle sibling);

    native static final protected Handle gtk_tree_store_prepend(
            Handle treeStore, Handle parent);

    native static final protected Handle gtk_tree_store_append(
            Handle treeStore, Handle parent);

    native static final protected boolean gtk_tree_store_is_ancestor(
            Handle treeStore, Handle iter, Handle descendant);

    native static final protected int gtk_tree_store_iter_depth(
            Handle treeStore, Handle iter);

    native static final protected void gtk_tree_store_clear(Handle treeStore);

    native static final protected boolean gtk_tree_store_iter_is_valid(
            Handle treeStore, Handle iter);

    native static final protected void gtk_tree_store_reorder(Handle treeStore,
            Handle iter, int[] newOrder);

    native static final protected void gtk_tree_store_swap(Handle treeStore,
            Handle iterA, Handle iterB);

    native static final protected void gtk_tree_store_move_before(
            Handle treeStore, Handle iter, Handle position);

    native static final protected void gtk_tree_store_move_after(
            Handle treeStore, Handle iter, Handle position);
}
