// SplitTable package org.javamoney.examples.ez.money.gui.table; import static org.javamoney.examples.ez.common.utility.I18NHelper.getSharedProperty; import static org.javamoney.examples.ez.money.ApplicationProperties.UI_CURRENCY_FORMAT; import static org.javamoney.examples.ez.money.KeywordKeys.NOT_CATEGORIZED; import static org.javamoney.examples.ez.money.model.dynamic.transaction.Split.MAX_SPLIT; import static org.javamoney.examples.ez.money.utility.EditorHelper.createAmountCellEditor; import static org.javamoney.examples.ez.money.utility.EditorHelper.createCategoryCellEditor; import static org.javamoney.examples.ez.money.utility.RenderHelper.setLookFor; import java.awt.Component; import javax.swing.JLabel; import javax.swing.JTable; import javax.swing.SwingConstants; import javax.swing.table.TableCellRenderer; import org.javamoney.examples.ez.money.gui.GUIConstants; import org.javamoney.examples.ez.money.gui.table.model.SplitModel; import org.javamoney.examples.ez.money.model.persisted.category.Category; import org.javamoney.examples.ez.money.model.persisted.category.CategoryCollection; import org.javamoney.examples.ez.common.gui.Table; /** * This class facilitates displaying transaction splits in a table. */ public final class SplitTable extends Table { /** * Constructs a new split table that will provide the specified categories to * be selected. * * @param collection The categories to provide in the table. */ public SplitTable(CategoryCollection collection) { super(COLUMNS, new SplitModel()); // Customize table. setGridColor(GUIConstants.COLOR_TABLE_GRID); setPreferredWidths(new int[] {25, 300, 75}); setRowHeight(GUIConstants.CELL_HEIGHT); // Set editors. getColumn(AMOUNT_COLUMN).setCellEditor(createAmountCellEditor()); getColumn(CATEGORY_COLUMN).setCellEditor(createCategoryCellEditor(collection)); // For some reason the table header is too small. This normalizes it. setRendererForHeaders(getDefaultHeaderRenderer()); } /** * This method adds a new split to the end of the table. The split added is * initialized with no category and an amount of 0. This method returns true * if the amount of splits in the table is less than the maximum allowed * splits, otherwise false. * * @return true or false. */ public boolean addSplit() { return addSplit(NOT_CATEGORIZED.toString(), UI_CURRENCY_FORMAT.format(0)); } /** * This method adds a new split with the specified category and amount to the * end of the table. This method returns true if the amount of splits in the * table is less than the maximum allowed splits, otherwise false. * * @param category The split's category. * @param amount The split's amount. * * @return true or false. */ public boolean addSplit(String category, String amount) { boolean result = false; if(getRowCount() < MAX_SPLIT) { ((SplitModel)getModel()).addRow(getRowCount(), category, amount); result = true; } return result; } /** * This method starts editing the category for the last row of the table. */ public void doEditCategory() { editCellAt(getRowCount() - 1, CATEGORY_COLUMN); } /** * This method returns the object responsible for rendering the cell at the * specified row and column. * * @param row The cell's row. * @param column The cell's column. * * @return The object responsible for rendering the cell at the specified row * and column. */ @Override public TableCellRenderer getCellRenderer(int row, int column) { return RENDER_HANDLER; } /** * This method removes the selected rows from the table. */ public void removeSelectedRows() { int[] rows = getSelectedRows(); if(rows.length != 0) { removeRows(rows); // Adjust the numbers of the splits that are left. for(int len = 0; len < getRowCount(); ++len) { ((SplitModel)getModel()).setValueAt("" + (len + 1), len, NUMBER_COLUMN); } } } /** * This method sets the amount of the split at the specified row to that of * the specified amount. * * @param amount The new amount the split should have. * @param row The row where the split is. */ public void setAmountAt(String amount, int row) { ((SplitModel)getModel()).setValueAt(amount, row, AMOUNT_COLUMN); } /** * An IndexOutOfBoundsException is being thrown after a row is removed and * then the previous row is edited. This method compares the row against the * row count before calling the super to prevent that exception. * * @param value The value to be displayed. * @param row The cell's row. * @param column The cell's column. */ @Override public void setValueAt(Object value, int row, int column) { if(row < getRowCount()) { super.setValueAt(value, row, column); } } ////////////////////////////////////////////////////////////////////////////// // Start of inner classes. ////////////////////////////////////////////////////////////////////////////// private class CellRenderHandler extends JLabel implements TableCellRenderer { public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { // Customize look. setLookFor(this, row, isSelected); // Text. if(value instanceof Category) { setText(((Category)value).getQIFName()); } else { setText(value.toString()); } // Alignment if(column == CATEGORY_COLUMN) { setHorizontalAlignment(SwingConstants.LEFT); } else if(column == NUMBER_COLUMN) { setHorizontalAlignment(SwingConstants.CENTER); } else { setHorizontalAlignment(SwingConstants.TRAILING); } return this; } } ////////////////////////////////////////////////////////////////////////////// // Start of class members. ////////////////////////////////////////////////////////////////////////////// private final CellRenderHandler RENDER_HANDLER = new CellRenderHandler(); private static final String[] COLUMNS = { "", getSharedProperty("category"), getSharedProperty("amount") }; /** * The column for the split's amount. */ public static final int AMOUNT_COLUMN = 2; /** * The column for the split's category. */ public static final int CATEGORY_COLUMN = 1; /** * The column for the split's number. */ public static final int NUMBER_COLUMN = 0; }