0001: package org.uispec4j;
0002:
0003: import junit.framework.Assert;
0004: import junit.framework.AssertionFailedError;
0005: import org.uispec4j.assertion.Assertion;
0006: import org.uispec4j.utils.ArrayUtils;
0007: import org.uispec4j.utils.ColorUtils;
0008: import org.uispec4j.utils.Utils;
0009:
0010: import javax.swing.*;
0011: import javax.swing.border.Border;
0012: import javax.swing.table.JTableHeader;
0013: import javax.swing.table.TableCellRenderer;
0014: import javax.swing.table.TableColumn;
0015: import javax.swing.table.TableModel;
0016: import java.awt.*;
0017: import java.util.Arrays;
0018: import java.util.HashMap;
0019: import java.util.Map;
0020:
0021: /**
0022: * Wrapper for JTable components.<p/>
0023: * The contents of the underlying table can be usually checked with String or Boolean values,
0024: * as in the following example:
0025: * <pre><code>
0026: * assertTrue(table.contentEquals(new String[]{
0027: * {"Bart", "Simpson"},
0028: * {"Marge", "Simpson"}
0029: * }));
0030: * </code></pre>
0031: * The conversion between the values (Strings) given in the test and the values
0032: * actually displayed by the table renderer is performed by a dedicated
0033: * {@link TableCellValueConverter}, which retrieves the graphical component that draws
0034: * the table cells and determines the displayed value accordingly.
0035: * A {@link DefaultTableCellValueConverter} is used by default by the Table component.
0036: */
0037: public class Table extends AbstractUIComponent {
0038: public static final String TYPE_NAME = "table";
0039: public static final Class[] SWING_CLASSES = { JTable.class };
0040:
0041: private JTable jTable;
0042: private Header header = new Header();
0043: private TableCellValueConverter defaultCellValueConverter = new DefaultTableCellValueConverter();
0044: private Map cellValuesConvertersByColumn = new HashMap();
0045:
0046: public Table(JTable table) {
0047: this .jTable = table;
0048: }
0049:
0050: public String getDescriptionTypeName() {
0051: return TYPE_NAME;
0052: }
0053:
0054: public Component getAwtComponent() {
0055: return jTable;
0056: }
0057:
0058: public JTable getJTable() {
0059: return jTable;
0060: }
0061:
0062: /**
0063: * Returns a helper interface which gives access to the table header.
0064: */
0065: public Header getHeader() {
0066: return header;
0067: }
0068:
0069: /**
0070: * Sets a new converter for analyzing the table cells content.
0071: */
0072: public void setDefaultCellValueConverter(
0073: TableCellValueConverter cellValueConverter) {
0074: this .defaultCellValueConverter = cellValueConverter;
0075: }
0076:
0077: /**
0078: * Sets a new converter for analyzing the cells of a given column.
0079: */
0080: public void setCellValueConverter(int column,
0081: TableCellValueConverter tableCellValueConverter) {
0082: cellValuesConvertersByColumn.put(new Integer(column),
0083: tableCellValueConverter);
0084: }
0085:
0086: public void click(int row, int column) {
0087: click(row, column, Key.Modifier.NONE);
0088: }
0089:
0090: public void click(int row, int column, Key.Modifier modifier) {
0091: Rectangle rect = jTable.getCellRect(row, column, false);
0092: Mouse.doClickInRectangle(this , rect, false, modifier);
0093: }
0094:
0095: public void rightClick(int row, int column) {
0096: Rectangle rect = jTable.getCellRect(row, column, false);
0097: Mouse.doClickInRectangle(this , rect, true, Key.Modifier.NONE);
0098: }
0099:
0100: public void doubleClick(int row, int column) {
0101: Rectangle rect = jTable.getCellRect(row, column, false);
0102: Mouse.doClickInRectangle(this , rect, false, Key.Modifier.NONE);
0103: Mouse.doDoubleClickInRectangle(this , rect);
0104: }
0105:
0106: public Trigger triggerClick(final int row, final int column,
0107: final Key.Modifier modifier) {
0108: return new Trigger() {
0109: public void run() throws Exception {
0110: click(row, column, modifier);
0111: }
0112: };
0113: }
0114:
0115: public Trigger triggerRightClick(final int row, final int column) {
0116: return new Trigger() {
0117: public void run() throws Exception {
0118: rightClick(row, column);
0119: }
0120: };
0121: }
0122:
0123: public Trigger triggerDoubleClick(final int row, final int column) {
0124: return new Trigger() {
0125: public void run() throws Exception {
0126: doubleClick(row, column);
0127: }
0128: };
0129: }
0130:
0131: public int getRowCount() {
0132: return jTable.getRowCount();
0133: }
0134:
0135: public int getColumnCount() {
0136: return jTable.getColumnCount();
0137: }
0138:
0139: /**
0140: * Returns the object (String or Boolean) displayed in a given cell.<p/>
0141: * The returned object is that returned by the current TableCellValueConverter
0142: * used by the table.
0143: *
0144: * @see #setCellValueConverter(int, TableCellValueConverter)
0145: * @see #setDefaultCellValueConverter(TableCellValueConverter)
0146: */
0147: public Object getContentAt(int row, int column) {
0148: return getValueAt(row, column);
0149: }
0150:
0151: /**
0152: * Returns the displayed in a given cell using a specific converter.
0153: */
0154: public Object getContentAt(int row, int column,
0155: TableCellValueConverter converter) {
0156: return converter.getValue(row, column,
0157: getComponent(row, column), jTable.getValueAt(row,
0158: column));
0159: }
0160:
0161: /**
0162: * Returns a {@link Cell} object for interacting with the content of an individual table cell.<p/>
0163: * Sample usage:
0164: * <pre><code>
0165: * ComboBox comboBox = table.editCell(0, 0).getComboBox();
0166: * assertTrue(comboBox.contentEquals(choices));
0167: * comboBox.select("b");
0168: * </code></pre>
0169: */
0170: public Cell editCell(int row, int column) {
0171: Assert.assertTrue("Cell (" + row + "," + column
0172: + ") is not editable", jTable.isCellEditable(row,
0173: column));
0174: Component cellEditor = getSwingEditorComponentAt(row, column);
0175: JPanel cellPanel = new JPanel();
0176: cellPanel.add(cellEditor);
0177: return new Cell(cellPanel);
0178: }
0179:
0180: /**
0181: * Represents a table cell. This class extends Panel, so that all the component searching
0182: * methods available in Panel can be used to access the specific component displayed in the cell.
0183: */
0184: public class Cell extends Panel {
0185: public Cell(Container container) {
0186: super (container);
0187: }
0188: }
0189:
0190: /**
0191: * Inputs some text in a given cell.<p/>
0192: * This method only works when the underlying editor is a JTextField or a JComboBox -
0193: * it will throw an exception if this is not the case, or if the cell is not editable.
0194: * Please refer to {@link #editCell(int, int)} for a more flexible edition method.<p/>
0195: */
0196: public void editCell(int row, int column, String value,
0197: boolean validateChange) {
0198: if (!jTable.isCellEditable(row, column)) {
0199: throw new RuntimeException("Cell (" + row + ", " + column
0200: + ") is not editable");
0201: }
0202: Component cellEditor = getSwingEditorComponentAt(row, column);
0203: if (JTextField.class.isInstance(cellEditor)) {
0204: JTextField textField = ((JTextField) cellEditor);
0205: textField.setText(value);
0206: if (validateChange) {
0207: textField.postActionEvent();
0208: }
0209: } else {
0210: if (JComboBox.class.isInstance(cellEditor)) {
0211: JComboBox jCombo = (JComboBox) cellEditor;
0212: if (validateChange) {
0213: ComboBox comboBox = new ComboBox(jCombo);
0214: comboBox.select(value);
0215: }
0216: } else {
0217: throw new RuntimeException("Unexpected editor at ("
0218: + row + ", " + column + "): "
0219: + cellEditor.getClass().getName());
0220: }
0221: }
0222: }
0223:
0224: /**
0225: * Checks that no header is displayed for this table.
0226: */
0227: public Assertion hasHeader() {
0228: return new Assertion() {
0229: public void check() {
0230: if (jTable.getTableHeader() == null) {
0231: Assert.fail("The table contains an header");
0232: }
0233: }
0234: };
0235: }
0236:
0237: /**
0238: * Checks the values displayed in the table.<p/>
0239: * Sample usage:
0240: * <pre><code>
0241: * assertTrue(table.contentEquals(new Object[][]{
0242: * {"a", Boolean.TRUE, "3"},
0243: * {"c", Boolean.FALSE, "4"}
0244: * }));
0245: * </code></pre>
0246: * The conversion between the displayed values and the objects to
0247: * be given in the array can be customized with
0248: * {@link #setCellValueConverter(int, TableCellValueConverter)}
0249: */
0250: public Assertion contentEquals(final Object[][] expected) {
0251: return new Assertion() {
0252: public void check() {
0253: try {
0254: Assert.assertEquals(expected.length, jTable
0255: .getRowCount());
0256: for (int i = 0; i < expected.length; i++) {
0257: checkRow(i, expected[i]);
0258: }
0259: } catch (AssertionFailedError e) {
0260: Assert.assertEquals(ArrayUtils.toString(expected),
0261: getContent());
0262: throw e;
0263: }
0264: }
0265: };
0266: }
0267:
0268: /**
0269: * Checks the values displayed in the table for a given set of columns.
0270: * @see #contentEquals(Object[][])
0271: */
0272: public Assertion contentEquals(final String[] columnNames,
0273: final Object[][] expected) {
0274: return new Assertion() {
0275: public void check() throws Exception {
0276: int rowCount = jTable.getRowCount();
0277: if (expected.length != rowCount) {
0278: throwError("Expected " + expected.length
0279: + " rows but found " + rowCount,
0280: columnNames, expected);
0281: }
0282:
0283: for (int rowIndex = 0; rowIndex < expected.length; rowIndex++) {
0284: Object[] row = expected[rowIndex];
0285: if (columnNames.length != row.length) {
0286: Assert.fail("Expected array should have "
0287: + columnNames.length
0288: + " elements for each row "
0289: + "- invalid row " + rowIndex + ": "
0290: + ArrayUtils.toString(row));
0291: }
0292:
0293: for (int columnIndex = 0; columnIndex < columnNames.length; columnIndex++) {
0294: int actualIndex = findColumnIndex(columnNames[columnIndex]);
0295: if (!Utils.equals(
0296: expected[rowIndex][columnIndex],
0297: getValueAt(rowIndex, actualIndex))) {
0298: throwError("Error at (" + rowIndex + ", "
0299: + columnIndex + ")", columnNames,
0300: expected);
0301: }
0302: }
0303: }
0304: }
0305: };
0306: }
0307:
0308: private void throwError(String message, String[] columnNames,
0309: Object[][] expected) {
0310: String actualContent = getContent(columnNames);
0311: Assert.assertEquals(message, ArrayUtils.toString(expected),
0312: actualContent);
0313: Assert.fail("Actual: " + actualContent);// in case the string comparison didn't fail
0314: }
0315:
0316: public Assertion rowEquals(final int rowIndex,
0317: final Object[] expectedRow) {
0318: return new Assertion() {
0319: public void check() {
0320: if (rowIndex < 0) {
0321: Assert.fail("Row index should be positive");
0322: }
0323: if (rowIndex >= jTable.getRowCount()) {
0324: Assert
0325: .fail("Table contains only "
0326: + jTable.getRowCount()
0327: + " rows, unable to access row "
0328: + rowIndex);
0329: }
0330: try {
0331: checkRow(rowIndex, expectedRow);
0332: } catch (AssertionFailedError e) {
0333: StringBuffer buffer = new StringBuffer();
0334: dumpRow(jTable, rowIndex, buffer, ",");
0335: Assert.assertEquals(ArrayUtils
0336: .toString(expectedRow), buffer);
0337: }
0338: }
0339: };
0340: }
0341:
0342: public Assertion rowEquals(final int rowIndex,
0343: final String[] columnNames, final Object[] expected) {
0344: return new Assertion() {
0345: public void check() throws Exception {
0346: if (rowIndex < 0) {
0347: Assert.fail("Row index should be positive");
0348: }
0349: if (rowIndex >= jTable.getRowCount()) {
0350: Assert
0351: .fail("Table contains only "
0352: + jTable.getRowCount()
0353: + " rows, unable to access row "
0354: + rowIndex);
0355: }
0356: if (columnNames.length != expected.length) {
0357: Assert.fail("Expected array should have "
0358: + columnNames.length
0359: + " elements for each row "
0360: + "- invalid row " + rowIndex + ": "
0361: + ArrayUtils.toString(expected));
0362: }
0363: Object[] actual = new Object[expected.length];
0364: for (int columnIndex = 0; columnIndex < columnNames.length; columnIndex++) {
0365: int actualIndex = findColumnIndex(columnNames[columnIndex]);
0366: actual[columnIndex] = getValueAt(rowIndex,
0367: actualIndex);
0368: }
0369: ArrayUtils.assertEquals("Unexpected content at row "
0370: + rowIndex, expected, actual);
0371: }
0372: };
0373: }
0374:
0375: public Assertion columnEquals(final int columnIndex,
0376: final Object[] expectedColumn) {
0377: return new Assertion() {
0378: public void check() {
0379: if (columnIndex < 0) {
0380: Assert.fail("Column index should be positive");
0381: }
0382: if (columnIndex >= jTable.getColumnCount()) {
0383: Assert.fail("Table contains only "
0384: + jTable.getColumnCount()
0385: + " columns, unable to access column "
0386: + columnIndex);
0387: }
0388: try {
0389: checkColumn(columnIndex, expectedColumn);
0390: } catch (AssertionFailedError e) {
0391: StringBuffer buffer = new StringBuffer();
0392: dumpColumn(jTable, columnIndex, buffer, ",");
0393: Assert.assertEquals(ArrayUtils
0394: .toString(expectedColumn), buffer);
0395: }
0396: }
0397: };
0398: }
0399:
0400: public Assertion isEmpty() {
0401: return new Assertion() {
0402: public void check() {
0403: try {
0404: Assert.assertEquals(0, jTable.getRowCount());
0405: } catch (AssertionFailedError e) {
0406: Assert.fail("Expected: empty table but was:"
0407: + getContent());
0408: }
0409: }
0410: };
0411: }
0412:
0413: /**
0414: * Checks the foreground color of the table cells
0415: *
0416: * @see <a href="http://www.uispec4j.org/usingcolors.html">Using colors</a>
0417: */
0418: public Assertion foregroundEquals(final Object[][] colors) {
0419: return new Assertion() {
0420: public void check() {
0421: checkColors(colors, new ComponentColorAccessor() {
0422: public Color getColor(Component component) {
0423: return component.getForeground();
0424: }
0425: });
0426: }
0427: };
0428: }
0429:
0430: /**
0431: * Checks the background color of the table cells
0432: *
0433: * @see <a href="http://www.uispec4j.org/usingcolors.html">Using colors</a>
0434: */
0435: public Assertion backgroundEquals(final Object[][] colors) {
0436: return new Assertion() {
0437: public void check() {
0438: checkColors(colors, new ComponentColorAccessor() {
0439: public Color getColor(Component component) {
0440: return component.getBackground();
0441: }
0442: });
0443: }
0444: };
0445: }
0446:
0447: private interface ComponentPropertyAccessor {
0448: Object getProperty(Component component);
0449: }
0450:
0451: public Assertion borderEquals(final Border[][] borders) {
0452: return new Assertion() {
0453: public void check() {
0454: assertCellPropertyEquals(borders,
0455: new ComponentPropertyAccessor() {
0456: public Object getProperty(
0457: Component component) {
0458: if (!JComponent.class
0459: .isAssignableFrom(component
0460: .getClass())) {
0461: throw new RuntimeException(
0462: "Component '"
0463: + component
0464: .getClass()
0465: + "' does not support borders");
0466: }
0467: return ((JComponent) component)
0468: .getBorder();
0469: }
0470: });
0471: }
0472: };
0473: }
0474:
0475: private int findColumnIndex(String columnName) {
0476: for (int columnIndex = 0; columnIndex < jTable.getColumnCount(); columnIndex++) {
0477: if (jTable.getColumnName(columnIndex).equalsIgnoreCase(
0478: columnName)) {
0479: return columnIndex;
0480: }
0481: }
0482: throw new AssertionFailedError("Column '" + columnName
0483: + "' not found");
0484: }
0485:
0486: public Assertion isEditable(final boolean[][] expected) {
0487: return new Assertion() {
0488: public void check() {
0489: Boolean[][] actual = new Boolean[jTable.getRowCount()][jTable
0490: .getColumnCount()];
0491: for (int i = 0; i < actual.length; i++) {
0492: Boolean[] row = actual[i];
0493: for (int j = 0; j < row.length; j++) {
0494: actual[i][j] = Boolean.valueOf(jTable
0495: .isCellEditable(i, j));
0496: }
0497: }
0498: ArrayUtils.assertEquals(ArrayUtils
0499: .toBooleanObjects(expected), actual);
0500: }
0501: };
0502: }
0503:
0504: public Assertion columnIsEditable(final int columnIndex,
0505: final boolean isEditable) {
0506: return new Assertion() {
0507: public void check() {
0508: for (int i = 0; i < jTable.getRowCount(); i++) {
0509: if (jTable.isCellEditable(i, columnIndex) != isEditable) {
0510: if (isEditable) {
0511: Assert.fail("Cell at row " + i
0512: + " is not editable");
0513: } else {
0514: Assert.fail("Cell at row " + i
0515: + " is editable");
0516: }
0517: }
0518: }
0519: }
0520: };
0521: }
0522:
0523: public Assertion cellIsEditable(final int rowIndex,
0524: final int columnIndex) {
0525: return new Assertion() {
0526: public void check() {
0527: Assert.assertTrue(jTable.isCellEditable(rowIndex,
0528: columnIndex));
0529: }
0530: };
0531: }
0532:
0533: public Assertion columnIsEditable(final String columnName,
0534: final boolean shouldBeEditable) {
0535: return columnIsEditable(findColumnIndex(columnName),
0536: shouldBeEditable);
0537: }
0538:
0539: private static interface ComponentColorAccessor {
0540: Color getColor(Component component);
0541: }
0542:
0543: public Assertion selectionIsEmpty() {
0544: return new Assertion() {
0545: public void check() {
0546: Assert.assertTrue("Selection is not empty", jTable
0547: .getSelectionModel().isSelectionEmpty());
0548: }
0549: };
0550: }
0551:
0552: /**
0553: * Checks the selection on a cell-by-cell basis.
0554: */
0555: public Assertion selectionEquals(final boolean[][] expected) {
0556: return new Assertion() {
0557: public void check() {
0558: int rowCount = expected.length;
0559: int columnCount = expected[0].length;
0560: Boolean[][] actual = new Boolean[rowCount][columnCount];
0561: if (jTable.getCellSelectionEnabled()) {
0562: for (int row = 0; row < rowCount; row++) {
0563: for (int column = 0; column < columnCount; column++) {
0564: actual[row][column] = Boolean
0565: .valueOf(jTable.isCellSelected(row,
0566: column));
0567: }
0568: }
0569: } else {
0570: for (int row = 0; row < rowCount; row++) {
0571: boolean isRowSelected = jTable
0572: .isRowSelected(row);
0573: for (int column = 0; column < columnCount; column++) {
0574: actual[row][column] = Boolean
0575: .valueOf(isRowSelected);
0576: }
0577: }
0578: }
0579: ArrayUtils.orderedCompare(ArrayUtils
0580: .toBooleanObjects(expected), actual);
0581: }
0582: };
0583: }
0584:
0585: public Assertion rowIsSelected(final int rowIndex) {
0586: return new Assertion() {
0587: public void check() {
0588: Assert.assertTrue(jTable.isRowSelected(rowIndex));
0589: }
0590: };
0591: }
0592:
0593: public Assertion cellIsSelected(final int rowIndex,
0594: final int columnIndex) {
0595: return new Assertion() {
0596: public void check() {
0597: if (!jTable.getCellSelectionEnabled()) {
0598: Assert
0599: .fail("Cell-level selection is not supported on this table");
0600: }
0601: Assert.assertTrue(jTable.isCellSelected(rowIndex,
0602: columnIndex));
0603: }
0604: };
0605: }
0606:
0607: public String toString() {
0608: return getContent();
0609: }
0610:
0611: private String getContent() {
0612: StringBuffer buffer = new StringBuffer();
0613: buffer.append('[');
0614: for (int row = 0, rowCount = jTable.getRowCount(); row < rowCount; row++) {
0615: if (row > 0) {
0616: buffer.append("\n ");
0617: }
0618: buffer.append('[');
0619: dumpRow(jTable, row, buffer, ",\t");
0620: buffer.append(']');
0621: }
0622: buffer.append(']');
0623: return buffer.toString();
0624: }
0625:
0626: private String getContent(String[] columnNames) {
0627: StringBuffer buffer = new StringBuffer();
0628: buffer.append('[');
0629: for (int row = 0, rowCount = jTable.getRowCount(); row < rowCount; row++) {
0630: if (row > 0) {
0631: buffer.append("\n ");
0632: }
0633: buffer.append('[');
0634: for (int col = 0, colCount = columnNames.length; col < colCount; col++) {
0635: buffer.append(getValueAt(row,
0636: findColumnIndex(columnNames[col])));
0637: if (col < (colCount - 1)) {
0638: buffer.append(",\t");
0639: }
0640: }
0641: buffer.append(']');
0642: }
0643: buffer.append(']');
0644: return buffer.toString();
0645: }
0646:
0647: public Component getSwingEditorComponentAt(int row, int column) {
0648: jTable.editCellAt(row, column);
0649: return jTable.getEditorComponent();
0650: }
0651:
0652: public void resizeColumn(String columnName, int width) {
0653: findColumn(columnName).setPreferredWidth(width);
0654: }
0655:
0656: public Assertion columnSizeEquals(final String columnName,
0657: final int expectedWidth) {
0658: return new Assertion() {
0659: public void check() {
0660: Assert.assertEquals(expectedWidth, findColumn(
0661: columnName).getPreferredWidth());
0662: }
0663: };
0664: }
0665:
0666: public Assertion columnSizeEquals(final int columnIndex,
0667: final int expectedWidth) {
0668: return new Assertion() {
0669: public void check() {
0670: Assert.assertEquals(expectedWidth, jTable
0671: .getColumnModel().getColumn(columnIndex)
0672: .getPreferredWidth());
0673: }
0674: };
0675: }
0676:
0677: public Assertion rowsAreSelected(final int[] rowIndexes) {
0678: return new Assertion() {
0679: public void check() {
0680: int[] actualSelection = jTable.getSelectedRows();
0681: Arrays.sort(actualSelection);
0682: int[] expectedSelection = (int[]) rowIndexes.clone();
0683: Arrays.sort(expectedSelection);
0684: ArrayUtils.assertEquals(expectedSelection,
0685: actualSelection);
0686: }
0687: };
0688: }
0689:
0690: public void selectCell(int row, int column) {
0691: if (!jTable.getCellSelectionEnabled()) {
0692: Assert
0693: .fail("Individual cell selection is not allowed on this table");
0694: }
0695: jTable.setRowSelectionInterval(row, row);
0696: jTable.setColumnSelectionInterval(column, column);
0697: }
0698:
0699: public void selectRow(int row) {
0700: jTable.setRowSelectionInterval(row, row);
0701: if (jTable.getCellSelectionEnabled()) {
0702: jTable.setColumnSelectionInterval(0, jTable
0703: .getColumnCount() - 1);
0704: }
0705: }
0706:
0707: public void selectRows(int[] rowIndexes) {
0708: jTable.getSelectionModel().setValueIsAdjusting(true);
0709: try {
0710: jTable.clearSelection();
0711: for (int i = 0; i < rowIndexes.length; i++) {
0712: int row = rowIndexes[i];
0713: jTable.addRowSelectionInterval(row, row);
0714: }
0715: if (jTable.getCellSelectionEnabled()) {
0716: jTable.setColumnSelectionInterval(0, jTable
0717: .getColumnCount() - 1);
0718: }
0719: } finally {
0720: jTable.getSelectionModel().setValueIsAdjusting(false);
0721: }
0722: }
0723:
0724: public void selectRows(int start, int end) {
0725: if (start > end) {
0726: throw new IllegalArgumentException("Invalid indexes: "
0727: + start + " > " + end);
0728: }
0729: jTable.setRowSelectionInterval(start, end);
0730: }
0731:
0732: public void selectBlock(int top, int left, int bottom, int right) {
0733: Assert.assertTrue(
0734: "Only row-level selection is allowed on this table",
0735: jTable.getCellSelectionEnabled());
0736: if ((top > bottom) && (left > right)) {
0737: throw new IllegalArgumentException(
0738: "Invalid block definition - expected top <= bottom and left <= right");
0739: }
0740: jTable.setRowSelectionInterval(top, bottom);
0741: jTable.setColumnSelectionInterval(left, right);
0742: }
0743:
0744: public void addRowToSelection(int row) {
0745: jTable.addRowSelectionInterval(row, row);
0746: if (jTable.getCellSelectionEnabled()) {
0747: jTable.setColumnSelectionInterval(0, jTable
0748: .getColumnCount() - 1);
0749: }
0750: }
0751:
0752: public void removeRowFromSelection(int row) {
0753: Assert.assertTrue("Row " + row + " is not selected", jTable
0754: .isRowSelected(row));
0755: jTable.removeRowSelectionInterval(row, row);
0756: }
0757:
0758: public void clearSelection() {
0759: jTable.clearSelection();
0760: }
0761:
0762: /**
0763: * Helper interface for manipulating the table header, if any
0764: */
0765: public class Header {
0766: private Header() {
0767: }
0768:
0769: public String[] getColumnNames() {
0770: String[] columnNames = new String[jTable.getColumnCount()];
0771: for (int columnIndex = 0; columnIndex < jTable
0772: .getColumnCount(); columnIndex++) {
0773: columnNames[columnIndex] = jTable
0774: .getColumnName(columnIndex);
0775: }
0776: return columnNames;
0777: }
0778:
0779: public int findColumnIndex(String columnName) {
0780: return Table.this .findColumnIndex(columnName);
0781: }
0782:
0783: /**
0784: * Checks the column names.
0785: */
0786: public Assertion contentEquals(final String[] expectedHeaders) {
0787: return new Assertion() {
0788: public void check() {
0789: checkHeader();
0790: try {
0791: Assert.assertEquals(expectedHeaders.length,
0792: jTable.getColumnCount());
0793: for (int i = 0; i < expectedHeaders.length; i++) {
0794: Assert.assertEquals(expectedHeaders[i],
0795: jTable.getColumnName(i));
0796: }
0797: } catch (AssertionFailedError e) {
0798: Assert.assertEquals(ArrayUtils
0799: .toString(expectedHeaders), ArrayUtils
0800: .toString(getColumnNames()));
0801: throw e;
0802: }
0803: }
0804: };
0805: }
0806:
0807: /**
0808: * Returns a string description of the default background color.
0809: */
0810: public String getDefaultBackground() {
0811: checkHeader();
0812: return ColorUtils.getColorDescription(jTable
0813: .getTableHeader().getBackground());
0814: }
0815:
0816: /**
0817: * Checks the background color on each column of the table header.
0818: */
0819: public Assertion backgroundEquals(final Object[] expectedColors) {
0820: return new Assertion() {
0821: public void check() {
0822: checkHeader();
0823: TableModel model = jTable.getModel();
0824: TableCellRenderer headerRenderer = jTable
0825: .getTableHeader().getDefaultRenderer();
0826: for (int columnIndex = 0; columnIndex < model
0827: .getColumnCount(); columnIndex++) {
0828: Component component = headerRenderer
0829: .getTableCellRendererComponent(
0830: jTable,
0831: model
0832: .getColumnName(columnIndex),
0833: false, false, -1, columnIndex);
0834: ColorUtils.assertEquals(
0835: "Unexpected color at column "
0836: + columnIndex,
0837: expectedColors[columnIndex], component
0838: .getBackground());
0839: }
0840: }
0841: };
0842: }
0843:
0844: public void click(int columnIndex) {
0845: checkHeader();
0846: JTableHeader tableHeader = jTable.getTableHeader();
0847: Mouse.doClickInRectangle(tableHeader, tableHeader
0848: .getHeaderRect(columnIndex), false,
0849: Key.Modifier.NONE);
0850: }
0851:
0852: public void click(String columnName) {
0853: checkHeader();
0854: JTableHeader tableHeader = jTable.getTableHeader();
0855: int columnIndex = findColumnIndex(columnName);
0856: Mouse.doClickInRectangle(tableHeader, tableHeader
0857: .getHeaderRect(columnIndex), false,
0858: Key.Modifier.NONE);
0859: }
0860:
0861: public Trigger triggerClick(final String columnName) {
0862: return new Trigger() {
0863: public void run() throws Exception {
0864: click(columnName);
0865: }
0866: };
0867: }
0868:
0869: public Trigger triggerClick(final int columnIndex) {
0870: return new Trigger() {
0871: public void run() throws Exception {
0872: click(columnIndex);
0873: }
0874: };
0875: }
0876:
0877: public void rightClick(int columnIndex) {
0878: checkHeader();
0879: JTableHeader tableHeader = jTable.getTableHeader();
0880: Mouse.doClickInRectangle(tableHeader, tableHeader
0881: .getHeaderRect(columnIndex), true,
0882: Key.Modifier.NONE);
0883: }
0884:
0885: public void rightClick(String columnName) {
0886: checkHeader();
0887: JTableHeader tableHeader = jTable.getTableHeader();
0888: int columnIndex = findColumnIndex(columnName);
0889: Mouse.doClickInRectangle(tableHeader, tableHeader
0890: .getHeaderRect(columnIndex), true,
0891: Key.Modifier.NONE);
0892: }
0893:
0894: public Trigger triggerRightClick(final int columnIndex) {
0895: return new Trigger() {
0896: public void run() throws Exception {
0897: rightClick(columnIndex);
0898: }
0899: };
0900: }
0901:
0902: public Trigger triggerRightClick(final String columnName) {
0903: return new Trigger() {
0904: public void run() throws Exception {
0905: rightClick(columnName);
0906: }
0907: };
0908: }
0909:
0910: private void checkHeader() {
0911: Assert.assertNotNull("The table contains no header", jTable
0912: .getTableHeader());
0913: }
0914: }
0915:
0916: private void checkColors(Object[][] colors,
0917: ComponentColorAccessor accessor) {
0918: Assert.assertEquals(colors.length, jTable.getRowCount());
0919: for (int row = 0; row < colors.length; row++) {
0920: for (int col = 0; col < colors[row].length; col++) {
0921: TableCellRenderer cellRenderer = jTable
0922: .getCellRenderer(row, col);
0923: Component component = cellRenderer
0924: .getTableCellRendererComponent(jTable, jTable
0925: .getModel().getValueAt(row, col),
0926: jTable.isCellSelected(row, col), false,
0927: row, col);
0928: ColorUtils.assertEquals("Error at (" + row + ", " + col
0929: + ") -", colors[row][col], accessor
0930: .getColor(component));
0931: }
0932: }
0933: }
0934:
0935: private TableColumn findColumn(String columnName) {
0936: int columnIndex = findColumnIndex(columnName);
0937: if (columnIndex == -1) {
0938: throw new RuntimeException("Column '" + columnName
0939: + "' not found");
0940: }
0941: return jTable.getColumnModel().getColumn(columnIndex);
0942: }
0943:
0944: private void dumpRow(JTable table, int row, StringBuffer buffer,
0945: String separator) {
0946: for (int col = 0, colCount = table.getColumnCount(); col < colCount; col++) {
0947: buffer.append(getValueAt(row, col));
0948: if (col < (colCount - 1)) {
0949: buffer.append(separator);
0950: }
0951: }
0952: }
0953:
0954: private void dumpColumn(JTable table, int col, StringBuffer buffer,
0955: String separator) {
0956: for (int row = 0, rowCount = table.getRowCount(); row < rowCount; row++) {
0957: buffer.append(getValueAt(row, col));
0958: if (row < (rowCount - 1)) {
0959: buffer.append(separator);
0960: }
0961: }
0962: }
0963:
0964: private void checkRow(int rowIndex, Object[] expectedRow) {
0965: Assert
0966: .assertEquals(expectedRow.length, jTable
0967: .getColumnCount());
0968: for (int columnIndex = 0; columnIndex < expectedRow.length; columnIndex++) {
0969: checkValueAt(rowIndex, columnIndex,
0970: expectedRow[columnIndex]);
0971: }
0972: }
0973:
0974: private void checkColumn(int columnIndex, Object[] expectedColumn) {
0975: Assert
0976: .assertEquals(expectedColumn.length, jTable
0977: .getRowCount());
0978: for (int rowIndex = 0; rowIndex < expectedColumn.length; rowIndex++) {
0979: checkValueAt(rowIndex, columnIndex,
0980: expectedColumn[rowIndex]);
0981: }
0982: }
0983:
0984: private void checkValueAt(int rowIndex, int columnIndex,
0985: Object expectedValue) {
0986: Assert.assertEquals("Element at (" + rowIndex + ", "
0987: + columnIndex + ") does not match", expectedValue,
0988: getValueAt(rowIndex, columnIndex));
0989: }
0990:
0991: private Object getValueAt(int rowIndex, int columnIndex) {
0992: return getCellValueConverter(columnIndex).getValue(rowIndex,
0993: columnIndex, getComponent(rowIndex, columnIndex),
0994: jTable.getValueAt(rowIndex, columnIndex));
0995: }
0996:
0997: private TableCellValueConverter getCellValueConverter(
0998: int columnIndex) {
0999: TableCellValueConverter specificConverter = (TableCellValueConverter) cellValuesConvertersByColumn
1000: .get(new Integer(columnIndex));
1001: if (specificConverter != null) {
1002: return specificConverter;
1003: }
1004: return defaultCellValueConverter;
1005: }
1006:
1007: private void assertCellPropertyEquals(Object[][] properties,
1008: ComponentPropertyAccessor accessor) {
1009: Assert.assertEquals(properties.length, jTable.getRowCount());
1010: for (int row = 0; row < properties.length; row++) {
1011: for (int col = 0; col < properties[row].length; col++) {
1012: TableCellRenderer cellRenderer = jTable
1013: .getCellRenderer(row, col);
1014: Component component = cellRenderer
1015: .getTableCellRendererComponent(jTable, jTable
1016: .getModel().getValueAt(row, col),
1017: jTable.isCellSelected(row, col), false,
1018: row, col);
1019: Assert.assertEquals("Error at (" + row + ", " + col
1020: + ") -", properties[row][col], accessor
1021: .getProperty(component));
1022: }
1023: }
1024: }
1025:
1026: private Component getComponent(int row, int column) {
1027: return jTable.getCellRenderer(row, column)
1028: .getTableCellRendererComponent(jTable,
1029: jTable.getValueAt(row, column),
1030: jTable.isCellSelected(row, column), false, row,
1031: column);
1032: }
1033: }
|