Package simplesheet

Source Code of simplesheet.SheetTableUI

/*
* (swing1.1beta3)
*
*/
package simplesheet;

import java.awt.event.KeyEvent;
import java.util.Iterator;
import javax.swing.border.Border;
import simplesheet.model.column.Column;
import simplesheet.model.selection.CellPosition;
import simplesheet.model.CellRenderer;
import simplesheet.model.SheetModel;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.HashSet;
import javax.swing.*;
import javax.swing.plaf.ComponentUI;
import simplesheet.model.column.ColumnListener;
import simplesheet.model.row.Row;
import simplesheet.model.row.RowListener;
import simplesheet.model.selection.SheetSelectionModel;

/**
* @version 1.0 11/26/98
*/
class SheetTableUI extends ComponentUI {

    private SheetTable table;
    private MyMouse mouseListener = new MyMouse();
    private MyKeyboard keyboardListener = new MyKeyboard();

    private ColumnListener localColumnsListener = new ColumnsListener();
    private RowListener localRowsListener = new RowsListener();

    private HashSet<Integer> recalcCols = new HashSet<Integer>();
    private HashSet<Integer> recalcRows = new HashSet<Integer>();


    public SheetTable getTable() {
        return table;
    }

    public void setTable(SheetTable table) {
        this.table = table;
        SheetModel model = table.getModel();
        for(int i=0; i<model.getRowCount(); i++) {
            model.getRow(i).addRowListener(localRowsListener);
        }
        for(int i=0; i<model.getColumnCount(); i++) {
            model.getColumn(i).addColumnListener(localColumnsListener);
        }
    }

    @Override
    public void installUI(JComponent c) {
        if(c instanceof SheetTable == false) {
            throw new IllegalArgumentException(getClass().getSimpleName()
                    + " can only be used in conjuction with object instance of  "
                    + SheetTable.class.getSimpleName());
        }
        super.installUI(c);
        c.addMouseListener(mouseListener);
        c.addMouseMotionListener(mouseListener);
        c.addKeyListener(keyboardListener);
    }

    @Override
    public void uninstallUI(JComponent c) {
        c.removeMouseListener(mouseListener);
        c.removeMouseMotionListener(mouseListener);
        c.removeKeyListener(keyboardListener);
        table = null;
    }

    private class Spanned {
        public int rows;
        public int cols;
        public int width;

        public Spanned(int rows, int cols, int width) {
            this.rows = rows;
            this.cols = cols;
            this.width = width;
        }
    }

    @Override
    public void paint(Graphics g, JComponent c) {
        recalcDimension(g);

        Color oldColor = g.getColor();
        Rectangle oldRc = g.getClipBounds();

        Insets borderInsets = null;
        Border border = table.getBorder();
        if(border != null) {
            borderInsets = border.getBorderInsets(table);
        } else {
            borderInsets = new Insets(0, 0, 0, 0);
        }
        Rectangle clipRc = fixRectangle(oldRc, borderInsets);

        //calc rectangle
        SheetModel model = table.getModel();
        CellPosition origin0 = getTopLeft(clipRc);
        CellPosition originN = getBottomRight(clipRc);
        if(origin0 == null || originN == null) {
            //no cells
            return;
        }
       
        int yBase = borderInsets.top;
        for (int iRow = 0; iRow < origin0.row; iRow++) {
            yBase += model.getRow(iRow).getHeight();
        }
        int xBase = borderInsets.left;
        for (int iCol = 0; iCol < origin0.col; iCol++) {
            xBase += model.getColumn(iCol).getWidth();
        }

        Spanned spanned[] = new Spanned[originN.col - origin0.col + 1];

        for (int iRow = origin0.row; iRow <= originN.row; iRow++) {
            int xLocalBase = xBase;
            for (int iCol = origin0.col; iCol <= originN.col; ) { /// increment at end
                //check if spanned
                int index = iCol - origin0.col;
                if(spanned[index] != null) {
                   spanned[index].rows--;
                   iCol += spanned[index].cols;
                   xLocalBase += spanned[index].width;

                   if(spanned[index].rows == 0) {
                       spanned[index] = null;
                   }
                   continue;
                }
               
                //define dimensions
                CellPosition origin = model.getOrigin(new CellPosition(iRow, iCol));
                Dimension size = model.getSize(origin);
                Rectangle rc = new Rectangle();
                //y offset for spanned cells may be > 0
                rc.y = yBase;
                for(int i=0; i < iRow-origin.row; i++) {
                    rc.y -= model.getRow(origin.row + i).getHeight();
                }
                //x offset for spanned cells may be > 0
                rc.x = xLocalBase;
                for(int i=0; i < iCol-origin.col; i++) {
                    rc.x -= model.getColumn(origin.col + i).getWidth();
                }
                //define cell width
                rc.width = 0;
                for (int i = 0; i < size.width; i++) {
                    rc.width += model.getColumn(origin.col + i).getWidth();
                }
                //define  cell height
                rc.height = 0;
                for (int i = 0; i < size.height; i++) {
                    rc.height += model.getRow(origin.row + i).getHeight();
                }

                if(clipRc.intersects(rc)) {
                    //paint cell
                    g.setClip(clipRc.createIntersection(rc));
                    paintCell(g, rc, origin);

                    //update span info
                    int yLeft = (origin.row + size.height) - iRow;
                    if(yLeft > 1) {
                        int xLeft = (origin.col + size.width) - iCol;
                        spanned[index] = new Spanned(yLeft-1, xLeft, rc.width);
                    }
                }
                //update current position
                iCol += size.width;
                xLocalBase += rc.width;
            }
            //update current position
            yBase += model.getRow(iRow).getHeight();
        }
        g.setColor(oldColor);
        g.setClip(oldRc);
    }

