package TestTree;

import org.gnu.gtk.CellRenderer;
import org.gnu.gtk.CellRendererText;
import org.gnu.gtk.CellRendererToggle;
import org.gnu.gtk.CheckButton;
import org.gnu.gtk.DataColumn;
import org.gnu.gtk.DataColumnBoolean;
import org.gnu.gtk.DataColumnInt;
import org.gnu.gtk.DataColumnString;
import org.gnu.gtk.Gtk;
import org.gnu.gtk.ListStore;
import org.gnu.gtk.PolicyType;
import org.gnu.gtk.ScrolledWindow;
import org.gnu.gtk.SelectionMode;
import org.gnu.gtk.ShadowType;
import org.gnu.gtk.SortType;
import org.gnu.gtk.TreeIter;
import org.gnu.gtk.TreeIterComparison;
import org.gnu.gtk.TreeModel;
import org.gnu.gtk.TreeModelFilter;
import org.gnu.gtk.TreeModelFilterVisibleMethod;
import org.gnu.gtk.TreeModelSort;
import org.gnu.gtk.TreeSortable;
import org.gnu.gtk.TreeView;
import org.gnu.gtk.TreeViewColumn;
import org.gnu.gtk.TreeViewRowSeparatorMethod;
import org.gnu.gtk.VBox;
import org.gnu.gtk.Window;
import org.gnu.gtk.WindowType;
import org.gnu.gtk.event.LifeCycleEvent;
import org.gnu.gtk.event.LifeCycleListener;
import org.gnu.gtk.event.ToggleEvent;
import org.gnu.gtk.event.ToggleListener;
import org.gnu.gtk.event.TreeViewColumnEvent;
import org.gnu.gtk.event.TreeViewColumnListener;
import org.gnu.gtk.event.TreeViewEvent;
import org.gnu.gtk.event.TreeViewListener;

/**
 * Example program to show the power of GTK's TreeView and TreeModels. This
 * program shows a basic example of using TreeView, ListStore, TreeModelSort and
 * TreeModelFilter classes.
 */
public class TestTree {

    public static final Object[][] DATA = {
            { "Pro", new Integer(111), Boolean.TRUE, "2004-05-12" },
            { "Amateur", new Integer(444), Boolean.FALSE, "2004-05-11" },
            { "Beginner", new Integer(111), Boolean.TRUE, "2004-05-10" },
            { "Pro", new Integer(555), Boolean.FALSE, "2004-05-09" },
            { "Amateur", new Integer(222), Boolean.TRUE, "2004-05-08" },
            { "Beginner", new Integer(666), Boolean.FALSE, "2004-05-07" },
            { "Null!", new Integer(333), Boolean.TRUE, null },

            { "Pro", new Integer(1111), Boolean.FALSE, "2004-06-12" },
            { "Amateur", new Integer(4444), Boolean.TRUE, "2004-06-11" },
            { "Beginner", new Integer(1111), Boolean.FALSE, "2004-06-10" },
            { "Pro", new Integer(5555), Boolean.TRUE, "2004-06-09" },
            { "Amateur", new Integer(2222), Boolean.FALSE, "2004-06-08" },
            { "Beginner", new Integer(6666), Boolean.TRUE, "2004-06-07" },

            { "Amateur", new Integer(11), Boolean.TRUE, "2004-04-01" },
            { "Pro", new Integer(44), Boolean.FALSE, "2004-04-02" },
            { "Pro", new Integer(11), Boolean.TRUE, "2004-04-03" },
            { "Beginner", new Integer(55), Boolean.FALSE, "2004-04-04" },
            { "Beginner", new Integer(22), Boolean.TRUE, "2004-04-05" },
            { "Amateur", new Integer(66), Boolean.FALSE, "2004-04-06" },
            { "Null!", new Integer(999), Boolean.FALSE, null },

            { "Beginner", new Integer(11111), Boolean.FALSE, "2005-01-32" },
            { "Amateur", new Integer(44444), Boolean.FALSE, "2005-01-33" },
            { "Pro", new Integer(11111), Boolean.FALSE, "2005-01-34" },
            { "Beginner", new Integer(55555), Boolean.TRUE, "2005-01-35" },
            { "Amateur", new Integer(22222), Boolean.TRUE, "2005-01-36" },
            { "Pro", new Integer(66666), Boolean.FALSE, "2005-01-37" } };

