Coverage Report - org.homeunix.thecave.buddi.view.panels.MyBudgetPanel
 
Classes in this File Line Coverage Branch Coverage Complexity
MyBudgetPanel
79%
75/94
50%
11/22
2.824
MyBudgetPanel$1
9%
1/11
0%
0/10
2.824
MyBudgetPanel$2
100%
6/6
N/A
2.824
MyBudgetPanel$3
16%
1/6
0%
0/18
2.824
MyBudgetPanel$4
36%
4/11
25%
1/4
2.824
MyBudgetPanel$5
20%
1/5
0%
0/2
2.824
MyBudgetPanel$6
16%
1/6
0%
0/2
2.824
MyBudgetPanel$7
33%
1/3
N/A
2.824
 
 1  
 /*
 2  
  * Created on Jul 30, 2007 by wyatt
 3  
  */
 4  
 package org.homeunix.thecave.buddi.view.panels;
 5  
 
 6  
 import java.awt.BorderLayout;
 7  
 import java.awt.FlowLayout;
 8  
 import java.awt.KeyEventDispatcher;
 9  
 import java.awt.KeyboardFocusManager;
 10  
 import java.awt.Point;
 11  
 import java.awt.event.ActionEvent;
 12  
 import java.awt.event.ActionListener;
 13  
 import java.awt.event.KeyEvent;
 14  
 import java.awt.event.MouseAdapter;
 15  
 import java.awt.event.MouseEvent;
 16  
 import java.util.Date;
 17  
 import java.util.HashMap;
 18  
 import java.util.LinkedList;
 19  
 import java.util.List;
 20  
 import java.util.Map;
 21  
 
 22  
 import javax.swing.JComboBox;
 23  
 import javax.swing.JLabel;
 24  
 import javax.swing.JPanel;
 25  
 import javax.swing.JScrollPane;
 26  
 import javax.swing.JSpinner;
 27  
 import javax.swing.event.ChangeEvent;
 28  
 import javax.swing.event.ChangeListener;
 29  
 import javax.swing.event.TreeExpansionEvent;
 30  
 import javax.swing.event.TreeExpansionListener;
 31  
 import javax.swing.event.TreeSelectionEvent;
 32  
 import javax.swing.event.TreeSelectionListener;
 33  
 import javax.swing.table.TableModel;
 34  
 import javax.swing.tree.TreePath;
 35  
 
 36  
 import org.homeunix.thecave.buddi.Const;
 37  
 import org.homeunix.thecave.buddi.i18n.BuddiKeys;
 38  
 import org.homeunix.thecave.buddi.i18n.keys.BudgetCategoryTypes;
 39  
 import org.homeunix.thecave.buddi.model.BudgetCategory;
 40  
 import org.homeunix.thecave.buddi.model.BudgetCategoryType;
 41  
 import org.homeunix.thecave.buddi.model.Document;
 42  
 import org.homeunix.thecave.buddi.model.impl.FilteredLists;
 43  
 import org.homeunix.thecave.buddi.model.impl.ModelFactory;
 44  
 import org.homeunix.thecave.buddi.model.prefs.PrefsModel;
 45  
 import org.homeunix.thecave.buddi.model.swing.BudgetDateSpinnerModel;
 46  
 import org.homeunix.thecave.buddi.model.swing.MyBudgetTreeTableModel;
 47  
 import org.homeunix.thecave.buddi.plugin.api.util.TextFormatter;
 48  
 import org.homeunix.thecave.buddi.util.InternalFormatter;
 49  
 import org.homeunix.thecave.buddi.view.MainFrame;
 50  
 import org.homeunix.thecave.buddi.view.menu.items.EditEditTransactions;
 51  
 import org.homeunix.thecave.buddi.view.swing.MyBudgetTableAmountCellEditor;
 52  
 import org.homeunix.thecave.buddi.view.swing.MyBudgetTableAmountCellRenderer;
 53  
 import org.homeunix.thecave.buddi.view.swing.MyBudgetTreeNameCellRenderer;
 54  
 import org.homeunix.thecave.buddi.view.swing.TranslatorListCellRenderer;
 55  
 import org.jdesktop.swingx.JXTreeTable;
 56  
 import org.jdesktop.swingx.decorator.HighlighterFactory;
 57  
 import org.jdesktop.swingx.table.ColumnFactory;
 58  
 import org.jdesktop.swingx.table.TableColumnExt;
 59  
 
 60  
 import ca.digitalcave.moss.common.OperatingSystemUtil;
 61  
 import ca.digitalcave.moss.swing.MossDecimalField;
 62  
 import ca.digitalcave.moss.swing.MossPanel;
 63  
 
 64  0
 public class MyBudgetPanel extends MossPanel implements ActionListener {
 65  
         public static final long serialVersionUID = 0;
 66  
 
 67  
         private final JXTreeTable tree;
 68  
         private final JLabel balanceLabel;
 69  
 
 70  
         private final BudgetDateSpinnerModel dateSpinnerModel;
 71  
         private final JSpinner dateSpinner;
 72  
         private final JComboBox periodTypeComboBox;
 73  
 
 74  
         private final MyBudgetTreeTableModel treeTableModel;
 75  
         
 76  3034
         private final Map<BudgetCategoryType, Date> periodDateMap = new HashMap<BudgetCategoryType, Date>();
 77  
 
 78  
         private final MainFrame parent;
 79  
 
 80  
         public MyBudgetPanel(MainFrame parent) {
 81  3034
                 super(true);
 82  3034
                 this.parent = parent;
 83  3034
                 this.treeTableModel = new MyBudgetTreeTableModel((Document) parent.getDocument());
 84  3034
                 tree = new JXTreeTable(){
 85  
                         public static final long serialVersionUID = 0;
 86  
                         @Override
 87  
                         public String getToolTipText(MouseEvent event) {
 88  0
                                 if (PrefsModel.getInstance().isShowTooltips()){
 89  0
                                         Point p = event.getPoint();
 90  0
                                         int rowIndex = rowAtPoint(p);
 91  
 
 92  0
                                         if (this.getPathForRow(rowIndex) != null){
 93  0
                                                 Object[] path = this.getPathForRow(rowIndex).getPath();
 94  0
                                                 if (path != null && path.length > 0){
 95  0
                                                         Object node = path[path.length - 1];
 96  0
                                                         if (node instanceof BudgetCategory)
 97  0
                                                                 return ((BudgetCategory) node).getNotes();
 98  
                                                 }
 99  
                                         }
 100  
                                 }
 101  0
                                 return null;
 102  
                         }
 103  
                 };
 104  3034
                 tree.setColumnFactory(new ColumnFactory(){
 105  
                         @Override
 106  
                         public void configureTableColumn(TableModel arg0, TableColumnExt arg1) {
 107  12628
                                 super.configureTableColumn(arg0, arg1);
 108  
                                 
 109  12628
                                 MossDecimalField editor = new MossDecimalField(0, true, 2);
 110  12628
                                 arg1.setCellRenderer(new MyBudgetTableAmountCellRenderer());
 111  12628
                                 arg1.setCellEditor(new MyBudgetTableAmountCellEditor(editor));
 112  12628
                         }
 113  
                 });
 114  3034
                 tree.setTreeTableModel(treeTableModel);
 115  
 
 116  3025
                 balanceLabel = new JLabel();
 117  3025
                 dateSpinnerModel = new BudgetDateSpinnerModel(treeTableModel);
 118  3025
                 dateSpinner = new JSpinner(dateSpinnerModel);
 119  
 //                dateSpinner = new JSpinner(new SpinnerDateModel(new Date(), DateUtil.getDate(1900, Calendar.JANUARY), DateUtil.getDate(3000, Calendar.DECEMBER), Calendar.MONTH));
 120  
 //                monthComboBox = new JComboBox(new DefaultComboBoxModel(MonthKeys.values()));
 121  3025
                 periodTypeComboBox = new JComboBox(BudgetCategoryTypes.values());
 122  
 
 123  3025
                 open();
 124  3025
         }
 125  
 
 126  
         public List<BudgetCategory> getSelectedBudgetCategories(){
 127  3880
                 List<BudgetCategory> budgetCategories = new LinkedList<BudgetCategory>();
 128  
 
 129  3880
                 for (Integer i : tree.getSelectedRows()) {
 130  0
                         budgetCategories.add((BudgetCategory) tree.getModel().getValueAt(i, -1));
 131  
                 }
 132  
 
 133  3880
                 return budgetCategories;
 134  
         }
 135  
         
 136  
         public void setNextPeriod(){
 137  0
                 dateSpinner.setValue(dateSpinnerModel.getNextValue());
 138  0
         }
 139  
         
 140  
         public void setPreviousPeriod(){
 141  0
                 dateSpinner.setValue(dateSpinnerModel.getPreviousValue());
 142  0
         }
 143  
 
 144  
         public void actionPerformed(ActionEvent e) {
 145  0
                 if (e.getSource().equals(periodTypeComboBox)){
 146  0
                         periodDateMap.put(treeTableModel.getSelectedBudgetPeriodType(), (Date) dateSpinnerModel.getValue());
 147  0
                         if (periodTypeComboBox != null && periodTypeComboBox.getSelectedItem() != null)
 148  0
                                 treeTableModel.setSelectedBudgetPeriodType(ModelFactory.getBudgetCategoryType(periodTypeComboBox.getSelectedItem().toString()));
 149  
                         
 150  0
                         if (periodDateMap.get(treeTableModel.getSelectedBudgetPeriodType()) == null)
 151  0
                                 dateSpinnerModel.setValue(treeTableModel.getSelectedBudgetPeriodType().getStartOfBudgetPeriod(dateSpinnerModel.getDate()));
 152  
                         else
 153  0
                                 dateSpinnerModel.setValue(periodDateMap.get(treeTableModel.getSelectedBudgetPeriodType()));
 154  0
                         this.fireStructureChanged();
 155  0
                         this.updateContent();
 156  0
                         parent.updateMenus();
 157  
                 }
 158  0
         }
 159  
 
 160  
         public void init() {
 161  3025
                 super.init();
 162  3025
                 tree.setRootVisible(false);
 163  3025
                 tree.setShowsRootHandles(true);
 164  3025
                 tree.setAutoResizeMode(JXTreeTable.AUTO_RESIZE_ALL_COLUMNS);
 165  3025
                 tree.setClosedIcon(null);
 166  3025
                 tree.setOpenIcon(null);
 167  3025
                 tree.setLeafIcon(null);
 168  3025
                 tree.setTreeCellRenderer(new MyBudgetTreeNameCellRenderer());
 169  
 
 170  
 //                for (int i = 1; i < treeTableModel.getColumnCount(); i++){                        
 171  3025
                         final KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
 172  
                         //This passes arrow keys on to the table, to allow cell navigation.
 173  3025
                         manager.addKeyEventDispatcher(new KeyEventDispatcher(){
 174  
 //                                private int lastColumnSelected = 2;
 175  
                                 
 176  
                                 public boolean dispatchKeyEvent(KeyEvent e) {
 177  0
                                         if (MyBudgetPanel.this.parent.isActive()
 178  
                                                         && MyBudgetPanel.this.parent.isMyBudgetTabSelected()
 179  
                                                         && MyBudgetPanel.this.tree.getSelectedRow() != -1
 180  
                                                         && MyBudgetPanel.this.tree.getSelectedColumn() != -1
 181  
                                                         && e.getModifiers() == 0
 182  
                                                         && (e.getKeyCode() == KeyEvent.VK_UP
 183  
                                                                         || e.getKeyCode() == KeyEvent.VK_DOWN
 184  
                                                                         || e.getKeyCode() == KeyEvent.VK_RIGHT
 185  
                                                                         || e.getKeyCode() == KeyEvent.VK_LEFT)){
 186  
                                                 
 187  
 //                                                if (e.getKeyCode() == KeyEvent.VK_RIGHT 
 188  
 //                                                                && lastColumnSelected == 3
 189  
 //                                                                && MyBudgetPanel.this.tree.getSelectedColumn() == 3){
 190  
 //                                                        Object previous = dateSpinnerModel.getPreviousValue();
 191  
 //                                                        if (previous instanceof Date){
 192  
 ////                                                                treeTableModel.setSelectedDate((Date) previous);
 193  
 //                                                                dateSpinner.setValue(previous);
 194  
 ////                                                                fireStructureChanged();
 195  
 ////                                                                updateContent();
 196  
 //                                                        }
 197  
 //                                                }
 198  
 //                                                else if (e.getKeyCode() == KeyEvent.VK_LEFT
 199  
 //                                                                && lastColumnSelected == 1
 200  
 //                                                                && MyBudgetPanel.this.tree.getSelectedColumn() == 1){
 201  
 //                                                        Object next = dateSpinnerModel.getNextValue();
 202  
 //                                                        if (next instanceof Date){
 203  
 ////                                                                treeTableModel.setSelectedDate((Date) next);
 204  
 //                                                                dateSpinner.setValue(next);
 205  
 ////                                                                fireStructureChanged();
 206  
 ////                                                                updateContent();
 207  
 //                                                        }                
 208  
 //                                                }
 209  
 //                                                
 210  
 //                                                System.out.println(lastColumnSelected + ", " + MyBudgetPanel.this.tree.getSelectedColumn());
 211  
 //                                                lastColumnSelected = MyBudgetPanel.this.tree.getSelectedColumn();
 212  
                                                 
 213  0
                                                 manager.redispatchEvent(tree, e);
 214  0
                                                 e.consume();
 215  
                                                 
 216  0
                                                 return true;
 217  
                                         }
 218  0
                                         return false;
 219  
                                 }
 220  
                         });
 221  
 //                        tree.getColumn(i).setCellRenderer(new MyBudgetTableAmountCellRenderer());
 222  
 //                        tree.getColumn(i).setCellEditor(new MyBudgetTableAmountCellEditor(editor));
 223  
 //                }
 224  
 //                tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
 225  
 //                tree.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
 226  
 //                tree.setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
 227  3025
                 tree.addHighlighter(HighlighterFactory.createAlternateStriping(Const.COLOR_EVEN_ROW, Const.COLOR_ODD_ROW));
 228  
 
 229  3025
                 tree.addTreeExpansionListener(new TreeExpansionListener(){
 230  
                         public void treeCollapsed(TreeExpansionEvent event) {
 231  0
                                 Object o = event.getPath().getPath()[event.getPath().getPath().length - 1];
 232  0
                                 if (o instanceof BudgetCategory){
 233  0
                                         BudgetCategory bc = (BudgetCategory) o;
 234  0
                                         bc.setExpanded(false);
 235  
                                 }
 236  0
                         }
 237  
                         public void treeExpanded(TreeExpansionEvent event) {
 238  6
                                 Object o = event.getPath().getPath()[event.getPath().getPath().length - 1];
 239  6
                                 if (o instanceof BudgetCategory){
 240  0
                                         BudgetCategory bc = (BudgetCategory) o;
 241  0
                                         bc.setExpanded(true);
 242  
                                 }                                
 243  6
                         }
 244  
                 });
 245  
                 
 246  3025
                 tree.addMouseListener(new MouseAdapter(){
 247  
                         public void mouseClicked(MouseEvent arg0) {
 248  0
                                 if (arg0.getClickCount() >= 2)
 249  0
                                         new EditEditTransactions(parent).doClick();
 250  0
                                 super.mouseClicked(arg0);
 251  0
                         }
 252  
                 });
 253  
 
 254  3025
                 JScrollPane listScroller = new JScrollPane(tree);
 255  
 
 256  
 //                dateSpinner.setPreferredSize(new Dimension(300, dateSpinner.getPreferredSize().height));
 257  
 //                dateSpinner.setEditor(new JSpinner.DateEditor(dateSpinner, "MMMM yyyy"));
 258  3025
                 dateSpinner.setPreferredSize(InternalFormatter.getComponentSize(dateSpinner, 120));
 259  3025
                 dateSpinner.addChangeListener(new ChangeListener(){
 260  
                         public void stateChanged(ChangeEvent arg0) {
 261  0
                                 if (dateSpinner.getValue() instanceof Date)
 262  0
                                         treeTableModel.setSelectedDate((Date) dateSpinner.getValue());
 263  0
                                 fireStructureChanged();
 264  0
                                 updateContent();
 265  0
                         }
 266  
                 });
 267  
 
 268  
 //                periodTypeComboBox.setPreferredSize(dateSpinner.getPreferredSize());
 269  3025
                 periodTypeComboBox.setSelectedItem(ModelFactory.getBudgetCategoryType(BudgetCategoryTypes.BUDGET_CATEGORY_TYPE_MONTH));
 270  3025
                 periodTypeComboBox.addActionListener(this);
 271  3025
                 periodTypeComboBox.setRenderer(new TranslatorListCellRenderer());
 272  
 
 273  3025
                 JPanel balanceLabelPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
 274  3025
                 balanceLabelPanel.add(new JLabel(TextFormatter.getTranslation(BuddiKeys.BUDGET_NET_INCOME)));
 275  3025
                 balanceLabelPanel.add(periodTypeComboBox);
 276  3025
                 balanceLabelPanel.add(balanceLabel);
 277  
 
 278  3025
                 JPanel listScrollerPanel = new JPanel(new BorderLayout());
 279  3025
                 listScrollerPanel.add(listScroller, BorderLayout.CENTER);
 280  3025
                 listScrollerPanel.add(balanceLabelPanel, BorderLayout.SOUTH);
 281  
 
 282  3025
                 JPanel spinnerPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
 283  3025
                 spinnerPanel.add(new JLabel(TextFormatter.getTranslation(BuddiKeys.CURRENT_BUDGET_PERIOD)));
 284  3025
                 spinnerPanel.add(dateSpinner);
 285  
 
 286  
 //                JPanel periodPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
 287  
 //                periodPanel.add(new JLabel(TextFormatter.getTranslation(BuddiKeys.SHOW_BUDGET_CATEGORIES_FOR_PERIOD)));
 288  
 //                periodPanel.add(periodTypeComboBox);
 289  
 
 290  3025
                 JPanel topPanel = new JPanel(new BorderLayout());
 291  
 //                topPanel.add(periodPanel, BorderLayout.EAST);
 292  3025
                 topPanel.add(spinnerPanel, BorderLayout.EAST);
 293  
 
 294  3025
                 JPanel mainPanel = new JPanel(); 
 295  3025
                 mainPanel.setLayout(new BorderLayout());
 296  
 
 297  3025
                 mainPanel.add(topPanel, BorderLayout.NORTH);
 298  3025
                 mainPanel.add(listScrollerPanel, BorderLayout.CENTER);
 299  
 
 300  3025
                 if (OperatingSystemUtil.isMac()){
 301  0
                         listScroller.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
 302  
                 }
 303  
 
 304  3025
                 tree.addTreeSelectionListener(new TreeSelectionListener(){
 305  
                         public void valueChanged(TreeSelectionEvent arg0) {
 306  0
                                 parent.updateContent();
 307  
 //                                tree.editCellAt(tree.getSelectedRow(), tree.getSelectedColumn());
 308  0
                         }
 309  
                 });
 310  
 
 311  3025
                 updateButtons();
 312  
 
 313  
 //                String dataFile = model.getFile() == null ? "" : " - " + model.getFile();
 314  
 //                this.setTitle(PrefsModel.getInstance().getTranslator().get(BuddiKeys.MY_BUDGET) + dataFile + " - " + PrefsModel.getInstance().getTranslator().get(BuddiKeys.BUDDI));
 315  
 //                this.setJMenuBar(new BudgetFrameMenuBar(this));
 316  
 
 317  3025
                 this.setLayout(new BorderLayout());
 318  3025
                 this.add(mainPanel, BorderLayout.CENTER);
 319  3025
         }
 320  
 
 321  
         public void updateContent() {
 322  12310
                 super.updateContent();
 323  
 
 324  
 //                int rowSelected = tree.getSelectedRow();
 325  
 //                int columnSelected = tree.getSelectedColumn();
 326  
                 
 327  
                 //Refresh the column headers.  For some stupid reason you have
 328  
                 // to do it manually, even though the model itself updates and 
 329  
                 // fires a change event.
 330  49240
                 for (int i = 1; i < treeTableModel.getColumnCount(); i++)
 331  36930
                         tree.getColumn(i).setHeaderValue(treeTableModel.getColumnName(i));
 332  
 
 333  
                 //Update the date spinner
 334  12310
                 dateSpinner.setEditor(new JSpinner.DateEditor(dateSpinner, treeTableModel.getSelectedBudgetPeriodType().getDateFormat()));
 335  
 
 336  
                 //Fire a change event on the table model.
 337  
 //                treeTableModel.fireStructureChanged();
 338  
 
 339  
                 //Update the balance label
 340  12310
                 long budgetedNetIncome = 0;
 341  
                 //We make a new linked list containing all of the filtered list to avoid the potential of a concurrent
 342  
                 // modification exception.
 343  12310
                 for (BudgetCategory bc : new LinkedList<BudgetCategory>(new FilteredLists.BudgetCategoryListFilteredByPeriodType(
 344  
                                 (Document) parent.getDocument(), 
 345  
                                 treeTableModel.getSelectedBudgetPeriodType()))) {
 346  123100
                         budgetedNetIncome += (bc.getAmount(treeTableModel.getSelectedDate()) * (bc.isIncome() ? 1 : -1));
 347  
                 }
 348  12310
                 balanceLabel.setText(TextFormatter.getHtmlWrapper(TextFormatter.getFormattedCurrency(budgetedNetIncome)));
 349  
 
 350  
                 //Restore the state of the expanded / unrolled nodes.
 351  12310
                 for (BudgetCategory bc : ((Document) parent.getDocument()).getBudgetCategories()) {
 352  123100
                         TreePath path = new TreePath(new Object[]{treeTableModel.getRoot(), bc});
 353  123100
                         if (bc.isExpanded())
 354  0
                                 tree.expandPath(path);
 355  
                         else
 356  123100
                                 tree.collapsePath(path);
 357  123100
                 }
 358  
                 
 359  
                 //Re-select the last cell
 360  
 //                System.out.println(rowSelected + " - " + columnSelected);
 361  
 //                tree.changeSelection(rowSelected, columnSelected, false, false);
 362  
                 
 363  
                 //Update the menus (especially to get correct Copy From / To dates)
 364  12310
                 parent.updateMenus();
 365  12310
         }
 366  
         
 367  
         public MyBudgetTreeTableModel getTreeTableModel(){
 368  1680
                 return treeTableModel;
 369  
         }
 370  
         
 371  
         public void fireStructureChanged(){
 372  132
                 treeTableModel.fireStructureChanged();
 373  132
         }
 374  
 }