/* Copyright (C) 2000, 2001, Geert Vernaeve. All Rights Reserved. */
package gve.calc.formula;
import java.awt.*;
import java.util.Hashtable;
// PENDING: maybe also store baselines of components in a HashTable?
// PENDING: the hashtable never forgets added components, even if they are
// removed forever.
public class TabularLayout implements LayoutManager2 {
int [] colWidth;
int [] rowHeight;
int [] rowBaseLine;
int rows,cols;
private Container target;
private Hashtable preferredSizes = new Hashtable();
Pixels of space between rows |
public static int VSPACE = 5;
Pixels of space between columns |
public int HSPACE = 5;
public final static byte LEFT = 0;
public final static byte CENTER = 1;
public final static byte RIGHT = 2;
HGAP pixels to the left and right of the matrix are used for painting the delimiters |
private int hgap = 0,vgap = 0;
public TabularLayout(int rows,int cols) {
this.rows = rows;
this.cols = cols;
}
public void setRows(int rows) {
this.rows = rows;
forgetData();
}
public void setCols(int cols) {
this.cols = cols;
forgetData();
}
private void forgetData() {
colWidth = null;
rowHeight = null;
rowBaseLine = null;
}
public int getRowHeight(int row) { return getRowHeight(target,row); }
public int getRowHeight(Container target,int row) {
this.target = target;
collectData();
return rowHeight[row];
}
public void setHgap(int hgap) { this.hgap = hgap; }
public void setVgap(int vgap) { this.vgap = vgap; }
public int getHgap() { return hgap; }
public int getVgap() { return vgap; }
Create a new int array filled with -1 |
private static int [] newarray(int size) {
int [] result = new int[size];
for (int i = size-1; i>=0; i--) result[i] = -1;
return result;
}
public void addLayoutComponent(String name,Component comp) {}
public void addLayoutComponent(Component comp,Object constraints) {
forgetData();
}
public byte getColAlignment(int j) { return CENTER; }
public void removeLayoutComponent(Component comp) {
forgetData();
}
int sumArray(int [] arr) {
int result = 0;
for (int i = arr.length-1; i>=0; i--)
result += arr[i];
return result;
}
public Dimension preferredLayoutSize(Container target) {
this.target = target;
collectData();
int extrawidth = 0;
if (target instanceof TabularView && ((TabularView)target).getCursorPos()!=0)
extrawidth = target.getFontMetrics(target.getFont()).charWidth(' ');
return new Dimension(extrawidth + HSPACE*(cols-1) + hgap*2 + sumArray(colWidth),
VSPACE*(rows-1) + vgap*2 + sumArray(rowHeight));
}
public Dimension minimumLayoutSize(Container target) {
return preferredLayoutSize(target);
}
public Dimension maximumLayoutSize(Container target) {
this.target = target;
return new Dimension(Short.MAX_VALUE,Short.MAX_VALUE);
}
public float getLayoutAlignmentX(Container target) { return 0.5f; }
public float getLayoutAlignmentY(Container target) { return 0.5f; }
public void invalidateLayout(Container target) {
this.target = target;
forgetData();
}
public void layoutContainer(Container target) {
this.target = target;
for (int i = target.getComponentCount()-1; i>=0; i--) {
Component comp = target.getComponent(i);
if (!(comp.isValid())) {
preferredSizes.put(comp,comp.getPreferredSize());
comp.validate();
}
}
collectData();
int xleft = hgap;
if (target instanceof TabularView && ((TabularView)target).getCursorPos()==HasCursorPos.Somewhere_LEFT)
xleft += target.getFontMetrics(target.getFont()).charWidth(' ');
// layout the components
int ypos = vgap;
for (int i = 0; i < rows; i++) {
int xpos = xleft;
for (int j = 0; j < cols; j++) {
Component comp = target.getComponent(j + i*cols);
Dimension siz = getPreferredSize(comp);
int bas;
if (comp instanceof HasBaseline)
bas = ((HasBaseline)comp).getBaseline();
else bas = siz.height / 2;
int xdispl = 0;
switch (getColAlignment(j)) {
case LEFT: break;
case CENTER:
xdispl += (colWidth[j] - siz.width) / 2;
break;
case RIGHT: xdispl += colWidth[j] - siz.width;
break;
}
comp.setBounds(xpos + xdispl,ypos + rowBaseLine[i] - bas,siz.width,siz.height);
xpos += colWidth[j] + HSPACE;
}
ypos += rowHeight[i] + VSPACE;
}
}
int pixel2colBetween(int xpixel) {
int xscan = hgap;
collectData();
for (int j = 0; j < colWidth.length; j++) {
if (xpixel < xscan+colWidth[j]/2) {
return j;
}
xscan += colWidth[j];
if (j+1 < colWidth.length) xscan += HSPACE;
}
return colWidth.length;
}
Result is always a valid row index |
public int pixel2rowAt(int ypixel) {
int yscan = vgap;
collectData();
for (int i = 0; i < rowHeight.length; i++) {
if (ypixel < yscan+rowHeight[i]) return i;
yscan += rowHeight[i];
if (i+1 < rowHeight.length) yscan += VSPACE;
}
return rowHeight.length - 1;
}
If the cursor is to the left of part 0, return 0.
If the cursor is between part 0 and 1, return 1 etc.
Result is a valid row index OR one more |
int pixel2rowBetween(int ypixel) {
int yscan = vgap;
collectData();
for (int i = 0; i < rowHeight.length; i++) {
if (ypixel < yscan+rowHeight[i]/2) return i;
yscan += rowHeight[i];
if (i+1 < rowHeight.length) yscan += VSPACE;
}
return rowHeight.length;
}
Does comp.getPreferredSize() but uses an internal buffer |
private Dimension getPreferredSize(Component comp) {
Dimension siz = null;
if (comp.isValid()) siz = (Dimension)preferredSizes.get(comp);
if (siz == null) {
siz = comp.getPreferredSize();
preferredSizes.put(comp,siz);
}
return siz;
}
Fill colWidth[], rowHeight[], rowBaseLine[] |
void collectData() {
if (colWidth!=null && rowHeight!=null && rowBaseLine!=null)
// Every time the data is invalid, forgetData() has been called.
// So we are sure that if the three pointers are non-null, they contain
// valid data.
// This little check makes table editing a *lot* faster!
return;
//long start=System.currentTimeMillis();
if (colWidth == null) colWidth = newarray(cols);
if (rowHeight == null) rowHeight = newarray(rows);
if (rowBaseLine == null) rowBaseLine = newarray(rows);
for (int i = 0; i < rows; i++) {
int rowbase = 0;
int rowdescent = 0;
for (int j = 0; j < cols; j++) {
Component comp = target.getComponent(j + i*cols);
Dimension siz = getPreferredSize(comp);
int bas;
if (comp instanceof HasBaseline)
bas = ((HasBaseline)comp).getBaseline();
else bas = siz.height / 2;
if (bas > rowbase) rowbase = bas;
if (siz.height-bas > rowdescent) rowdescent = siz.height-bas;
if (siz.width > colWidth[j]) colWidth[j] = siz.width;
}
rowHeight[i] = rowbase + rowdescent;
rowBaseLine[i] = rowbase;
}
//long time=System.currentTimeMillis()-start;
//System.out.println("TabularLayout.collectData(): spent "+time+" ("+cols+"x"+rows+")");
//try {throw new Error();} catch (Error e) { e.printStackTrace();}
}
}