// RegisterPanel package org.javamoney.examples.ez.money.gui.view.register; import static org.javamoney.examples.ez.common.utility.ButtonHelper.buildButton; import static org.javamoney.examples.ez.common.utility.I18NHelper.getSharedProperty; import static java.awt.event.KeyEvent.VK_BACK_SPACE; import static java.awt.event.KeyEvent.VK_DELETE; import static java.awt.event.KeyEvent.VK_R; import static org.javamoney.examples.ez.money.ApplicationProperties.creditBalanceIsPositive; import static org.javamoney.examples.ez.money.ApplicationProperties.getRegisterColumnToSort; import static org.javamoney.examples.ez.money.ApplicationProperties.viewByMonth; import static org.javamoney.examples.ez.money.gui.table.RegisterTable.LABEL_COLUMN; import static org.javamoney.examples.ez.money.gui.table.RegisterTable.RECONCILED_COLUMN; import static org.javamoney.examples.ez.money.model.dynamic.transaction.RegisterTransaction.setMultiplier; import static org.javamoney.examples.ez.money.model.dynamic.transaction.RegisterTransaction.setStartingBalance; import static org.javamoney.examples.ez.money.model.persisted.account.AccountTypeKeys.CREDIT; import static org.javamoney.examples.ez.money.utility.DialogHelper.buildMessage; import static org.javamoney.examples.ez.money.utility.DialogHelper.choose; import static org.javamoney.examples.ez.money.utility.DialogHelper.decide; import static org.javamoney.examples.ez.money.utility.DialogHelper.inform; import static org.javamoney.examples.ez.money.utility.TransactionDateHelper.isInRange; import static org.javamoney.examples.ez.money.utility.TransactionHelper.getCorrespondingTransferReference; 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.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.SwingConstants; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import org.javamoney.examples.ez.money.IconKeys; import org.javamoney.examples.ez.money.gui.GUIConstants; import org.javamoney.examples.ez.money.gui.chooser.LabelChooser; import org.javamoney.examples.ez.money.gui.chooser.MonthPeriodChooser; import org.javamoney.examples.ez.money.gui.dialog.AccountStatementDialog; import org.javamoney.examples.ez.money.gui.dialog.EditTransactionsDialog; import org.javamoney.examples.ez.money.gui.table.RegisterTable; import org.javamoney.examples.ez.money.model.dynamic.transaction.RegisterTransaction; import org.javamoney.examples.ez.money.model.dynamic.transaction.TransactionFilter; import org.javamoney.examples.ez.money.model.persisted.account.Account; import org.javamoney.examples.ez.money.model.persisted.transaction.LabelKeys; import org.javamoney.examples.ez.money.model.persisted.transaction.Transaction; import org.javamoney.examples.ez.money.report.TransactionWriter; import org.javamoney.examples.ez.common.gui.Panel; import org.javamoney.examples.ez.common.gui.PopupMenu; import org.javamoney.examples.ez.common.gui.ScrollPane; import org.javamoney.examples.ez.common.utility.I18NHelper; /** * This class facilitates displaying and interacting with an account's * transactions. */ public final class RegisterPanel extends Panel { /** * */ private static final long serialVersionUID = 6315609604386251385L; /** * Constructs a new register panel that will reference the specified account. * * @param account The account to reference. */ public RegisterPanel(Account account) { setAccount(account); setMonthPeriodChooser(new MonthPeriodChooser()); setRegisterBalancePanel(new RegisterBalancePanel()); setTable(new RegisterTable()); setScrollPane(new ScrollPane(getTable())); setTypeTabs(new TypeTabs(account.getType())); buildPanel(); // Add listeners. getMonthPeriodChooser().addActionListener(new ActionHandler()); getTable().addKeyListener(new KeyHandler()); getTable().addMouseListener(createPopupMenu()); getTable().addMouseListener(new MouseHandler()); getTable().getSelectionModel().addListSelectionListener(new SelectionHandler()); } /** * This method unselects all selected transactions in the register's table. */ public void clearTableSelection() { getTable().clearSelection(); } /** * This method puts all the account's transactions into the register table and * updates its balance. * * @param filter The filter to determine what transactions can be added. */ public void updateView(TransactionFilter filter) { updateView(filter, null); } /** * This method puts all the account's transactions into the register table and * updates its balance. * * @param filter The filter to determine what transactions can be added. * @param scrollTo The transaction to scroll to. */ public void updateView(TransactionFilter filter, Transaction scrollTo) { double total = 0.0; double pending = 0.0; setFilter(filter); getMonthPeriodChooser().setVisible(viewByMonth()); getTable().clear(); for(Transaction trans : getAccount().getTransactions()) { total += trans.getAmount().getNumber().doubleValue(); if(trans.isReconciled() == false) { pending += trans.getAmount().getNumber().doubleValue(); } if(canAddTransaction(trans) == true) { getTable().add(new RegisterTransaction(trans, total)); } } // Set up the register transactions so that they display the proper balance. if(getAccount().getType() == CREDIT && creditBalanceIsPositive() == true) { setMultiplier(-1); } else { setMultiplier(1); } setStartingBalance(getAccount().getBalance().getNumber().doubleValue() - total); // Display data. getRegisterBalancePanel().displayFor(getAccount(), pending); getTable().display(); getTypeTabs().clear(); // Scroll to the transaction if applicable. if(scrollTo != null) { scrollToRow(scrollTo); } else { scrollToRow(getTable().getElementCount()); } } ////////////////////////////////////////////////////////////////////////////// // Start of private methods. ////////////////////////////////////////////////////////////////////////////// private void buildPanel() { // Build scroll pane. getScrollPane().setBackground(GUIConstants.COLOR_BACKGROUND_FILL); // Build panel. setFill(GridBagConstraints.BOTH); add(createFilterPanel(), 0, 0, 1, 1, 0, 0); add(getScrollPane(), 0, 1, 1, 1, 100, 100); add(createOptionsPanel(), 0, 2, 1, 1, 0, 0); add(getRegisterBalancePanel(), 0, 3, 1, 1, 0, 0); add(getTypeTabs(), 0, 4, 1, 1, 0, 0); } private boolean canAddTransaction(Transaction trans) { boolean result = true; if(getMonthPeriodChooser().isVisible() == true) { result = isInRange(trans, getMonthPeriodChooser().getStartDate(), getMonthPeriodChooser().getEndDate()); } if(result == true) { result = getFilter().test(trans); } return result; } private LabelKeys chooseLabel() { LabelChooser chooser = new LabelChooser(); LabelKeys label = null; if(choose(createLabelPanel(chooser)) == true) { label = chooser.getSelectedLabel(); } return label; } private Panel createFilterPanel() { Panel panel = new Panel(); // Build panel. panel.setAnchor(GridBagConstraints.EAST); panel.add(getMonthPeriodChooser(), 0, 0, 1, 1, 100, 100); return panel; } private Panel createLabelPanel(LabelChooser chooser) { Panel panel = new Panel(); String message = buildMessage(getProperty("label.title"), getProperty("label.description") + ": "); // Build panel. panel.setAnchor(GridBagConstraints.WEST); panel.add(message, 0, 0, 1, 1, 100, 50); panel.setFill(GridBagConstraints.HORIZONTAL); panel.add(chooser, 0, 1, 1, 1, 100, 50); return panel; } private static JMenuItem createMenuItem(String command, ActionHandler handler) { JMenuItem item = new JMenuItem(); // Build items. buildButton(item, command, handler); return item; } private Panel createOptionsPanel() { Panel panel = new Panel(); PopupMenu menu = createPopupMenu(); JLabel options = new JLabel(getProperty("options")); menu.setBehaveLikeMenu(true); options.addMouseListener(menu); options.setHorizontalTextPosition(SwingConstants.LEFT); options.setIcon(IconKeys.MENU_ARROW.getIcon()); // Build panel. panel.setFill(GridBagConstraints.BOTH); panel.addSpacer(0, 0, 1, 1, 100, 100); panel.add(IconKeys.ACTIONS.getIcon(), 1, 0, 1, 1, 0, 0); panel.add(options, 2, 0, 1, 1, 0, 0); panel.addEmptyCellAt(3, 0, 15); return panel; } private PopupMenu createPopupMenu() { PopupMenu menu = new PopupMenu(); ActionHandler handler = new ActionHandler(); // Add items to menu. menu.add(createMenuItem(ACTION_RECONCILED, handler)); menu.add(createMenuItem(ACTION_PENDING, handler)); menu.addSeparator(); menu.add(createMenuItem(ACTION_REMOVE, handler)); menu.addSeparator(); menu.add(createMenuItem(ACTION_LABEL, handler)); menu.addSeparator(); menu.add(createMenuItem(ACTION_MASS_UPDATE, handler)); menu.addSeparator(); menu.add(createMenuItem(ACTION_STATEMENT, handler)); menu.add(createMenuItem(ACTION_PRINT, handler)); return menu; } private Account getAccount() { return itsAccount; } private TransactionFilter getFilter() { return itsFilter; } private MonthPeriodChooser getMonthPeriodChooser() { return itsMonthPeriodChooser; } private static String getProperty(String key) { return I18NHelper.getProperty("RegisterPanel." + key); } private RegisterBalancePanel getRegisterBalancePanel() { return itsRegisterBalancePanel; } private ScrollPane getScrollPane() { return itsScrollPane; } private RegisterTable getTable() { return itsTable; } private TypeTabs getTypeTabs() { return itsTypeTabs; } private void print() { ArrayList<RegisterTransaction> list = getTable().getSelectedElements(); Transaction[] transactions = new Transaction[list.size()]; for(int len = 0; len < transactions.length; ++len) { transactions[len] = list.get(len).getTransaction(); } TransactionWriter.generate(transactions); } private void massUpdate() { ArrayList<RegisterTransaction> list = getTable().getSelectedElements(); if(list.size() == 1) { getTypeTabs().doEdit(list.get(0).getTransaction(), true); } else { if(new EditTransactionsDialog(list).showDialog() == true) { updateView(getFilter()); } } } private void remove() { int[] rows = getTable().getSelectedRows(); String description = null; String quantity = null; String title = null; if(rows.length > 1) { quantity = getProperty("transactions"); } else { quantity = getProperty("transaction"); } // Construct the dialog's text. title = getSharedProperty("remove") + " " + quantity + "?"; description = getProperty("remove.description.prefix") + " " + quantity + " " + getProperty("remove.description"); if(decide(title, description) == true) { for(RegisterTransaction trans : getTable().getSelectedElements()) { removeFrom(getAccount(), trans.getTransaction()); } updateView(getFilter()); } } private void scrollToRow(int row) { getScrollPane().scroll(row * getTable().getRowHeight()); } private void scrollToRow(Transaction scrollTo) { int index = getTable().getList().size() - 1; // Find the last index. while(index > 0) { if(getTable().get(index).getTransaction() == scrollTo) { break; } --index; } getTable().selectRow(index); // Scrolling puts the view at the top of the row. If the row is the last // element, scroll to the end of the table. if(index == getTable().getElementCount() - 1) { index = getTable().getElementCount(); } scrollToRow(index); } private void setAccount(Account account) { itsAccount = account; } private void setFilter(TransactionFilter filter) { itsFilter = filter; } private void setMonthPeriodChooser(MonthPeriodChooser chooser) { itsMonthPeriodChooser = chooser; } private void setLabel() { LabelKeys label = chooseLabel(); if(label != null) { for(int row : getTable().getSelectedRows()) { Transaction trans = getTable().get(row).getTransaction(); trans.setLabel(label); // Apply to transfer if applicable. trans = getCorrespondingTransferReference(trans, getAccount()); if(trans != null) { trans.setLabel(label); } } // Update the table if the transactions are being sorted by their label. if(getRegisterColumnToSort() == LABEL_COLUMN) { updateView(getFilter()); } else { getTable().repaint(); } } } private void setReconciled(boolean reconciled) { for(int row : getTable().getSelectedRows()) { Transaction trans = getTable().get(row).getTransaction(); Transaction transfer = getCorrespondingTransferReference(trans, getAccount()); trans.setIsReconciled(reconciled); // Apply to transfer if applicable. if(transfer != null) { transfer.setIsReconciled(reconciled); } } updateView(getFilter()); } private void setRegisterBalancePanel(RegisterBalancePanel panel) { itsRegisterBalancePanel = panel; } private void setScrollPane(ScrollPane pane) { itsScrollPane = pane; } private void setTable(RegisterTable table) { itsTable = table; } private void setTypeTabs(TypeTabs tabs) { itsTypeTabs = tabs; } ////////////////////////////////////////////////////////////////////////////// // Start of inner classes. ////////////////////////////////////////////////////////////////////////////// private class ActionHandler implements ActionListener { public void actionPerformed(ActionEvent event) { Object source = event.getSource(); String command = event.getActionCommand(); if(source == getMonthPeriodChooser()) { updateView(getFilter()); } else if(command.equals(ACTION_STATEMENT) == true) { new AccountStatementDialog(getAccount()).showDialog(); } else if(getTable().getSelectedRow() != -1) { if(command.equals(ACTION_LABEL) == true) { setLabel(); } else if(command.equals(ACTION_MASS_UPDATE) == true) { massUpdate(); } else if(command.equals(ACTION_PENDING) == true) { setReconciled(false); } else if(command.equals(ACTION_PRINT) == true) { print(); } else if(command.equals(ACTION_RECONCILED) == true) { setReconciled(true); } else if(command.equals(ACTION_REMOVE) == true) { remove(); } } else { inform(getProperty("select.title"), getProperty("select.description")); } } } private class KeyHandler extends KeyAdapter { @Override public void keyReleased(KeyEvent event) { char ch = Character.toUpperCase(event.getKeyChar()); if(ch == VK_BACK_SPACE || ch == VK_DELETE || ch == VK_R) { remove(); } } } private class MouseHandler extends MouseAdapter { @Override public void mouseClicked(MouseEvent event) { if(event.getButton() == MouseEvent.BUTTON1 && event.getClickCount() == 2) { RegisterTransaction trans = getTable().getSelectedElement(); if(trans != null) { int column = getTable().getIndexForColumn(getTable().getColumnIndexAtX(event.getX())); if(column == LABEL_COLUMN) { setLabel(); } else if(column == RECONCILED_COLUMN) { setReconciled(!trans.getTransaction().isReconciled()); } } } } } private class SelectionHandler implements ListSelectionListener { public void valueChanged(ListSelectionEvent event) { if(event.getValueIsAdjusting() == false) { RegisterTransaction trans = getTable().getSelectedElement(); if(trans != null) { getTypeTabs().doEdit(trans.getTransaction(), false); } } } } ////////////////////////////////////////////////////////////////////////////// // Start of class members. ////////////////////////////////////////////////////////////////////////////// private Account itsAccount; private TransactionFilter itsFilter; private MonthPeriodChooser itsMonthPeriodChooser; private RegisterBalancePanel itsRegisterBalancePanel; private ScrollPane itsScrollPane; private RegisterTable itsTable; private TypeTabs itsTypeTabs; private static final String ACTION_LABEL = getProperty("option.label"); private static final String ACTION_MASS_UPDATE = getSharedProperty("edit") + "..."; private static final String ACTION_PENDING = getSharedProperty("mark_pending"); private static final String ACTION_PRINT = getSharedProperty("print_transactions"); private static final String ACTION_RECONCILED = getSharedProperty("mark_reconciled"); private static final String ACTION_REMOVE = getSharedProperty("remove"); private static final String ACTION_STATEMENT = getProperty("option.statement"); }