    /**
     * make clip smaller than table
     * @param rc
     * @return
     */
    private Rectangle fixRectangle(Rectangle paintRc, Insets insets) {
        Rectangle visibleRc = table.getVisibleRect();
        Rectangle fixRc = new Rectangle();
        fixRc.x = Math.max(visibleRc.x + insets.left, paintRc.x);
        fixRc.y = Math.max(visibleRc.y + insets.top, paintRc.y);
        fixRc.width = paintRc.width;
        if(paintRc.x + paintRc.width > visibleRc.x + visibleRc.width) {
            fixRc.width -= (paintRc.x + paintRc.width) - (visibleRc.x + visibleRc.width);
        }
        fixRc.height = paintRc.height;
        if(paintRc.y + paintRc.height > visibleRc.y + visibleRc.height) {
            fixRc.width -= (paintRc.y + paintRc.height) - (visibleRc.y + visibleRc.height);
        }
        return fixRc;
    }

    /**
     *
     * @param rc
     * @return nearest cell in top left rect point, or null if no cell specified
     */
    private CellPosition getTopLeft(Rectangle rc) {
        Point topLeft = new Point(rc.x, rc.y);
        CellPosition pos = table.getCellAtPoint(topLeft);
        if(pos == null) {
            return null;
        }
        return table.getModel().getOrigin(pos);
    }


    /**
     *
     * @param rc
     * @return nearest cell in bottom right rect point, or null if no cell specified
     */
    private CellPosition getBottomRight(Rectangle rc) {
        Point bottomLeft = new Point(rc.x + rc.width, rc.y + rc.height);
        CellPosition pos = table.getCellAtPoint(bottomLeft);
        if(pos == null) {
            return null;
        }
        SheetModel model = table.getModel();
        CellPosition originN = model.getOrigin(pos);
        Dimension sizeN = model.getSize(originN);
        return new CellPosition(originN.row + sizeN.height-1, originN.col + sizeN.width-1);
    }

   
    private void paintCell(Graphics g, Rectangle cellRect, CellPosition pos) {
        CellPosition editingCell = table.getEditingCell();
        if (editingCell != null && editingCell.equals(pos)) {
            Component component = table.getEditorComponent();
            component.setBounds(cellRect);
            component.validate();
        } else {
            drawGrid(g, cellRect);

            CellRenderer renderer = table.getDefaultRenderer();
            Component component  = table.prepareRenderer(renderer, pos);
            component.setBounds(cellRect);

            component.paint(g);
        }
    }


