/* SCCS %W%---%G%--%U% */ // Copyright: Copyright (c) 1997 University of Southern California Brain Project. // Copyright: This software may be freely copied provided the toplevel // Copyright: COPYRIGHT file is included with each such copy. // Copyright: Email nsl@java.usc.edu. package nslj.src.display; import nslj.src.lang.*; import java.util.*; import java.awt.*; public class NslGrid extends Panel { private Image gridImage; private Image hBorderImage; private Image vBorderImage; private Graphics gridGraphics; private Graphics hBorderGraphics; private Graphics vBorderGraphics; private Scrollbar horizontal, vertical; private FontMetrics fontMetrics; private Font font; private Color background, foreground; private Component component; private boolean gridInitialized = false; private boolean editFlag = true; private boolean redraw = false; private boolean mouseDown = false; private int horizontalScrollUnit; private int verticalScrollUnit; private int numberOfColumns, numberOfRows; private int imageWidth, imageHeight; private int screenWidth, screenHeight; private int gridWidth, gridHeight; private int borderWidth, borderHeight; private int cellHeight, cellWidth; private int hSbHeight, hSbWidth; private int vSbHeight, vSbWidth; private int vSbShift, hSbShift; private int hSbValue, vSbValue; private int prevRow, prevColumn; private int currentRow, currentColumn; private int drawX, drawY; private Cell[] headerElements; private Row[] rowElements; public NslGrid(NslFrame frame, int rows, int columns) { super(); //System.out.println("Creating Grid: "+rows+"x"+columns); setLayout(null); horizontal = new Scrollbar(Scrollbar.HORIZONTAL); //horizontal.addAdjustmentListener(); vertical = new Scrollbar(Scrollbar.VERTICAL); //vertical.addAdjustmentListener(); add(horizontal); add(vertical); hSbValue = 0; vSbValue = 0; String fn = frame.getFontName()==null?"Times":frame.getFontName(); String bg = frame.getBackgroundColor()==null?"white":frame.getBackgroundColor(); String fg = frame.getForegroundColor()==null?"black":frame.getForegroundColor(); font = new Font(fn, Font.PLAIN,12); background = NslColor.getColor(bg); foreground = NslColor.getColor(fg); numberOfRows = rows; numberOfColumns = columns; borderWidth = 80; borderHeight = 25; cellWidth = 80; cellHeight = 25; gridWidth = borderWidth + cellWidth*numberOfColumns; gridHeight = borderHeight + cellHeight*numberOfRows; headerElements = new Cell[numberOfColumns+1]; rowElements = new Row[numberOfRows+1]; Cell cell = new Cell(); headerElements[0] = cell; for (int i=1; i<=numberOfColumns; i++) { cell = new Cell(); /*cell.bgColor = Color.lightGray; cell.fgColor = Color.black;*/ cell.setValue(""+(i-1)); headerElements[i]=cell; } rowElements[0] = new Header(headerElements); createRows(); } public void setEditable(boolean flag) { editFlag = flag; } private void setHScrollValues() { if (gridInitialized) { int increment = Math.round(screenWidth/horizontalScrollUnit); horizontal.setValues(hSbValue,increment,0,Math.round(imageWidth/horizontalScrollUnit)); horizontal.setBlockIncrement((int)(increment*0.9)); } } private void setVScrollValues() { if (gridInitialized) { int increment = Math.round((screenHeight-borderHeight)/verticalScrollUnit); vertical.setValues(vSbValue,increment,0,Math.round((imageHeight-borderHeight)/verticalScrollUnit)); vertical.setBlockIncrement((int)(increment*0.9)); } } public void setDrawableArea() { if (gridInitialized) { imageWidth = (gridWidth > screenWidth) ? gridWidth : screenWidth; imageHeight = (gridHeight > screenHeight) ? gridHeight : screenHeight; } } public void setBounds(int x, int y, int width, int height) { super.setBounds(x,y,width,height); //System.out.println("SetBounds was called: "+x+", "+y+", "+width+", "+height); Insets in = getInsets(); drawX = in.left; drawY = in.top; hSbHeight = horizontal.getMinimumSize().height; vSbWidth = vertical.getMinimumSize().width; screenWidth = width - (in.left + in.right) - vSbWidth; screenHeight = height - (in.top + in.bottom) - hSbHeight; vertical.setBounds(screenWidth+in.left,drawY,vSbWidth,screenHeight); //System.out.println("Vertical: "+(screenWidth+in.left)+", "+drawY+", "+vSbWidth+", "+screenHeight); horizontal.setBounds(drawX,screenHeight+in.top,screenWidth,hSbHeight); //System.out.println("Horizontal: "+drawX+", "+(screenHeight+in.top)+", "+screenWidth+", "+hSbHeight); setDrawableArea(); setHScrollValues(); setVScrollValues(); repaint(); } public boolean createRows() { Cell cell; Cell[] newRow; TextField comp; for (int j=1; j<=numberOfRows; j++) { newRow = new Cell[numberOfColumns+1]; cell = new Cell(); newRow[0] = cell; comp = new TextField(""+(j-1)); cell.setComponent(comp); cell.setValue(""+(j-1)); for (int i=1; i<=numberOfColumns; i++) { cell = new Cell(); comp = new TextField("0.0"); cell.setComponent(comp); cell.setValue("0.0"); newRow[i]=cell; } rowElements[j] = new Row(newRow); } setVScrollValues(); gridImage = null; vBorderImage = null; repaint(); return true; } private void drawGrid(Graphics g) { Graphics tg = g.create(drawX,drawY,imageWidth,borderHeight); rowElements[0].draw(tg); tg.dispose(); for (int i=1; i <= numberOfRows; i++) { tg = g.create(drawX,cellHeight*i,imageWidth,cellHeight); rowElements[i].draw(tg); tg.dispose(); } int height = (imageHeight > gridHeight) ? gridHeight : imageHeight; g.setColor(foreground); //System.out.println("ImageHeight: "+imageHeight); //System.out.println("GridHeight: "+gridHeight); //System.out.println("Last: "+drawX+", "+height+", "+imageWidth+", "+height); g.drawLine(drawX,height-1,imageWidth-1,height-1); return; } private void drawVerticalBorder(Graphics g) { int y; int y1; g.setColor(foreground); g.drawLine(drawX,drawY,drawX,screenHeight); if (vBorderImage == null) { vBorderImage = createImage(borderWidth,gridHeight); vBorderGraphics = vBorderImage.getGraphics(); y1 = borderHeight; for (int i=0; i<=numberOfRows; i++) { y = cellHeight*i+1; vBorderGraphics.setColor(Color.lightGray); vBorderGraphics.fillRect(0,y,borderWidth,(y1-y)); vBorderGraphics.setColor(background); vBorderGraphics.drawLine(0,y,borderWidth,y); vBorderGraphics.drawLine(0,y,0,y1); vBorderGraphics.setColor(foreground); vBorderGraphics.drawLine(borderWidth-1,y,borderWidth-1,y1); vBorderGraphics.drawLine(0,y1,borderWidth-1,y1); if (i>0) { vBorderGraphics.drawString(""+(i-1),3,y+(cellHeight + fontMetrics.getHeight())/2 - fontMetrics.getDescent()); } y1 += cellHeight; } } vSbShift = vSbValue*verticalScrollUnit; vSbShift = (screenHeight-imageHeight) > -vSbShift ? (imageHeight-screenHeight) : vSbShift; int actualY = drawY-vSbShift; if (vBorderImage != null) { g.drawImage(vBorderImage,drawX+1,actualY,this); } g.setColor(Color.lightGray); g.fillRect(drawX+1,0,borderWidth,borderHeight); g.setColor(background); g.drawLine(drawX+1,borderHeight,borderWidth,borderHeight); g.drawLine(drawX+1,0,drawX+1,borderHeight); g.setColor(foreground); g.drawLine(borderWidth,0,borderWidth,borderHeight); g.drawLine(drawX+1,0,borderWidth,0); g.drawLine(drawX+1,borderHeight,borderWidth,borderHeight); int height = (imageHeight > gridHeight) ? gridHeight : imageHeight; g.setColor(foreground); g.drawLine(drawX,height-1,imageWidth-1,height-1); } private void invalidate(boolean flag) { if (rowElements != null) { for (int i=0; i<=numberOfRows; i++) { rowElements[i].invalidate(flag); } } } public Component getComponent(int row, int column) { Row currRow; Cell cell; if ((row < 0) || (row > numberOfRows) || (column <= 0) || (column > numberOfColumns)) return null; currRow = rowElements[row]; cell = currRow.getCell(column); return cell.getComponent(); } public String getComponentValue (int row, int column) { Component cmp = getComponent(row, column); if (cmp instanceof TextField) return ((TextField)cmp).getText(); else return null; } public boolean setValue(int row, int column, String value) { Row currRow; Cell cell; if ((row <= 0) || (row > numberOfRows) || (column <= 0) || (column > numberOfColumns)) return false; rowElements[row].getCell(column).setValue(value); gridImage = null; repaint(); return true; } public void cleanCell() { if (component != null) { component.setVisible(false); } } private void displayCell() { Component oldComp; Row row; if (component != null) { row = rowElements[prevRow]; Cell cell = row.getCell(prevColumn); String oldVal = cell.getValue(); String newVal = getComponentValue(prevRow,prevColumn); if ((oldVal != null) && (oldVal.equals(newVal) == false)) { setValue(prevRow,prevColumn,newVal); if (rowElements != null) { row.invalidate(true); redraw = true; repaint(); } } } oldComp = getComponent(currentRow,currentColumn); if (component != oldComp) { if (component != null) remove(component); component = oldComp; if (component != null) add(component); } if (component != null) { if ((cellHeight*currentRow-vSbShift) >= borderHeight) { int compWidth,compHeight; compWidth = (screenWidth > (cellWidth*currentColumn-hSbShift + cellWidth)) ? cellWidth : (screenWidth - (cellWidth*currentColumn-hSbShift)); compHeight = (screenHeight > (cellHeight*currentRow-vSbShift + cellHeight)) ? cellHeight : (screenHeight - (cellHeight*currentRow-vSbShift)); if ((cellWidth*currentColumn-hSbShift) >= borderWidth) component.setBounds(cellWidth*currentColumn-hSbShift, cellHeight*currentRow-vSbShift, compWidth, compHeight); else component.setBounds(borderWidth, cellHeight*currentRow-vSbShift, cellWidth-hSbShift, compHeight); component.setVisible(true); component.requestFocus(); } else { component.setVisible(false); } } } public boolean mouseDown(Event evt, int x, int y) { x += hSbShift; y += vSbShift; mouseDown = true; return false; } public boolean mouseUp(Event evt, int x, int y) { if (y <= borderHeight || x <= borderWidth || y > gridHeight || x > gridWidth) { return true; } x += hSbShift; y += vSbShift; Point p = new Point(0,0); p.x = (int)(x/cellWidth); p.y = (int)(y/cellHeight); prevRow = currentRow; prevColumn = currentColumn; currentRow = p.y; currentColumn = p.x; if (editFlag) displayCell(); Row row = rowElements[currentRow]; row.invalidate(true); redraw = true; repaint(); mouseDown = false; return true; } public boolean handleEvent(Event evt) { switch (evt.id) { case Event.KEY_PRESS: if (evt.key==9) { prevRow = currentRow; prevColumn = currentColumn; if ((currentRow == numberOfRows)&&(currentColumn == numberOfColumns)) return super.handleEvent(evt); if (currentColumn == numberOfColumns) { currentRow++; currentColumn = 1; } else { currentColumn++; } displayCell(); repaint(); } case Event.SCROLL_LINE_UP: case Event.SCROLL_LINE_DOWN: case Event.SCROLL_PAGE_UP: case Event.SCROLL_PAGE_DOWN: case Event.SCROLL_ABSOLUTE: if (evt.target == horizontal) { hSbValue = horizontal.getValue(); setHScrollValues(); repaint(); return true; } else if (evt.target == vertical) { vSbValue = vertical.getValue(); setVScrollValues(); repaint(); return true; } } return super.handleEvent(evt); } public void paint(Graphics g) { Graphics temp; super.paint(g); g.setFont(font); if (!gridInitialized) { fontMetrics = g.getFontMetrics(); horizontalScrollUnit = fontMetrics.charWidth(' '); verticalScrollUnit = fontMetrics.getHeight() + 15; borderHeight = cellHeight = verticalScrollUnit; gridWidth = borderWidth + cellWidth*numberOfColumns; gridHeight = borderHeight + cellHeight*numberOfRows; gridInitialized = true; setDrawableArea(); } if (gridImage==null) { setDrawableArea(); gridImage = createImage(imageWidth,imageHeight); gridGraphics = gridImage.getGraphics(); invalidate(true); drawGrid(gridGraphics); setHScrollValues(); setVScrollValues(); } else if (redraw) { setDrawableArea(); drawGrid(gridGraphics); redraw = false; } if (gridImage!=null) { hSbShift = hSbValue*horizontalScrollUnit; hSbShift = (screenWidth-imageWidth) > -hSbShift ? (imageWidth-screenWidth) : hSbShift; vSbShift = vSbValue*verticalScrollUnit; vSbShift = (screenHeight-imageHeight) > -vSbShift ? (imageHeight-screenHeight) : vSbShift; drawVerticalBorder(g); int x = 1; int y = borderHeight + 1; int actualX = drawX-hSbShift; int actualY = drawY-vSbShift; x += borderWidth; try{ g.clipRect(x,0,screenWidth,screenHeight); if (hBorderImage == null) { hBorderImage = createImage(gridWidth, y); hBorderGraphics = hBorderImage.getGraphics(); Header row = (Header)rowElements[0]; row.invalidate(true); //System.out.println("--->Before header draw: "+(x-1)+", "+0+", "+gridWidth+", "+y); row.draw(hBorderGraphics,new Rectangle(x-1, 0, gridWidth, y)); } if (hBorderImage != null) { g.drawImage(hBorderImage,actualX,drawY,this); } g.clipRect(x,y,screenWidth,screenHeight); if (gridImage != null) { g.drawImage(gridImage,actualX,actualY,this); } } catch (Exception e) { e.printStackTrace(); } } if (horizontal.isVisible() && vertical.isVisible()) { g.setColor(Color.lightGray); g.fillRect(screenWidth,screenHeight,vSbWidth,hSbHeight); } if (editFlag) displayCell(); } public void update(Graphics g) { paint(g); } private class Row { protected int x, y, rH, rW; protected boolean redraw = true; protected Cell[] elements; public Row(Cell[] cells) { elements = cells; } public Cell getCell(int i) { if (i <= numberOfColumns) { return elements[i]; } else { return null; } } public void invalidate (boolean flag) { this.redraw = flag; if (elements != null) { for (int i=0; i < elements.length; i++) { elements[i].invalidate(flag); } } } protected void drawBorder(Graphics g) { int x1 = x + rW; int y1 = y + rH; //System.out.println("Row draw border: "+x+", "+y+", "+x1+", "+y); g.setColor(foreground); g.drawLine(x,y,x1,y); g.drawLine(x,y,x,y1); g.drawLine(x1,y,x1,y1); } protected void drawMargin (Graphics g) { int x0 = x + 1; int y0 = y + 1; int x1 = cellWidth-1; int y1 = y + rH - 1; //System.out.println("Row draw margin: "+x0+", "+y0+", "+x1+", "+y1); g.setColor(Color.lightGray); g.fillRect(x0,y0,x1,y1); g.setColor(background); g.drawLine(x0,y0,x1,y0); g.drawLine(x0,y0,x0,y1); g.setColor(Color.gray); g.drawLine(x1,y0,x1,y1); g.drawLine(x0,y1,x1,y1); //System.out.println("-->Row draw margin title"); elements[0].drawValue(new Rectangle(1, y,cellWidth-1,rH),g); if (redraw){ g.setColor(background); g.fillRect(cellWidth,y,rW,rH); } } public void draw(Graphics g) { if (this.redraw && (g != null)) { int startX,endX; Rectangle clipRect = g.getClipBounds(); x = clipRect.x; y = clipRect.y; rH = clipRect.height; rW = clipRect.width; //System.out.println("Row draw: "+x+", "+y+", "+rH+", "+rW); drawMargin(g); for (int i=1; i<=numberOfColumns; i++) { startX = cellWidth*i +1; endX = cellWidth*i + cellWidth - 1; g.setColor(Color.gray); g.drawLine(cellWidth*i,y,cellWidth*i,y+rH); g.setColor(foreground); elements[i].draw(new Rectangle(startX,y,cellWidth-1,rH),g); //System.out.println("Row draw change?: "+x+", "+y+", "+rH+", "+rW); } drawBorder(g); this.redraw = false; } } } private class Header extends Row { public Header(Cell[] cells) { super(cells); } public void draw (Graphics g) { if (this.redraw && (g != null)) { Rectangle clipRect = g.getClipBounds(); draw(g,clipRect); } this.redraw = false; } public void draw(Graphics g, Rectangle rect) { if (this.redraw && (g != null)) { int x0, y0, x1, y1, rW, rH; x = rect.x; y = rect.y; rW = rect.width; rH = rect.height; x1 = x + rW; y1 = y + rH; g.setColor(Color.lightGray); g.fillRect(x,y,rW,rH); //System.out.println("Header draw: "+x+", "+y+", "+x1+", "+y); g.setColor(foreground); g.drawLine(x,y,x1,y); g.drawLine(x,y1-1,x1,y1-1); g.drawLine(x,y,x,y1); g.drawLine(x1,y,x1,y1); for (int i=1; i<=numberOfColumns; i++) { x0 = cellWidth*i+1; y0 = y + 1; x1 = x0+cellWidth-1; y1 = y + rH-1; g.setColor(Color.lightGray); g.fillRect(x0,y0,cellWidth,rH); g.setColor(background); g.drawLine(x0,y0,x1,y0); g.drawLine(x0,y0,x0,y1); g.setColor(foreground); g.drawLine(x1,y0,x1,y1); g.drawLine(x0,y1,x1,y1); elements[i].draw(new Rectangle(cellWidth*i+2, y+2,cellWidth-2,rH-2),g,Color.lightGray); } } this.redraw = false; } } private class Cell { private boolean redraw = true; private String value; private Component component; public String getValue() { return value; } public Component getComponent() { return component; } public void setValue (String val) { this.value = val; if (component instanceof TextField) { ((TextField)component).setText(this.value); } this.redraw = true; } public void setComponent (Component comp) { component = comp; } public void invalidate(boolean flag) { this.redraw = flag; } public void draw (Rectangle rect) { if (component != null) { component.setBounds(rect.x,rect.y,rect.width,rect.height); } } public void drawValue(Rectangle rect, Graphics g) { if (this.redraw) { int x = rect.x + 2; int y = rect.y + (rect.height + fontMetrics.getHeight())/2 - fontMetrics.getDescent(); g.setColor(foreground); g.drawString(value,x,y); } this.redraw = false; } public void draw (Rectangle rect, Graphics g, Color bg) { if (this.redraw) { int x = rect.x + 2; int y = rect.y + (rect.height + fontMetrics.getHeight())/2 - fontMetrics.getDescent(); g.setColor(bg); g.fillRect(rect.x,rect.y,rect.width,rect.height-1); g.setColor(foreground); g.drawString(value,x,y); } this.redraw = false; } public void draw (Rectangle rect, Graphics g) { if (this.redraw) { int x = rect.x + 2; int y = rect.y + (rect.height + fontMetrics.getHeight())/2 - fontMetrics.getDescent(); g.setColor(background); g.fillRect(rect.x,rect.y,rect.width,rect.height-1); g.setColor(foreground); g.drawString(value,x,y); } this.redraw = false; } } }