1 | |
|
2 | |
|
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 | |
|
120 | |
|
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 | |
|
171 | 3025 | final KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager(); |
172 | |
|
173 | 3025 | manager.addKeyEventDispatcher(new KeyEventDispatcher(){ |
174 | |
|
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 | |
|
188 | |
|
189 | |
|
190 | |
|
191 | |
|
192 | |
|
193 | |
|
194 | |
|
195 | |
|
196 | |
|
197 | |
|
198 | |
|
199 | |
|
200 | |
|
201 | |
|
202 | |
|
203 | |
|
204 | |
|
205 | |
|
206 | |
|
207 | |
|
208 | |
|
209 | |
|
210 | |
|
211 | |
|
212 | |
|
213 | 0 | manager.redispatchEvent(tree, e); |
214 | 0 | e.consume(); |
215 | |
|
216 | 0 | return true; |
217 | |
} |
218 | 0 | return false; |
219 | |
} |
220 | |
}); |
221 | |
|
222 | |
|
223 | |
|
224 | |
|
225 | |
|
226 | |
|
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 | |
|
257 | |
|
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 | |
|
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 | |
|
287 | |
|
288 | |
|
289 | |
|
290 | 3025 | JPanel topPanel = new JPanel(new BorderLayout()); |
291 | |
|
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 | |
|
308 | 0 | } |
309 | |
}); |
310 | |
|
311 | 3025 | updateButtons(); |
312 | |
|
313 | |
|
314 | |
|
315 | |
|
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 | |
|
325 | |
|
326 | |
|
327 | |
|
328 | |
|
329 | |
|
330 | 49240 | for (int i = 1; i < treeTableModel.getColumnCount(); i++) |
331 | 36930 | tree.getColumn(i).setHeaderValue(treeTableModel.getColumnName(i)); |
332 | |
|
333 | |
|
334 | 12310 | dateSpinner.setEditor(new JSpinner.DateEditor(dateSpinner, treeTableModel.getSelectedBudgetPeriodType().getDateFormat())); |
335 | |
|
336 | |
|
337 | |
|
338 | |
|
339 | |
|
340 | 12310 | long budgetedNetIncome = 0; |
341 | |
|
342 | |
|
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 | |
|
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 | |
|
360 | |
|
361 | |
|
362 | |
|
363 | |
|
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 | |
} |