    private TreeView treeWidget;

    private ListStore store;

    private TreeModelFilter filter;

    private TreeModelSort sortable;

    private DataColumnString dataString;

    private DataColumnInt dataInt;

    private DataColumnBoolean dataBool;

    private DataColumnString dataString2;

    private CheckButton ckfilter;

    public static void main(String[] argv) {
        Gtk.init(argv);
        TestTree tt = new TestTree();
        Gtk.main();
    }

    public TestTree() {
        Window window = new Window(WindowType.TOPLEVEL);
        window.setTitle("Test Tree");
        window.setDefaultSize(320, 500);
        window.addListener(new Life());

        // Construct the tree view widget.
        treeWidget = new TreeView();
        treeWidget.setAlternateRowColor(true);
        treeWidget.getSelection().setMode(SelectionMode.BROWSE);
        treeWidget.addListener(new TreeViewListener() {
            public void treeViewEvent(TreeViewEvent event) {
                if (event.isOfType(TreeViewEvent.Type.ROW_ACTIVATED)) {
                    System.out.println("activated");
                }
            }
        });
        // Create a ScorlledWindow to hold the TreeView.
        ScrolledWindow scroll = new ScrolledWindow();
        scroll.setShadowType(ShadowType.NONE);
        scroll.setPolicy(PolicyType.AUTOMATIC, PolicyType.AUTOMATIC);
        scroll.add(treeWidget);
        // Create the filter check box.
        ckfilter = new CheckButton("Filter booleans?", false);
        ckfilter.addListener(new CheckFilterListener());
        // Create a VBox to hold the treeview and checkbutton.
        VBox box = new VBox(false, 5);
        box.packStart(scroll, true, true, 5);
        box.packStart(ckfilter, false, false, 5);

        //
        // Create the treemodel.
        // 

        // Make some data blocks to refer to the data for the tree.
        dataString = new DataColumnString();
        dataInt = new DataColumnInt();
        dataBool = new DataColumnBoolean();
        dataString2 = new DataColumnString();
        // Construct a new list store for the data of the tree.
        store = new ListStore(new DataColumn[] { dataString, dataInt, dataBool,
                dataString2 });
        addData(DATA);
        // Create a filter to show only selected data.
        filter = new TreeModelFilter(store);
        // Set to filter the visible column.
        // filter.setVisibleColumn( dataBool );
        // Set to filter using a specific filter class.
        filter.setVisibleMethod(new TreeFilter());
        // Create a tree model sorter on top of the filtered list.
        sortable = new TreeModelSort(filter);
        // Set the view to be the filtered-sorted list.
        treeWidget.setModel(sortable);
        // Set to display the dataBool=false rows as separators.
        // treeWidget.setRowSeparatorMethod( new RowSeparator() );

        // Create the Type column.
        TreeViewColumn column = new TreeViewColumn();
        column.setTitle("Type");
        column.setResizable(true);
        column.setReorderable(true);
        column.setClickable(true);
        treeWidget.appendColumn(column);
        CellRenderer renderer = new CellRendererText();
        column.packStart(renderer, true);
        column.addAttributeMapping(renderer, CellRendererText.Attribute.TEXT,
                dataString);
        column.addListener(new SortedColumnListener(dataString, sortable));
        sortable.setSortMethod(new TypeColumn(), dataString);

        // Create the Number column.
        column = new TreeViewColumn();
        column.setTitle("Number");
        column.setResizable(true);
        column.setReorderable(true);
        column.setClickable(true);
        treeWidget.appendColumn(column);
        renderer = new CellRendererText();
        column.packStart(renderer, true);
        column.addAttributeMapping(renderer, CellRendererText.Attribute.TEXT,
                dataInt);
        column.addListener(new SortedColumnListener(dataInt, sortable));
        sortable.setSortMethod(new NumberColumn(), dataInt);

        // Create the Boolean column.
        column = new TreeViewColumn();
        column.setTitle("Boolean");
        column.setResizable(true);
        column.setReorderable(true);
        column.setClickable(true);
        treeWidget.appendColumn(column);
        renderer = new CellRendererToggle();
        column.packStart(renderer, true);
        column.addAttributeMapping(renderer,
                CellRendererToggle.Attribute.ACTIVE, dataBool);

        // Create the Timestamp column.
        column = new TreeViewColumn();
        column.setTitle("Date");
        column.setResizable(true);
        column.setReorderable(true);
        column.setClickable(true);
        treeWidget.appendColumn(column);
        renderer = new CellRendererText();
        column.packStart(renderer, true);
        column.addAttributeMapping(renderer, CellRendererText.Attribute.TEXT,
                dataString2);
        column.addListener(new SortedColumnListener(dataString2, sortable));
        sortable.setSortMethod(new TimestampColumn(), dataString2);

        window.add(box);
        window.showAll();
    }

