001: package org.gui4j.core.swing;
002:
003: /**
004: * FlexiBasicTableUI.java
005: *
006: * Created: Tue May 18 11:19:04 1999
007: *
008: * @author Thomas Wernitz, Da Vinci Communications Ltd <thomas_wernitz@clear.net.nz>
009: *
010: * credit to Zafir Anjum for JTableEx and thanks to SUN for their source code ;)
011: */
012:
013: import java.awt.Component;
014: import java.awt.Dimension;
015: import java.awt.Graphics;
016: import java.awt.Point;
017: import java.awt.Rectangle;
018: import java.util.Enumeration;
019:
020: import javax.swing.JComponent;
021: import javax.swing.table.JTableHeader;
022: import javax.swing.table.TableCellRenderer;
023: import javax.swing.table.TableColumn;
024: import javax.swing.table.TableModel;
025:
026: public class MultiLineBasicTableUI extends
027: javax.swing.plaf.basic.BasicTableUI {
028:
029: public MultiLineBasicTableUI() {
030: super ();
031: }
032:
033: private Dimension createTableSize(long width) {
034: int numCols = table.getColumnCount();
035: int numRows = table.getRowCount();
036: TableModel tm = table.getModel();
037: int fontHeight = table.getFontMetrics(table.getFont())
038: .getHeight();
039: int[] height = new int[numRows];
040: for (int i = 0; i < numRows; i++)
041: height[i] = fontHeight; // init to font height as minimum
042:
043: Enumeration cols = table.getColumnModel().getColumns();
044: int i = 0;
045: while (cols.hasMoreElements()) {
046: TableColumn col = (TableColumn) cols.nextElement();
047: TableCellRenderer tcr = col.getCellRenderer();
048: int colWidth = col.getWidth();
049: for (int j = 0; j < numRows; j++) {
050: if (tcr instanceof MultiLineCellRenderer) {
051: height[j] = Math.max(height[j],
052: ((MultiLineTable) table).getHeight(
053: (String) tm.getValueAt(j, i),
054: colWidth));
055: }
056: }
057: i++;
058: }
059:
060: int totalMarginWidth = table.getColumnModel().getColumnMargin()
061: * numCols;
062: // Width is always positive. The call to abs() is a workaround for
063: // a bug in the 1.1.6 JIT on Windows.
064: long widthWithMargin = Math.abs(width) + totalMarginWidth;
065: if (widthWithMargin > Integer.MAX_VALUE) {
066: widthWithMargin = Integer.MAX_VALUE;
067: }
068: int totalHeight = 0;
069: for (int k = 0; k < numRows; k++)
070: totalHeight += height[k];
071: return new Dimension((int) widthWithMargin, totalHeight
072: + numRows * table.getRowMargin());
073: }
074:
075: public Dimension getMinimumSize(JComponent c) {
076: long width = 0;
077: Enumeration enumeration = table.getColumnModel().getColumns();
078: while (enumeration.hasMoreElements()) {
079: TableColumn aColumn = (TableColumn) enumeration
080: .nextElement();
081: width = width + aColumn.getMinWidth();
082: }
083: return createTableSize(width);
084: }
085:
086: /**
087: * Return the preferred size of the table. The preferred height is the
088: * row height (plus inter-cell spacing) times the number of rows.
089: * The preferred width is the sum of the preferred widths of each column
090: * (plus inter-cell spacing).
091: * @param c
092: * @return Dimension
093: */
094: public Dimension getPreferredSize(JComponent c) {
095: long width = 0;
096: Enumeration enumeration = table.getColumnModel().getColumns();
097: while (enumeration.hasMoreElements()) {
098: TableColumn aColumn = (TableColumn) enumeration
099: .nextElement();
100: width = width + aColumn.getPreferredWidth();
101: }
102: return createTableSize(width);
103: }
104:
105: /**
106: * Return the maximum size of the table. The maximum height is the
107: * row height (plus inter-cell spacing) times the number of rows.
108: * The maximum width is the sum of the maximum widths of each column
109: * (plus inter-cell spacing).
110: * @param c
111: * @return Dimension
112: */
113: public Dimension getMaximumSize(JComponent c) {
114: long width = 0;
115: Enumeration enumeration = table.getColumnModel().getColumns();
116: while (enumeration.hasMoreElements()) {
117: TableColumn aColumn = (TableColumn) enumeration
118: .nextElement();
119: width = width + aColumn.getMaxWidth();
120: }
121: return createTableSize(width);
122: }
123:
124: public void paint(Graphics g, JComponent c) {
125: Rectangle oldClipBounds = g.getClipBounds();
126: Rectangle clipBounds = new Rectangle(oldClipBounds);
127: int tableWidth = table.getColumnModel().getTotalColumnWidth();
128: clipBounds.width = Math.min(clipBounds.width, tableWidth);
129: g.setClip(clipBounds);
130:
131: // Paint the grid
132: paintGrid(g);
133:
134: // Paint the rows
135: int firstIndex = table.rowAtPoint(new Point(0, clipBounds.y));
136: int lastIndex = lastVisibleRow(clipBounds);
137:
138: int rowMargin = table.getRowMargin();
139: Rectangle rowRect = new Rectangle(0, 0, tableWidth,
140: ((MultiLineTable) table).getRowHeight(firstIndex)
141: + rowMargin);
142: rowRect.y = 0;
143: for (int i = 0; i < firstIndex; i++) {
144: rowRect.y += ((MultiLineTable) table).getRowHeight(i)
145: + rowMargin;
146: }
147:
148: for (int index = firstIndex; index <= lastIndex; index++) {
149: // Paint any rows that need to be painted
150: if (rowRect.intersects(clipBounds)) {
151: paintRow(g, index);
152: }
153: rowRect.y += ((MultiLineTable) table).getRowHeight(index)
154: + rowMargin;
155: }
156: g.setClip(oldClipBounds);
157: }
158:
159: private void paintGrid(Graphics g) {
160: g.setColor(table.getGridColor());
161:
162: if (table.getShowHorizontalLines()) {
163: paintHorizontalLines(g);
164: }
165: if (table.getShowVerticalLines()) {
166: paintVerticalLines(g);
167: }
168: }
169:
170: /*
171: * This method paints horizontal lines regardless of whether the
172: * table is set to paint one automatically.
173: */
174: private void paintHorizontalLines(Graphics g) {
175: Rectangle r = g.getClipBounds();
176: Rectangle rect = r;
177:
178: int firstIndex = table.rowAtPoint(new Point(0, r.y));
179: int lastIndex = lastVisibleRow(r);
180: int rowMargin = table.getRowMargin();
181:
182: int y = -rowMargin;
183: for (int i = 0; i < firstIndex; i++) {
184: y += ((MultiLineTable) table).getRowHeight(i) + rowMargin;
185: }
186:
187: for (int index = firstIndex; index <= lastIndex; index++) {
188: y += ((MultiLineTable) table).getRowHeight(index)
189: + rowMargin;
190: if ((y >= rect.y) && (y <= (rect.y + rect.height))) {
191: g.drawLine(rect.x, y, rect.x + rect.width - 1, y);
192: }
193: }
194: }
195:
196: /*
197: * This method paints vertical lines regardless of whether the
198: * table is set to paint one automatically.
199: */
200: private void paintVerticalLines(Graphics g) {
201: Rectangle rect = g.getClipBounds();
202: int x = 0;
203: int count = table.getColumnCount();
204: int horizontalSpacing = table.getIntercellSpacing().width;
205: for (int index = 0; index <= count; index++) {
206: if ((x > 0)
207: && (((x - 1) >= rect.x) && ((x - 1) <= (rect.x + rect.width)))) {
208: g.drawLine(x - 1, rect.y, x - 1, rect.y + rect.height
209: - 1);
210: }
211:
212: if (index < count)
213: x += (table.getColumnModel().getColumn(index))
214: .getWidth()
215: + horizontalSpacing;
216: }
217: }
218:
219: private void paintRow(Graphics g, int row) {
220: Rectangle rect = g.getClipBounds();
221: int column = 0;
222: boolean drawn = false;
223: int draggedColumnIndex = -1;
224: Rectangle draggedCellRect = null;
225: Dimension spacing = table.getIntercellSpacing();
226: JTableHeader header = table.getTableHeader();
227:
228: // Set up the cellRect
229: Rectangle cellRect = new Rectangle();
230: cellRect.height = ((MultiLineTable) table).getRowHeight(row)
231: + spacing.height;
232: cellRect.y = 0;
233: for (int i = 0; i < row; i++) {
234: cellRect.y += ((MultiLineTable) table).getRowHeight(i)
235: + spacing.height;
236: }
237:
238: Enumeration enumeration = table.getColumnModel().getColumns();
239:
240: // Paint the non-dragged table cells first
241: while (enumeration.hasMoreElements()) {
242: TableColumn aColumn = (TableColumn) enumeration
243: .nextElement();
244:
245: cellRect.width = aColumn.getWidth() + spacing.width;
246: if (cellRect.intersects(rect)) {
247: drawn = true;
248: if ((header == null)
249: || (aColumn != header.getDraggedColumn())) {
250: paintCell(g, cellRect, row, column);
251: } else {
252: // Paint a gray well in place of the moving column
253: // This would be unnecessary if we drew the grid more cleverly
254: g.setColor(table.getParent().getBackground());
255: g.fillRect(cellRect.x, cellRect.y, cellRect.width,
256: cellRect.height);
257: draggedCellRect = new Rectangle(cellRect);
258: draggedColumnIndex = column;
259: }
260: } else {
261: if (drawn)
262: // Don't need to iterate through the rest
263: break;
264: }
265:
266: cellRect.x += cellRect.width;
267: column++;
268: }
269:
270: // paint the dragged cell if we are dragging
271: if (draggedColumnIndex != -1 && draggedCellRect != null) {
272: draggedCellRect.x += header.getDraggedDistance();
273:
274: // Fill the background
275: g.setColor(table.getBackground());
276: g.fillRect(draggedCellRect.x, draggedCellRect.y,
277: draggedCellRect.width, draggedCellRect.height);
278:
279: // paint grid if necessary.
280: g.setColor(table.getGridColor());
281: int x1 = draggedCellRect.x;
282: int y1 = draggedCellRect.y;
283: int x2 = x1 + draggedCellRect.width - 1;
284: int y2 = y1 + draggedCellRect.height - 1;
285: if (table.getShowVerticalLines()) {
286: // Left
287: // g.drawLine(x1-1, y1, x1-1, y2);
288: // Right
289: g.drawLine(x2, y1, x2, y2);
290: }
291: // Bottom
292: if (table.getShowHorizontalLines()) {
293: g.drawLine(x1, y2, x2, y2);
294: }
295:
296: // Render the cell value
297: paintCell(g, draggedCellRect, row, draggedColumnIndex);
298: }
299: }
300:
301: private void paintCell(Graphics g, Rectangle cellRect, int row,
302: int column) {
303: // The cellRect is inset by half the intercellSpacing before painted
304: int spacingHeight = table.getRowMargin();
305: int spacingWidth = table.getColumnModel().getColumnMargin();
306:
307: // Round so that when the spacing is 1 the cell does not paint obscure lines.
308: cellRect.setBounds(cellRect.x + spacingWidth / 2, cellRect.y
309: + spacingHeight / 2, cellRect.width - spacingWidth,
310: cellRect.height - spacingHeight);
311:
312: if (table.isEditing() && table.getEditingRow() == row
313: && table.getEditingColumn() == column) {
314: Component component = table.getEditorComponent();
315: component.setBounds(cellRect);
316: component.validate();
317: } else {
318: TableCellRenderer renderer = table.getCellRenderer(row,
319: column);
320: Component component = table.prepareRenderer(renderer, row,
321: column);
322:
323: if (component.getParent() == null) {
324: rendererPane.add(component);
325: }
326: rendererPane.paintComponent(g, component, table,
327: cellRect.x, cellRect.y, cellRect.width,
328: cellRect.height, true);
329: }
330: // Have to restore the cellRect back to it's orginial size
331: cellRect.setBounds(cellRect.x - spacingWidth / 2, cellRect.y
332: - spacingHeight / 2, cellRect.width + spacingWidth,
333: cellRect.height + spacingHeight);
334:
335: }
336:
337: private int lastVisibleRow(Rectangle clip) {
338: int lastIndex = table.rowAtPoint(new Point(0, clip.y
339: + clip.height - 1));
340: // If the table does not have enough rows to fill the view we'll get -1.
341: // Replace this with the index of the last row.
342: if (lastIndex == -1) {
343: lastIndex = table.getRowCount() - 1;
344: }
345: return lastIndex;
346: }
347:
348: } // MultiLineBasicTableUI
|