org.angnysa.yaba.swing.BudgetFrame.java Source code

Java tutorial

Introduction

Here is the source code for org.angnysa.yaba.swing.BudgetFrame.java

Source

package org.angnysa.yaba.swing;

/*
 * #%L
 * Yet Another Budget Application
 * %%
 * Copyright (C) 2012 angnysa
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the 
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public 
 * License along with this program.  If not, see
 * <http://www.gnu.org/licenses/gpl-3.0.html>.
 * #L%
 */

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.NumberFormat;

import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.SpringLayout;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.text.DefaultFormatterFactory;
import javax.swing.text.NumberFormatter;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.LineAndShapeRenderer;

import org.joda.time.LocalDate;
import org.joda.time.Period;
import org.joda.time.ReadablePeriod;
import org.joda.time.Years;

import org.angnysa.yaba.dto.TransactionDefinition;
import org.angnysa.yaba.service.TransactionService;
import org.angnysa.yaba.service.impl.DefaultTransactionService;
import org.angnysa.yaba.swing.ext.CustomCellEditor;
import org.angnysa.yaba.swing.ext.FormattedTableCellRenderer;
import org.angnysa.yaba.swing.ext.OptionalValueFormatter;
import org.angnysa.yaba.text.format.JodaLocalDateFormat;
import org.angnysa.yaba.text.format.JodaPeriodFormat;
import org.angnysa.yaba.text.format.TransactionAmountFormatFactory;;

public class BudgetFrame extends JFrame {
    private static final long serialVersionUID = 1L;

    private int id;

    private JTable reconciliationTable;
    private ReconciliationTableModel reconciliationModel;

    private JTable transactionTable;
    private TransactionTableModel transactionModel;

    private JPanel simulationPanel;
    private SimulationDataset simulationDataset;

    private JFormattedTextField amountFld;
    private JFormattedTextField fromFld;
    private JFormattedTextField toFld;
    private JFormattedTextField periodFld;

    private TransactionService service;

