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, (int)((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.
                if ( model.getValue( iter, dataBool ) ) {
                    return true;
                } else {
                    return false;
                }
            } 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;
        }
    }
}