    private void drawGrid(Graphics g, Rectangle cellRect) {
        Color c = g.getColor();
        g.setColor(table.getDefaultBackgroundColor());
        g.fillRect(cellRect.x, cellRect.y, cellRect.width, cellRect.height);

        g.setColor(table.getGridColor());
        //g.clearRect(cellRect.x, cellRect.y, cellRect.width - 1, cellRect.height - 1);
        int bottom = cellRect.y + cellRect.height - 1;
        int right = cellRect.x + cellRect.width - 1;
        g.drawPolyline(
                new int[]{cellRect.x,   right,      right    },
                new int[]{bottom,       bottom,     cellRect.y},
                3);
        g.setColor(c);
    }


    private void recalcDimension(Graphics g) {
        SheetModel model = table.getModel();
        Iterator<Integer> it = recalcCols.iterator();
        while(it.hasNext()) {
            int index = it.next();
            Column col = model.getColumn(index);
            if(col.isForceRecalcWidth()) {
                recalcColWidth(g, index);
            }
        }
        recalcCols.clear();
        it = recalcRows.iterator();
        while(it.hasNext()) {
            int index = it.next();
            Row row = model.getRow(index);
            if(row.isForceRecalcHeight()) {
                recalcRowHeight(g, index);
            }
        }
        recalcRows.clear();
    }

    /**
     * calculates column width
     * @param g
     * @param iCol
     */
    private void recalcColWidth(Graphics g, int iCol) {
        int maxWidth = 0;
        SheetModel model = table.getModel();
        CellRenderer renderer = table.getDefaultRenderer();
        for(int iRow=0; iRow<model.getRowCount(); /* ath the end*/) {
            CellPosition pos = model.getOrigin(new CellPosition(iRow, iCol));
            Dimension size = model.getSize(pos);
            if(size.height > 1 || size.width > 1) {
                iRow += size.height;
                continue;
            }
            int iWidth = renderer.getPreferredWidth(table, g, model.getValueAt(pos));
            if(iWidth > maxWidth) {
                maxWidth = iWidth;
            }
            iRow++;
        }
        Column column = model.getColumn(iCol);
        if(maxWidth < column.getMinWidth()) {
            column.setWidth(column.getMinWidth());
        } else if(maxWidth  == 0) {
            //min width may be zero
            column.setDefaultWidth();
        } else if(maxWidth > column.getMaxWidth()) {
            column.setWidth(column.getMaxWidth());
        } else {
            column.setWidth(maxWidth);
        }
    }

    private void recalcRowHeight(Graphics g, int iRow) {
        int maxHeight = 0;
        SheetModel model = table.getModel();
        CellRenderer renderer = table.getDefaultRenderer();
        for(int iCol=0; iCol<model.getColumnCount(); /* ath the end*/) {
            CellPosition pos = model.getOrigin(new CellPosition(iRow, iCol));
            Dimension size = model.getSize(pos);
            if(size.height > 1 || size.width > 1) {
                iCol += size.width;
                continue;
            }
            int width = model.getColumn(iCol).getWidth();
            int iHeight = renderer.getPreferredHeight(table, g, model.getValueAt(pos), width);
            if(iHeight > maxHeight) {
                maxHeight = iHeight;
            }
            iCol++;
        }
        Row row = model.getRow(iRow);
        if(maxHeight < row.getMinHeight()) {
            row.setHeight(row.getMinHeight());
        } else if(maxHeight  == 0) {
            //min width may be zero
            row.setDefaultHeight();
        } else if(maxHeight > row.getMaxHeight()) {
            row.setHeight(row.getMaxHeight());
        } else {
            row.setHeight(maxHeight);
        }
    }

    /**
     *
     * @param c
     * @return
     */
    @Override
    public Dimension getMaximumSize(JComponent c) {
        return new Dimension(65000, 65000);
    }

    private Dimension getBorderedDimensions(JComponent c) {
        Border border = c.getBorder();
        Dimension res = new Dimension();
        if(border != null) {
            Insets insets = border.getBorderInsets(c);
            res.height += insets.top + insets.bottom;
            res.width += insets.left + insets.right;
        }
        return res;
    }
   
