/** * MultiLineBasicTableUI.java * * This class provides a BasicTableUI for JMultilineTable. * (c) 2006 EduMIPS64 project - Rizzo Vanni G. * * Special Thanks to Thomas Wernitz (thomas_wernitz@clear.net.nz) * for his source code. * * This file is part of the EduMIPS64 project, and is released under the GNU * General Public License. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.edumips64.ui.swing; import java.awt.*; import javax.swing.*; import javax.swing.table.*; import java.util.*; public class MultiLineBasicTableUI extends javax.swing.plaf.basic.BasicTableUI { private Dimension createTableSize(long width) { int numCols = table.getColumnCount(); int numRows = table.getRowCount(); TableModel tm = table.getModel(); int fontHeight = table.getFontMetrics(table.getFont()).getHeight(); int[] height = new int[numRows]; for (int i = 0; i < numRows; i++) { height[i] = fontHeight; // init to font height as minimum } Enumeration<TableColumn> cols = table.getColumnModel().getColumns(); int i = 0; while (cols.hasMoreElements()) { TableColumn col = cols.nextElement(); TableCellRenderer tcr = col.getCellRenderer(); int colWidth = col.getWidth(); for (int j = 0; j < numRows; j++) { if (tcr instanceof MultiLineCellRenderer) { height[j] = Math.max(height[j], ((MultiLineTable) table).getHeight((String) tm.getValueAt(j, i), colWidth)); } } i++; } int totalMarginWidth = table.getColumnModel().getColumnMargin() * numCols; // Width is always positive. The call to abs() is a workaround for // a bug in the 1.1.6 JIT on Windows. long widthWithMargin = Math.abs(width) + totalMarginWidth; if (widthWithMargin > Integer.MAX_VALUE) { widthWithMargin = Integer.MAX_VALUE; } int totalHeight = 0; for (int k = 0; k < numRows; k++) { totalHeight += height[k]; } return new Dimension((int) widthWithMargin, totalHeight + numRows * table.getRowMargin()); } public Dimension getMinimumSize(JComponent c) { long width = 0; Enumeration<TableColumn> enumeration = table.getColumnModel().getColumns(); while (enumeration.hasMoreElements()) { TableColumn aColumn = enumeration.nextElement(); width = width + aColumn.getMinWidth(); } return createTableSize(width); } /** * Return the preferred size of the table. The preferred height is the * row height (plus inter-cell spacing) times the number of rows. * The preferred width is the sum of the preferred widths of each column * (plus inter-cell spacing). */ public Dimension getPreferredSize(JComponent c) { long width = 0; Enumeration<TableColumn> enumeration = table.getColumnModel().getColumns(); while (enumeration.hasMoreElements()) { TableColumn aColumn = enumeration.nextElement(); width = width + aColumn.getPreferredWidth(); } return createTableSize(width); } /** * Return the maximum size of the table. The maximum height is the * row height (plus inter-cell spacing) times the number of rows. * The maximum width is the sum of the maximum widths of each column * (plus inter-cell spacing). */ public Dimension getMaximumSize(JComponent c) { long width = 0; Enumeration<TableColumn> enumeration = table.getColumnModel().getColumns(); while (enumeration.hasMoreElements()) { TableColumn aColumn = enumeration.nextElement(); width = width + aColumn.getMaxWidth(); } return createTableSize(width); } public void paint(Graphics g, JComponent c) { Rectangle oldClipBounds = g.getClipBounds(); Rectangle clipBounds = new Rectangle(oldClipBounds); int tableWidth = table.getColumnModel().getTotalColumnWidth(); clipBounds.width = Math.min(clipBounds.width, tableWidth); g.setClip(clipBounds); // Paint the grid paintGrid(g); // Paint the rows int firstIndex = table.rowAtPoint(new Point(0, clipBounds.y)); int lastIndex = lastVisibleRow(clipBounds); int rowMargin = table.getRowMargin(); Rectangle rowRect = new Rectangle(0, 0, tableWidth, ((MultiLineTable) table).getRowHeight(firstIndex) + rowMargin); rowRect.y = 0; for (int i = 0; i < firstIndex; i++) { rowRect.y += ((MultiLineTable) table).getRowHeight(i) + rowMargin; } for (int index = firstIndex; index <= lastIndex; index++) { // Paint any rows that need to be painted if (rowRect.intersects(clipBounds)) { paintRow(g, index); } rowRect.y += ((MultiLineTable) table).getRowHeight(index) + rowMargin; } g.setClip(oldClipBounds); } private void paintGrid(Graphics g) { g.setColor(table.getGridColor()); if (table.getShowHorizontalLines()) { paintHorizontalLines(g); } if (table.getShowVerticalLines()) { paintVerticalLines(g); } } /* * This method paints horizontal lines regardless of whether the * table is set to paint one automatically. */ private void paintHorizontalLines(Graphics g) { Rectangle r = g.getClipBounds(); Rectangle rect = r; int firstIndex = table.rowAtPoint(new Point(0, r.y)); int lastIndex = lastVisibleRow(r); int rowMargin = table.getRowMargin(); int y = - rowMargin; for (int i = 0; i < firstIndex; i++) { y += ((MultiLineTable) table).getRowHeight(i) + rowMargin; } for (int index = firstIndex; index <= lastIndex; index ++) { y += ((MultiLineTable) table).getRowHeight(index) + rowMargin; if ((y >= rect.y) && (y <= (rect.y + rect.height))) { g.drawLine(rect.x, y, rect.x + rect.width - 1, y); } } } /* * This method paints vertical lines regardless of whether the * table is set to paint one automatically. */ private void paintVerticalLines(Graphics g) { Rectangle rect = g.getClipBounds(); int x = 0; int count = table.getColumnCount(); int horizontalSpacing = table.getIntercellSpacing().width; for (int index = 0; index <= count; index ++) { if ((x > 0) && (((x - 1) >= rect.x) && ((x - 1) <= (rect.x + rect.width)))) { g.drawLine(x - 1, rect.y, x - 1, rect.y + rect.height - 1); } if (index < count) { x += table.getColumnModel().getColumn(index).getWidth() + horizontalSpacing; } } } private void paintRow(Graphics g, int row) { Rectangle rect = g.getClipBounds(); int column = 0; boolean drawn = false; int draggedColumnIndex = -1; Rectangle draggedCellRect = null; Dimension spacing = table.getIntercellSpacing(); JTableHeader header = table.getTableHeader(); // Set up the cellRect Rectangle cellRect = new Rectangle(); cellRect.height = ((MultiLineTable) table).getRowHeight(row) + spacing.height; cellRect.y = 0; for (int i = 0; i < row; i++) { cellRect.y += ((MultiLineTable) table).getRowHeight(i) + spacing.height; } Enumeration<TableColumn> enumeration = table.getColumnModel().getColumns(); // Paint the non-dragged table cells first while (enumeration.hasMoreElements()) { TableColumn aColumn = enumeration.nextElement(); cellRect.width = aColumn.getWidth() + spacing.width; if (cellRect.intersects(rect)) { drawn = true; if ((header == null) || (aColumn != header.getDraggedColumn())) { paintCell(g, cellRect, row, column); } else { // Paint a gray well in place of the moving column // This would be unnecessary if we drew the grid more cleverly g.setColor(table.getParent().getBackground()); g.fillRect(cellRect.x, cellRect.y, cellRect.width, cellRect.height); draggedCellRect = new Rectangle(cellRect); draggedColumnIndex = column; } } else { if (drawn) // Don't need to iterate through the rest { break; } } cellRect.x += cellRect.width; column++; } // paint the dragged cell if we are dragging if (draggedColumnIndex != -1 && draggedCellRect != null) { draggedCellRect.x += header.getDraggedDistance(); // Fill the background g.setColor(table.getBackground()); g.fillRect(draggedCellRect.x, draggedCellRect.y, draggedCellRect.width, draggedCellRect.height); // paint grid if necessary. g.setColor(table.getGridColor()); int x1 = draggedCellRect.x; int y1 = draggedCellRect.y; int x2 = x1 + draggedCellRect.width - 1; int y2 = y1 + draggedCellRect.height - 1; if (table.getShowVerticalLines()) { // Left // g.drawLine(x1-1, y1, x1-1, y2); // Right g.drawLine(x2, y1, x2, y2); } // Bottom if (table.getShowHorizontalLines()) { g.drawLine(x1, y2, x2, y2); } // Render the cell value paintCell(g, draggedCellRect, row, draggedColumnIndex); } } private void paintCell(Graphics g, Rectangle cellRect, int row, int column) { // The cellRect is inset by half the intercellSpacing before painted int spacingHeight = table.getRowMargin(); int spacingWidth = table.getColumnModel().getColumnMargin(); // Round so that when the spacing is 1 the cell does not paint obscure lines. cellRect.setBounds(cellRect.x + spacingWidth / 2, cellRect.y + spacingHeight / 2, cellRect.width - spacingWidth, cellRect.height - spacingHeight); if (table.isEditing() && table.getEditingRow() == row && table.getEditingColumn() == column) { Component component = table.getEditorComponent(); component.setBounds(cellRect); component.validate(); } else { TableCellRenderer renderer = table.getCellRenderer(row, column); Component component = table.prepareRenderer(renderer, row, column); if (component.getParent() == null) { rendererPane.add(component); } rendererPane.paintComponent(g, component, table, cellRect.x, cellRect.y, cellRect.width, cellRect.height, true); } // Have to restore the cellRect back to it's orginial size cellRect.setBounds(cellRect.x - spacingWidth / 2, cellRect.y - spacingHeight / 2, cellRect.width + spacingWidth, cellRect.height + spacingHeight); } private int lastVisibleRow(Rectangle clip) { int lastIndex = table.rowAtPoint(new Point(0, clip.y + clip.height - 1)); // If the table does not have enough rows to fill the view we'll get -1. // Replace this with the index of the last row. if (lastIndex == -1) { lastIndex = table.getRowCount() - 1; } return lastIndex; } } // MultiLineBasicTableUI