All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.alee.laf.table.TablePainter Maven / Gradle / Ivy

Go to download

WebLaf is a Java Swing Look and Feel and extended components library for cross-platform applications

There is a newer version: 2.2.1
Show newest version
package com.alee.laf.table;

import com.alee.laf.table.ITablePainter;
import com.alee.laf.table.WebTable;
import com.alee.laf.table.WebTableUI;
import com.alee.managers.tooltip.ToolTipProvider;
import com.alee.painter.AbstractPainter;
import com.alee.utils.CompareUtils;

import javax.swing.*;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

/**
 * @author Alexandr Zernov
 */

public class TablePainter extends AbstractPainter implements ITablePainter
{
    /**
     * Listeners.
     */
    protected MouseAdapter mouseAdapter;

    /**
     * Runtime variables.
     */
    protected Point rolloverCell;

    /**
     * Painting variables.
     */
    protected CellRendererPane rendererPane = null;

    @Override
    public void install ( final E c, final U ui )
    {
        super.install ( c, ui );

        // Rollover listener
        mouseAdapter = new MouseAdapter ()
        {
            @Override
            public void mouseMoved ( final MouseEvent e )
            {
                updateMouseover ( e );
            }

            @Override
            public void mouseDragged ( final MouseEvent e )
            {
                updateMouseover ( e );
            }

            @Override
            public void mouseExited ( final MouseEvent e )
            {
                clearMouseover ();
            }

            private void updateMouseover ( final MouseEvent e )
            {
                final Point point = e.getPoint ();
                final Point cell = p ( component.columnAtPoint ( point ), component.rowAtPoint ( point ) );
                if ( cell.x != -1 && cell.y != -1 )
                {
                    if ( !CompareUtils.equals ( rolloverCell, cell ) )
                    {
                        updateRolloverCell ( rolloverCell, cell );
                    }
                }
                else
                {
                    clearMouseover ();
                }
            }

            private void clearMouseover ()
            {
                if ( rolloverCell != null )
                {
                    updateRolloverCell ( rolloverCell, null );
                }
            }

            private void updateRolloverCell ( final Point oldCell, final Point newCell )
            {
                // Updating rollover cell
                rolloverCell = newCell;

                // Updating custom WebLaF tooltip display state
                final ToolTipProvider provider = getToolTipProvider ();
                if ( provider != null )
                {
                    final int oldIndex = oldCell != null ? oldCell.y : -1;
                    final int oldColumn = oldCell != null ? oldCell.x : -1;
                    final int newIndex = newCell != null ? newCell.y : -1;
                    final int newColumn = newCell != null ? newCell.x : -1;
                    provider.hoverCellChanged ( component, oldIndex, oldColumn, newIndex, newColumn );
                }
            }
        };
        component.addMouseListener ( mouseAdapter );
        component.addMouseMotionListener ( mouseAdapter );
    }

    @Override
    public void uninstall ( final E c, final U ui )
    {
        // Removing listeners
        component.removeMouseListener ( mouseAdapter );
        component.removeMouseMotionListener ( mouseAdapter );
        mouseAdapter = null;

        super.uninstall ( c, ui );
    }

    @Override
    public void prepareToPaint ( final CellRendererPane rendererPane )
    {
        this.rendererPane = rendererPane;
    }

