Coverage Report - org.homeunix.thecave.buddi.model.swing.MyBudgetTreeTableModel
 
Classes in this File Line Coverage Branch Coverage Complexity
MyBudgetTreeTableModel
48%
60/123
32%
34/104
4.55
 
 1  
 /*
 2  
  * Created on Aug 4, 2007 by wyatt
 3  
  */
 4  
 package org.homeunix.thecave.buddi.model.swing;
 5  
 
 6  
 import java.text.SimpleDateFormat;
 7  
 import java.util.Date;
 8  
 import java.util.HashMap;
 9  
 import java.util.List;
 10  
 import java.util.Map;
 11  
 
 12  
 import org.homeunix.thecave.buddi.i18n.BuddiKeys;
 13  
 import org.homeunix.thecave.buddi.i18n.keys.BudgetCategoryTypes;
 14  
 import org.homeunix.thecave.buddi.model.BudgetCategory;
 15  
 import org.homeunix.thecave.buddi.model.BudgetCategoryType;
 16  
 import org.homeunix.thecave.buddi.model.Document;
 17  
 import org.homeunix.thecave.buddi.model.Transaction;
 18  
 import org.homeunix.thecave.buddi.model.TransactionSplit;
 19  
 import org.homeunix.thecave.buddi.model.impl.FilteredLists;
 20  
 import org.homeunix.thecave.buddi.model.impl.ModelFactory;
 21  
 import org.homeunix.thecave.buddi.model.prefs.PrefsModel;
 22  
 import org.homeunix.thecave.buddi.plugin.api.exception.InvalidValueException;
 23  
 import org.homeunix.thecave.buddi.plugin.api.util.TextFormatter;
 24  
 import org.jdesktop.swingx.treetable.AbstractTreeTableModel;
 25  
 
 26  
 import ca.digitalcave.moss.collections.FilteredList;
 27  
 
 28  
 public class MyBudgetTreeTableModel extends AbstractTreeTableModel {
 29  
 
 30  
         private final Document model;
 31  
         private final Object root;
 32  
         private Date selectedDate;
 33  
         private BudgetCategoryType selectedBudgetPeriodType;
 34  
 
 35  
         private final Map<BudgetCategoryType, List<BudgetCategory>> budgetCategoriesByType;
 36  
         //private final Map<Object, BudgetCategoryListFilteredByDeleted> childrenMap;
 37  
         private List<BudgetCategory> rootChildren;
 38  
 
 39  
         //Where the selected month is in relation to the edge of the table.
 40  3034
         private final int monthOffset = 2; 
 41  
 
 42  
         public MyBudgetTreeTableModel(Document model) {
 43  3034
                 super(new Object());
 44  
                 //Map<BudgetCategoryType, List<BudgetCategory>> budgetCategoriesByType = new HashMap<BudgetCategoryType, List<BudgetCategory>>();
 45  3034
                 budgetCategoriesByType = new HashMap<BudgetCategoryType, List<BudgetCategory>>();
 46  
                 //this.childrenMap = new HashMap<Object, BudgetCategoryListFilteredByDeleted>();
 47  
 
 48  3034
                 this.model = model;
 49  3034
                 this.root = getRoot();
 50  3034
                 this.selectedDate = new Date();
 51  
                 //                this.monthOffset = 2; //This puts the current month in the middle of three columns.
 52  
 
 53  
 
 54  21238
                 for (BudgetCategoryTypes typeEnum : BudgetCategoryTypes.values()) {
 55  18204
                         BudgetCategoryType type = ModelFactory.getBudgetCategoryType(typeEnum);
 56  18204
                         budgetCategoriesByType.put(type, new FilteredLists.BudgetCategoryListFilteredByPeriodType(model, type));
 57  
                 }
 58  3034
         }
 59  
 
 60  
         public Date getSelectedDate() {
 61  199891
                 return selectedDate;
 62  
         }
 63  
 
 64  
         public void setSelectedDate(Date selectedDate) {
 65  0
                 this.selectedDate = getSelectedBudgetPeriodType().getStartOfBudgetPeriod(selectedDate);
 66  0
         }
 67  
 
 68  
         public BudgetCategoryType getSelectedBudgetPeriodType(){
 69  172506
                 if (selectedBudgetPeriodType == null)
 70  3034
                         selectedBudgetPeriodType = ModelFactory.getBudgetCategoryType(BudgetCategoryTypes.BUDGET_CATEGORY_TYPE_MONTH);
 71  172506
                 return selectedBudgetPeriodType;
 72  
         }
 73  
 
 74  
         public void setSelectedBudgetPeriodType(BudgetCategoryType periodType){
 75  0
                 this.selectedBudgetPeriodType = periodType;
 76  0
                 this.rootChildren = null;
 77  
 
 78  0
                 setSelectedDate(getSelectedDate());
 79  0
         }
 80  
 
 81  
         private List<BudgetCategory> getRootChildren(){
 82  53562
                 if (rootChildren == null)
 83  3034
                         if (PrefsModel.getInstance().isShowFlatBudget())
 84  0
                                 rootChildren = new FilteredLists.BudgetCategoryListFilteredByDeleted(model, budgetCategoriesByType.get(getSelectedBudgetPeriodType()));
 85  
                         else
 86  3034
                                 rootChildren = new FilteredLists.BudgetCategoryListFilteredByDeleted(model, new FilteredLists.BudgetCategoryListFilteredByParent(model, budgetCategoriesByType.get(getSelectedBudgetPeriodType()), null));
 87  53562
                 return rootChildren;
 88  
         }
 89  
 
 90  
         public int getColumnCount() {
 91  197102
                 return PrefsModel.getInstance().getNumberOfBudgetColumns();
 92  
         }
 93  
 
 94  
         @Override
 95  
         public String getColumnName(int column) {
 96  51238
                 if (column == 0)
 97  3157
                         return TextFormatter.getTranslation(BuddiKeys.BUDGET_CATEGORY);
 98  
 
 99  48081
                 if (column >= 1 && column < getColumnCount())
 100  48081
                         return new SimpleDateFormat(getSelectedBudgetPeriodType().getDateFormat()).format(getColumnDate(column));
 101  
 
 102  0
                 return "";
 103  
         }
 104  
 
 105  
         public Object getValueAt(Object node, int column) {
 106  49038
                 if (column == -1)
 107  0
                         return node;
 108  49038
                 if (node instanceof BudgetCategory){
 109  42982
                         BudgetCategory bc = (BudgetCategory) node;
 110  42982
                         if (column == 0)
 111  33412
                                 return bc;
 112  9570
                         if (column >= 1 && column < getColumnCount()){
 113  
 
 114  
                                 //We use an Object[] array to return a bunch of information.  This is quite
 115  
                                 // a complicated setup, due to the complexity of the budget information.
 116  
                                 // The object array contains the following information, by index:
 117  
                                 // 0: The budget category associated with this value
 118  
                                 // 1: The amount for this given column
 119  
                                 // 2: The amount total for all children of this node
 120  
                                 // 3: The depth of the node (used for indenting)
 121  
 
 122  9570
                                 Object[] retValues = new Object[6];
 123  9570
                                 retValues[0] = bc;
 124  9570
                                 retValues[1] = bc.getAmount(getColumnDate(column));
 125  9570
                                 retValues[2] = getChildCount(node) == 0 ? 0 : getChildTotal(node, column);
 126  9570
                                 retValues[3] = getChildDepth(node);
 127  9570
                                 retValues[4] = getActual(bc, getColumnDate(column), false);
 128  9570
                                 retValues[5] = getActual(bc, getColumnDate(column), true);
 129  
 
 130  
                                 //long value = bc.getAmount(getColumnDate(column));
 131  
                                 //return TextFormatter.getHtmlWrapper(TextFormatter.getFormattedCurrency(value, InternalFormatter.isRed(bc, value)));
 132  9570
                                 return retValues;
 133  
                         }
 134  
                 }
 135  6056
                 return null;
 136  
         }
 137  
 
 138  
         private long getActual(BudgetCategory bc, Date date, boolean includeChildren) {
 139  19140
                 List<Transaction> transactions = model.getTransactions(bc, date,
 140  
                                 getSelectedBudgetPeriodType().getEndOfBudgetPeriod(date));
 141  
 
 142  19140
                 long actual = 0;
 143  19140
                 for (Transaction transaction : transactions) {
 144  0
                         if (!transaction.isDeleted()){
 145  0
                                 if (transaction.getTo() instanceof BudgetCategory){
 146  0
                                         actual -= transaction.getAmount();
 147  
                                 } 
 148  0
                                 else if (transaction.getFrom() instanceof BudgetCategory){
 149  0
                                         actual += transaction.getAmount();
 150  
                                 }
 151  0
                                 for (TransactionSplit split : transaction.getToSplits()) {
 152  0
                                         if(split.getSource().getFullName().equals(bc.getFullName()))
 153  0
                                                 actual -= split.getAmount();
 154  
                                 }
 155  0
                                 for (TransactionSplit split : transaction.getFromSplits()) {
 156  0
                                         if(split.getSource().getFullName().equals(bc.getFullName()))
 157  0
                                                 actual += split.getAmount();
 158  
                                 }
 159  
                         }
 160  
                 }
 161  
 
 162  19140
                 if(includeChildren) {
 163  9570
                         for(BudgetCategory child: bc.getChildren()) {
 164  
                                 // we could avoid recursion, but it's just so cool
 165  0
                                 actual += getActual(child, date, true);
 166  
                         }
 167  
                 }
 168  
 
 169  19140
                 return actual;
 170  
         }
 171  
 
 172  
 
 173  
         private int getChildDepth(Object node){
 174  9570
                 if (node instanceof BudgetCategory && !PrefsModel.getInstance().isShowFlatBudget()){
 175  9570
                         if (((BudgetCategory) node).getParent() == null)
 176  9570
                                 return 0;
 177  0
                         return getChildDepth(((BudgetCategory) node).getParent()) + 1;
 178  
                 }
 179  0
                 return 0;
 180  
         }
 181  
 
 182  
         private long getChildTotal(Object node, int column){
 183  0
                 if (PrefsModel.getInstance().isShowFlatBudget())
 184  0
                         return ((BudgetCategory) node).getAmount(getColumnDate(column));
 185  0
                 if (node instanceof BudgetCategory){
 186  0
                         long childTotal = ((BudgetCategory) node).getAmount(getColumnDate(column));
 187  0
                         for (int i = 0; i < getChildCount(node); i++){
 188  0
                                 childTotal += getChildTotal(getChild(node, i), column);
 189  
                         }
 190  0
                         return childTotal;
 191  
                 }
 192  0
                 return 0;
 193  
         }
 194  
 
 195  
         public Object getChild(Object parent, int childIndex) {
 196  31568
                 if (parent.equals(root)){
 197  
                         //                        if (rootChildren == null)
 198  
                         //                                rootChildren = new BudgetCategoryListFilteredByDeleted(model, new BudgetCategoryListFilteredByParent(model, budgetCategoriesByType.get(getSelectedBudgetPeriodType()), null)); 
 199  31568
                         return getRootChildren().get(childIndex);
 200  
                 }
 201  0
                 if (parent instanceof BudgetCategory && !PrefsModel.getInstance().isShowFlatBudget()){
 202  
                         //                        List<BudgetCategory> budgetCategories = new BudgetCategoryListFilteredByDeleted(model, new BudgetCategoryListFilteredByParent(model, budgetCategoriesByType.get(getSelectedBudgetPeriodType()), (BudgetCategory) parent));
 203  
                         //                        if (childIndex < budgetCategories.size())
 204  0
                         return ((BudgetCategory) parent).getChildren().get(childIndex);
 205  
                 }
 206  0
                 return null;
 207  
         }
 208  
 
 209  
         public int getChildCount(Object parent) {
 210  66184
                 if (parent.equals(root)){
 211  
                         //                                childrenMap.put(parent, new BudgetCategoryListFilteredByDeleted(model, new BudgetCategoryListFilteredByParent(model, budgetCategoriesByType.get(getSelectedBudgetPeriodType()), null)));
 212  
                         //                                return new BudgetCategoryListFilteredByDeleted(model, new BudgetCategoryListFilteredByParent(model, budgetCategoriesByType.get(getSelectedBudgetPeriodType()), null)).size();
 213  
                         //                                return budgetCategories.size();
 214  21862
                         return getRootChildren().size();
 215  
                 }
 216  44322
                 if (parent instanceof BudgetCategory && !PrefsModel.getInstance().isShowFlatBudget()){
 217  
                         //                                childrenMap.put(parent, new BudgetCategoryListFilteredByDeleted(model, new BudgetCategoryListFilteredByParent(model, budgetCategoriesByType.get(getSelectedBudgetPeriodType()), (BudgetCategory) parent)));
 218  
                         //                                return new BudgetCategoryListFilteredByDeleted(model, new BudgetCategoryListFilteredByParent(model, budgetCategoriesByType.get(getSelectedBudgetPeriodType()), (BudgetCategory) parent)).size();
 219  
                         //                                return budgetCategories.size();
 220  44302
                         return ((BudgetCategory) parent).getChildren().size();
 221  
                 }
 222  
                 //                }
 223  
 
 224  20
                 return 0;
 225  
                 //                return childrenMap.get(parent).size();
 226  
         }
 227  
 
 228  
         public int getIndexOfChild(Object parent, Object child) {
 229  0
                 if (parent == null || child == null)
 230  0
                         return -1;
 231  
 
 232  0
                 if (parent.equals(root) && child instanceof BudgetCategory){
 233  0
                         return getRootChildren().indexOf(child);
 234  
                 }
 235  0
                 if (parent instanceof BudgetCategory && child instanceof BudgetCategory && !PrefsModel.getInstance().isShowFlatBudget()){
 236  0
                         return ((BudgetCategory) parent).getChildren().indexOf(child);
 237  
                 }
 238  0
                 return -1;
 239  
         }
 240  
 
 241  
 
 242  
 
 243  
         @Override
 244  
         public void setValueAt(Object value, Object node, int column) {
 245  0
                 if (column >= 1 && column < getColumnCount()){
 246  0
                         if (node instanceof BudgetCategory){
 247  0
                                 BudgetCategory bc = (BudgetCategory) node;
 248  
                                 try {
 249  0
                                         long amount = Long.parseLong(value.toString());
 250  0
                                         bc.setAmount(getColumnDate(column), amount);
 251  
                                 }
 252  0
                                 catch (InvalidValueException ive){} 
 253  0
                                 catch (NumberFormatException nfe){}
 254  
                         }
 255  
                 }
 256  0
         }
 257  
 
 258  
         @Override
 259  
         public boolean isCellEditable(Object node, int column) {
 260  0
                 if (node instanceof BudgetCategory && column >= 1 && column < getColumnCount())
 261  0
                         return true;
 262  0
                 return false;
 263  
         }
 264  
 
 265  
         private Date getColumnDate(int column){
 266  76791
                 return getSelectedBudgetPeriodType().getBudgetPeriodOffset(getSelectedDate(), column - monthOffset);
 267  
         }
 268  
 
 269  
         @Override
 270  
         public String toString() {
 271  0
                 StringBuilder sb = new StringBuilder();
 272  
 
 273  0
                 for (int i = 0; i < getChildCount(root); i++) {
 274  0
                         Object o1 = getChild(root, i);
 275  0
                         sb.append(o1).append(" [");
 276  0
                         for (int j = 0; j < getChildCount(o1); j++){
 277  0
                                 Object o2 = getChild(o1, j);
 278  0
                                 sb.append(o2);
 279  0
                                 if (j < (getChildCount(o1) - 1))
 280  0
                                         sb.append(", ");
 281  
                         }
 282  0
                         sb.append("]  ");
 283  
                 }
 284  
 
 285  0
                 return sb.toString();
 286  
         }
 287  
 
 288  
         public void fireStructureChanged(){
 289  132
                 ((FilteredList<?>) getRootChildren()).updateFilteredList();
 290  132
                 for (List<BudgetCategory> list : budgetCategoriesByType.values()) {
 291  792
                         ((FilteredList<?>) list).updateFilteredList();        
 292  
                 }
 293  132
                 modelSupport.fireNewRoot();
 294  132
         }
 295  
 }