    protected void addData(Object[][] data) {
        Object[] row = null;
        TreeIter iter = null;

        for (int i = 0; i < data.length; i++) {
            iter = store.appendRow();
            row = data[i];
            store.setValue(iter, dataString, (String) row[0]);
            store.setValue(iter, dataInt, ((Integer) row[1]).intValue());
            store.setValue(iter, dataBool, ((Boolean) row[2]).booleanValue());
            store.setValue(iter, dataString2, (String) row[3]);
        }
    }

    protected class RowSeparator implements TreeViewRowSeparatorMethod {
        public boolean isSeparator(TreeModel model, TreeIter iter) {
            return !model.getValue(iter, dataBool);
        }
    }

    protected class CheckFilterListener implements ToggleListener {
        public void toggleEvent(ToggleEvent event) {
            // Re-filter the list.
            filter.refilter();
        }
    }

    protected class TreeFilter implements TreeModelFilterVisibleMethod {
        public boolean filter(TreeModel model, TreeIter iter) {
            // This is a simple filter.
            // Check if the filter toggle has been selected.
            if (ckfilter.getState()) {
                // If it has then filter this row based on the boolean
                // field of the model.
            	return model.getValue(iter, dataBool);
            } else {
                // If the toggle has not been selected, no filtering is
                // performed.
                return true;
            }
        }
    }

    /**
     * Listen for events on the column headers. Change the sorting based on
     * these events.
     */
    protected class SortedColumnListener implements TreeViewColumnListener {
        private DataColumn column;

        private TreeSortable store;

        public SortedColumnListener(DataColumn column, TreeSortable store) {
            this.column = column;
            this.store = store;
        }

        public void columnClickedEvent(TreeViewColumnEvent event) {
            SortType type = SortType.ASCENDING;
            DataColumn sorted = store.getSortColumn();
            if (sorted != null) {
                if (sorted.equals(column)) {
                    type = store.getSortOrder();
                    if (type.equals(SortType.ASCENDING)) {
                        type = SortType.DESCENDING;
                    } else {
                        type = SortType.ASCENDING;
                    }
                }
            }
            store.setSortColumn(column, type);
        }
    }

    protected class TypeColumn implements TreeIterComparison {
        public int compareTreeIters(TreeModel store, TreeIter a, TreeIter b) {
            String as = store.getValue(a, dataString);
            String bs = store.getValue(b, dataString);
            return as.compareTo(bs);
        }
    }

    protected class NumberColumn implements TreeIterComparison {
        public int compareTreeIters(TreeModel store, TreeIter a, TreeIter b) {
            Integer as = new Integer(store.getValue(a, dataInt));
            Integer bs = new Integer(store.getValue(b, dataInt));
            return as.compareTo(bs);
        }
    }

    protected class TimestampColumn implements TreeIterComparison {
        public int compareTreeIters(TreeModel store, TreeIter a, TreeIter b) {
            String as = store.getValue(a, dataString2);
            String bs = store.getValue(b, dataString2);
            return as.compareTo(bs);
        }
    }

    protected class Life implements LifeCycleListener {
        public void lifeCycleEvent(LifeCycleEvent event) {
        }

        public boolean lifeCycleQuery(LifeCycleEvent event) {
            if (event.isOfType(LifeCycleEvent.Type.DESTROY)
                    || event.isOfType(LifeCycleEvent.Type.DELETE)) {
                Gtk.mainQuit();
            }
            return false;
        }
    }
}
