Coverage Report - org.homeunix.thecave.buddi.view.dialogs.SplitTransactionDialog
 
Classes in this File Line Coverage Branch Coverage Complexity
SplitTransactionDialog
93%
133/142
61%
16/26
2.364
SplitTransactionDialog$1
25%
1/4
N/A
2.364
SplitTransactionDialog$2
100%
4/4
N/A
2.364
SplitTransactionDialog$3
100%
8/8
N/A
2.364
 
 1  
 /*
 2  
  * Created on Aug 6, 2007 by wyatt
 3  
  */
 4  
 package org.homeunix.thecave.buddi.view.dialogs;
 5  
 
 6  
 import java.awt.BorderLayout;
 7  
 import java.awt.Dimension;
 8  
 import java.awt.FlowLayout;
 9  
 import java.awt.GridBagConstraints;
 10  
 import java.awt.GridBagLayout;
 11  
 import java.awt.GridLayout;
 12  
 import java.awt.event.ActionEvent;
 13  
 import java.awt.event.ActionListener;
 14  
 import java.awt.event.FocusAdapter;
 15  
 import java.awt.event.FocusEvent;
 16  
 import java.awt.event.KeyAdapter;
 17  
 import java.awt.event.KeyEvent;
 18  
 import java.util.ArrayList;
 19  
 import java.util.List;
 20  
 import java.util.logging.Level;
 21  
 import java.util.logging.Logger;
 22  
 
 23  
 import javax.swing.JButton;
 24  
 import javax.swing.JLabel;
 25  
 import javax.swing.JPanel;
 26  
 
 27  
 import org.homeunix.thecave.buddi.i18n.BuddiKeys;
 28  
 import org.homeunix.thecave.buddi.i18n.keys.ButtonKeys;
 29  
 import org.homeunix.thecave.buddi.model.Document;
 30  
 import org.homeunix.thecave.buddi.model.Source;
 31  
 import org.homeunix.thecave.buddi.model.TransactionSplit;
 32  
 import org.homeunix.thecave.buddi.model.impl.ModelFactory;
 33  
 import org.homeunix.thecave.buddi.model.prefs.PrefsModel;
 34  
 import org.homeunix.thecave.buddi.model.swing.SourceComboBoxModel;
 35  
 import org.homeunix.thecave.buddi.plugin.api.exception.InvalidValueException;
 36  
 import org.homeunix.thecave.buddi.plugin.api.util.TextFormatter;
 37  
 import org.homeunix.thecave.buddi.util.InternalFormatter;
 38  
 import org.homeunix.thecave.buddi.view.TransactionFrame;
 39  
 import org.homeunix.thecave.buddi.view.swing.SourceListCellRenderer;
 40  
 
 41  
 import ca.digitalcave.moss.swing.MossDecimalField;
 42  
 import ca.digitalcave.moss.swing.MossDialog;
 43  
 import ca.digitalcave.moss.swing.MossScrollingComboBox;
 44  
 
 45  
 /**
 46  
  * This class lets a user modify / create a list of split transactions.  When this is done, 
 47  
  * call the getSplits() method on it to return the list of splits as currently defined in it.
 48  
  * 
 49  
  * @author wyatt
 50  
  *
 51  
  */
 52  53
 public class SplitTransactionDialog extends MossDialog implements ActionListener {
 53  
 
 54  
         public static final long serialVersionUID = 0;
 55  
 
 56  
         private final JButton save;
 57  
         private final JButton cancel;
 58  
         private final JButton add;
 59  
         
 60  
         private final JLabel desired;
 61  
         private final JLabel current;
 62  
         private final JLabel difference;
 63  
 
 64  
         private final Document model;
 65  
         private final Source associatedSource;
 66  
         private final List<TransactionSplit> workingSplits;
 67  
         private List<TransactionSplit> completedSplits; //How we pass the splits back to the calling frame.  This is null if canceled, and working splits if saved.
 68  
         private final long amount; //The sum of all splits must equal this number.
 69  
         private final boolean from; //Is this for a To or From?  This will affect what types of BCs can be used.
 70  
         
 71  
         private final JPanel splitPanels;
 72  
 
 73  
         public SplitTransactionDialog(TransactionFrame frame, Document model, List<TransactionSplit> splits, Source associatedSource, long amount, boolean from) {
 74  102
                 super(frame, true);
 75  
 
 76  102
                 this.model = model;
 77  102
                 this.workingSplits = new ArrayList<TransactionSplit>(splits != null ? splits : new ArrayList<TransactionSplit>());
 78  102
                 this.associatedSource = associatedSource;
 79  102
                 this.amount = amount;
 80  102
                 this.from = from;
 81  
                 
 82  102
                 this.desired = new JLabel();
 83  102
                 this.current = new JLabel();
 84  102
                 this.difference = new JLabel();
 85  
 
 86  102
                 splitPanels = new JPanel();
 87  
                 
 88  102
                 save = new JButton(PrefsModel.getInstance().getTranslator().get(ButtonKeys.BUTTON_SAVE));
 89  102
                 cancel = new JButton(PrefsModel.getInstance().getTranslator().get(ButtonKeys.BUTTON_CANCEL));
 90  102
                 add = new JButton(PrefsModel.getInstance().getTranslator().get(ButtonKeys.BUTTON_ADD_SPLIT));                
 91  102
         }
 92  
 
 93  
         public void init() {
 94  102
                 super.init();
 95  
 
 96  
                 try {
 97  102
                         if (this.workingSplits.size() == 0)
 98  102
                                 this.workingSplits.add(ModelFactory.createTransactionSplit(null, 0l));
 99  
                 }
 100  0
                 catch (InvalidValueException ive){
 101  0
                         Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Error populating split list", ive);
 102  102
                 }
 103  
 
 104  
                 
 105  102
                 this.setTitle(TextFormatter.getTranslation(BuddiKeys.SPLIT_EDITOR));
 106  102
                 this.setLayout(new BorderLayout());
 107  
                 
 108  102
                 save.setPreferredSize(InternalFormatter.getButtonSize(save));
 109  102
                 cancel.setPreferredSize(InternalFormatter.getButtonSize(cancel));
 110  102
                 current.getPreferredSize().width = 200;
 111  102
                 desired.getPreferredSize().width = 200;
 112  102
                 difference.getPreferredSize().width = 200;
 113  
                 
 114  102
                 splitPanels.setLayout(new GridBagLayout());
 115  102
                 this.add(splitPanels, BorderLayout.NORTH);
 116  
 
 117  102
                 JPanel saveCancelButtonsPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
 118  102
                 JPanel addButtonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
 119  
                 
 120  102
                 addButtonPanel.add(add);
 121  102
                 saveCancelButtonsPanel.add(addButtonPanel);
 122  102
                 saveCancelButtonsPanel.add(cancel);
 123  102
                 saveCancelButtonsPanel.add(save);
 124  
                 
 125  102
                 JPanel bottomPanel = new JPanel(new GridLayout(0, 2));
 126  
                 
 127  102
                 bottomPanel.add(addButtonPanel);
 128  102
                 bottomPanel.add(saveCancelButtonsPanel);
 129  102
                 this.add(bottomPanel, BorderLayout.SOUTH);
 130  
                 
 131  102
                 save.addActionListener(this);
 132  102
                 cancel.addActionListener(this);
 133  102
                 add.addActionListener(this);
 134  
                 
 135  102
                 this.getRootPane().setDefaultButton(save);
 136  102
         }
 137  
 
 138  
         public void updateButtons() {
 139  361
                 super.updateButtons();
 140  
 
 141  361
                 long amount = 0;
 142  361
                 boolean allSplitsValid = true;
 143  361
                 for (TransactionSplit split : workingSplits) {
 144  343
                         amount += split.getAmount();
 145  343
                         if (split.getSource() == null || split.getAmount() == 0l)
 146  343
                                 allSplitsValid = false;
 147  
                 }
 148  
                 
 149  
                 //The Add button is enabled only if there are no blank splits.  Thus, we can have at most
 150  
                 // one blank row at a time.
 151  361
                 add.setEnabled(allSplitsValid);
 152  
                 
 153  361
                 desired.setText(TextFormatter.getHtmlWrapper(TextFormatter.getFormattedCurrency(this.amount)));
 154  361
                 current.setText(TextFormatter.getHtmlWrapper(TextFormatter.getFormattedCurrency(amount)));
 155  361
                 difference.setText(TextFormatter.getHtmlWrapper(TextFormatter.getFormattedCurrency(this.amount - amount)));
 156  
 
 157  361
                 save.setEnabled(amount == this.amount && allSplitsValid);
 158  361
         }
 159  
 
 160  
         /**
 161  
          * In this class, updateContent() will force a complete refresh of all
 162  
          * split entries.
 163  
          */
 164  
         public void updateContent() {
 165  112
                 splitPanels.removeAll();
 166  
                 
 167  112
                 splitPanels.setLayout(new GridBagLayout());
 168  112
                 GridBagConstraints c = new GridBagConstraints();
 169  112
                 c.weighty = 0;
 170  112
                 c.gridy = 0;
 171  112
                 c.fill = GridBagConstraints.HORIZONTAL;
 172  
                 
 173  112
                 for (TransactionSplit split : workingSplits) {
 174  103
                         final MossScrollingComboBox source = new MossScrollingComboBox();
 175  103
                         final MossDecimalField amount = new MossDecimalField();
 176  103
                         final TransactionSplit finalSplit = split;
 177  
                         
 178  103
                         amount.addKeyListener(new KeyAdapter(){
 179  
                                 @Override
 180  
                                 public void keyTyped(KeyEvent e) {
 181  0
                                         setAmount(source, finalSplit, amount);
 182  0
                                         updateButtons();
 183  0
                                 }
 184  
                         });
 185  
                         
 186  103
                         source.setPreferredSize(new Dimension(150, source.getPreferredSize().height));
 187  103
                         amount.setPreferredSize(new Dimension(100, amount.getPreferredSize().height));
 188  
                         
 189  103
                         source.setModel(new SourceComboBoxModel(model, from, false, associatedSource));
 190  103
                         source.setRenderer(new SourceListCellRenderer(TextFormatter.getTranslation(BuddiKeys.HINT_SOURCE), source));
 191  
                         
 192  103
                         source.setSelectedItem(split.getSource());
 193  103
                         amount.setValue(split.getAmount());
 194  
 
 195  103
                         c.weightx = 0.2;
 196  103
                         c.gridx = 0;
 197  103
                         splitPanels.add(source, c);
 198  
                         
 199  103
                         c.weightx = 0.1;
 200  103
                         c.gridx = 1;
 201  103
                         splitPanels.add(amount, c);
 202  
 
 203  103
                         c.weightx = 0.0;
 204  103
                         c.gridx = 2;
 205  
                         
 206  103
                         JButton remove = new JButton("-");
 207  103
                         remove.setFocusable(false);
 208  103
                         remove.addActionListener(new ActionListener(){
 209  
                                 public void actionPerformed(ActionEvent e) {
 210  9
                                         workingSplits.remove(finalSplit);
 211  9
                                         updateContent();
 212  9
                                 }
 213  
                         });
 214  
                         
 215  103
                         FocusAdapter fa = new FocusAdapter(){
 216  
                                 @Override
 217  
                                 public void focusGained(FocusEvent e) {
 218  103
                                         super.focusGained(e);
 219  103
                                         updateButtons();
 220  103
                                 }
 221  
                                 
 222  
                                 @Override
 223  
                                 public void focusLost(FocusEvent e) {
 224  44
                                         super.focusLost(e);
 225  44
                                         setAmount(source, finalSplit, amount);
 226  44
                                         updateButtons();
 227  44
                                 }
 228  
                         };
 229  103
                         source.addFocusListener(fa);
 230  103
                         amount.addFocusListener(fa);
 231  
                         
 232  103
                         splitPanels.add(remove, c);
 233  103
                         source.requestFocusInWindow();
 234  
                         
 235  103
                         c.gridy++;
 236  103
                 }
 237  
                 
 238  
 //                JPanel currentPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
 239  
 //                JPanel desiredPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
 240  
 //                JPanel differencePanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
 241  
 //                desiredPanel.add(desired);
 242  
 //                currentPanel.add(current);
 243  
 //                differencePanel.add(difference);
 244  
 
 245  112
                 c.anchor = GridBagConstraints.EAST;
 246  
                 
 247  112
                 c.weightx = 0.2;
 248  112
                 c.gridx = 0;
 249  112
                 splitPanels.add(new JLabel(TextFormatter.getTranslation(BuddiKeys.SPLIT_TOTAL)), c);
 250  112
                 c.weightx = 0.1;
 251  112
                 c.gridx = 1;
 252  112
                 splitPanels.add(current, c);
 253  112
                 c.gridy++;
 254  
                 
 255  112
                 c.weightx = 0.2;
 256  112
                 c.gridx = 0;
 257  112
                 splitPanels.add(new JLabel(TextFormatter.getTranslation(BuddiKeys.TRANSACTION_AMOUNT)), c);
 258  112
                 c.weightx = 0.1;
 259  112
                 c.gridx = 1;
 260  112
                 splitPanels.add(desired, c);
 261  112
                 c.gridy++;
 262  
                 
 263  112
                 c.weightx = 0.2;
 264  112
                 c.gridx = 0;
 265  112
                 splitPanels.add(new JLabel(TextFormatter.getTranslation(BuddiKeys.SPLIT_TRANSACTION_DIFFERENCE)), c);
 266  112
                 c.weightx = 0.1;
 267  112
                 c.gridx = 1;
 268  112
                 splitPanels.add(difference, c);
 269  
                 
 270  
                 //Force a refresh
 271  112
                 splitPanels.invalidate();
 272  
                 
 273  112
                 this.pack();
 274  
                 
 275  112
                 updateButtons();
 276  112
         }
 277  
         
 278  
         private void setAmount(MossScrollingComboBox source, TransactionSplit finalSplit, MossDecimalField amount){
 279  
                 try {
 280  44
                         if (source.getSelectedItem() instanceof Source){
 281  0
                                 finalSplit.setSource((Source) source.getSelectedItem());
 282  
                         }
 283  
                         else {
 284  44
                                 finalSplit.setSource(null);
 285  
                         }
 286  44
                         finalSplit.setAmount(amount.getValue());
 287  
                 }
 288  0
                 catch (InvalidValueException ive){
 289  0
                         Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Error setting split information", ive);
 290  44
                 }
 291  
 
 292  44
         }
 293  
         
 294  
         public void actionPerformed(ActionEvent e) {
 295  38
                 if (e.getSource().equals(add)){
 296  
                         try {
 297  1
                                 workingSplits.add(ModelFactory.createTransactionSplit(null, 0l));
 298  1
                                 updateContent();
 299  
                         }
 300  0
                         catch (InvalidValueException ive){
 301  0
                                 Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Error adding split", ive);
 302  1
                         }
 303  
                 }
 304  37
                 else if (e.getSource().equals(cancel)){
 305  36
                         completedSplits = null;
 306  36
                         this.closeWindow();
 307  
                 }
 308  1
                 else if (e.getSource().equals(save)){
 309  1
                         completedSplits = workingSplits;
 310  1
                         this.closeWindow();
 311  
                 }
 312  0
                 else if (e.getActionCommand().equals("UPDATE")){
 313  0
                         updateButtons();
 314  
                 }
 315  38
         }
 316  
         
 317  
         public List<TransactionSplit> getSplits(){
 318  37
                 return completedSplits;
 319  
         }
 320  
 }