    @Override
    public void paint ( final Graphics2D g2d, final Rectangle bounds, final E c, final U ui )
    {
        final Rectangle clip = g2d.getClipBounds ();

        //        Rectangle bounds = table.getBounds();
        // account for the fact that the graphics has already been translated
        // into the table's bounds
        //        bounds.x = bounds.y = 0;

        if ( component.getRowCount () <= 0 || component.getColumnCount () <= 0 ||
                // this check prevents us from painting the entire table
                // when the clip doesn't intersect our bounds at all
                !bounds.intersects ( clip ) )
        {

            paintDropLines ( g2d );
            return;
        }

        final Point upperLeft = clip.getLocation ();
        if ( !ltr )
        {
            upperLeft.x++;
        }

        final Point lowerRight = p ( clip.x + clip.width - ( ltr ? 1 : 0 ), clip.y + clip.height );

        int rMin = component.rowAtPoint ( upperLeft );
        int rMax = component.rowAtPoint ( lowerRight );
        // This should never happen (as long as our bounds intersect the clip,
        // which is why we bail above if that is the case).
        if ( rMin == -1 )
        {
            rMin = 0;
        }
        // If the table does not have enough rows to fill the view we'll get -1.
        // (We could also get -1 if our bounds don't intersect the clip,
        // which is why we bail above if that is the case).
        // Replace this with the index of the last row.
        if ( rMax == -1 )
        {
            rMax = component.getRowCount () - 1;
        }

        int cMin = component.columnAtPoint ( ltr ? upperLeft : lowerRight );
        int cMax = component.columnAtPoint ( ltr ? lowerRight : upperLeft );
        // This should never happen.
        if ( cMin == -1 )
        {
            cMin = 0;
        }
        // If the table does not have enough columns to fill the view we'll get -1.
        // Replace this with the index of the last column.
        if ( cMax == -1 )
        {
            cMax = component.getColumnCount () - 1;
        }

        // Paint the grid.
        paintGrid ( g2d, rMin, rMax, cMin, cMax );

        // Paint the cells.
        paintCells ( g2d, rMin, rMax, cMin, cMax );

        paintDropLines ( g2d );

        rendererPane = null;
    }

    protected void paintDropLines ( final Graphics g )
    {
        final JTable.DropLocation loc = component.getDropLocation ();
        if ( loc == null )
        {
            return;
        }

        final Color color = UIManager.getColor ( "Table.dropLineColor" );
        final Color shortColor = UIManager.getColor ( "Table.dropLineShortColor" );
        if ( color == null && shortColor == null )
        {
            return;
        }

        Rectangle rect;

        rect = getHDropLineRect ( loc );
        if ( rect != null )
        {
            final int x = rect.x;
            final int w = rect.width;
            if ( color != null )
            {
                extendRect ( rect, true );
                g.setColor ( color );
                g.fillRect ( rect.x, rect.y, rect.width, rect.height );
            }
            if ( !loc.isInsertColumn () && shortColor != null )
            {
                g.setColor ( shortColor );
                g.fillRect ( x, rect.y, w, rect.height );
            }
        }

        rect = getVDropLineRect ( loc );
        if ( rect != null )
        {
            final int y = rect.y;
            final int h = rect.height;
            if ( color != null )
            {
                extendRect ( rect, false );
                g.setColor ( color );
                g.fillRect ( rect.x, rect.y, rect.width, rect.height );
            }
            if ( !loc.isInsertRow () && shortColor != null )
            {
                g.setColor ( shortColor );
                g.fillRect ( rect.x, y, rect.width, h );
            }
        }
    }

    protected Rectangle getHDropLineRect ( final JTable.DropLocation loc )
    {
        if ( !loc.isInsertRow () )
        {
            return null;
        }

        int row = loc.getRow ();
        int col = loc.getColumn ();
        if ( col >= component.getColumnCount () )
        {
            col--;
        }

        final Rectangle rect = component.getCellRect ( row, col, true );

        if ( row >= component.getRowCount () )
        {
            row--;
            final Rectangle prevRect = component.getCellRect ( row, col, true );
            rect.y = prevRect.y + prevRect.height;
        }

        if ( rect.y == 0 )
        {
            rect.y = -1;
        }
        else
        {
            rect.y -= 2;
        }

        rect.height = 3;

        return rect;
    }

    protected Rectangle getVDropLineRect ( final JTable.DropLocation loc )
    {
        if ( !loc.isInsertColumn () )
        {
            return null;
        }

        int col = loc.getColumn ();
        Rectangle rect = component.getCellRect ( loc.getRow (), col, true );

        if ( col >= component.getColumnCount () )
        {
            col--;
            rect = component.getCellRect ( loc.getRow (), col, true );
            if ( ltr )
            {
                rect.x = rect.x + rect.width;
            }
        }
        else if ( !ltr )
        {
            rect.x = rect.x + rect.width;
        }

        if ( rect.x == 0 )
        {
            rect.x = -1;
        }
        else
        {
            rect.x -= 2;
        }

        rect.width = 3;

        return rect;
    }

