/**
* Copyright (c) 2012, Lindsay Bradford and other Contributors.
* All rights reserved.
*
* This program and the accompanying materials are made available
* under the terms of the BSD 3-Clause licence which accompanies
* this distribution, and is available at
* http://opensource.org/licenses/BSD-3-Clause
*/
package blacksmyth.personalfinancier.view.budget;
import java.awt.Component;
import java.util.LinkedList;
import java.util.Observer;
import javax.swing.DefaultCellEditor;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.event.TableModelEvent;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import blacksmyth.general.BlacksmythSwingUtilities;
import blacksmyth.personalfinancier.model.CashFlowFrequency;
import blacksmyth.personalfinancier.model.budget.BudgetModel;
import blacksmyth.personalfinancier.view.ViewPreferences;
import blacksmyth.personalfinancier.view.WidgetFactory;
public class IncomeItemTable extends JTable {
private boolean showDerivedColumns = true;
private LinkedList<TableColumn> tableColumnList = new LinkedList<TableColumn>();
private static final INCOME_ITEM_COLUMNS[] DERIVED_COLUMNS = {
INCOME_ITEM_COLUMNS.Daily,
INCOME_ITEM_COLUMNS.Weekly,
INCOME_ITEM_COLUMNS.Fortnightly,
INCOME_ITEM_COLUMNS.Monthly,
INCOME_ITEM_COLUMNS.Quarterly,
INCOME_ITEM_COLUMNS.Yearly,
};
private static final long serialVersionUID = 1L;
private static final int CELL_BUFFER = 15;
public IncomeItemTable(BudgetModel budgetModel) {
super(
new IncomeItemTableModel(budgetModel)
);
getSelectionModel().setSelectionMode(
ListSelectionModel.SINGLE_INTERVAL_SELECTION
);
// Without disabling autoStartsEdit, the DELETE key binding for removing table rows fails.
this.putClientProperty("JTable.autoStartsEdit", Boolean.FALSE);
setupColumns();
for(INCOME_ITEM_COLUMNS column : INCOME_ITEM_COLUMNS.values()) {
tableColumnList.add(
getColFromEnum(column)
);
}
BlacksmythSwingUtilities.enableEnterKeyEditsInJTable(this);
this.getIncomeItemTableModel().fireTableDataChanged();
}
private void setupColumns() {
this.tableHeader.setReorderingAllowed(false);
this.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
setupCategoryCol();
setupAmountCol(INCOME_ITEM_COLUMNS.Amount);
setupFrequencyCol();
setupAmountCol(INCOME_ITEM_COLUMNS.Daily);
setupAmountCol(INCOME_ITEM_COLUMNS.Weekly);
setupAmountCol(INCOME_ITEM_COLUMNS.Fortnightly);
setupAmountCol(INCOME_ITEM_COLUMNS.Monthly);
setupAmountCol(INCOME_ITEM_COLUMNS.Quarterly);
setupAmountCol(INCOME_ITEM_COLUMNS.Yearly);
setupAccountCol();
}
private void setupAccountCol() {
getColFromEnum(INCOME_ITEM_COLUMNS.Account).setCellRenderer(
WidgetFactory.createTableCellRenderer(JTextField.CENTER)
);
DefaultCellEditor editor = BudgetWidgetFactory.createBudgetAccountCellEditor();
getColFromEnum(INCOME_ITEM_COLUMNS.Account).setCellEditor(editor);
this.getIncomeItemTableModel().addModelObserver(
(Observer) editor.getComponent()
);
BlacksmythSwingUtilities.lockColumnWidth(
getColFromEnum(INCOME_ITEM_COLUMNS.Account),
BlacksmythSwingUtilities.getTextWidth(
WidgetFactory.ACCOUNT_BUFFER
) + CELL_BUFFER
);
}
private void setupAmountCol(INCOME_ITEM_COLUMNS thisColumn) {
BlacksmythSwingUtilities.lockColumnWidth(
getColFromEnum(thisColumn),
BlacksmythSwingUtilities.getTextWidth(
WidgetFactory.DECIMAL_FORMAT_PATTERN
) + CELL_BUFFER
);
getColFromEnum(thisColumn).setCellRenderer(
WidgetFactory.createAmountCellRenderer()
);
getColFromEnum(thisColumn).setCellEditor(
WidgetFactory.createAmountCellEditor()
);
}
private void setupCategoryCol() {
getColFromEnum(INCOME_ITEM_COLUMNS.Category).setCellRenderer(
WidgetFactory.createTableCellRenderer(JTextField.CENTER)
);
DefaultCellEditor editor = BudgetWidgetFactory.createIncomeCategoryCellEditor(
getIncomeItemTableModel().getBudgetModel()
);
this.getIncomeItemTableModel().addModelObserver(
(Observer) editor.getComponent()
);
getColFromEnum(INCOME_ITEM_COLUMNS.Category).setCellEditor(editor);
BlacksmythSwingUtilities.lockColumnWidth(
getColFromEnum(INCOME_ITEM_COLUMNS.Category),
BlacksmythSwingUtilities.getTextWidth(" Variable Essential ")
);
}
private void setupFrequencyCol() {
getColFromEnum(INCOME_ITEM_COLUMNS.Frequency).setCellRenderer(
WidgetFactory.createTableCellRenderer(JTextField.CENTER)
);
DefaultCellEditor editor = BudgetWidgetFactory.createCashFlowFrequencyCellEditor();
getColFromEnum(INCOME_ITEM_COLUMNS.Frequency).setCellEditor(editor);
BlacksmythSwingUtilities.lockColumnWidth(
getColFromEnum(INCOME_ITEM_COLUMNS.Frequency),
(int) editor.getComponent().getPreferredSize().getWidth()
);
}
public void tableChanged(TableModelEvent e) {
this.setVisible(false);
super.tableChanged(e);
this.setVisible(true);
}
private TableColumn getColFromEnum(INCOME_ITEM_COLUMNS thisEnum) {
return this.getColumnModel().getColumn(thisEnum.ordinal());
}
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
Component cellRenderer = super.prepareRenderer(renderer, row, column);
WidgetFactory.prepareTableCellRenderer(
this,
cellRenderer,
row,
column
);
// One final tweak specific to this table below.
// when the frequency selected matches the column name, render the
// foreground text of the cell slightly differently.
if (this.getColumnName(column) == this.getFrequencyAt(row).toString()) {
cellRenderer.setForeground(
ViewPreferences.getInstance().getPreferredBudgetFrequencyCellColor()
);
}
return cellRenderer;
}
private CashFlowFrequency getFrequencyAt(int row) {
return (CashFlowFrequency) this.getModel().getValueAt(
row,
INCOME_ITEM_COLUMNS.Frequency.ordinal()
);
}
public IncomeItemTableModel getIncomeItemTableModel() {
return (IncomeItemTableModel) getModel();
}
public void addBudgetItem() {
int row = this.getSelectedRow();
// if nothing selected, but there are entries, add entry at end.
if (row == -1 && this.getRowCount() > 0) {
row = this.getRowCount() - 1;
}
this.getIncomeItemTableModel().addIncomeItem(row + 1);
BlacksmythSwingUtilities.scrollRowToVisible(
this,
row + 1
);
this.selectionModel.setSelectionInterval(
row + 1,
row + 1
);
this.requestFocus();
}
public void removeBudgetItems() {
if (this.getSelectedRowCount() == 0) return;
this.getIncomeItemTableModel().removeItems(
this.getSelectedRows()
);
this.requestFocus();
}
public void moveSelectedItemDown() {
int row = this.getSelectedRow();
if (row < 0 || row == this.getRowCount() - 1) return; // nothing to do
this.getIncomeItemTableModel().moveIncomeItemDown(row);
this.selectionModel.setSelectionInterval(row + 1, row + 1);
BlacksmythSwingUtilities.scrollRowToVisible(this, row + 1);
this.requestFocus();
}
public void moveSelectedItemUp() {
int row = this.getSelectedRow();
if (row <= 0) return; // nothing to do
this.getIncomeItemTableModel().moveIncomeItemUp(row);
this.selectionModel.setSelectionInterval(row - 1, row - 1);
BlacksmythSwingUtilities.scrollRowToVisible(this, row - 1);
this.requestFocus();
}
public void toggleDerivedColumnView() {
this.setShowDerivedColumns(
!this.isShowDerivedColumns()
);
}
public boolean isShowDerivedColumns() {
return showDerivedColumns;
}
public void setShowDerivedColumns(boolean showDerivedColumns) {
this.showDerivedColumns = showDerivedColumns;
this.updateDerivedColumns();
}
private void updateDerivedColumns() {
final int totalColumns = this.getColumnCount();
for(int i = 0; i < totalColumns; i++) {
this.removeColumn(
this.getColumnModel().getColumn(0)
);
}
for(int i = 0; i < this.getModel().getColumnCount(); i++) {
INCOME_ITEM_COLUMNS modelColumn = INCOME_ITEM_COLUMNS.values()[i];
boolean isDerivedColumn = false;
for(INCOME_ITEM_COLUMNS derivedColumn : DERIVED_COLUMNS) {
if (derivedColumn.equals(modelColumn)) isDerivedColumn = true;
}
if (!isDerivedColumn) {
this.addColumn(
this.tableColumnList.get(i)
);
}
if (isDerivedColumn && this.isShowDerivedColumns()) {
this.addColumn(
this.tableColumnList.get(i)
);
}
}
}
}