/** * 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.math.BigDecimal; import java.util.Arrays; import java.util.Observable; import java.util.Observer; import javax.swing.undo.CompoundEdit; import blacksmyth.personalfinancier.control.budget.command.AddExpenseItemCommand; import blacksmyth.personalfinancier.control.budget.command.ChangeExpenseAccountCommand; import blacksmyth.personalfinancier.control.budget.command.ChangeExpenseAmountCommand; import blacksmyth.personalfinancier.control.budget.command.ChangeExpenseCategoryCommand; import blacksmyth.personalfinancier.control.budget.command.ChangeExpenseDescriptionCommand; import blacksmyth.personalfinancier.control.budget.command.ChangeExpenseFrequencyCommand; import blacksmyth.personalfinancier.control.budget.command.MoveExpenseItemDownCommand; import blacksmyth.personalfinancier.control.budget.command.MoveExpenseItemUpCommand; import blacksmyth.personalfinancier.control.budget.command.RemoveExpenseItemCommand; import blacksmyth.personalfinancier.model.BigDecimalFactory; import blacksmyth.personalfinancier.model.CashFlowFrequency; import blacksmyth.personalfinancier.model.Money; import blacksmyth.personalfinancier.model.CashFlowFrequencyUtility; import blacksmyth.personalfinancier.model.budget.BudgetEvent; import blacksmyth.personalfinancier.model.budget.BudgetItem; import blacksmyth.personalfinancier.model.budget.BudgetModel; enum EXPENSE_ITEM_COLUMNS { Category, Description, Amount, Frequency, Daily, Weekly,Fortnightly, Monthly, Quarterly, Yearly, Account } class ExpenseItemTableModel extends AbstractBudgetTableModel<EXPENSE_ITEM_COLUMNS> { public ExpenseItemTableModel(BudgetModel budgetModel) { super(); setBudgetModel(budgetModel); } @SuppressWarnings({ "unchecked", "rawtypes" }) public Class getColumnClass(int colNum) { switch (this.getColumnEnumValueAt(colNum)) { case Category: return String.class; case Description: return String.class; case Amount: return Money.class; case Frequency: return CashFlowFrequency.class; case Daily: case Weekly: case Fortnightly: case Monthly: case Quarterly: case Yearly: return BigDecimal.class; case Account: return String.class; } return Object.class; } public int getRowCount() { return getBudgetModel().getExpenseItems().size(); } public boolean isCellEditable(int rowNum, int colNum) { switch (this.getColumnEnumValueAt(colNum)) { case Daily: case Weekly: case Fortnightly: case Monthly: case Quarterly: case Yearly: return false; default: return true; } } public Object getValueAt(int rowNum, int colNum) { BudgetItem item = getBudgetModel().getExpenseItems().get(rowNum); switch (this.getColumnEnumValueAt(colNum)) { case Category: return item.getCategory(); case Description: return item.getDescription(); case Amount: return item.getBudgettedAmount().getTotal(); case Daily: return convertAmount(item, CashFlowFrequency.Daily); case Weekly: return convertAmount(item, CashFlowFrequency.Weekly); case Fortnightly: return convertAmount(item, CashFlowFrequency.Fortnightly); case Monthly: return convertAmount(item, CashFlowFrequency.Monthly); case Quarterly: return convertAmount(item, CashFlowFrequency.Quarterly); case Yearly: return convertAmount(item, CashFlowFrequency.Yearly); case Frequency: return item.getFrequency(); case Account: return item.getBudgetAccount().getNickname(); default: return null; } } private BigDecimal convertAmount(BudgetItem item, CashFlowFrequency newFrequency) { return CashFlowFrequencyUtility.convertFrequencyAmount( item.getBudgettedAmount().getTotal(), item.getFrequency(), newFrequency ); } public void setValueAt(Object value, int rowNum, int colNum) { switch (this.getColumnEnumValueAt(colNum)) { case Category: getBudgetModel().getUndoManager().addEdit( ChangeExpenseCategoryCommand.doCmd( getBudgetModel(), rowNum, (String) value ) ); break; case Description: getBudgetModel().getUndoManager().addEdit( ChangeExpenseDescriptionCommand.doCmd( getBudgetModel(), rowNum, (String) value ) ); break; case Amount: getBudgetModel().getUndoManager().addEdit( ChangeExpenseAmountCommand.doCmd( getBudgetModel(), rowNum, BigDecimalFactory.create((String) value) ) ); break; case Frequency: getBudgetModel().getUndoManager().addEdit( ChangeExpenseFrequencyCommand.doCmd( getBudgetModel(), rowNum, CashFlowFrequency.valueOf((String) value) ) ); break; case Account: getBudgetModel().getUndoManager().addEdit( ChangeExpenseAccountCommand.doCmd( getBudgetModel(), rowNum, (String) value ) ); break; } } /** * Forces a table refresh whenever the BudgetModel this TableModel * observes sends an update. */ @Override public void update(Observable budgeModelAsObject, Object budgetEventAsObject) { BudgetEvent event = (BudgetEvent) budgetEventAsObject; if (event.getItemType() == BudgetEvent.ItemType.ExpenseItems || event.getItemType() == BudgetEvent.ItemType.AllItems) { this.fireTableDataChanged(); } } public void addModelObserver(Observer observer) { this.getBudgetModel().addObserver(observer); } public void addExpenseItem(int row) { getBudgetModel().getUndoManager().addEdit( AddExpenseItemCommand.doCmd( getBudgetModel(), row ) ); } public void removeItems(int[] rows) { CompoundEdit removeItemsEdit = new CompoundEdit(); Arrays.sort(rows); // guarantee we're iterating over the rows in correct order. for(int rowIdx = rows.length - 1; rowIdx > -1; rowIdx--) { removeItemsEdit.addEdit( RemoveExpenseItemCommand.doCmd( getBudgetModel(), rows[rowIdx] ) ); } removeItemsEdit.end(); getBudgetModel().getUndoManager().addEdit(removeItemsEdit); } public void moveExpenseItemDown(int row) { getBudgetModel().getUndoManager().addEdit( MoveExpenseItemDownCommand.doCmd( getBudgetModel(), row ) ); } public void moveExpenseItemUp(int row) { getBudgetModel().getUndoManager().addEdit( MoveExpenseItemUpCommand.doCmd( getBudgetModel(), row ) ); } }