import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumnModel;

import javax.swing.Scrollable;
import javax.swing.SwingConstants;

import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Rectangle;

import java.awt.Component;


/** This is not intented for use, just for demonstration (standalone JTableHeader,
    some elementary Scrollable techniques).

    Name is not quite correct, but currently vertical component orientations
    are not supported (where this would a) become a "VerticalHeader", b)
    break because the implementation is not width/height symmetric) and it
    is not really known how vertical mode will somewhen work.

    (C) 2003 Christian Kaufhold
*/
    
public class HorizontalHeader
    extends JTableHeader
    implements Scrollable, SwingConstants
{
    private Object prototype;
    private float viewableColumnCount;


    public HorizontalHeader(TableColumnModel data)
    {
        super(data);
    }



    public Dimension getMinimumSize()
    {
        if (isMinimumSizeSet())
            return super.getMinimumSize();

        return preferredSize_impl();
    }


    public Dimension getMaximumSize()
    {
        if (isMaximumSizeSet())
            return super.getMaximumSize();

        return preferredSize_impl();
    }

    public Dimension getPreferredSize()
    {
        if (isPreferredSizeSet())
            return super.getPreferredSize();

        return preferredSize_impl();
    }


    private Dimension preferredSize_impl()
    {
        Dimension result = new Dimension(super.getPreferredSize());

        Insets n = getInsets();

        // Correct width not to use the preferred widths

        result.width = getColumnModel().getTotalColumnWidth() + n.left + n.right;

        // Correct height to fit the prototype
        
        Component c = getDefaultRenderer().getTableCellRendererComponent
            (null, prototype, false, false, -1, -1);

        add(c);

        result.height = Math.max(result.height, c.getPreferredSize().height + n.top + n.bottom);

        remove(c);

        return result;
    }
    


    // Only plain Scrollable implementation

    public boolean getScrollableTracksViewportWidth()
    {
        return getParent().getWidth() > getPreferredSize().width; // do not underflow
    }

    public boolean getScrollableTracksViewportHeight()
    {
        return getParent().getHeight() > getPreferredSize().height;
    }



    public int getScrollableBlockIncrement(Rectangle r, int orientation, int direction)
    {
        return orientation == VERTICAL
            ? r.height * direction
            : r.width * direction;
    }

    public int getScrollableUnitIncrement(Rectangle r, int orientation, int direction)
    {
        return orientation == VERTICAL
            ? r.height * direction / 10
            : r.width * direction / 10; // arbitrary values
    }


    public Dimension getPreferredScrollableViewportSize()
    {
        Dimension result = preferredSize_impl();

        Insets n = getInsets();

        Component c = getDefaultRenderer().getTableCellRendererComponent
            (null, prototype, false, false, -1, -1);

        add(c);

        result.width = (int)(c.getPreferredSize().width * viewableColumnCount) + n.left + n.right;

        remove(c);

        return result;
    }


    public void setPrototype(Object value)
    {
        prototype = value;

        revalidate(); 
    }


    /** used for determining the viewport size (=default renderer's preferred width for
        this value * viewableColumnCount (+Insets))
        also used as a lower bound for the preferred height (by default renderer's).
        'null' is allowed and will be used anyway.
        
     */
    public final Object prototype()
    {
        return prototype;
    }


    /** requires: value > 0, !isNaN(value). */
    public void setViewableColumnCount(float value)
    {
        if (value == viewableColumnCount)
            return;

        
        viewableColumnCount = value;

        revalidate(); // probably won't matter
    }


    public final float viewableColumnCount()
    {
        return viewableColumnCount;
    }





    public static void main(String[] args)
    {
        TableColumnModel data = new javax.swing.table.DefaultTableColumnModel();

        for (int i = 0; i < args.length; i++)
        {
            javax.swing.table.TableColumn c = new javax.swing.table.TableColumn();
            
            c.setHeaderValue(args[i]);

            data.addColumn(c);
        }

        HorizontalHeader h = new HorizontalHeader(data);

        h.setPrototype("1234567890");
        h.setViewableColumnCount(3);
        
        javax.swing.JFrame f = new javax.swing.JFrame();

        f.getContentPane().add(new javax.swing.JScrollPane(h));

        f.pack(); f.show();
    }
}

