// TransactionFactory
package org.javamoney.examples.ez.money.gui.view.register;
import static org.javamoney.examples.ez.money.ApplicationProperties.UI_CURRENCY_SYMBOL;
import static org.javamoney.examples.ez.money.ApplicationProperties.UI_CURRENCY_FORMAT;
import static org.javamoney.examples.ez.money.ApplicationProperties.UI_DATE_FORMAT;
import static org.javamoney.examples.ez.money.ApplicationProperties.newTransactionsArePending;
import static org.javamoney.examples.ez.money.ApplicationProperties.setNewTransactionsArePending;
import static org.javamoney.examples.ez.money.ApplicationThread.getFrame;
import static org.javamoney.examples.ez.money.KeywordKeys.TRANSFER_TO;
import static org.javamoney.examples.ez.money.gui.view.register.FormButtonKeys.CANCEL;
import static org.javamoney.examples.ez.money.gui.view.register.FormButtonKeys.DATE_PICKER;
import static org.javamoney.examples.ez.money.gui.view.register.FormButtonKeys.EDIT;
import static org.javamoney.examples.ez.money.gui.view.register.FormButtonKeys.ENTER;
import static org.javamoney.examples.ez.money.gui.view.register.FormButtonKeys.NEW;
import static org.javamoney.examples.ez.money.gui.view.register.FormButtonKeys.NEXT;
import static org.javamoney.examples.ez.money.gui.view.register.FormButtonKeys.PENDING;
import static org.javamoney.examples.ez.money.gui.view.register.FormButtonKeys.SPLIT;
import static org.javamoney.examples.ez.money.gui.view.register.FormFieldKeys.AMOUNT;
import static org.javamoney.examples.ez.money.gui.view.register.FormFieldKeys.CHECK_NUMBER;
import static org.javamoney.examples.ez.money.gui.view.register.FormFieldKeys.DATE;
import static org.javamoney.examples.ez.money.gui.view.register.FormFieldKeys.NOTES;
import static org.javamoney.examples.ez.money.model.DataManager.getAccounts;
import static org.javamoney.examples.ez.money.model.DataManager.getExpenses;
import static org.javamoney.examples.ez.money.model.DataManager.getIncome;
import static org.javamoney.examples.ez.money.model.DataManager.getPayees;
import static org.javamoney.examples.ez.money.model.dynamic.transaction.TransactionTypeKeys.EXPENSE;
import static org.javamoney.examples.ez.money.model.dynamic.transaction.TransactionTypeKeys.INCOME;
import static org.javamoney.examples.ez.money.model.dynamic.transaction.TransactionTypeKeys.TRANSFER;
import static org.javamoney.examples.ez.money.model.persisted.account.AccountTypeKeys.CREDIT;
import static org.javamoney.examples.ez.money.utility.DialogHelper.inform;
import static org.javamoney.examples.ez.money.utility.IDHelper.purgeIdentifier;
import static org.javamoney.examples.ez.money.utility.TransactionHelper.isSplit;
import static org.javamoney.examples.ez.money.utility.TransactionHelper.removeFrom;
import java.awt.GridBagConstraints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;
import javax.money.MonetaryAmount;
import org.javamoney.examples.ez.money.gui.dialog.SplitDialog;
import org.javamoney.examples.ez.money.gui.view.RegisterView;
import org.javamoney.examples.ez.money.gui.view.ViewKeys;
import org.javamoney.examples.ez.money.model.dynamic.transaction.TransactionTypeKeys;
import org.javamoney.examples.ez.money.model.persisted.account.Account;
import org.javamoney.examples.ez.money.model.persisted.payee.Payee;
import org.javamoney.examples.ez.money.model.persisted.transaction.Transaction;
import org.javamoney.examples.ez.money.utility.TransactionDateHelper;
import org.javamoney.examples.ez.common.gui.Panel;
import org.javamoney.examples.ez.common.utility.I18NHelper;
import org.javamoney.moneta.Money;
/**
* This class facilitates creating transactions.
*/
abstract class TransactionFactory extends Panel {
/**
*
*/
private static final long serialVersionUID = 6592068985005342909L;
/**
* Constructs a new transaction creator for the specified transaction type.
*
* @param key
* The type of transactions to create.
*/
protected TransactionFactory(TransactionTypeKeys key) {
setForm(new Form(key, new ActionHandler()));
setLastUsedDate(new Date());
// Build panel.
setFill(GridBagConstraints.BOTH);
add(getForm(), 0, 0, 1, 1, 100, 100);
clear();
enableForm(false);
}
/**
* This method adds the specified transaction to the current account. It
* then returns the transaction if it was successfully added, otherwise it
* returns null.
*
* @param trans
* The transaction to add.
*
* @return The transaction if successfully added, otherwise null.
*/
protected final Transaction addTransaction(Transaction trans) {
return addTransactionTo(getAccount(), trans);
}
/**
* This method adds the specified transaction to the specified account. It
* then returns the transaction if it was successfully added, otherwise it
* returns null.
*
* @param account
* The account to add the transaction to.
* @param trans
* The transaction to add.
*
* @return The transaction if successfully added, otherwise null.
*/
protected final Transaction addTransactionTo(Account account,
Transaction trans) {
boolean result = account.addTransaction(trans);
if (result == false) {
trans = null;
inform(getProperty("error.title") + " \"" + account + "\".",
getProperty("error.description"));
}
return trans;
}
/**
* This method clears its form and defaults all its values.
*/
protected final void clear() {
getForm().clearFields();
getForm().getButton(PENDING).setSelected(newTransactionsArePending());
getForm().getField(DATE).setText(
UI_DATE_FORMAT.format(getLastUsedDate()));
setEditModeTransaction(null);
setIsInEditMode(false);
setSplit(null);
}
/**
* This method creates and then adds the newly created transaction to its
* account. It then returns the transaction if it was successfully added,
* otherwise it returns null.
*
* @return The transaction if successfully added, otherwise null.
*/
protected abstract Transaction createAndAdd();
/**
* This method creates and returns a new transaction from the criteria
* provided by the form. The specified key is used to determine the proper
* amount; expenses are negative and incomes are positive.
*
* @param type
* The type of transaction to create.
*
* @return A new transaction.
*/
protected final Transaction createTransaction(TransactionTypeKeys type) {
Transaction trans = null;
String payee = getForm().getPayFrom();
double amount = parseAmount();
// Put amount in proper form.
if ((type == INCOME && amount < 0.0)
|| (type == EXPENSE && amount >= 0.0)) {
amount = -amount;
}
// Put payee in proper form.
payee = purgeIdentifier(payee);
trans = new Transaction(getForm().getField(CHECK_NUMBER).getText(),
parseDate(), payee, Money.of(amount,
UI_CURRENCY_SYMBOL.getCurrency()), getCategory(),
getForm().getField(NOTES).getText());
// Set attributes not applicable in the constructor.
trans.setIsReconciled(getForm().getButton(PENDING).isSelected() == false);
if (isInEditMode() == true) {
trans.setLabel(getEditModeTransaction().getLabel());
}
return trans;
}
/**
* The method causes the creator to enter edit mode with the specified
* transaction.
*
* @param trans
* The transaction to edit.
* @param startEdit
* Whether or not to start editing the transaction.
*/
protected final void doEdit(Transaction trans, boolean startEdit) {
enableForm(false);
getForm().getButton(EDIT).setEnabled(true);
fillFormWith(trans);
setIsInEditMode(true);
setEditModeTransaction(trans);
if (startEdit == true) {
enableForm(true);
getForm().getButton(EDIT).setEnabled(false);
getForm().getButton(PENDING).requestFocus();
}
}
/**
* This method causes the creator to enter new mode.
*/
protected void doNew() {
getRegisterView().clearTableSelection();
clear();
enableForm(true);
getForm().getButton(EDIT).setEnabled(false);
getForm().getField(CHECK_NUMBER).requestFocus();
}
/**
* This method enables or disables the elements of the from depending of the
* specified value.
*
* @param value
* true or false.
*/
protected final void enableForm(boolean value) {
getForm().enableForm(value);
if (getForm().getType() == TRANSFER) {
// Initialize both chooser with the current account. At least one
// will be
// correct.
if (isInEditMode() == false) {
getForm().getPayFromChooser().setSelectedItem(
getAccount().getIdentifier());
getForm().getPayToChooser().setSelectedItem(
getAccount().getIdentifier());
}
// Enforce that making a payment to a credit card is a transfer to.
if (getAccount().getType() == CREDIT) {
getForm().getPayToChooser().setEnabled(false);
}
}
}
/**
* This method returns the account this form is referencing.
*
* @return The account this form is referencing.
*/
protected final Account getAccount() {
return getRegisterView().getAccount();
}
/**
* This method returns the category.
*
* @return The category.
*/
protected final String getCategory() {
String category = null;
if (getSplit() != null) {
category = getSplit();
} else {
category = getForm().getPayTo();
}
return category;
}
/**
* This method returns the creator's form.
*
* @return The creator's form.
*/
protected final Form getForm() {
return itsForm;
}
// ////////////////////////////////////////////////////////////////////////////
// Start of private methods.
// ////////////////////////////////////////////////////////////////////////////
private void addPayeeToCollection() {
if (getForm().getType() != TRANSFER) {
Payee payee = new Payee(getForm().getPayFrom());
if (payee.getIdentifier().length() != 0) {
getPayees().add(payee);
getForm().getPayFromChooser().displayElements();
}
}
}
private void applyChanges() {
Transaction transAdded = createAndAdd();
if (transAdded != null) {
if (isInEditMode() == true) {
removeFrom(getAccount(), getEditModeTransaction());
} else {
setLastUsedDate(transAdded.getDate());
setNewTransactionsArePending(getForm().getButton(PENDING)
.isSelected());
}
addPayeeToCollection();
clear();
enableForm(false);
getRegisterView().displayTransactions(transAdded);
getForm().getButton(NEW).requestFocus();
}
}
private void fillFormWith(Transaction trans) {
getForm().getButton(PENDING).setSelected(trans.isReconciled() == false);
getForm().getField(CHECK_NUMBER).setText(trans.getCheckNumber());
getForm().getField(DATE)
.setText(UI_DATE_FORMAT.format(trans.getDate()));
getForm().getField(NOTES).setText(trans.getNotes());
setAmount(trans.getAmount());
if (getForm().getType() == TRANSFER) {
if (trans.getCategory().equals(TRANSFER_TO.toString()) == true) {
getForm().getPayFromChooser().setSelectedItem(
getAccount().getIdentifier());
getForm().getPayToChooser().setSelectedItem(trans.getPayee());
} else {
getForm().getPayFromChooser().setSelectedItem(trans.getPayee());
getForm().getPayToChooser().setSelectedItem(
getAccount().getIdentifier());
}
} else {
getForm().getPayFromChooser().setSelectedItem(trans.getPayee());
if (isSplit(trans) == true) {
getForm().setPayToIsSplit(true);
setSplit(trans.getCategory());
} else {
getForm().getPayToChooser()
.setSelectedItem(trans.getCategory());
}
}
}
private Transaction getEditModeTransaction() {
return itsEditModeTransaction;
}
private Date getLastUsedDate() {
return itsLastUsedDate;
}
private static String getProperty(String key) {
return I18NHelper.getProperty("TypeCreator." + key);
}
private RegisterView getRegisterView() {
return (RegisterView) getFrame().getViews().getView(ViewKeys.REGISTER);
}
private String getSplit() {
return itsSplit;
}
private boolean isInEditMode() {
return itsIsInEditMode;
}
private String nextCheckNumber() {
Account account = null;
int max = 0;
if (getForm().getType() == TRANSFER) {
account = (Account) getAccounts().get(getForm().getPayFrom());
} else {
account = getAccount();
}
for (Transaction trans : account.getTransactions()) {
if (trans.getCheckNumber().length() != 0) {
try {
int number = Integer.parseInt(trans.getCheckNumber());
if (max < number) {
max = number;
}
} catch (Exception exception) {
// Ignored.
}
}
}
return "" + (max + 1);
}
private double parseAmount() {
double amount = 0.0;
try {
String str = getForm().getField(AMOUNT).getText();
if (str.length() != 0) {
amount = UI_CURRENCY_FORMAT.parse(str);
}
} catch (Exception exception) {
// Ignored.
}
return amount;
}
private Date parseDate() {
Date date = getLastUsedDate();
String text = getForm().getField(DATE).getText();
try {
date = UI_DATE_FORMAT.parse(text);
} catch (Exception exception) {
// Ignored.
}
return date;
}
private void setAmount(double value) {
getForm().getField(AMOUNT).setText(
UI_CURRENCY_FORMAT.format(Math.abs(value)));
}
private void setAmount(MonetaryAmount value) {
setAmount(value.getNumber().doubleValue());
}
private void setEditModeTransaction(Transaction trans) {
itsEditModeTransaction = trans;
}
private void setForm(Form panel) {
itsForm = panel;
}
private void setIsInEditMode(boolean value) {
itsIsInEditMode = value;
}
private void setLastUsedDate(Date date) {
itsLastUsedDate = date;
}
private void setSplit(String split) {
itsSplit = split;
}
private void showDateDialog() {
Date date = TransactionDateHelper.showDateDialog(parseDate());
getForm().getField(DATE).setText(UI_DATE_FORMAT.format(date));
getForm().getPayFromChooser().requestFocus();
}
private void showSplitDialog() {
SplitDialog split = null;
if (getForm().getType() == EXPENSE) {
split = new SplitDialog(getExpenses(), getCategory(), parseAmount());
} else {
split = new SplitDialog(getIncome(), getCategory(), parseAmount());
}
if (split.showDialog() == true) {
setAmount(split.getTotal());
setSplit(split.getSplit());
getForm().setPayToIsSplit(getSplit() != null);
}
}
// ////////////////////////////////////////////////////////////////////////////
// Start of inner classes.
// ////////////////////////////////////////////////////////////////////////////
private class ActionHandler implements ActionListener {
public void actionPerformed(ActionEvent event) {
Object source = event.getSource();
if (source == getForm().getButton(CANCEL)) {
clear();
enableForm(false);
getRegisterView().clearTableSelection();
} else if (source == getForm().getButton(DATE_PICKER)) {
showDateDialog();
} else if (source == getForm().getButton(EDIT)) {
enableForm(true);
getForm().getButton(EDIT).setEnabled(false);
getForm().getButton(PENDING).requestFocus();
} else if (source == getForm().getButton(ENTER)) {
applyChanges();
} else if (source == getForm().getButton(NEW)) {
doNew();
} else if (source == getForm().getButton(NEXT)) {
getForm().getField(CHECK_NUMBER).setText(nextCheckNumber());
getForm().getField(DATE).requestFocus();
} else if (source == getForm().getButton(SPLIT)) {
showSplitDialog();
}
}
}
// ////////////////////////////////////////////////////////////////////////////
// Start of class members.
// ////////////////////////////////////////////////////////////////////////////
private Transaction itsEditModeTransaction;
private Form itsForm;
private boolean itsIsInEditMode;
private Date itsLastUsedDate;
private String itsSplit;
}