/* * @(#)ColumnList.java 1.5 02/08/21 * * Copyright (c) 1996-2002 Sun Microsystems, Inc. All rights reserved. */ package com.sun.media.ui; import java.util.*; import java.awt.*; import java.awt.event.*; public class ColumnList extends Canvas implements MouseListener, FocusListener, KeyListener, ComponentListener { public static final int TYPE_INTEGER = 1; public static final int TYPE_DOUBLE = 2; public static final int TYPE_STRING = 3; public static final int TYPE_DATE = 4; private static final int MARGIN_VERT = 2; private static final int MARGIN_HORZ = 6; private static final Color COLOR_HEADER_BG = Color.lightGray; private static final Color COLOR_HEADER_FG = Color.black; private static final Color COLOR_SHADOW_TOP = Color.white; private static final Color COLOR_SHADOW_BOTTOM = Color.darkGray; // private static final Color COLOR_SEL_BG = new Color ( 0, 0, 128 ); // private static final Color COLOR_SEL_FG = Color.yellow; private static final Color COLOR_SEL_BG = Color.white; private static final Color COLOR_SEL_FG = Color.black; private Vector vectorColumns = new Vector (); // array of ColumnData private Vector vectorRows = new Vector (); // array of RowData private boolean boolFocus = false; private boolean boolSetColumnWidthAsPreferred = false; private int nScrollPosHorz = 0; private int nScrollPosVert = 0; private int nCurrentIndex = 0; private int nVisibleRows = 1; private Font fontHeader = new Font ( "Dialog", Font.PLAIN, 12 ); private Font fontItem = new Font ( "Dialog", Font.PLAIN, 12 ); private int nHeightHeader; private int nHeightRow; public ColumnList ( String arrColumnNames[] ) { super (); int i; int nCount; ColumnData column; nCount = arrColumnNames.length; for ( i = 0; i < nCount; i++ ) { column = new ColumnData ( arrColumnNames[i], TYPE_STRING ); vectorColumns.addElement ( column ); } try { init(); } catch (Exception e) { e.printStackTrace(); } } public void addRow ( Object arrValues[] ) { RowData rowData; rowData = new RowData ( arrValues ); vectorRows.addElement ( rowData ); repaint (); } public void removeRow ( int nRowIndex ) { vectorRows.removeElementAt ( nRowIndex ); repaint (); } public void setCellValue ( Object value, int nRowIndex, int nColumnIndex ) { RowData rowData; rowData = (RowData) vectorRows.elementAt ( nRowIndex ); rowData.setValue ( value, nColumnIndex ); repaint (); } public void setColumnWidth ( int nWidth, int nColumnIndex ) { ColumnData columnData; columnData = (ColumnData) vectorColumns.elementAt ( nColumnIndex ); columnData.nWidth = nWidth; repaint (); } public void setColumnWidth ( int nWidth ) { int i; int nCount; ColumnData columnData; nCount = vectorColumns.size (); for ( i = 0; i < nCount; i++ ) { columnData = (ColumnData) vectorColumns.elementAt ( i ); columnData.nWidth = nWidth; } repaint (); } public void setColumnWidthAsPreferred ( int nColumnIndex ) { int nWidth; ColumnData columnData; columnData = (ColumnData) vectorColumns.elementAt ( nColumnIndex ); nWidth = getPreferredColumnWidth ( nColumnIndex ); columnData.nWidth = nWidth; repaint (); } public void setColumnWidthAsPreferred () { int i; int nCount; int nWidth; int nWidthTotal; ColumnData columnData; Rectangle rect; int nWidthExtra; nCount = vectorColumns.size (); nWidthTotal = 0; for ( i = 0; i < nCount; i++ ) { columnData = (ColumnData) vectorColumns.elementAt ( i ); nWidth = getPreferredColumnWidth ( i ); columnData.nWidth = nWidth; nWidthTotal += nWidth; } rect = getBounds (); if ( rect.width < 1 ) boolSetColumnWidthAsPreferred = true; rect.width -= 2; if ( rect.width > nWidthTotal ) { nWidthExtra = (rect.width - nWidthTotal) / nCount; nWidthTotal = rect.width; for ( i = 0; i < nCount; i++ ) { columnData = (ColumnData) vectorColumns.elementAt ( i ); if ( i < nCount - 1 ) columnData.nWidth += nWidthExtra; else columnData.nWidth = nWidthTotal; nWidthTotal -= columnData.nWidth; } } repaint (); } public Dimension getPreferredSize () { int i; int nCount; Dimension dim; int nWidth; int nHeight; dim = new Dimension (); dim.height += this.nHeightHeader; nHeight = this.nHeightRow; nHeight *= vectorRows.size (); dim.height += nHeight; // columns nCount = vectorColumns.size (); for ( i = 0; i < nCount; i++ ) { nWidth = this.getPreferredColumnWidth ( i ); dim.width += nWidth; } dim.width += 3; // for shadow lines dim.height += 3; // for shadow lines return ( dim ); } public boolean isFocusTraversable () { return ( true ); } public void update ( Graphics g ) { Rectangle rectClient; Image image; Graphics graphics; rectClient = this.getBounds (); image = createImage ( rectClient.width, rectClient.height ); if ( image != null ) graphics = image.getGraphics (); else graphics = g; paint ( graphics ); if ( image != null ) g.drawImage ( image, 0, 0, this ); } public void paint ( Graphics graphics ) { int i, j; int nColCount; int nRowCount; Rectangle rect; Rectangle rectClient; Font font; FontMetrics fontMetrics; ColumnData columnData; RowData rowData; int nStartX; String strValue; int nX; int nY; int nWidth; int nHeight; int nLength; rectClient = this.getBounds (); rectClient.x = 0; rectClient.y = 0; rect = new Rectangle ( rectClient ); super.paint ( graphics ); graphics.setColor ( COLOR_SHADOW_BOTTOM ); graphics.drawRect ( rect.x, rect.y, rect.width - 2, rect.height - 2 ); graphics.setColor ( COLOR_SHADOW_TOP ); graphics.drawLine ( rect.x + rect.width - 1, rect.y + 1, rect.x + rect.width - 1, rect.y + rect.height - 1 ); graphics.drawLine ( rect.x + 1, rect.y + rect.height - 1, rect.x + rect.width - 1, rect.y + rect.height - 1 ); nColCount = vectorColumns.size (); nRowCount = vectorRows.size (); rect.x += 1; rect.y += 1; nStartX = rect.x; // draw header fontMetrics = this.getFontMetrics ( fontHeader ); graphics.setFont ( this.fontHeader ); nHeight = fontMetrics.getHeight (); rect.height = nHeightHeader; for ( i = nScrollPosHorz; i < nColCount; i++ ) { columnData = (ColumnData) vectorColumns.elementAt ( i ); rect.width = columnData.nWidth; if ( rect.x + rect.width > rectClient.x + rectClient.width - 1 ) rect.width = rectClient.x + rectClient.width - 1 - rect.x; // draw header graphics.setColor ( COLOR_HEADER_BG ); graphics.fillRect ( rect.x, rect.y, rect.width, rect.height ); graphics.setColor ( COLOR_SHADOW_TOP ); graphics.drawLine ( rect.x, rect.y, rect.x, rect.y + rect.height - 2 ); graphics.drawLine ( rect.x, rect.y, rect.x + rect.width - 2, rect.y ); graphics.setColor ( COLOR_SHADOW_BOTTOM ); graphics.drawLine ( rect.x + rect.width - 1, rect.y + 1, rect.x + rect.width - 1, rect.y + rect.height - 1 ); graphics.drawLine ( rect.x + 1, rect.y + rect.height - 1, rect.x + rect.width - 1, rect.y + rect.height - 1 ); strValue = columnData.strName; nLength = strValue.length (); nWidth = fontMetrics.stringWidth ( strValue ); while ( nWidth > rect.width - 2 * MARGIN_HORZ && nLength > 0 ) { nLength--; strValue = strValue.substring ( 0, nLength ) + "..."; nWidth = fontMetrics.stringWidth ( strValue ); } nX = rect.x + (rect.width - nWidth) / 2; nY = rect.y + rect.height - (rect.height - nHeight) / 2 - fontMetrics.getMaxDescent(); graphics.setColor ( this.getForeground() ); graphics.drawString ( strValue, nX, nY ); rect.x += rect.width; } // draw rows font = this.getFont (); fontMetrics = this.getFontMetrics ( font ); graphics.setFont ( font ); nHeight = fontMetrics.getHeight (); rect.y += rect.height; rect.height = nHeightRow; for ( j = nScrollPosVert; j < nRowCount; j++ ) { rect.x = nStartX; if ( j == nCurrentIndex ) { rect.width = rectClient.width - 3; graphics.setColor ( COLOR_SEL_BG ); graphics.fillRect ( rect.x, rect.y, rect.width, rect.height ); graphics.setColor ( COLOR_SEL_FG ); if ( boolFocus == true ) { drawDottedLine ( graphics, rect.x, rect.y, rect.x + rect.width - 1, rect.y ); drawDottedLine ( graphics, rect.x, rect.y + rect.height - 1, rect.x + rect.width - 1, rect.y + rect.height - 1 ); } } else graphics.setColor ( this.getForeground() ); rowData = (RowData) vectorRows.elementAt ( j ); for ( i = nScrollPosHorz; i < nColCount; i++ ) { columnData = (ColumnData) vectorColumns.elementAt ( i ); rect.width = columnData.nWidth; if ( rect.x + rect.width > rectClient.x + rectClient.width - 1 ) rect.width = rectClient.x + rectClient.width - 1 - rect.x; strValue = rowData.getValue(i).toString(); nLength = strValue.length (); nWidth = fontMetrics.stringWidth ( strValue ); while ( nWidth > rect.width - 2 * MARGIN_HORZ && nLength > 0 ) { nLength--; strValue = strValue.substring ( 0, nLength ) + "..."; nWidth = fontMetrics.stringWidth ( strValue ); } nX = rect.x + MARGIN_HORZ; nY = rect.y + rect.height - (rect.height - nHeight) / 2 - fontMetrics.getMaxDescent(); graphics.drawString ( strValue, nX, nY ); rect.x += rect.width; } rect.y += rect.height; } } public void mouseClicked ( MouseEvent event ) { } public void mousePressed ( MouseEvent event ) { int x, y; int nIndex; x = event.getX (); y = event.getY (); y -= 1 + nHeightHeader; if ( y >= 0 ) { nIndex = y / nHeightRow; if ( nIndex >= 0 && nIndex < vectorRows.size() - nScrollPosVert ) nCurrentIndex = nIndex + nScrollPosVert; } this.requestFocus (); repaint (); } public void mouseReleased ( MouseEvent event ) { } public void mouseEntered ( MouseEvent event ) { } public void mouseExited ( MouseEvent event ) { } public void keyTyped ( KeyEvent event ) { } public void keyPressed ( KeyEvent event ) { int nKeyCode; int nIndex; nKeyCode = event.getKeyCode (); nIndex = nCurrentIndex; if ( nKeyCode == KeyEvent.VK_DOWN ) nIndex++; else if ( nKeyCode == KeyEvent.VK_UP ) nIndex--; else if ( nKeyCode == KeyEvent.VK_HOME ) nIndex = 0; else if ( nKeyCode == KeyEvent.VK_END ) nIndex = vectorRows.size() - 1; else if ( nKeyCode == KeyEvent.VK_PAGE_UP ) nIndex -= nVisibleRows; else if ( nKeyCode == KeyEvent.VK_PAGE_DOWN ) nIndex += nVisibleRows; if ( nIndex > vectorRows.size() - 1 ) nIndex = vectorRows.size() - 1; if ( nIndex < 0 ) nIndex = 0; if ( nIndex != nCurrentIndex ) { nCurrentIndex = nIndex; if ( nScrollPosVert + nVisibleRows < nCurrentIndex ) nScrollPosVert = nCurrentIndex - nVisibleRows + 1; if ( nScrollPosVert > nCurrentIndex ) nScrollPosVert = nCurrentIndex; repaint (); } } public void keyReleased ( KeyEvent event ) { } public void focusGained ( FocusEvent event ) { if ( boolFocus == true ) return; boolFocus = true; repaint (); } public void focusLost ( FocusEvent event ) { if ( boolFocus == false ) return; boolFocus = false; repaint (); } public void componentResized ( ComponentEvent event ) { Rectangle rect; if ( boolSetColumnWidthAsPreferred == true ) { boolSetColumnWidthAsPreferred = false; this.setColumnWidthAsPreferred (); } rect = getBounds (); rect.height -= 3 + nHeightHeader; nVisibleRows = rect.height / nHeightRow; if ( nVisibleRows < 1 ) nVisibleRows = 1; } public void componentMoved ( ComponentEvent event ) { } public void componentShown ( ComponentEvent event ) { } public void componentHidden ( ComponentEvent event ) { } private void init () throws Exception { this.setFont ( fontItem ); this.computeHeights (); this.setBackground ( Color.white ); this.addMouseListener ( this ); this.addKeyListener ( this ); this.addFocusListener ( this ); this.addComponentListener ( this ); } private int getPreferredColumnWidth ( int nColumnIndex ) { int i; int nCount; int nWidth; int nWidthMax; Font font; FontMetrics fontMetrics; String strValue; ColumnData columnData; RowData rowData; columnData = (ColumnData) vectorColumns.elementAt ( nColumnIndex ); // header fontMetrics = this.getFontMetrics ( fontHeader ); strValue = columnData.strName; nWidthMax = fontMetrics.stringWidth ( strValue ) + 2 * MARGIN_HORZ + 2; // rows font = this.getFont (); fontMetrics = this.getFontMetrics ( font ); nCount = vectorRows.size (); for ( i = 0; i < nCount; i++ ) { rowData = (RowData) vectorRows.elementAt ( i ); strValue = rowData.getValue(nColumnIndex).toString(); nWidth = fontMetrics.stringWidth ( strValue ) + 2 * MARGIN_HORZ; nWidthMax = Math.max ( nWidthMax, nWidth ); } return ( nWidthMax ); } private void computeHeights () { Font font; FontMetrics fontMetrics; fontMetrics = this.getFontMetrics ( fontHeader ); nHeightHeader = fontMetrics.getHeight (); nHeightHeader += 2; // shadow lines nHeightHeader += 2 * MARGIN_VERT; font = this.getFont (); fontMetrics = this.getFontMetrics ( font ); nHeightRow = fontMetrics.getHeight (); nHeightRow += 2 * MARGIN_VERT; } private void drawDottedLine ( Graphics graphics, int nX1, int nY1, int nX2, int nY2 ) { int nX, nY; double dDiv; if ( nX1 == nX2 && nY1 == nY2 ) { drawDot ( graphics, nX1, nY1 ); return; } if ( nX1 > nX2 ) { nX = nX1; nX1 = nX2; nX2 = nX; } if ( nY1 > nY2 ) { nY = nY1; nY1 = nY2; nY2 = nY; } if ( nX2 - nX1 > nY2 - nY1 ) { dDiv = (double)(nY2 - nY1) / (nX2 - nX1); for ( nX = nX1; nX <= nX2; nX++ ) { nY = (int)Math.rint ( nY1 + (nX - nX1) * dDiv ); drawDot ( graphics, nX, nY ); } } else { dDiv = (nX2 - nX1) / (nY2 - nY1); for ( nY = nY1; nY <= nY2; nY++ ) { nX = (int)Math.rint ( nX1 + (nY - nY1) * dDiv ); drawDot ( graphics, nX, nY ); } } } private void drawDot ( Graphics graphics, int nX, int nY ) { if ( (nX + nY) % 2 == 0 ) graphics.drawLine ( nX, nY, nX, nY ); } } class ColumnData { String strName; int nType; int nWidth = 120; public ColumnData ( String strName, int nType ) { this.strName = strName; this.nType = nType; } public String toString () { return ( strName ); } } class RowData { private Vector vectorValues = new Vector (); public RowData ( Object arrValues[] ) { int i; int nCount; if ( arrValues != null ) { nCount = arrValues.length; for ( i = 0; i < nCount; i++ ) vectorValues.addElement ( arrValues[i] ); } } void setValue ( Object value, int nColumn ) { vectorValues.setElementAt ( value, nColumn ); } Object getValue ( int nColumn ) { Object value; value = vectorValues.elementAt ( nColumn ); return ( value ); } }