/*
* (swing1.1beta3)
*
*/
package simplesheet;
import simplesheet.model.CellRenderer;
import simplesheet.model.defaults.DefaultCellRenderer;
import simplesheet.model.cell.TableCell;
import simplesheet.model.SheetModel;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.plaf.ComponentUI;
import simplesheet.model.selection.CellPosition;
import simplesheet.model.SheetModelListener;
import simplesheet.model.selection.DefaultSheetSelectionModel;
import simplesheet.model.selection.SheetSelectionEvent;
import simplesheet.model.selection.SheetSelectionListener;
import simplesheet.model.selection.SheetSelectionModel;
/**
* @version 1.0 11/26/98
*/
public class SheetTable extends JComponent {
public static final int WRONG_INDEX = -1;
private SheetSelectionModel selectionModel;
private SheetModel model;
private CellRenderer defaultRenderer;
private Color gridColor = Color.GRAY;
private Color defaultBackgroundColor = Color.WHITE;
private SheetModelListener modelListener = new ModelListener();
private SheetSelectionListener selectionListener = new SelectionListener();
/**
*
* @param model
*/
public SheetTable(SheetModel model) {
this.model = model;
setUI(new SheetTableUI());
setDefaultRenderer(new DefaultCellRenderer());
setSelectionModel(new DefaultSheetSelectionModel());
model.addSheetModelListener(modelListener);
}
private void setDefaultRenderer(CellRenderer sheetRenderer) {
defaultRenderer = sheetRenderer;
}
public CellRenderer getDefaultRenderer() {
return defaultRenderer;
}
public Color getDefaultBackgroundColor() {
return defaultBackgroundColor;
}
public void setDefaultBackgroundColor(Color defauiltBackgroundColor) {
this.defaultBackgroundColor = defauiltBackgroundColor;
}
public JComponent getEditorComponent() {
return null;
}
public SheetSelectionModel getSelectionModel() {
return selectionModel;
}
@Override
public void repaint(long tm, int x, int y, int width, int height) {
super.repaint(tm, x, y, width, height);
}
@Override
public void repaint(Rectangle r) {
super.repaint(r);
}
public void setSelectionModel(SheetSelectionModel selectionModel) {
if (this.selectionModel != null) {
this.selectionModel.removeSheetSelectionListener(selectionListener);
}
selectionModel.addSheetSelectionListener(selectionListener);
this.selectionModel = selectionModel;
selectionModel.setMaxColumnIndex(model.getColumnCount()-1);
selectionModel.setMaxRowIndex(model.getRowCount()-1);
}
@Override
protected void setUI(ComponentUI newUI) {
if (newUI instanceof SheetTableUI == false) {
newUI = new SheetTableUI();
}
((SheetTableUI) newUI).setTable(this);
super.setUI(newUI);
}
@Override
public String getUIClassID() {
return SheetTableUI.class.getSimpleName();
}
@Override
public void updateUI() {
setUI((SheetTableUI) UIManager.getUI(this));
}
public void setModel(SheetModel model) {
model.addSheetModelListener(modelListener);
this.model = model;
selectionModel.setMaxColumnIndex(model.getColumnCount()-1);
selectionModel.setMaxRowIndex(model.getRowCount()-1);
}
public SheetModel getModel() {
return model;
}
protected int getRowAtPoint(Point point, Insets borderInsets) {
if (point.y < borderInsets.top) {
return 0;
}
int y = borderInsets.top;
for (int iRow = 0; iRow < model.getRowCount(); iRow++) {
y += model.getRow(iRow).getHeight();
if (y > point.y) {
return iRow;
}
}
return model.getRowCount() - 1;
}
protected int getColumnAtPoint(Point point, Insets borderInsets) {
if (point.x < borderInsets.left) {
return 0;
}
int x = borderInsets.left;
for (int iCol = 0; iCol < model.getColumnCount(); iCol++) {
x += model.getColumn(iCol).getWidth();
if (x > point.x) {
return iCol;
}
}
return model.getColumnCount() - 1;
}
/**
*
* @param point
* @return nearest cell, or null if no cell in table
*/
public CellPosition getCellAtPoint(Point point) {
if(model.getRowCount() == 0 || model.getColumnCount() == 0) {
return null;
}
Insets borderInsets = null;
Border border = getBorder();
if(border != null) {
borderInsets = border.getBorderInsets(this);
} else {
borderInsets = new Insets(0, 0, 0, 0);
}
int colPos = getColumnAtPoint(point, borderInsets);
int rowPos = getRowAtPoint(point, borderInsets);
return new CellPosition(rowPos, colPos);
}
public Color getGridColor() {
return gridColor;
}
public void setGridColor(Color gridColor) {
this.gridColor = gridColor;
}
public Component prepareRenderer(CellRenderer renderer, CellPosition pos) {
TableCell value = model.getValueAt(pos);
CellPosition lead = selectionModel.getLead();
boolean focused = (lead != null) && pos.equals(lead) ? true : false;
return renderer.getSheetCellRendererComponent(this, value,
selectionModel.isSelected(pos), focused);
}
public CellPosition getEditingCell() {
return null;
}
public Rectangle getCellRect(CellPosition pos) {
CellPosition origin = model.getOrigin(pos);
if(origin == null) {
return null;
}
Insets borderInsets = null;
Border border = getBorder();
if(border != null) {
borderInsets = border.getBorderInsets(this);
} else {
borderInsets = new Insets(0, 0, 0, 0);
}
Rectangle rc = new Rectangle();
rc.y = borderInsets.top;
for (int iRow = 0; iRow < origin.row; iRow++) {
rc.y += model.getRow(iRow).getHeight();
}
rc.x = borderInsets.left;
for (int iCol = 0; iCol < origin.col; iCol++) {
rc.x += model.getColumn(iCol).getWidth();
}
Dimension size = model.getSize(origin);
for (int iRow = 0; iRow < size.height; iRow++) {
rc.height += model.getRow(origin.row + iRow).getHeight();
}
for (int iCol = 0; iCol < size.width; iCol++) {
rc.width += model.getColumn(origin.col + iCol).getWidth();
}
return rc;
}
@Override
public boolean isFocusTraversable() {
return true;
}
private class ModelListener implements SheetModelListener {
@Override
public void cellUpdated(CellPosition pos) {
Rectangle rc = getCellRect(pos);
if(rc != null) {
repaint(rc.x, rc.y, rc.width, rc.height);
}
}
@Override
public void dataChanged() {
repaint();
}
}
private class SelectionListener implements SheetSelectionListener {
@Override
public void valueChanged(SheetSelectionEvent e) {
Rectangle prevSelRc = null;
if(e.isPrevousSelected()) {
prevSelRc = getRect(e.getOldAnkor(), e.getOldLead());
}
Rectangle selRc = null;
if (!selectionModel.isSelectionEmpty()) {
selRc = getRect(selectionModel.getAnchor(), selectionModel.getLead());
}
if(prevSelRc != null
&& selRc != null
&& prevSelRc.intersects(selRc)) {
repaint(prevSelRc.union(selRc));
} else {
if(prevSelRc != null) {
repaint(prevSelRc);
}
if(selRc != null) {
repaint(selRc);
}
}
}
private Rectangle getRect(CellPosition ankor, CellPosition lead) {
Rectangle rc = null;
if (ankor.equals(lead)) {
rc = getCellRect(ankor);
} else {
int minCol = Math.min(ankor.col, lead.col);
int maxCol = Math.max(ankor.col, lead.col);
int minRow = Math.min(ankor.row, lead.row);
int maxRow = Math.max(ankor.row, lead.row);
rc = getRowRect(minCol, maxCol, ankor.row);
if(lead.row != ankor.row) {
rc = rc.union(getRowRect(minCol, maxCol, lead.row));
}
rc = rc.union(getColRect(minRow, maxRow, ankor.col));
if(ankor.col != lead.col) {
rc = rc.union(getColRect(minRow, maxRow, lead.col));
}
}
return rc;
}
private Rectangle getRowRect(int a, int b, int row) {
Rectangle rc = new Rectangle();
for(int i=a; i<=b; i++) {
rc = rc.union(getCellRect(new CellPosition(row, i)));
}
return rc;
}
private Rectangle getColRect(int a, int b, int col) {
Rectangle rc = new Rectangle();
for(int i=a; i<=b; i++) {
rc = rc.union(getCellRect(new CellPosition(i, col)));
}
return rc;
}
}
}