// SplitDialog
package org.javamoney.examples.ez.money.gui.dialog;
import static org.javamoney.examples.ez.common.utility.BorderHelper.createTitledBorder;
import static org.javamoney.examples.ez.common.utility.ButtonHelper.buildButton;
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.gui.table.SplitTable.AMOUNT_COLUMN;
import static org.javamoney.examples.ez.money.gui.table.SplitTable.CATEGORY_COLUMN;
import static org.javamoney.examples.ez.money.model.dynamic.transaction.Split.AMOUNT_SEPARATOR;
import static org.javamoney.examples.ez.money.model.dynamic.transaction.Split.ITEM_SEPARATOR;
import static org.javamoney.examples.ez.money.model.dynamic.transaction.Split.ITEM_SEPARATOR_CHAR;
import java.awt.GridBagConstraints;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JLabel;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import org.javamoney.examples.ez.money.IconKeys;
import org.javamoney.examples.ez.money.gui.GUIConstants;
import org.javamoney.examples.ez.money.gui.table.SplitTable;
import org.javamoney.examples.ez.money.locale.CurrencyFormat;
import org.javamoney.examples.ez.money.locale.CurrencyFormatKeys;
import org.javamoney.examples.ez.money.model.dynamic.transaction.Split;
import org.javamoney.examples.ez.money.model.persisted.category.CategoryCollection;
import org.javamoney.examples.ez.common.gui.DialogHeader;
import org.javamoney.examples.ez.common.gui.Link;
import org.javamoney.examples.ez.common.gui.Panel;
import org.javamoney.examples.ez.common.gui.ScrollPane;
import org.javamoney.examples.ez.common.utility.I18NHelper;
/**
* This class facilitates building a split for a transaction.
*/
public
final
class
SplitDialog
extends ApplicationDialog
{
/**
* Constructs a new split dialog that will reference the specified split, have
* the specified transaction total, and provide the specified categories to be
* selected.
*
* @param collection The categories to provide in the table to be selected.
* @param split The split to reference.
* @param total The total amount of the transaction.
*/
public
SplitDialog(CategoryCollection collection, String split, double total)
{
super(575, 425);
setAllowEvents(true);
setTable(new SplitTable(collection));
setTotal(total);
createLabels();
buildPanel();
initializeTable(split, getTotal());
// Add listeners.
getTable().getModel().addTableModelListener(new TableModelHandler());
}
/**
* This method returns the formatted split, or null if the dialog was
* cancelled or the split is empty.
*
* @return The formatted split.
*/
public
String
getSplit()
{
String str = "";
if(wasAccepted() == true)
{
for(int len = 0; len < getTable().getRowCount(); ++len)
{
try
{
String amount = (String)getTable().getValueAt(len, AMOUNT_COLUMN);
String category = (String)getTable().getValueAt(len, CATEGORY_COLUMN);
if(category.equals(NOT_CATEGORIZED.toString()) == true)
{
category = "";
}
str += ITEM_SEPARATOR + category + AMOUNT_SEPARATOR +
US_DOLLAR.format(UI_CURRENCY_FORMAT.parse(amount));
}
catch(Exception exception)
{
// Ignored.
}
}
}
if(str.length() == 0)
{
str = null;
}
return str;
}
/**
* This method returns the combined amount of all the splits.
*
* @return The combined amount of all the splits.
*/
public
double
getTotal()
{
return itsTotal;
}
/**
* This method returns true if the dialog was accepted, otherwise false.
*
* @return true or false.
*/
public
boolean
showDialog()
{
runDialog();
return wasAccepted();
}
//////////////////////////////////////////////////////////////////////////////
// Start of private methods.
//////////////////////////////////////////////////////////////////////////////
private
boolean
allowEvents()
{
return itsAllowEvents;
}
private
void
buildPanel()
{
ActionHandler handler = new ActionHandler();
// Build panel.
getContentPane().setFill(GridBagConstraints.BOTH);
getContentPane().add(createDialogHeader(), 0, 0, 1, 1, 100, 0);
getContentPane().add(createTablePanel(), 0, 1, 1, 1, 0, 100);
getContentPane().add(createOptionsPanel(), 0, 2, 1, 1, 0, 0);
getContentPane().add(createDetailsPanel(), 0, 3, 1, 1, 0, 0);
getContentPane().add(createOKCancelButtonPanel(handler), 0, 4, 1, 1, 0, 0);
}
private
Panel
createDetailsPanel()
{
Panel panel = new Panel();
Panel details = new Panel();
String gap = ": ";
// Build details panel.
details.setAnchor(GridBagConstraints.EAST);
details.add(getProperty("sum") + gap, 0, 0, 1, 1, 0, 33);
details.add(getProperty("unassigned") + gap, 0, 1, 1, 1, 0, 33);
details.add(getProperty("total") + gap, 0, 2, 1, 1, 0, 34);
details.setAnchor(GridBagConstraints.WEST);
for(int len = 0; len < getLabels().length; ++len)
{
details.add(getLabels()[len], 1, len, 1, 1, 100, 0);
}
details.setBorder(createTitledBorder(getProperty("details")));
// Build panel.
panel.setFill(GridBagConstraints.BOTH);
panel.add(details, 0, 0, 1, 1, 100, 100);
panel.setInsets(new Insets(0, 15, 0, 15));
return panel;
}
private
static
DialogHeader
createDialogHeader()
{
String description = getProperty("description");
String title = getProperty("title");
return new DialogHeader(title, description, IconKeys.DIALOG_SPLIT.getIcon());
}
private
void
createLabels()
{
itsLabels = new JLabel[3];
for(int len = 0; len < getLabels().length; ++len)
{
getLabels()[len] = new JLabel(UI_CURRENCY_FORMAT.format(0));
}
}
private
Panel
createOptionsPanel()
{
Panel panel = new Panel();
ActionHandler handler = new ActionHandler();
Link add = new Link();
Link remove = new Link();
// Build buttons.
buildButton(add, ACTION_ADD, handler);
buildButton(remove, ACTION_REMOVE, handler);
// Build panel.
panel.setAnchor(GridBagConstraints.EAST);
panel.add(add, 0, 0, 1, 1, 50, 50);
panel.setAnchor(GridBagConstraints.CENTER);
panel.addEmptyCellAt(1, 0);
panel.setAnchor(GridBagConstraints.WEST);
panel.add(remove, 2, 0, 1, 1, 50, 50);
return panel;
}
private
Panel
createTablePanel()
{
Panel panel = new Panel();
ScrollPane scrollPane = new ScrollPane(getTable());
// Build scroll pane.
scrollPane.setBackground(GUIConstants.COLOR_BACKGROUND_FILL);
// Build panel.
panel.setFill(GridBagConstraints.BOTH);
panel.add(scrollPane, 0, 0, 1, 1, 100, 100);
panel.setInsets(new Insets(7, 15, 0, 15));
return panel;
}
private
JLabel[]
getLabels()
{
return itsLabels;
}
private
static
String
getProperty(String key)
{
return I18NHelper.getProperty("SplitDialog." + key);
}
private
SplitTable
getTable()
{
return itsTable;
}
private
void
initializeTable(String category, double total)
{
Split split = null;
double sum = 0.0;
// Put into proper split form.
if(category.length() == 0 || category.charAt(0) != ITEM_SEPARATOR_CHAR)
{
category = ITEM_SEPARATOR + category + AMOUNT_SEPARATOR + US_DOLLAR.format(0);
}
split = new Split(category, total);
for(int len = 0; len < split.size(); ++len)
{
double amount = Math.abs(split.getAmount(len));
category = split.getCategory(len);
if(category.length() == 0)
{
category = NOT_CATEGORIZED.toString();
}
getTable().addSplit(category, UI_CURRENCY_FORMAT.format(amount));
sum += amount;
}
getLabels()[SUM].setText(UI_CURRENCY_FORMAT.format(sum));
getLabels()[TOTAL].setText(UI_CURRENCY_FORMAT.format(total));
getLabels()[UNASSIGNED].setText(UI_CURRENCY_FORMAT.format(total - sum));
}
private
void
setAllowEvents(boolean value)
{
itsAllowEvents = value;
}
private
void
setTable(SplitTable table)
{
itsTable = table;
}
private
void
setTotal(double total)
{
itsTotal = total;
}
private
void
updateDetails()
{
double total = 0.0;
// Stop responding to events.
setAllowEvents(false);
for(int len = 0; len < getTable().getRowCount(); ++len)
{
try
{
String str = (String)getTable().getValueAt(len, AMOUNT_COLUMN);
double amount = UI_CURRENCY_FORMAT.parse(str);
total += amount;
getTable().setAmountAt(UI_CURRENCY_FORMAT.format(amount), len);
}
catch(Exception exception)
{
getTable().setAmountAt(UI_CURRENCY_FORMAT.format(0), len);
}
}
getLabels()[SUM].setText(UI_CURRENCY_FORMAT.format(total));
if(total > getTotal())
{
getLabels()[TOTAL].setText(UI_CURRENCY_FORMAT.format(total));
getLabels()[UNASSIGNED].setText(UI_CURRENCY_FORMAT.format(0.0));
setTotal(total);
}
else
{
getLabels()[UNASSIGNED].setText(UI_CURRENCY_FORMAT.format(getTotal() - total));
}
// Resume responding to events.
setAllowEvents(true);
}
//////////////////////////////////////////////////////////////////////////////
// Start of inner classes.
//////////////////////////////////////////////////////////////////////////////
private
class
ActionHandler
implements ActionListener
{
public
void
actionPerformed(ActionEvent event)
{
String command = event.getActionCommand();
if(command.equals(ACTION_ADD) == true)
{
if(getTable().addSplit() == true)
{
getTable().doEditCategory();
}
}
else if(command.equals(ACTION_REMOVE) == true)
{
getTable().removeSelectedRows();
updateDetails();
}
else
{
setAccepted(command.equals(ACTION_OK));
dispose();
}
}
}
private
class
TableModelHandler
implements TableModelListener
{
public
void
tableChanged(TableModelEvent event)
{
if(event.getColumn() == AMOUNT_COLUMN && event.getType() == TableModelEvent.UPDATE)
{
if(allowEvents() == true)
{
updateDetails();
}
}
}
}
//////////////////////////////////////////////////////////////////////////////
// Start of class members.
//////////////////////////////////////////////////////////////////////////////
private boolean itsAllowEvents;
private JLabel[] itsLabels;
private SplitTable itsTable;
private double itsTotal;
private static final CurrencyFormat US_DOLLAR = CurrencyFormatKeys.US_DOLLAR.getFormat();
private static final String ACTION_ADD = getProperty("add");
private static final String ACTION_REMOVE = getSharedProperty("remove");
private static final int SUM = 0;
private static final int TOTAL = 2;
private static final int UNASSIGNED = 1;
}