/* * JournalComponent.java * * Status: Functional * * Todo list: */ package gui; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.border.*; import javax.swing.event.*; import javax.swing.table.*; import java.util.*; import finance.*; import gui.dialog.JournalEntryDialog; import static finance.Journal.DataModel.DATE_COL; import static finance.Journal.DataModel.DESC_COL; import static finance.Journal.DataModel.DEBIT_COL; import static finance.Journal.DataModel.CREDIT_COL; import static finance.Journal.DataModel.COLUMN_COUNT; /** * The user interface component for {@link Journal Journal}s. */ public class JournalComponent extends JPanel { private static class CellRenderer extends JPanel implements TableCellRenderer { private static Border innerBorder = BorderFactory.createMatteBorder(0, 0, 1, 0, (Color)UIManager.getDefaults().get("Table.gridColor")); private static Border selectedBorder = BorderFactory.createMatteBorder(2, 0, 1, 0, SystemColor.textHighlight); private static Border panelBorder = BorderFactory.createMatteBorder(2, 0, 1, 0, SystemColor.controlHighlight); private GridBagConstraints constraints = new GridBagConstraints(); private JPanel panel = new JPanel(); public CellRenderer() { super(); setOpaque(true); setLayout(new GridBagLayout()); setBorder(panelBorder); panel.setOpaque(false); panel.setLayout(new GridBagLayout()); //panel.setBorder(BorderFactory.createEmptyBorder()); constraints.gridwidth = GridBagConstraints.REMAINDER; constraints.anchor = GridBagConstraints.NORTHWEST; constraints.fill = GridBagConstraints.BOTH; constraints.weightx = 1; add(panel, constraints); } public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { int height = 4; super.setBackground(row % 2 == 0 ? Constants.bgRowEven : Constants.bgRowOdd); if(isSelected) setBorder(selectedBorder); else setBorder(panelBorder); setFont(table.getFont()); panel.removeAll(); if(value != null && value instanceof JournalEntry) { JournalEntry entry = (JournalEntry)value; boolean dateAdded = false; JLabel label = null; for(AccountEntry ae : entry.getAmounts()) { label = getLabel(column, entry, ae); if(column == DATE_COL && dateAdded == false) { label.setText(Constants.dateShort.format(entry.getDate())); dateAdded = true; } panel.add(label, constraints); height += label.getPreferredSize().height; } label = getLabel(column, entry, null); panel.add(label, constraints); height += label.getPreferredSize().height; if(table.getRowHeight(row) != height) table.setRowHeight(row, height); } return this; } protected JLabel getLabel(int column, JournalEntry je, AccountEntry ae) { JLabel label = null; String s = ""; switch(column) { case DATE_COL: label = new JLabel(" "); break; case DESC_COL: if(ae != null) { if(!ae.getDebit().equals("")) label = new JLabel(" " + ae.getAccountName()); else if(!ae.getCredit().equals("")) label = new JLabel(" " + ae.getAccountName()); } else label = new JLabel(" " + je.getDescription()); break; case DEBIT_COL: if(ae != null && !(s = ae.getDebit()).equals("")) { label = new JLabel(s); label.setBackground(ae.getBalanceType() == BalanceType.DEBIT ? Constants.bgBalanceNormal : Constants.bgBalanceAbnormal); label.setOpaque(true); } else label = new JLabel(" "); break; case CREDIT_COL: if(ae != null && !(s = ae.getCredit()).equals("")) { label = new JLabel(s); label.setBackground(ae.getBalanceType() == BalanceType.CREDIT ? Constants.bgBalanceNormal : Constants.bgBalanceAbnormal); label.setOpaque(true); } else label = new JLabel(" "); break; default: label = new JLabel(" "); break; } if(column == DESC_COL && ae == null) label.setFont(getFont().deriveFont(Font.ITALIC)); else label.setFont(getFont()); if(column == DATE_COL || column == DESC_COL) label.setHorizontalAlignment(SwingConstants.LEFT); else label.setHorizontalAlignment(SwingConstants.RIGHT); label.setBorder(innerBorder); return label; } } /** * This class is used to monitor the table for double-click events, and invoke * ButtonHandler.button_EditEntry_Handler when one is detected. */ private static class DblClickHandler extends MouseAdapter { JournalComponent container; DblClickHandler(JournalComponent container) { this.container = container; } public void mousePressed(MouseEvent e) { if(e.getClickCount() < 2) return; //TODO: Construct a proper ActionEvent to pass. //ActionEvent(e.getSource(),, "edit") container.buttonHandler.button_EditEntry_Handler(null); } } private class SelectionHandler implements ListSelectionListener { public void valueChanged(ListSelectionEvent e) { if(e.getValueIsAdjusting()) return; if(e.getSource() instanceof ListSelectionModel) { ListSelectionModel list = (ListSelectionModel)e.getSource(); if(list.isSelectionEmpty()) { buttonEdit.setEnabled(false); buttonDelete.setEnabled(false); } else { buttonEdit.setEnabled(true); buttonDelete.setEnabled(true); } } } } private class ButtonHandler { /** * Adds a new journal entry. This is the {@link ActionListener * ActionListener} method for the "Add Entry" button. */ public void button_AddEntry_Handler(ActionEvent event) { JournalEntryDialog.showAdd(journal); } /** * Edits the selected journal entry. This is the {@link ActionListener * ActionListener} method for the "Edit Entry" button. */ public void button_EditEntry_Handler(ActionEvent event) { int row = table.getSelectedRow(); if(row == -1) return; Object entry = model.getValueAt(row, 0); if(entry instanceof JournalEntry) JournalEntryDialog.showEdit(journal, (JournalEntry)entry); } /** * Deletes the selected journal entry, after prompting the user. This is * the {@link ActionListener ActionListener} method for the "Delete Entry" * button. */ public void button_DeleteEntry_Handler(ActionEvent event) { int row = table.getSelectedRow(); String msg = "Are you sure you want to delete the selected entry?"; if(row == -1) return; if(JOptionPane.showConfirmDialog(Main.instance, msg, "Confirm Delete", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) { Object entry = model.getValueAt(row, 0); if(entry instanceof JournalEntry) journal.remove((JournalEntry)entry); } } } /** The table used to display entries from the {@code Journal}. */ JTable table = null; TableModel model = null; /** The {@code Journal} interfaced to by this {@code JournalComponent}. */ Journal journal = null; private JButton buttonAdd = new JButton("Add Entry"); private JButton buttonEdit = new JButton("Edit Entry"); private JButton buttonDelete = new JButton("Delete Entry"); private ButtonHandler buttonHandler = new ButtonHandler(); /** * Constructs a new {@code JournalComponent}. * * @param journal the {@code Journal} interfaced to by this {@code * JournalComponent}. */ public JournalComponent(Journal journal) { this.journal = journal; setLayout(new GridBagLayout()); GridBagConstraints c = new GridBagConstraints(); c.gridwidth = GridBagConstraints.REMAINDER; c.weightx = 1; c.weighty = 1; c.fill = GridBagConstraints.BOTH; model = journal.getDataModel(); table = new JTable(model); table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); table.getSelectionModel().addListSelectionListener(new SelectionHandler()); table.getTableHeader().setReorderingAllowed(false); table.addMouseListener(new DblClickHandler(this)); for(int i=0; i