    protected Rectangle extendRect ( final Rectangle rect, final boolean horizontal )
    {
        if ( rect != null )
        {
            if ( horizontal )
            {
                rect.x = 0;
                rect.width = component.getWidth ();
            }
            else
            {
                rect.y = 0;

                if ( component.getRowCount () != 0 )
                {
                    final Rectangle lastRect = component.getCellRect ( component.getRowCount () - 1, 0, true );
                    rect.height = lastRect.y + lastRect.height;
                }
                else
                {
                    rect.height = component.getHeight ();
                }
            }
        }

        return rect;
    }

    /*
     * Paints the grid lines within aRect, using the grid color set with setGridColor. Paints vertical lines
     * if getShowVerticalLines() returns true and paints horizontal lines if getShowHorizontalLines()
     * returns true.
     */
    protected void paintGrid ( final Graphics g, final int rMin, final int rMax, final int cMin, final int cMax )
    {
        g.setColor ( component.getGridColor () );

        final Rectangle minCell = component.getCellRect ( rMin, cMin, true );
        final Rectangle maxCell = component.getCellRect ( rMax, cMax, true );
        final Rectangle damagedArea = minCell.union ( maxCell );

        if ( component.getShowHorizontalLines () )
        {
            final int tableWidth = damagedArea.x + damagedArea.width;
            int y = damagedArea.y;
            for ( int row = rMin; row <= rMax; row++ )
            {
                y += component.getRowHeight ( row );
                g.drawLine ( damagedArea.x, y - 1, tableWidth - 1, y - 1 );
            }
        }
        if ( component.getShowVerticalLines () )
        {
            final TableColumnModel cm = component.getColumnModel ();
            final int tableHeight = damagedArea.y + damagedArea.height;
            int x;
            if ( ltr )
            {
                x = damagedArea.x;
                for ( int column = cMin; column <= cMax; column++ )
                {
                    final int w = cm.getColumn ( column ).getWidth ();
                    x += w;
                    g.drawLine ( x - 1, 0, x - 1, tableHeight - 1 );
                }
            }
            else
            {
                x = damagedArea.x;
                for ( int column = cMax; column >= cMin; column-- )
                {
                    final int w = cm.getColumn ( column ).getWidth ();
                    x += w;
                    g.drawLine ( x - 1, 0, x - 1, tableHeight - 1 );
                }
            }
        }
    }

    protected void paintCells ( final Graphics g, final int rMin, final int rMax, final int cMin, final int cMax )
    {
        final JTableHeader header = component.getTableHeader ();
        final TableColumn draggedColumn = ( header == null ) ? null : header.getDraggedColumn ();

        final TableColumnModel cm = component.getColumnModel ();
        final int columnMargin = cm.getColumnMargin ();

        Rectangle cellRect;
        TableColumn aColumn;
        int columnWidth;
        if ( ltr )
        {
            for ( int row = rMin; row <= rMax; row++ )
            {
                cellRect = component.getCellRect ( row, cMin, false );
                for ( int column = cMin; column <= cMax; column++ )
                {
                    aColumn = cm.getColumn ( column );
                    columnWidth = aColumn.getWidth ();
                    cellRect.width = columnWidth - columnMargin;
                    if ( aColumn != draggedColumn )
                    {
                        paintCell ( g, cellRect, row, column );
                    }
                    cellRect.x += columnWidth;
                }
            }
        }
        else
        {
            for ( int row = rMin; row <= rMax; row++ )
            {
                cellRect = component.getCellRect ( row, cMin, false );
                aColumn = cm.getColumn ( cMin );
                if ( aColumn != draggedColumn )
                {
                    columnWidth = aColumn.getWidth ();
                    cellRect.width = columnWidth - columnMargin;
                    paintCell ( g, cellRect, row, cMin );
                }
                for ( int column = cMin + 1; column <= cMax; column++ )
                {
                    aColumn = cm.getColumn ( column );
                    columnWidth = aColumn.getWidth ();
                    cellRect.width = columnWidth - columnMargin;
                    cellRect.x -= columnWidth;
                    if ( aColumn != draggedColumn )
                    {
                        paintCell ( g, cellRect, row, column );
                    }
                }
            }
        }

        // Paint the dragged column if we are dragging.
        if ( draggedColumn != null )
        {
            paintDraggedArea ( g, rMin, rMax, draggedColumn, header.getDraggedDistance () );
        }

        // Remove any renderers that may be left in the rendererPane.
        rendererPane.removeAll ();
    }