    /**
     *
     * @param c
     * @return
     */
    @Override
    public Dimension getMinimumSize(JComponent c) {
        SheetModel model = table.getModel();
        Dimension res = getBorderedDimensions(c);
        for(int i=0; i<model.getRowCount(); i++) {
            res.height += model.getRow(i).getMinHeight();
        }
        for(int i=0; i<model.getColumnCount(); i++) {
            res.width += model.getColumn(i).getMinWidth();
        }
        return res;
    }

    @Override
    public Dimension getPreferredSize(JComponent c) {
        SheetModel model = table.getModel();
        Dimension res = getBorderedDimensions(c);
        for(int i=0; i<model.getRowCount(); i++) {
            res.height += model.getRow(i).getHeight();
        }
        for(int i=0; i<model.getColumnCount(); i++) {
            res.width += model.getColumn(i).getWidth();
        }
        return res;
    }

    private class MyKeyboard extends KeyAdapter {
        @Override
        public void keyPressed(KeyEvent e) {
            if(table.getEditingCell() != null) {
                return;
            }
            SheetSelectionModel sm = table.getSelectionModel();
            if(sm.isSelectionEmpty() || sm.getValueIsAdjusting()) {
               return;
            }
            CellPosition lead = getNextLead(e, sm.getLead());
            if(lead == null) {
                return;
            }
            CellPosition ankor = null;
            if((e.getModifiersEx() & KeyEvent.SHIFT_DOWN_MASK) > 0) {
                ankor = sm.getAnchor();
            } else {
                ankor = lead;
            }
            sm.setSelectionInterval(ankor, lead);
        }

        private CellPosition getNextLead(KeyEvent e, CellPosition lead) {
            SheetModel model = table.getModel();
            lead = model.getOrigin(lead);
            switch(e.getKeyCode()) {
                case KeyEvent.VK_DOWN : {
                    Dimension size = model.getSize(lead);
                    if(lead.row + size.height < model.getRowCount()) {
                        return model.getOrigin(new CellPosition(lead.row+size.height, lead.col));
                    }
                    break;
                }
                case KeyEvent.VK_UP : {
                    if(lead.row -1 >= 0) {
                        return model.getOrigin(new CellPosition(lead.row-1, lead.col));
                    }
                    break;
                }
                case KeyEvent.VK_RIGHT : {
                    Dimension size = model.getSize(lead);
                    if(lead.col + size.width < model.getColumnCount()) {
                        return model.getOrigin(new CellPosition(lead.row, lead.col+size.width));
                    }
                    break;
                }
                case KeyEvent.VK_LEFT : {
                    if(lead.col - 1 >= 0) {
                        return model.getOrigin(new CellPosition(lead.row, lead.col-1));
                    }
                    break;
                }
            }
            return null;
        }
    }

    private class MyMouse extends MouseAdapter {
        @Override
        public void mousePressed(MouseEvent e) {
            table.requestFocus();
            SheetSelectionModel semod = table.getSelectionModel();
            CellPosition pos = table.getCellAtPoint(e.getPoint());
            if(pos == null) {
                return;
            }
            pos = table.getModel().getOrigin(pos);
            if(!semod.getValueIsAdjusting()) {
                semod.setValueIsAdjusting(true);
                semod.setSelectionInterval(pos, pos);
            } else {
                semod.addSelectionInterval(pos);
            }
        }

        @Override
        public void mouseReleased(MouseEvent e) {
            SheetSelectionModel semod = table.getSelectionModel();
            semod.setValueIsAdjusting(false);
        }

        @Override
        public void mouseDragged(MouseEvent e) {
            SheetSelectionModel semod = table.getSelectionModel();
            CellPosition pos = table.getCellAtPoint(e.getPoint());
            if(pos == null) {
                return;
            }
            if(semod.getValueIsAdjusting()) {
                semod.addSelectionInterval(pos);
            }
        }
    }


    /**
     *
     */
    private class ColumnsListener implements ColumnListener {
        @Override
        public void widthChanged(int index) {}
        @Override
        public void recalcNeeded(int index) {
            recalcCols.add(index);
        }
    }

    /**
     *
     */
    private class RowsListener implements RowListener {
        @Override
        public void heightChanged(int index) {}
        @Override
        public void recalcNeeded(int index) {
            recalcRows.add(index);
        }
    }
}
TOP

Related Classes of simplesheet.SheetTableUI

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.