    public BudgetFrame(int id, DefaultTransactionService service) {
        super();

        this.id = id;
        this.service = service;

        setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                SwingMain.close(BudgetFrame.this.id);
            }
        });

        buildTransactionTable();
        buildReconciliationTable();
        buildSimulationPanel();
        buildMenubar();

        layoutComponents();
    }

    private void buildTransactionTable() {
        transactionModel = new TransactionTableModel(service);
        transactionTable = new JTable(transactionModel);
        transactionTable.setRowHeight((int) (transactionTable.getRowHeight() * 1.2));
        transactionTable.getColumnModel().getColumn(TransactionTableModel.COL_END)
                .setCellEditor(new CustomCellEditor(
                        new JFormattedTextField(new OptionalValueFormatter(new JodaLocalDateFormat()))));
        transactionTable.setDefaultEditor(LocalDate.class,
                new CustomCellEditor(new JFormattedTextField(new JodaLocalDateFormat())));
        transactionTable.setDefaultEditor(ReadablePeriod.class,
                new CustomCellEditor(new JFormattedTextField(new OptionalValueFormatter(new JodaPeriodFormat()))));
        transactionTable.setDefaultEditor(Double.class,
                new CustomCellEditor(new JFormattedTextField(NumberFormat.getNumberInstance())));
        transactionTable.setDefaultRenderer(LocalDate.class,
                new FormattedTableCellRenderer(new JodaLocalDateFormat()));
        transactionTable.setDefaultRenderer(ReadablePeriod.class,
                new FormattedTableCellRenderer(new JodaPeriodFormat()));
        transactionTable.setDefaultRenderer(Double.class,
                new FormattedTableCellRenderer(TransactionAmountFormatFactory.getFormat()));
        transactionTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        transactionTable.setAutoCreateRowSorter(true);
        transactionTable.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
                .put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), "delete"); //$NON-NLS-1$
        transactionTable.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
                .put(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0), "delete"); //$NON-NLS-1$
        transactionTable.getActionMap().put("delete", new AbstractAction() { //$NON-NLS-1$
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {

                int row = transactionTable.getSelectedRow();
                if (row >= 0) {
                    row = transactionTable.getRowSorter().convertRowIndexToModel(row);
                    transactionModel.deleteRow(row);
                }
            }
        });
    }

    private void buildReconciliationTable() {
        reconciliationModel = new ReconciliationTableModel(service);
        reconciliationTable = new JTable(reconciliationModel);
        reconciliationTable.setRowHeight((int) (reconciliationTable.getRowHeight() * 1.2));
        reconciliationTable.setDefaultEditor(LocalDate.class,
                new CustomCellEditor(new JFormattedTextField(new JodaLocalDateFormat())));
        reconciliationTable.setDefaultEditor(Double.class,
                new CustomCellEditor(new JFormattedTextField(NumberFormat.getNumberInstance())));
        reconciliationTable.setDefaultRenderer(LocalDate.class,
                new FormattedTableCellRenderer(new JodaLocalDateFormat()));
        reconciliationTable.setDefaultRenderer(Double.class,
                new FormattedTableCellRenderer(TransactionAmountFormatFactory.getFormat()));
        reconciliationTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        reconciliationTable.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
                .put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), "delete"); //$NON-NLS-1$
        reconciliationTable.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
                .put(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0), "delete"); //$NON-NLS-1$
        reconciliationTable.getActionMap().put("delete", new AbstractAction() { //$NON-NLS-1$
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {

                int row = reconciliationTable.getSelectedRow();
                if (row >= 0) {
                    reconciliationModel.deleteRow(row);
                }
            }
        });
        transactionTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {

            @Override
            public void valueChanged(ListSelectionEvent e) {
                if (!e.getValueIsAdjusting()) {
                    int row = transactionTable.getSelectedRow();
                    if (row >= 0) {
                        row = transactionTable.getRowSorter().convertRowIndexToModel(row);
                        TransactionDefinition td = transactionModel.getTransactionForRow(row);
                        if (td != null) {
                            reconciliationModel.setCurrentTransactionId(td.getId());
                        } else {
                            reconciliationModel.setCurrentTransactionId(-1);
                        }
                    } else {
                        reconciliationModel.setCurrentTransactionId(-1);
                    }
                }
            }
        });
    }

    private void buildSimulationPanel() {

        simulationPanel = new JPanel();
        SpringLayout springLayout = new SpringLayout();
        simulationPanel.setLayout(springLayout);

        // chart data
        simulationDataset = new SimulationDataset(service);
        simulationDataset.setInitial(0D);
        simulationDataset.setStart(new LocalDate());
        simulationDataset.setEnd(new LocalDate().plus(Years.ONE));
        simulationDataset.setPeriod(Period.months(1));
        simulationDataset.updateDataset();
        transactionModel.addTableModelListener(new TableModelListener() {

            @Override
            public void tableChanged(TableModelEvent e) {
                simulationDataset.updateDataset();
            }
        });
        reconciliationModel.addTableModelListener(new TableModelListener() {

            @Override
            public void tableChanged(TableModelEvent e) {
                simulationDataset.updateDataset();
            }
        });

        // initial amount label
        JLabel amountLbl = new JLabel(Messages.getString("simulation.field.initial-amount")); //$NON-NLS-1$
        springLayout.putConstraint(SpringLayout.WEST, amountLbl, 10, SpringLayout.WEST, simulationPanel);
        simulationPanel.add(amountLbl);

        // initial amount field
        amountFld = new JFormattedTextField(
                new DefaultFormatterFactory(new NumberFormatter(NumberFormat.getNumberInstance()),
                        new NumberFormatter(NumberFormat.getCurrencyInstance())));
        amountFld.setColumns(8);
        amountFld.setValue(simulationDataset.getInitial());
        amountFld.addPropertyChangeListener("value", new PropertyChangeListener() { //$NON-NLS-1$

            @Override
            public void propertyChange(PropertyChangeEvent e) {
                simulationDataset.setInitial(((Number) amountFld.getValue()).doubleValue());
                simulationDataset.updateDataset();
            }
        });
        springLayout.putConstraint(SpringLayout.VERTICAL_CENTER, amountLbl, 0, SpringLayout.VERTICAL_CENTER,
                amountFld);
        springLayout.putConstraint(SpringLayout.WEST, amountFld, 0, SpringLayout.EAST, amountLbl);
        springLayout.putConstraint(SpringLayout.NORTH, amountFld, 10, SpringLayout.NORTH, simulationPanel);
        simulationPanel.add(amountFld);

        // start date label
        JLabel fromLbl = new JLabel(Messages.getString("simulation.field.start-date")); //$NON-NLS-1$
        springLayout.putConstraint(SpringLayout.WEST, fromLbl, 10, SpringLayout.EAST, amountFld);
        simulationPanel.add(fromLbl);

        // start date field
        fromFld = new JFormattedTextField(new JodaLocalDateFormat());
        fromFld.setColumns(8);
        fromFld.setValue(simulationDataset.getStart());
        fromFld.addPropertyChangeListener("value", new PropertyChangeListener() { //$NON-NLS-1$

            @Override
            public void propertyChange(PropertyChangeEvent e) {
                simulationDataset.setStart((LocalDate) fromFld.getValue());
                simulationDataset.updateDataset();
            }
        });
        springLayout.putConstraint(SpringLayout.VERTICAL_CENTER, fromLbl, 0, SpringLayout.VERTICAL_CENTER, fromFld);
        springLayout.putConstraint(SpringLayout.WEST, fromFld, 0, SpringLayout.EAST, fromLbl);
        springLayout.putConstraint(SpringLayout.NORTH, fromFld, 10, SpringLayout.NORTH, simulationPanel);
        simulationPanel.add(fromFld);

        // end date label
        JLabel toLbl = new JLabel(Messages.getString("simulation.field.end-date")); //$NON-NLS-1$
        springLayout.putConstraint(SpringLayout.WEST, toLbl, 10, SpringLayout.EAST, fromFld);
        simulationPanel.add(toLbl);

        // end date field
        toFld = new JFormattedTextField(new JodaLocalDateFormat());
        toFld.setColumns(8);
        toFld.setValue(simulationDataset.getEnd());
        toFld.addPropertyChangeListener("value", new PropertyChangeListener() { //$NON-NLS-1$

            @Override
            public void propertyChange(PropertyChangeEvent e) {
                simulationDataset.setEnd((LocalDate) toFld.getValue());
                simulationDataset.updateDataset();
            }
        });
        springLayout.putConstraint(SpringLayout.VERTICAL_CENTER, toLbl, 0, SpringLayout.VERTICAL_CENTER, toFld);
        springLayout.putConstraint(SpringLayout.WEST, toFld, 0, SpringLayout.EAST, toLbl);
        springLayout.putConstraint(SpringLayout.NORTH, toFld, 10, SpringLayout.NORTH, simulationPanel);
        simulationPanel.add(toFld);

        // period label
        JLabel periodLbl = new JLabel(Messages.getString("simulation.field.period")); //$NON-NLS-1$
        springLayout.putConstraint(SpringLayout.WEST, periodLbl, 10, SpringLayout.EAST, toFld);
        simulationPanel.add(periodLbl);

        // period field
        periodFld = new JFormattedTextField(new JodaPeriodFormat());
        periodFld.setColumns(5);
        periodFld.setValue(simulationDataset.getPeriod());
        periodFld.addPropertyChangeListener("value", new PropertyChangeListener() { //$NON-NLS-1$

            @Override
            public void propertyChange(PropertyChangeEvent e) {
                simulationDataset.setPeriod((ReadablePeriod) periodFld.getValue());
                simulationDataset.updateDataset();
            }
        });
        springLayout.putConstraint(SpringLayout.VERTICAL_CENTER, periodLbl, 0, SpringLayout.VERTICAL_CENTER,
                periodFld);
        springLayout.putConstraint(SpringLayout.WEST, periodFld, 0, SpringLayout.EAST, periodLbl);
        springLayout.putConstraint(SpringLayout.NORTH, periodFld, 10, SpringLayout.NORTH, simulationPanel);
        simulationPanel.add(periodFld);

        // chart panel
        JFreeChart chart = ChartFactory.createLineChart("", Messages.getString("simulation.chart.date-axis-label"), //$NON-NLS-1$//$NON-NLS-2$
                Messages.getString("simulation.chart.amount-axis-label"), simulationDataset, //$NON-NLS-1$
                PlotOrientation.VERTICAL, false, true, false);
        CategoryPlot plot = (CategoryPlot) chart.getPlot();
        plot.getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.UP_45);
        LineAndShapeRenderer renderer = (LineAndShapeRenderer) plot.getRenderer();
        renderer.setBaseShapesFilled(true);
        renderer.setBaseShapesVisible(true);
        renderer.setBaseToolTipGenerator(new SimulationTooltipGenerator(service));
        ChartPanel chartPanel = new ChartPanel(chart);
        chartPanel.setDismissDelay(3600000);
        chartPanel.setInitialDelay(0);
        springLayout.putConstraint(SpringLayout.NORTH, chartPanel, 15, SpringLayout.SOUTH, periodFld);
        springLayout.putConstraint(SpringLayout.WEST, chartPanel, 10, SpringLayout.WEST, simulationPanel);
        springLayout.putConstraint(SpringLayout.SOUTH, chartPanel, -10, SpringLayout.SOUTH, simulationPanel);
        springLayout.putConstraint(SpringLayout.EAST, chartPanel, -10, SpringLayout.EAST, simulationPanel);
        simulationPanel.add(chartPanel);
    }

    private void buildMenubar() {
        JMenuBar menuBar = new JMenuBar();
        JMenu fileMenu = new JMenu(Messages.getString("menu.file.label")); //$NON-NLS-1$
        JMenuItem item;

        // new
        item = new JMenuItem(Messages.getString("menu.file.new")); //$NON-NLS-1$
        item.setAccelerator(
                KeyStroke.getKeyStroke(KeyEvent.VK_N, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
        item.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                SwingMain.newEditor(null);
            }
        });
        fileMenu.add(item);

        // open
        item = new JMenuItem(Messages.getString("menu.file.open")); //$NON-NLS-1$
        item.setAccelerator(
                KeyStroke.getKeyStroke(KeyEvent.VK_O, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
        item.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                SwingMain.open(id);
            }
        });
        fileMenu.add(item);

        // save
        item = new JMenuItem(Messages.getString("menu.file.save")); //$NON-NLS-1$
        item.setAccelerator(
                KeyStroke.getKeyStroke(KeyEvent.VK_S, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
        item.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                SwingMain.save(id);
            }
        });
        fileMenu.add(item);

        // save as
        item = new JMenuItem(Messages.getString("menu.file.save-as")); //$NON-NLS-1$
        item.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                SwingMain.saveas(id);
            }
        });
        fileMenu.add(item);

        // close
        item = new JMenuItem(Messages.getString("menu.file.close")); //$NON-NLS-1$
        item.setAccelerator(
                KeyStroke.getKeyStroke(KeyEvent.VK_W, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
        item.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                SwingMain.close(id);
            }
        });
        fileMenu.add(item);

        menuBar.add(fileMenu);
        setJMenuBar(menuBar);
    }

    private void layoutComponents() {
        setLayout(new BorderLayout());

        JSplitPane subSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true, new JScrollPane(transactionTable),
                new JScrollPane(reconciliationTable));
        subSplitPane.setPreferredSize(new Dimension(400, 600));

        JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, subSplitPane, simulationPanel);
        splitPane.setPreferredSize(new Dimension(1000, 600));

        add(splitPane, BorderLayout.CENTER);

        pack();

        subSplitPane.setDividerLocation(0.5);
        splitPane.setDividerLocation(0.4);
    }
}