    protected void paintCell ( final Graphics g, final Rectangle cellRect, final int row, final int column )
    {
        if ( component.isEditing () && component.getEditingRow () == row &&
                component.getEditingColumn () == column )
        {
            final Component editor = component.getEditorComponent ();
            editor.setBounds ( cellRect );
            editor.validate ();
        }
        else
        {
            final TableCellRenderer renderer = component.getCellRenderer ( row, column );
            final Component prepareRenderer = component.prepareRenderer ( renderer, row, column );
            rendererPane.paintComponent ( g, prepareRenderer, component, cellRect.x, cellRect.y, cellRect.width, cellRect.height, true );
        }
    }

    protected void paintDraggedArea ( final Graphics g, final int rMin, final int rMax, final TableColumn draggedColumn,
                                      final int distance )
    {
        final int draggedColumnIndex = viewIndexForColumn ( draggedColumn );

        final Rectangle minCell = component.getCellRect ( rMin, draggedColumnIndex, true );
        final Rectangle maxCell = component.getCellRect ( rMax, draggedColumnIndex, true );

        final Rectangle vacatedColumnRect = minCell.union ( maxCell );

        // Paint a gray well in place of the moving column.
        g.setColor ( component.getBackground () );
        g.fillRect ( vacatedColumnRect.x, vacatedColumnRect.y, vacatedColumnRect.width, vacatedColumnRect.height );

        // Move to the where the cell has been dragged.
        vacatedColumnRect.x += distance;

        // Fill the background.
        g.setColor ( component.getBackground () );
        g.fillRect ( vacatedColumnRect.x, vacatedColumnRect.y, vacatedColumnRect.width, vacatedColumnRect.height );

        // Paint the vertical grid lines if necessary.
        if ( component.getShowVerticalLines () )
        {
            g.setColor ( component.getGridColor () );
            final int x1 = vacatedColumnRect.x;
            final int y1 = vacatedColumnRect.y;
            final int x2 = x1 + vacatedColumnRect.width - 1;
            final int y2 = y1 + vacatedColumnRect.height - 1;
            // Left
            g.drawLine ( x1 - 1, y1, x1 - 1, y2 );
            // Right
            g.drawLine ( x2, y1, x2, y2 );
        }

        for ( int row = rMin; row <= rMax; row++ )
        {
            // Render the cell value
            final Rectangle r = component.getCellRect ( row, draggedColumnIndex, false );
            r.x += distance;
            paintCell ( g, r, row, draggedColumnIndex );

            // Paint the (lower) horizontal grid line if necessary.
            if ( component.getShowHorizontalLines () )
            {
                g.setColor ( component.getGridColor () );
                final Rectangle rcr = component.getCellRect ( row, draggedColumnIndex, true );
                rcr.x += distance;
                final int x1 = rcr.x;
                final int y1 = rcr.y;
                final int x2 = x1 + rcr.width - 1;
                final int y2 = y1 + rcr.height - 1;
                g.drawLine ( x1, y2, x2, y2 );
            }
        }
    }

    protected int viewIndexForColumn ( final TableColumn aColumn )
    {
        final TableColumnModel cm = component.getColumnModel ();
        for ( int column = 0; column < cm.getColumnCount (); column++ )
        {
            if ( cm.getColumn ( column ) == aColumn )
            {
                return column;
            }
        }
        return -1;
    }

    /**
     * Returns custom WebLaF tooltip provider.
     *
     * @return custom WebLaF tooltip provider
     */
    protected ToolTipProvider getToolTipProvider ()
    {
        return component != null && component instanceof WebTable ? ( ( WebTable ) component ).getToolTipProvider () : null;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy