1 | |
|
2 | |
|
3 | |
|
4 | |
package org.homeunix.thecave.buddi.view; |
5 | |
|
6 | |
import java.awt.BorderLayout; |
7 | |
import java.awt.FlowLayout; |
8 | |
import java.awt.GridBagConstraints; |
9 | |
import java.awt.GridBagLayout; |
10 | |
import java.awt.event.ActionEvent; |
11 | |
import java.awt.event.ActionListener; |
12 | |
import java.awt.event.ComponentAdapter; |
13 | |
import java.awt.event.ComponentEvent; |
14 | |
import java.awt.event.ItemEvent; |
15 | |
import java.awt.event.ItemListener; |
16 | |
import java.awt.event.KeyAdapter; |
17 | |
import java.awt.event.KeyEvent; |
18 | |
import java.awt.event.MouseAdapter; |
19 | |
import java.awt.event.MouseEvent; |
20 | |
import java.util.Date; |
21 | |
import java.util.List; |
22 | |
import java.util.logging.Level; |
23 | |
import java.util.logging.Logger; |
24 | |
|
25 | |
import javax.swing.BorderFactory; |
26 | |
import javax.swing.DefaultComboBoxModel; |
27 | |
import javax.swing.Icon; |
28 | |
import javax.swing.JButton; |
29 | |
import javax.swing.JComboBox; |
30 | |
import javax.swing.JLabel; |
31 | |
import javax.swing.JOptionPane; |
32 | |
import javax.swing.JPanel; |
33 | |
import javax.swing.JScrollPane; |
34 | |
import javax.swing.ListSelectionModel; |
35 | |
import javax.swing.UIManager; |
36 | |
import javax.swing.event.ListSelectionEvent; |
37 | |
import javax.swing.event.ListSelectionListener; |
38 | |
|
39 | |
import org.homeunix.thecave.buddi.Const; |
40 | |
import org.homeunix.thecave.buddi.i18n.BuddiKeys; |
41 | |
import org.homeunix.thecave.buddi.i18n.keys.ButtonKeys; |
42 | |
import org.homeunix.thecave.buddi.i18n.keys.TransactionClearedFilterKeys; |
43 | |
import org.homeunix.thecave.buddi.i18n.keys.TransactionDateFilterKeys; |
44 | |
import org.homeunix.thecave.buddi.i18n.keys.TransactionReconciledFilterKeys; |
45 | |
import org.homeunix.thecave.buddi.model.Account; |
46 | |
import org.homeunix.thecave.buddi.model.Document; |
47 | |
import org.homeunix.thecave.buddi.model.Source; |
48 | |
import org.homeunix.thecave.buddi.model.Transaction; |
49 | |
import org.homeunix.thecave.buddi.model.TransactionSplit; |
50 | |
import org.homeunix.thecave.buddi.model.impl.ModelFactory; |
51 | |
import org.homeunix.thecave.buddi.model.impl.SplitImpl; |
52 | |
import org.homeunix.thecave.buddi.model.prefs.PrefsModel; |
53 | |
import org.homeunix.thecave.buddi.model.swing.TransactionListModel; |
54 | |
import org.homeunix.thecave.buddi.plugin.BuddiPluginFactory; |
55 | |
import org.homeunix.thecave.buddi.plugin.api.BuddiTransactionCellRendererPlugin; |
56 | |
import org.homeunix.thecave.buddi.plugin.api.exception.InvalidValueException; |
57 | |
import org.homeunix.thecave.buddi.plugin.api.exception.ModelException; |
58 | |
import org.homeunix.thecave.buddi.plugin.api.util.TextFormatter; |
59 | |
import org.homeunix.thecave.buddi.plugin.builtin.cellrenderer.DefaultTransactionCellRenderer; |
60 | |
import org.homeunix.thecave.buddi.util.Formatter; |
61 | |
import org.homeunix.thecave.buddi.util.InternalFormatter; |
62 | |
import org.homeunix.thecave.buddi.view.menu.bars.BuddiMenuBar; |
63 | |
import org.homeunix.thecave.buddi.view.panels.TransactionEditorPanel; |
64 | |
import org.homeunix.thecave.buddi.view.swing.TranslatorListCellRenderer; |
65 | |
import org.jdesktop.swingx.JXCollapsiblePane; |
66 | |
import org.jdesktop.swingx.JXList; |
67 | |
import org.jdesktop.swingx.decorator.HighlighterFactory; |
68 | |
|
69 | |
import ca.digitalcave.moss.application.document.DocumentChangeEvent; |
70 | |
import ca.digitalcave.moss.application.document.DocumentChangeListener; |
71 | |
import ca.digitalcave.moss.common.ClassLoaderFunctions; |
72 | |
import ca.digitalcave.moss.common.OperatingSystemUtil; |
73 | |
import ca.digitalcave.moss.swing.MossAssociatedDocumentFrame; |
74 | |
import ca.digitalcave.moss.swing.MossSearchField; |
75 | |
import ca.digitalcave.moss.swing.MossSearchField.SearchTextChangedEvent; |
76 | |
import ca.digitalcave.moss.swing.MossSearchField.SearchTextChangedEventListener; |
77 | |
|
78 | 0 | public class TransactionFrame extends MossAssociatedDocumentFrame implements ActionListener { |
79 | |
public static final long serialVersionUID = 0; |
80 | |
|
81 | |
private static final int MIN_WIDTH = 400; |
82 | |
private static final int MIN_HEIGHT = 200; |
83 | |
|
84 | |
private final JXList list; |
85 | |
|
86 | |
private final TransactionEditorPanel transactionEditor; |
87 | |
private final JButton recordButton; |
88 | |
private final JButton clearButton; |
89 | |
private final JButton deleteButton; |
90 | |
private final MossSearchField searchField; |
91 | |
private final JComboBox dateFilterComboBox; |
92 | |
private final JComboBox clearedFilterComboBox; |
93 | |
private final JComboBox reconciledFilterComboBox; |
94 | |
private final JLabel overdraftCreditLimit; |
95 | |
|
96 | |
private final JLabel balancesLabel; |
97 | |
private final JLabel sumsLabel; |
98 | |
private final JLabel accountBalance; |
99 | |
private final JLabel clearedBalance; |
100 | |
private final JLabel reconciledBalance; |
101 | |
private final JLabel clearedSum; |
102 | |
private final JLabel reconciledSum; |
103 | |
private final JLabel notClearedSum; |
104 | |
private final JLabel notReconciledSum; |
105 | |
private final JPanel totalPanel; |
106 | |
|
107 | |
private final TransactionListModel listModel; |
108 | |
|
109 | |
private final Account associatedAccount; |
110 | |
private final Source associatedSource; |
111 | |
private final MainFrame parent; |
112 | |
|
113 | 0 | private boolean disableListEvents = false; |
114 | |
|
115 | |
private final DocumentChangeListener listener; |
116 | |
|
117 | |
public TransactionFrame(MainFrame parent, Source source){ |
118 | 0 | super(parent, TransactionFrame.class.getName() + ((Document) parent.getDocument()).getUid() + "_" + parent.getDocument().getFile() + "_" + (source != null ? source.getFullName() : "")); |
119 | 0 | this.setIconImage(ClassLoaderFunctions.getImageFromClasspath("img/BuddiFrameIcon.gif")); |
120 | 0 | this.associatedSource = source; |
121 | 0 | if (source instanceof Account) |
122 | 0 | this.associatedAccount = (Account) source; |
123 | |
else |
124 | 0 | this.associatedAccount = null; |
125 | 0 | this.listModel = new TransactionListModel((Document) parent.getDocument(), source); |
126 | 0 | this.parent = parent; |
127 | 0 | overdraftCreditLimit = new JLabel(); |
128 | |
|
129 | 0 | totalPanel = new JPanel(new BorderLayout()); |
130 | |
|
131 | 0 | dateFilterComboBox = new JComboBox(); |
132 | 0 | clearedFilterComboBox = new JComboBox(); |
133 | 0 | reconciledFilterComboBox = new JComboBox(); |
134 | |
|
135 | 0 | balancesLabel = new JLabel(); |
136 | 0 | sumsLabel = new JLabel(); |
137 | 0 | accountBalance = new JLabel(); |
138 | 0 | clearedBalance = new JLabel(); |
139 | 0 | reconciledBalance = new JLabel(); |
140 | 0 | clearedSum = new JLabel(); |
141 | 0 | notClearedSum = new JLabel(); |
142 | 0 | reconciledSum = new JLabel(); |
143 | 0 | notReconciledSum = new JLabel(); |
144 | |
|
145 | 0 | listener = new DocumentChangeListener(){ |
146 | |
public void documentChange(DocumentChangeEvent event) { |
147 | 0 | listModel.update(); |
148 | 0 | } |
149 | |
}; |
150 | |
|
151 | |
|
152 | |
|
153 | 0 | list = new JXList(){ |
154 | |
public final static long serialVersionUID = 0; |
155 | |
|
156 | |
@Override |
157 | |
public String getToolTipText(MouseEvent event) { |
158 | 0 | if (!PrefsModel.getInstance().isShowTooltips()) |
159 | 0 | return null; |
160 | 0 | int i = locationToIndex(event.getPoint()); |
161 | 0 | if (i >= 0 && i < getModel().getSize()){ |
162 | 0 | Object o = getModel().getElementAt(i); |
163 | |
|
164 | 0 | if (o instanceof Transaction){ |
165 | 0 | Transaction transaction = (Transaction) o; |
166 | |
|
167 | 0 | if (transaction != null){ |
168 | 0 | StringBuilder sb = new StringBuilder(); |
169 | |
|
170 | 0 | sb.append("<html>"); |
171 | 0 | sb.append(transaction.getDescription()); |
172 | |
|
173 | 0 | if (transaction.getNumber() != null){ |
174 | 0 | if (transaction.getNumber().length() > 0){ |
175 | 0 | sb.append("<br>"); |
176 | 0 | sb.append("#"); |
177 | 0 | sb.append(transaction.getNumber()); |
178 | |
} |
179 | |
} |
180 | |
|
181 | 0 | sb.append("<br>"); |
182 | 0 | if (TransactionFrame.this.associatedAccount != null){ |
183 | 0 | if (InternalFormatter.isRed(transaction, transaction.getTo().equals(TransactionFrame.this.associatedAccount))) |
184 | 0 | sb.append("<font color='red'>"); |
185 | 0 | sb.append(TextFormatter.getFormattedCurrency(transaction.getAmount())); |
186 | 0 | if (InternalFormatter.isRed(transaction, transaction.getTo().equals(TransactionFrame.this.associatedAccount))) |
187 | 0 | sb.append("</font>"); |
188 | |
} |
189 | |
|
190 | 0 | sb.append(" "); |
191 | 0 | sb.append(transaction.getFrom().getFullName()) |
192 | |
.append(" ") |
193 | |
.append(PrefsModel.getInstance().getTranslator().get(BuddiKeys.TO)) |
194 | |
.append(" ") |
195 | |
.append(transaction.getTo().getFullName()); |
196 | |
|
197 | 0 | if (transaction.getMemo() != null |
198 | |
&& transaction.getMemo().length() > 0){ |
199 | 0 | sb.append("<br>"); |
200 | 0 | sb.append(transaction.getMemo()); |
201 | |
} |
202 | |
|
203 | 0 | sb.append("</html>"); |
204 | |
|
205 | 0 | return sb.toString(); |
206 | |
} |
207 | |
} |
208 | |
} |
209 | |
|
210 | 0 | return ""; |
211 | |
} |
212 | |
}; |
213 | |
|
214 | |
|
215 | |
|
216 | 0 | transactionEditor = new TransactionEditorPanel(this, (Document) parent.getDocument(), associatedSource, false); |
217 | |
|
218 | 0 | recordButton = new JButton(PrefsModel.getInstance().getTranslator().get(ButtonKeys.BUTTON_RECORD)); |
219 | 0 | clearButton = new JButton(PrefsModel.getInstance().getTranslator().get(ButtonKeys.BUTTON_CLEAR)); |
220 | 0 | deleteButton = new JButton(PrefsModel.getInstance().getTranslator().get(ButtonKeys.BUTTON_DELETE)); |
221 | 0 | searchField = new MossSearchField(OperatingSystemUtil.isMac() ? "" : PrefsModel.getInstance().getTranslator().get(BuddiKeys.DEFAULT_SEARCH)); |
222 | 0 | } |
223 | |
|
224 | |
|
225 | |
|
226 | |
|
227 | |
|
228 | |
|
229 | |
public TransactionFrame(MainFrame parent, Source source, Transaction transaction) { |
230 | 0 | this(parent, source); |
231 | |
|
232 | |
|
233 | |
|
234 | |
|
235 | 0 | for (int index = this.listModel.getSize() - 1; index >= 0; --index) { |
236 | 0 | Transaction transactionToCheck = (Transaction) this.listModel.getElementAt(index); |
237 | 0 | if (transactionToCheck.equals(transaction)) { |
238 | 0 | list.ensureIndexIsVisible(index); |
239 | 0 | list.setSelectedIndex(index); |
240 | 0 | break; |
241 | |
} |
242 | |
} |
243 | |
|
244 | 0 | this.requestFocusInWindow(); |
245 | 0 | } |
246 | |
|
247 | |
@Override |
248 | |
public void initPostPack() { |
249 | 0 | super.initPostPack(); |
250 | |
|
251 | 0 | if (((Document) getDocument()).getBudgetCategories().size() > 0){ |
252 | |
try { |
253 | 0 | list.setPrototypeCellValue(ModelFactory.createTransaction(new Date(), "Relatively long description", 12345678, ((Document) getDocument()).getBudgetCategories().get(0), ((Document) getDocument()).getBudgetCategories().get(0))); |
254 | |
} |
255 | 0 | catch (InvalidValueException ive){} |
256 | |
} |
257 | |
|
258 | 0 | list.setModel(listModel); |
259 | 0 | list.ensureIndexIsVisible(listModel.getSize() - 1); |
260 | 0 | } |
261 | |
|
262 | |
@SuppressWarnings("unchecked") |
263 | |
@Override |
264 | |
public void init(){ |
265 | 0 | super.init(); |
266 | |
|
267 | 0 | ((Document) getDocument()).updateAllBalances(); |
268 | |
|
269 | 0 | list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); |
270 | 0 | BuddiTransactionCellRendererPlugin renderer = new DefaultTransactionCellRenderer(); |
271 | 0 | for (BuddiTransactionCellRendererPlugin r : (List<BuddiTransactionCellRendererPlugin>) BuddiPluginFactory.getPlugins(BuddiTransactionCellRendererPlugin.class)) { |
272 | 0 | if (r.getClass().getCanonicalName().equals(PrefsModel.getInstance().getTransactionCellRenderer())){ |
273 | 0 | renderer = r; |
274 | 0 | break; |
275 | |
} |
276 | |
} |
277 | |
|
278 | 0 | renderer.setAccount(associatedAccount); |
279 | 0 | list.setCellRenderer(renderer); |
280 | |
|
281 | 0 | recordButton.setPreferredSize(InternalFormatter.getButtonSize(recordButton)); |
282 | 0 | clearButton.setPreferredSize(InternalFormatter.getButtonSize(clearButton)); |
283 | 0 | deleteButton.setPreferredSize(InternalFormatter.getButtonSize(deleteButton)); |
284 | 0 | searchField.setPreferredSize(InternalFormatter.getComponentSize(searchField, 160)); |
285 | 0 | searchField.setMaximumSize(searchField.getPreferredSize()); |
286 | 0 | dateFilterComboBox.setPreferredSize(InternalFormatter.getComboBoxSize(dateFilterComboBox)); |
287 | 0 | clearedFilterComboBox.setPreferredSize(InternalFormatter.getComboBoxSize(clearedFilterComboBox)); |
288 | 0 | reconciledFilterComboBox.setPreferredSize(InternalFormatter.getComboBoxSize(reconciledFilterComboBox)); |
289 | |
|
290 | 0 | balancesLabel.setHorizontalAlignment(JLabel.RIGHT); |
291 | 0 | sumsLabel.setHorizontalAlignment(JLabel.RIGHT); |
292 | 0 | accountBalance.setHorizontalAlignment(JLabel.RIGHT); |
293 | 0 | clearedBalance.setHorizontalAlignment(JLabel.RIGHT); |
294 | 0 | reconciledBalance.setHorizontalAlignment(JLabel.RIGHT); |
295 | 0 | clearedSum.setHorizontalAlignment(JLabel.RIGHT); |
296 | 0 | notClearedSum.setHorizontalAlignment(JLabel.RIGHT); |
297 | 0 | reconciledSum.setHorizontalAlignment(JLabel.RIGHT); |
298 | 0 | notReconciledSum.setHorizontalAlignment(JLabel.RIGHT); |
299 | |
|
300 | |
|
301 | 0 | JPanel topRightPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 0, 0)); |
302 | 0 | topRightPanel.add(clearedFilterComboBox); |
303 | 0 | topRightPanel.add(reconciledFilterComboBox); |
304 | 0 | topRightPanel.add(dateFilterComboBox); |
305 | 0 | topRightPanel.add(searchField); |
306 | |
|
307 | 0 | JPanel topLeftPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0)); |
308 | 0 | topLeftPanel.add(overdraftCreditLimit); |
309 | |
|
310 | 0 | JPanel topPanelHolder = new JPanel(new BorderLayout()); |
311 | |
|
312 | 0 | topPanelHolder.add(topRightPanel, BorderLayout.SOUTH); |
313 | |
|
314 | 0 | final JXCollapsiblePane topCollapsiblePanel = new JXCollapsiblePane(new BorderLayout()); |
315 | 0 | topCollapsiblePanel.setCollapsed(!PrefsModel.getInstance().isSearchPaneVisible()); |
316 | 0 | topCollapsiblePanel.add(topPanelHolder, BorderLayout.CENTER); |
317 | |
|
318 | 0 | final Icon collapsed = UIManager.getIcon("Tree.collapsedIcon"); |
319 | 0 | final Icon expanded = UIManager.getIcon("Tree.expandedIcon"); |
320 | 0 | final JLabel searchCheck = new JLabel(PrefsModel.getInstance().isSearchPaneVisible() ? expanded : collapsed); |
321 | 0 | searchCheck.setVerticalAlignment(JLabel.TOP); |
322 | |
|
323 | 0 | searchField.addKeyListener(new KeyAdapter(){ |
324 | |
@Override |
325 | |
public void keyPressed(KeyEvent e) { |
326 | 0 | if (e.getKeyCode() == KeyEvent.VK_ENTER){ |
327 | 0 | e.consume(); |
328 | 0 | return; |
329 | |
} |
330 | |
else |
331 | 0 | super.keyPressed(e); |
332 | 0 | } |
333 | |
}); |
334 | 0 | searchCheck.addMouseListener(new MouseAdapter(){ |
335 | |
public void mouseClicked(MouseEvent e) { |
336 | 0 | if (searchCheck.getIcon().equals(expanded)) |
337 | 0 | searchCheck.setIcon(collapsed); |
338 | |
else |
339 | 0 | searchCheck.setIcon(expanded); |
340 | 0 | boolean hide = searchCheck.getIcon().equals(collapsed); |
341 | 0 | topCollapsiblePanel.setCollapsed(hide); |
342 | |
|
343 | 0 | PrefsModel.getInstance().setSearchPaneVisible(!hide); |
344 | 0 | } |
345 | |
}); |
346 | |
|
347 | 0 | JPanel spacerPanel = new JPanel(new BorderLayout()); |
348 | 0 | spacerPanel.add(topCollapsiblePanel, BorderLayout.NORTH); |
349 | |
|
350 | 0 | JPanel informationPanel = new JPanel(new GridBagLayout()); |
351 | 0 | GridBagConstraints gbc = new GridBagConstraints(); |
352 | 0 | gbc.gridy = 0; |
353 | 0 | gbc.fill = GridBagConstraints.HORIZONTAL; |
354 | 0 | gbc.weightx = 1; |
355 | 0 | gbc.weighty = 1; |
356 | 0 | gbc.ipadx = 10; |
357 | |
|
358 | 0 | gbc.gridx = 0; |
359 | 0 | informationPanel.add(sumsLabel, gbc); |
360 | |
|
361 | 0 | gbc.gridx = 1; |
362 | 0 | informationPanel.add(clearedSum, gbc); |
363 | |
|
364 | 0 | gbc.gridx = 2; |
365 | 0 | informationPanel.add(reconciledSum, gbc); |
366 | |
|
367 | |
|
368 | 0 | gbc.gridy = 1; |
369 | |
|
370 | 0 | gbc.gridx = 1; |
371 | 0 | informationPanel.add(notClearedSum, gbc); |
372 | |
|
373 | 0 | gbc.gridx = 2; |
374 | 0 | informationPanel.add(notReconciledSum, gbc); |
375 | |
|
376 | |
|
377 | 0 | gbc.gridy = 2; |
378 | |
|
379 | 0 | gbc.gridx = 0; |
380 | 0 | informationPanel.add(balancesLabel, gbc); |
381 | |
|
382 | 0 | gbc.gridx = 1; |
383 | 0 | informationPanel.add(clearedBalance, gbc); |
384 | |
|
385 | 0 | gbc.gridx = 2; |
386 | 0 | informationPanel.add(reconciledBalance, gbc); |
387 | |
|
388 | 0 | gbc.gridx = 3; |
389 | 0 | informationPanel.add(accountBalance, gbc); |
390 | |
|
391 | |
|
392 | |
|
393 | |
|
394 | 0 | JPanel topPanel = new JPanel(new BorderLayout()); |
395 | 0 | topPanel.add(searchCheck, BorderLayout.WEST); |
396 | 0 | topPanel.add(topLeftPanel, BorderLayout.NORTH); |
397 | 0 | topPanel.add(spacerPanel, BorderLayout.CENTER); |
398 | |
|
399 | |
|
400 | |
|
401 | |
|
402 | |
|
403 | |
|
404 | |
|
405 | |
|
406 | |
|
407 | |
|
408 | |
|
409 | |
|
410 | |
|
411 | |
|
412 | |
|
413 | |
|
414 | |
|
415 | |
|
416 | |
|
417 | |
|
418 | |
|
419 | |
|
420 | |
|
421 | |
|
422 | |
|
423 | |
|
424 | |
|
425 | |
|
426 | |
|
427 | 0 | JPanel informationPanelHolder = new JPanel(new FlowLayout(FlowLayout.RIGHT)); |
428 | 0 | informationPanelHolder.add(informationPanel); |
429 | |
|
430 | 0 | final JXCollapsiblePane bottomCollapsiblePanel = new JXCollapsiblePane(new BorderLayout()); |
431 | 0 | bottomCollapsiblePanel.setCollapsed(!PrefsModel.getInstance().isTotalPaneVisible()); |
432 | 0 | bottomCollapsiblePanel.add(informationPanelHolder, BorderLayout.CENTER); |
433 | |
|
434 | 0 | final JLabel totalCheck = new JLabel(PrefsModel.getInstance().isTotalPaneVisible() ? expanded : collapsed); |
435 | 0 | totalCheck.setVerticalAlignment(JLabel.TOP); |
436 | 0 | totalCheck.addMouseListener(new MouseAdapter(){ |
437 | |
public void mouseClicked(MouseEvent e) { |
438 | 0 | if (totalCheck.getIcon().equals(expanded)) |
439 | 0 | totalCheck.setIcon(collapsed); |
440 | |
else |
441 | 0 | totalCheck.setIcon(expanded); |
442 | 0 | boolean hide = totalCheck.getIcon().equals(collapsed); |
443 | 0 | bottomCollapsiblePanel.setCollapsed(hide); |
444 | |
|
445 | 0 | PrefsModel.getInstance().setTotalPaneVisible(!hide); |
446 | 0 | } |
447 | |
}); |
448 | |
|
449 | 0 | JPanel totalSpacerPanel = new JPanel(new BorderLayout()); |
450 | 0 | totalSpacerPanel.add(bottomCollapsiblePanel, BorderLayout.NORTH); |
451 | |
|
452 | 0 | totalPanel.add(totalCheck, BorderLayout.WEST); |
453 | 0 | totalPanel.add(totalSpacerPanel, BorderLayout.CENTER); |
454 | |
|
455 | 0 | this.getRootPane().setDefaultButton(recordButton); |
456 | |
|
457 | 0 | JPanel buttonPanelRight = new JPanel(new FlowLayout(FlowLayout.RIGHT)); |
458 | 0 | buttonPanelRight.add(clearButton); |
459 | 0 | buttonPanelRight.add(recordButton); |
460 | |
|
461 | 0 | JPanel buttonPanelLeft = new JPanel(new FlowLayout(FlowLayout.LEFT)); |
462 | 0 | buttonPanelLeft.add(deleteButton); |
463 | |
|
464 | 0 | JPanel buttonPanel = new JPanel(new BorderLayout()); |
465 | 0 | buttonPanel.add(buttonPanelRight, BorderLayout.EAST); |
466 | 0 | buttonPanel.add(buttonPanelLeft, BorderLayout.WEST); |
467 | |
|
468 | 0 | JScrollPane listScroller = new JScrollPane(list); |
469 | |
|
470 | 0 | JPanel scrollPanel = new JPanel(new BorderLayout()); |
471 | 0 | scrollPanel.add(listScroller, BorderLayout.CENTER); |
472 | 0 | scrollPanel.add(transactionEditor, BorderLayout.SOUTH); |
473 | |
|
474 | 0 | JPanel mainPanel = new JPanel(); |
475 | 0 | mainPanel.setLayout(new BorderLayout()); |
476 | 0 | mainPanel.add(scrollPanel, BorderLayout.CENTER); |
477 | 0 | mainPanel.add(totalPanel, BorderLayout.SOUTH); |
478 | |
|
479 | 0 | this.setLayout(new BorderLayout()); |
480 | 0 | this.add(topPanel, BorderLayout.NORTH); |
481 | 0 | this.add(mainPanel, BorderLayout.CENTER); |
482 | 0 | this.add(buttonPanel, BorderLayout.SOUTH); |
483 | |
|
484 | |
|
485 | |
|
486 | 0 | recordButton.addActionListener(this); |
487 | 0 | clearButton.addActionListener(this); |
488 | 0 | deleteButton.addActionListener(this); |
489 | |
|
490 | 0 | this.addComponentListener(new ComponentAdapter(){ |
491 | |
public void componentResized(ComponentEvent e) { |
492 | 0 | if (e.getComponent().getWidth() < MIN_WIDTH) |
493 | 0 | e.getComponent().setSize(MIN_WIDTH, e.getComponent().getHeight()); |
494 | 0 | if (e.getComponent().getHeight() < MIN_HEIGHT) |
495 | 0 | e.getComponent().setSize(e.getComponent().getWidth(), MIN_HEIGHT); |
496 | 0 | } |
497 | |
}); |
498 | |
|
499 | 0 | list.addHighlighter(HighlighterFactory.createAlternateStriping(Const.COLOR_EVEN_ROW, Const.COLOR_ODD_ROW)); |
500 | |
|
501 | 0 | if (OperatingSystemUtil.isMac()){ |
502 | 0 | listScroller.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); |
503 | |
} |
504 | |
else { |
505 | 0 | transactionEditor.setBorder(BorderFactory.createEmptyBorder(3, 0, 3, 0)); |
506 | |
} |
507 | |
|
508 | 0 | dateFilterComboBox.setModel(new DefaultComboBoxModel(TransactionDateFilterKeys.values())); |
509 | 0 | dateFilterComboBox.setRenderer(new TranslatorListCellRenderer()); |
510 | |
|
511 | 0 | clearedFilterComboBox.setModel(new DefaultComboBoxModel(TransactionClearedFilterKeys.values())); |
512 | 0 | clearedFilterComboBox.setRenderer(new TranslatorListCellRenderer()); |
513 | |
|
514 | 0 | reconciledFilterComboBox.setModel(new DefaultComboBoxModel(TransactionReconciledFilterKeys.values())); |
515 | 0 | reconciledFilterComboBox.setRenderer(new TranslatorListCellRenderer()); |
516 | |
|
517 | 0 | dateFilterComboBox.addItemListener(new ItemListener() { |
518 | |
public void itemStateChanged(ItemEvent e) { |
519 | 0 | if (dateFilterComboBox.getSelectedItem() == null){ |
520 | 0 | if (e.getItem().equals(dateFilterComboBox.getItemAt(0))){ |
521 | 0 | dateFilterComboBox.setSelectedIndex(1); |
522 | |
} |
523 | 0 | dateFilterComboBox.setSelectedIndex(0); |
524 | |
} |
525 | 0 | if (e.getStateChange() == ItemEvent.SELECTED) { |
526 | 0 | listModel.setDateFilter((TransactionDateFilterKeys) dateFilterComboBox.getSelectedItem()); |
527 | |
} |
528 | 0 | TransactionFrame.this.updateContent(); |
529 | 0 | list.ensureIndexIsVisible(listModel.getSize() - 1); |
530 | 0 | } |
531 | |
}); |
532 | 0 | clearedFilterComboBox.addItemListener(new ItemListener() { |
533 | |
public void itemStateChanged(ItemEvent e) { |
534 | 0 | if (clearedFilterComboBox.getSelectedItem() == null){ |
535 | 0 | if (e.getItem().equals(clearedFilterComboBox.getItemAt(0))){ |
536 | 0 | clearedFilterComboBox.setSelectedIndex(1); |
537 | |
} |
538 | 0 | clearedFilterComboBox.setSelectedIndex(0); |
539 | |
} |
540 | 0 | if (e.getStateChange() == ItemEvent.SELECTED) { |
541 | 0 | listModel.setClearedFilter((TransactionClearedFilterKeys) clearedFilterComboBox.getSelectedItem()); |
542 | |
} |
543 | 0 | TransactionFrame.this.updateContent(); |
544 | 0 | list.ensureIndexIsVisible(listModel.getSize() - 1); |
545 | 0 | } |
546 | |
}); |
547 | 0 | reconciledFilterComboBox.addItemListener(new ItemListener() { |
548 | |
public void itemStateChanged(ItemEvent e) { |
549 | 0 | if (reconciledFilterComboBox.getSelectedItem() == null){ |
550 | 0 | if (e.getItem().equals(reconciledFilterComboBox.getItemAt(0))){ |
551 | 0 | reconciledFilterComboBox.setSelectedIndex(1); |
552 | |
} |
553 | 0 | reconciledFilterComboBox.setSelectedIndex(0); |
554 | |
} |
555 | 0 | if (e.getStateChange() == ItemEvent.SELECTED) { |
556 | 0 | listModel.setReconciledFilter((TransactionReconciledFilterKeys) reconciledFilterComboBox.getSelectedItem()); |
557 | |
} |
558 | 0 | TransactionFrame.this.updateContent(); |
559 | 0 | list.ensureIndexIsVisible(listModel.getSize() - 1); |
560 | 0 | } |
561 | |
}); |
562 | |
|
563 | 0 | searchField.addSearchTextChangedEventListener(new SearchTextChangedEventListener(){ |
564 | |
public void searchTextChangedEventOccurred(SearchTextChangedEvent evt) { |
565 | 0 | listModel.setSearchText(searchField.getText()); |
566 | 0 | TransactionFrame.this.updateContent(); |
567 | 0 | list.ensureIndexIsVisible(listModel.getSize() - 1); |
568 | 0 | } |
569 | |
}); |
570 | |
|
571 | 0 | list.addListSelectionListener(new ListSelectionListener(){ |
572 | |
public void valueChanged(ListSelectionEvent arg0) { |
573 | 0 | if (!arg0.getValueIsAdjusting() && !TransactionFrame.this.disableListEvents){ |
574 | |
|
575 | 0 | if (transactionEditor.isChanged() |
576 | |
&& transactionEditor.getTransaction() != (Transaction) list.getSelectedValue()){ |
577 | |
int ret; |
578 | |
|
579 | 0 | if (transactionEditor.isTransactionValid(TransactionFrame.this.associatedAccount)){ |
580 | 0 | String[] options = new String[2]; |
581 | 0 | options[0] = PrefsModel.getInstance().getTranslator().get(ButtonKeys.BUTTON_YES); |
582 | 0 | options[1] = PrefsModel.getInstance().getTranslator().get(ButtonKeys.BUTTON_NO); |
583 | |
|
584 | 0 | ret = JOptionPane.showOptionDialog( |
585 | |
null, |
586 | |
PrefsModel.getInstance().getTranslator().get(BuddiKeys.TRANSACTION_CHANGED_MESSAGE), |
587 | |
PrefsModel.getInstance().getTranslator().get(BuddiKeys.TRANSACTION_CHANGED_TITLE), |
588 | |
JOptionPane.YES_NO_CANCEL_OPTION, |
589 | |
JOptionPane.PLAIN_MESSAGE, |
590 | |
null, |
591 | |
options, |
592 | |
options[0]); |
593 | 0 | if (ret == JOptionPane.YES_OPTION){ |
594 | 0 | recordButton.doClick(); |
595 | |
} |
596 | 0 | else if (ret == JOptionPane.NO_OPTION){ |
597 | 0 | transactionEditor.setChanged(false); |
598 | |
|
599 | |
|
600 | |
} |
601 | 0 | else if (ret == JOptionPane.CANCEL_OPTION){ |
602 | 0 | transactionEditor.setChanged(false); |
603 | 0 | list.setSelectedValue(transactionEditor.getTransaction(), true); |
604 | 0 | transactionEditor.setChanged(true); |
605 | 0 | return; |
606 | |
} |
607 | 0 | } |
608 | |
else{ |
609 | 0 | String[] options = new String[2]; |
610 | 0 | options[0] = PrefsModel.getInstance().getTranslator().get(ButtonKeys.BUTTON_YES); |
611 | 0 | options[1] = PrefsModel.getInstance().getTranslator().get(ButtonKeys.BUTTON_NO); |
612 | |
|
613 | 0 | ret = JOptionPane.showOptionDialog( |
614 | |
null, |
615 | |
PrefsModel.getInstance().getTranslator().get(BuddiKeys.TRANSACTION_CHANGED_INVALID_MESSAGE), |
616 | |
PrefsModel.getInstance().getTranslator().get(BuddiKeys.TRANSACTION_CHANGED_TITLE), |
617 | |
JOptionPane.YES_NO_OPTION, |
618 | |
JOptionPane.PLAIN_MESSAGE, |
619 | |
null, |
620 | |
options, |
621 | |
options[0]); |
622 | 0 | if (ret == JOptionPane.NO_OPTION){ |
623 | 0 | transactionEditor.setChanged(false); |
624 | |
|
625 | 0 | if (transactionEditor.getTransaction() == null) |
626 | 0 | list.clearSelection(); |
627 | |
else |
628 | 0 | list.setSelectedValue(transactionEditor.getTransaction(), true); |
629 | |
|
630 | 0 | transactionEditor.setChanged(true); |
631 | 0 | return; |
632 | |
} |
633 | 0 | else if (ret == JOptionPane.YES_OPTION){ |
634 | 0 | transactionEditor.setChanged(false); |
635 | |
} |
636 | |
} |
637 | |
} |
638 | |
|
639 | 0 | if (list.getSelectedValue() instanceof Transaction) { |
640 | 0 | Transaction t = (Transaction) list.getSelectedValue(); |
641 | |
|
642 | 0 | transactionEditor.setTransaction(t, false, recordButton); |
643 | |
|
644 | 0 | Logger.getLogger(this.getClass().getName()).finest("Set transaction to " + t); |
645 | 0 | } |
646 | 0 | else if (list.getSelectedValue() == null){ |
647 | 0 | transactionEditor.setTransaction(null, false, recordButton); |
648 | 0 | transactionEditor.updateContent(); |
649 | |
|
650 | 0 | Logger.getLogger(this.getClass().getName()).finest("Set transaction to null"); |
651 | |
} |
652 | |
|
653 | 0 | updateButtons(); |
654 | |
} |
655 | 0 | } |
656 | |
}); |
657 | |
|
658 | |
|
659 | 0 | if (PrefsModel.getInstance().getSearchText() != null){ |
660 | 0 | searchField.setText(PrefsModel.getInstance().getSearchText()); |
661 | |
} |
662 | 0 | listModel.setSearchText(searchField.getText()); |
663 | 0 | TransactionFrame.this.updateContent(); |
664 | 0 | list.ensureIndexIsVisible(listModel.getSize() - 1); |
665 | |
|
666 | 0 | if (PrefsModel.getInstance().getDateFilter() != null){ |
667 | |
try { |
668 | 0 | dateFilterComboBox.setSelectedItem(TransactionDateFilterKeys.valueOf(PrefsModel.getInstance().getDateFilter())); |
669 | |
} |
670 | 0 | catch (IllegalArgumentException iae){ |
671 | 0 | dateFilterComboBox.setSelectedItem(TransactionDateFilterKeys.TRANSACTION_FILTER_ALL_DATES); |
672 | 0 | } |
673 | |
} |
674 | 0 | if (PrefsModel.getInstance().getReconciledFilter() != null){ |
675 | |
try { |
676 | 0 | reconciledFilterComboBox.setSelectedItem(TransactionReconciledFilterKeys.valueOf(PrefsModel.getInstance().getReconciledFilter())); |
677 | |
} |
678 | 0 | catch (IllegalArgumentException iae){ |
679 | 0 | reconciledFilterComboBox.setSelectedItem(TransactionReconciledFilterKeys.TRANSACTION_FILTER_ALL_RECONCILED); |
680 | 0 | } |
681 | |
} |
682 | 0 | if (PrefsModel.getInstance().getClearedFilter() != null){ |
683 | |
try { |
684 | 0 | clearedFilterComboBox.setSelectedItem(TransactionClearedFilterKeys.valueOf(PrefsModel.getInstance().getClearedFilter())); |
685 | |
} |
686 | 0 | catch (IllegalArgumentException iae){ |
687 | 0 | clearedFilterComboBox.setSelectedItem(TransactionClearedFilterKeys.TRANSACTION_FILTER_ALL_CLEARED); |
688 | 0 | } |
689 | |
} |
690 | |
|
691 | 0 | getDocument().addDocumentChangeListener(listener); |
692 | |
|
693 | 0 | String dataFile = getDocument().getFile() == null ? "" : " - " + getDocument().getFile(); |
694 | 0 | this.setTitle(TextFormatter.getTranslation((associatedSource == null ? BuddiKeys.ALL_TRANSACTIONS : BuddiKeys.TRANSACTIONS)) |
695 | |
+ (associatedSource != null ? " - " + associatedSource.getFullName() : "") |
696 | |
+ dataFile + " - " + PrefsModel.getInstance().getTranslator().get(BuddiKeys.BUDDI)); |
697 | 0 | this.setJMenuBar(new BuddiMenuBar(this)); |
698 | 0 | } |
699 | |
|
700 | |
@Override |
701 | |
public void closeWindowWithoutPrompting() { |
702 | 0 | PrefsModel.getInstance().setSearchText(searchField.getText()); |
703 | 0 | PrefsModel.getInstance().setDateFilter(dateFilterComboBox.getSelectedItem() + ""); |
704 | 0 | PrefsModel.getInstance().setReconciledFilter(reconciledFilterComboBox.getSelectedItem() + ""); |
705 | 0 | PrefsModel.getInstance().setClearedFilter(clearedFilterComboBox.getSelectedItem() + ""); |
706 | |
|
707 | 0 | PrefsModel.getInstance().putWindowSize(getDocument().getFile() + (associatedSource == null ? BuddiKeys.ALL_TRANSACTIONS.toString() : associatedSource.getFullName()), this.getSize()); |
708 | 0 | PrefsModel.getInstance().putWindowLocation(getDocument().getFile() + (associatedSource == null ? BuddiKeys.ALL_TRANSACTIONS.toString() : associatedSource.getFullName()), this.getLocation()); |
709 | 0 | PrefsModel.getInstance().save(); |
710 | |
|
711 | 0 | super.closeWindowWithoutPrompting(); |
712 | 0 | } |
713 | |
|
714 | |
@Override |
715 | |
public void updateContent() { |
716 | 0 | super.updateContent(); |
717 | |
|
718 | 0 | if (associatedAccount != null |
719 | |
&& associatedAccount.getOverdraftCreditLimit() > 0 |
720 | |
&& ((PrefsModel.getInstance().isShowOverdraft() |
721 | |
&& !associatedAccount.getAccountType().isCredit()) |
722 | |
|| (PrefsModel.getInstance().isShowCreditRemaining() |
723 | |
&& associatedAccount.getAccountType().isCredit()))){ |
724 | |
long amountLeft; |
725 | 0 | amountLeft = (associatedAccount.getOverdraftCreditLimit() + associatedAccount.getBalance()); |
726 | 0 | double percentLeft = ((double) amountLeft) / associatedAccount.getOverdraftCreditLimit() * 100.0; |
727 | |
|
728 | 0 | StringBuffer sb = new StringBuffer(); |
729 | 0 | sb.append("<html>"); |
730 | 0 | sb.append( |
731 | |
TextFormatter.getTranslation( |
732 | |
(associatedAccount.getAccountType().isCredit() ? |
733 | |
BuddiKeys.AVAILABLE_CREDIT |
734 | |
: BuddiKeys.AVAILABLE_FUNDS))) |
735 | |
.append(": ") |
736 | |
.append(InternalFormatter.isRed(associatedAccount, amountLeft) ? "<font color='red'>" : "") |
737 | |
.append(TextFormatter.getFormattedCurrency(amountLeft)) |
738 | |
.append(InternalFormatter.isRed(associatedAccount, (long) percentLeft) ? "</font>" : ""); |
739 | 0 | if (associatedAccount.getAccountType().isCredit()){ |
740 | 0 | sb.append(" (") |
741 | |
.append(Formatter.getDecimalFormat().format(percentLeft)) |
742 | |
.append("%)"); |
743 | |
} |
744 | 0 | if (amountLeft < 0) |
745 | 0 | sb.append("</font></html>"); |
746 | |
|
747 | 0 | overdraftCreditLimit.setText(sb.toString()); |
748 | 0 | if (!associatedAccount.getAccountType().isCredit() && PrefsModel.getInstance().isShowTooltips()) |
749 | 0 | overdraftCreditLimit.setToolTipText(TextFormatter.getTranslation(BuddiKeys.TOOLTIP_AVAILABLE_FUNDS)); |
750 | 0 | overdraftCreditLimit.setVisible(true); |
751 | 0 | } |
752 | |
else { |
753 | 0 | overdraftCreditLimit.setText(""); |
754 | 0 | overdraftCreditLimit.setToolTipText(""); |
755 | 0 | overdraftCreditLimit.setVisible(false); |
756 | |
} |
757 | |
|
758 | |
|
759 | 0 | if (associatedSource != null){ |
760 | 0 | long clearedBalanceTotal = 0, clearedTotal = 0, notClearedTotal = 0; |
761 | 0 | long reconciledBalanceTotal = 0, reconciledTotal = 0, notReconciledTotal = 0; |
762 | |
|
763 | 0 | if (associatedAccount != null){ |
764 | 0 | clearedBalanceTotal = associatedAccount.getStartingBalance(); |
765 | 0 | reconciledBalanceTotal = associatedAccount.getStartingBalance(); |
766 | |
} |
767 | |
|
768 | 0 | for (Transaction t : listModel) { |
769 | 0 | if (!t.isDeleted()){ |
770 | 0 | if (t.getFrom().equals(associatedSource)){ |
771 | 0 | if (t.isClearedFrom()){ |
772 | 0 | clearedTotal -= t.getAmount(); |
773 | 0 | clearedBalanceTotal -= t.getAmount(); |
774 | |
} |
775 | |
else |
776 | 0 | notClearedTotal -= t.getAmount(); |
777 | |
|
778 | 0 | if (t.isReconciledFrom()){ |
779 | 0 | reconciledTotal -= t.getAmount(); |
780 | 0 | reconciledBalanceTotal -= t.getAmount(); |
781 | |
} |
782 | |
else |
783 | 0 | notReconciledTotal -= t.getAmount(); |
784 | |
} |
785 | 0 | else if (t.getTo().equals(associatedSource)){ |
786 | 0 | if (t.isClearedTo()){ |
787 | 0 | clearedTotal += t.getAmount(); |
788 | 0 | clearedBalanceTotal += t.getAmount(); |
789 | |
} |
790 | |
else |
791 | 0 | notClearedTotal += t.getAmount(); |
792 | |
|
793 | 0 | if (t.isReconciledTo()){ |
794 | 0 | reconciledTotal += t.getAmount(); |
795 | 0 | reconciledBalanceTotal += t.getAmount(); |
796 | |
} |
797 | |
else |
798 | 0 | notReconciledTotal += t.getAmount(); |
799 | |
} |
800 | 0 | else if (t.getFrom() instanceof SplitImpl){ |
801 | 0 | for (TransactionSplit split : t.getFromSplits()){ |
802 | 0 | if (split.getSource().equals(associatedSource)){ |
803 | 0 | if (t.isClearedFrom()){ |
804 | 0 | clearedTotal -= split.getAmount(); |
805 | 0 | clearedBalanceTotal -= split.getAmount(); |
806 | |
} |
807 | |
else |
808 | 0 | notClearedTotal -= split.getAmount(); |
809 | |
|
810 | 0 | if (t.isReconciledFrom()){ |
811 | 0 | reconciledTotal -= split.getAmount(); |
812 | 0 | reconciledBalanceTotal -= split.getAmount(); |
813 | |
} |
814 | |
else |
815 | 0 | notReconciledTotal -= split.getAmount(); |
816 | |
|
817 | |
} |
818 | |
} |
819 | |
} |
820 | 0 | else if (t.getTo() instanceof SplitImpl){ |
821 | 0 | for (TransactionSplit split : t.getToSplits()){ |
822 | 0 | if (split.getSource().equals(associatedSource)){ |
823 | 0 | if (t.isClearedTo()){ |
824 | 0 | clearedTotal += split.getAmount(); |
825 | 0 | clearedBalanceTotal += split.getAmount(); |
826 | |
} |
827 | |
else |
828 | 0 | notClearedTotal += split.getAmount(); |
829 | |
|
830 | 0 | if (t.isReconciledTo()){ |
831 | 0 | reconciledTotal += split.getAmount(); |
832 | 0 | reconciledBalanceTotal += split.getAmount(); |
833 | |
} |
834 | |
else |
835 | 0 | notReconciledTotal += split.getAmount(); |
836 | |
} |
837 | |
} |
838 | |
} |
839 | |
else { |
840 | 0 | Logger.getLogger(this.getClass().getName()).severe("Neither TO nor FROM equals the associated source. The value of TO is " + t.getTo().getFullName() + " and the value of FROM is " + t.getFrom().getFullName() + ", and associatedSource is " + associatedSource); |
841 | |
} |
842 | |
} |
843 | |
} |
844 | |
|
845 | 0 | clearedBalance.setText("<html>" + TextFormatter.getTranslation(BuddiKeys.BALANCE_OF_TRANSACTIONS_CLEARED) + " " + TextFormatter.getFormattedCurrency(clearedBalanceTotal) + "</html>"); |
846 | 0 | clearedSum.setText("<html>" + TextFormatter.getTranslation(BuddiKeys.SUM_OF_TRANSACTIONS_CLEARED) + " " + TextFormatter.getFormattedCurrency(clearedTotal) + "</html>"); |
847 | 0 | notClearedSum.setText("<html>" + TextFormatter.getTranslation(BuddiKeys.SUM_OF_TRANSACTIONS_NOT_CLEARED) + " " + TextFormatter.getFormattedCurrency(notClearedTotal) + "</html>"); |
848 | |
|
849 | 0 | reconciledBalance.setText("<html>" + TextFormatter.getTranslation(BuddiKeys.BALANCE_OF_TRANSACTIONS_RECONCILED) + " " + TextFormatter.getFormattedCurrency(reconciledBalanceTotal) + "</html>"); |
850 | 0 | reconciledSum.setText("<html>" + TextFormatter.getTranslation(BuddiKeys.SUM_OF_TRANSACTIONS_RECONCILED) + " " + TextFormatter.getFormattedCurrency(reconciledTotal) + "</html>"); |
851 | 0 | notReconciledSum.setText("<html>" + TextFormatter.getTranslation(BuddiKeys.SUM_OF_TRANSACTIONS_NOT_RECONCILED) + " " + TextFormatter.getFormattedCurrency(notReconciledTotal) + "</html>"); |
852 | |
} |
853 | |
|
854 | |
|
855 | |
|
856 | |
|
857 | |
|
858 | 0 | boolean accountNotFiltered = associatedAccount != null && !listModel.isListFiltered(); |
859 | 0 | boolean listFiltered = listModel.isListFiltered(); |
860 | 0 | boolean clearedOrReconciled = PrefsModel.getInstance().isShowCleared() || PrefsModel.getInstance().isShowReconciled(); |
861 | |
|
862 | 0 | if (associatedAccount != null) |
863 | 0 | accountBalance.setText("<html><b>" + (clearedOrReconciled ? TextFormatter.getTranslation(BuddiKeys.BALANCE_OF_ACCOUNT) : "") + " " + TextFormatter.getFormattedCurrency(associatedAccount.getBalance()) + "</b></html>"); |
864 | |
|
865 | |
|
866 | 0 | if (listFiltered) |
867 | 0 | sumsLabel.setText("<html><b>" + TextFormatter.getTranslation(BuddiKeys.FILTERED_SUM_LABEL) + "</b></html>"); |
868 | |
else |
869 | 0 | sumsLabel.setText("<html><b>" + TextFormatter.getTranslation(BuddiKeys.SUM_LABEL) + "</b></html>"); |
870 | 0 | balancesLabel.setText("<html><b>" + TextFormatter.getTranslation((clearedOrReconciled ? BuddiKeys.BALANCES_LABEL : BuddiKeys.BALANCE_LABEL)) + "</b></html>"); |
871 | |
|
872 | 0 | balancesLabel.setVisible(accountNotFiltered); |
873 | 0 | sumsLabel.setVisible(PrefsModel.getInstance().isShowCleared() || PrefsModel.getInstance().isShowReconciled()); |
874 | |
|
875 | |
|
876 | 0 | accountBalance.setVisible(accountNotFiltered); |
877 | |
|
878 | |
|
879 | 0 | reconciledBalance.setVisible(accountNotFiltered && PrefsModel.getInstance().isShowReconciled()); |
880 | 0 | reconciledSum.setVisible(PrefsModel.getInstance().isShowReconciled()); |
881 | 0 | notReconciledSum.setVisible(PrefsModel.getInstance().isShowReconciled()); |
882 | |
|
883 | |
|
884 | 0 | clearedBalance.setVisible(accountNotFiltered && PrefsModel.getInstance().isShowCleared()); |
885 | 0 | clearedSum.setVisible(PrefsModel.getInstance().isShowCleared()); |
886 | 0 | notClearedSum.setVisible(PrefsModel.getInstance().isShowCleared()); |
887 | |
|
888 | |
|
889 | 0 | totalPanel.setVisible(accountNotFiltered || PrefsModel.getInstance().isShowCleared() || PrefsModel.getInstance().isShowReconciled()); |
890 | |
|
891 | |
|
892 | 0 | clearedFilterComboBox.setVisible(PrefsModel.getInstance().isShowCleared()); |
893 | 0 | reconciledFilterComboBox.setVisible(PrefsModel.getInstance().isShowReconciled()); |
894 | |
|
895 | 0 | this.repaint(); |
896 | 0 | } |
897 | |
|
898 | |
public void updateButtons(){ |
899 | 0 | super.updateButtons(); |
900 | |
|
901 | 0 | if (transactionEditor == null |
902 | |
|| transactionEditor.getTransaction() == null){ |
903 | 0 | recordButton.setText(PrefsModel.getInstance().getTranslator().get(ButtonKeys.BUTTON_RECORD)); |
904 | 0 | clearButton.setText(PrefsModel.getInstance().getTranslator().get(ButtonKeys.BUTTON_CLEAR)); |
905 | 0 | deleteButton.setEnabled(false); |
906 | |
} |
907 | |
else{ |
908 | 0 | recordButton.setText(PrefsModel.getInstance().getTranslator().get(ButtonKeys.BUTTON_UPDATE)); |
909 | 0 | clearButton.setText(PrefsModel.getInstance().getTranslator().get(ButtonKeys.BUTTON_NEW)); |
910 | 0 | deleteButton.setEnabled(true); |
911 | |
} |
912 | |
|
913 | 0 | if (list.getSelectedValue() instanceof Transaction){ |
914 | 0 | if (((Transaction) list.getSelectedValue()).isDeleted()) |
915 | 0 | deleteButton.setText(TextFormatter.getTranslation(ButtonKeys.BUTTON_UNDELETE)); |
916 | |
else |
917 | 0 | deleteButton.setText(TextFormatter.getTranslation(ButtonKeys.BUTTON_DELETE)); |
918 | |
} |
919 | 0 | } |
920 | |
|
921 | |
public void actionPerformed(ActionEvent e) { |
922 | 0 | if (e.getSource().equals(recordButton)){ |
923 | 0 | if (!transactionEditor.isTransactionValid(this.associatedSource)){ |
924 | 0 | String[] options = new String[1]; |
925 | 0 | options[0] = PrefsModel.getInstance().getTranslator().get(ButtonKeys.BUTTON_OK); |
926 | |
|
927 | 0 | JOptionPane.showOptionDialog( |
928 | |
TransactionFrame.this, |
929 | |
PrefsModel.getInstance().getTranslator().get(BuddiKeys.RECORD_BUTTON_ERROR), |
930 | |
PrefsModel.getInstance().getTranslator().get(BuddiKeys.ERROR), |
931 | |
JOptionPane.DEFAULT_OPTION, |
932 | |
JOptionPane.ERROR_MESSAGE, |
933 | |
null, |
934 | |
options, |
935 | |
options[0] |
936 | |
); |
937 | 0 | return; |
938 | |
} |
939 | |
|
940 | |
|
941 | 0 | getDocument().startBatchChange(); |
942 | |
|
943 | |
Transaction t; |
944 | |
boolean isUpdate; |
945 | |
|
946 | 0 | if (recordButton.getText().equals(TextFormatter.getTranslation(ButtonKeys.BUTTON_UPDATE))) |
947 | 0 | isUpdate = true; |
948 | 0 | else if (recordButton.getText().equals(TextFormatter.getTranslation(ButtonKeys.BUTTON_RECORD))) |
949 | 0 | isUpdate = false; |
950 | |
else { |
951 | 0 | Logger.getLogger(this.getClass().getName()).warning("Unknown record button state: " + recordButton.getText()); |
952 | 0 | return; |
953 | |
} |
954 | |
|
955 | 0 | if (isUpdate && transactionEditor.isDangerouslyChanged()) { |
956 | 0 | String[] options = new String[2]; |
957 | 0 | options[0] = PrefsModel.getInstance().getTranslator().get(ButtonKeys.BUTTON_CREATE_NEW_TRANSACTION); |
958 | 0 | options[1] = PrefsModel.getInstance().getTranslator().get(ButtonKeys.BUTTON_OVERWRITE_TRANSACTON); |
959 | |
|
960 | 0 | int ret = JOptionPane.showOptionDialog( |
961 | |
null, |
962 | |
PrefsModel.getInstance().getTranslator().get(BuddiKeys.MESSAGE_CHANGE_EXISTING_TRANSACTION), |
963 | |
PrefsModel.getInstance().getTranslator().get(BuddiKeys.MESSAGE_CHANGE_EXISTING_TRANSACTION_TITLE), |
964 | |
JOptionPane.YES_NO_OPTION, |
965 | |
JOptionPane.WARNING_MESSAGE, |
966 | |
null, |
967 | |
options, |
968 | |
options[0]); |
969 | |
|
970 | 0 | if (ret == JOptionPane.YES_OPTION){ |
971 | 0 | isUpdate = false; |
972 | |
} |
973 | |
} |
974 | |
|
975 | |
try { |
976 | 0 | if(isUpdate) { |
977 | 0 | t = transactionEditor.getTransactionUpdated(); |
978 | |
|
979 | |
} else { |
980 | 0 | t = transactionEditor.getTransactionNew(); |
981 | 0 | getDataModel().addTransaction(t); |
982 | |
} |
983 | |
} |
984 | 0 | catch (ModelException me){ |
985 | 0 | Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "Error in record button in Transaction frame", me); |
986 | 0 | return; |
987 | 0 | } |
988 | |
|
989 | 0 | getDataModel().updateAllBalances(); |
990 | |
|
991 | 0 | getDataModel().finishBatchChange(); |
992 | |
|
993 | 0 | transactionEditor.setTransaction(null, true, recordButton); |
994 | 0 | list.clearSelection(); |
995 | 0 | updateButtons(); |
996 | |
|
997 | |
|
998 | 0 | if (!isUpdate){ |
999 | 0 | Date currentTransactionDate = t.getDate(); |
1000 | |
|
1001 | |
|
1002 | |
|
1003 | |
|
1004 | |
|
1005 | 0 | for (int index = listModel.getSize() - 1; index >= 0; --index) { |
1006 | 0 | Transaction transactionToCheck = (Transaction) listModel.getElementAt(index); |
1007 | 0 | if (transactionToCheck.getDate().equals(currentTransactionDate)) { |
1008 | 0 | list.ensureIndexIsVisible(index); |
1009 | 0 | break; |
1010 | |
} |
1011 | |
} |
1012 | |
} |
1013 | |
|
1014 | 0 | disableListEvents = false; |
1015 | |
|
1016 | 0 | transactionEditor.resetSelection(); |
1017 | 0 | transactionEditor.setChanged(false); |
1018 | |
|
1019 | 0 | listModel.update(); |
1020 | 0 | this.updateContent(); |
1021 | 0 | parent.updateContent(); |
1022 | 0 | } |
1023 | 0 | else if (e.getSource().equals(clearButton)){ |
1024 | 0 | String[] options = new String[2]; |
1025 | 0 | options[0] = PrefsModel.getInstance().getTranslator().get(ButtonKeys.BUTTON_YES); |
1026 | 0 | options[1] = PrefsModel.getInstance().getTranslator().get(ButtonKeys.BUTTON_NO); |
1027 | |
|
1028 | 0 | if (!transactionEditor.isChanged() |
1029 | |
|| JOptionPane.showOptionDialog( |
1030 | |
TransactionFrame.this, |
1031 | |
PrefsModel.getInstance().getTranslator().get(BuddiKeys.CLEAR_TRANSACTION_LOSE_CHANGES), |
1032 | |
PrefsModel.getInstance().getTranslator().get(BuddiKeys.CLEAR_TRANSACTION), |
1033 | |
JOptionPane.YES_NO_OPTION, |
1034 | |
JOptionPane.QUESTION_MESSAGE, |
1035 | |
null, |
1036 | |
options, |
1037 | |
options[0]) == JOptionPane.YES_OPTION){ |
1038 | |
|
1039 | 0 | transactionEditor.setTransaction(null, true, recordButton); |
1040 | 0 | transactionEditor.updateContent(); |
1041 | 0 | list.ensureIndexIsVisible(list.getModel().getSize() - 1); |
1042 | 0 | list.clearSelection(); |
1043 | |
|
1044 | 0 | updateButtons(); |
1045 | |
} |
1046 | 0 | } |
1047 | 0 | else if (e.getSource().equals(deleteButton)){ |
1048 | 0 | if (deleteButton.getText().equals(TextFormatter.getTranslation(ButtonKeys.BUTTON_UNDELETE))){ |
1049 | 0 | Transaction t = (Transaction) list.getSelectedValue(); |
1050 | |
try { |
1051 | 0 | t.setDeleted(false); |
1052 | |
} |
1053 | 0 | catch (InvalidValueException ive){ |
1054 | 0 | Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Invalid Value Exception", ive); |
1055 | 0 | } |
1056 | |
|
1057 | 0 | ((Document) getDocument()).updateAllBalances(); |
1058 | 0 | updateContent(); |
1059 | 0 | this.repaint(); |
1060 | 0 | } |
1061 | 0 | else if (deleteButton.getText().equals(TextFormatter.getTranslation(ButtonKeys.BUTTON_DELETE))){ |
1062 | 0 | String[] options = new String[3]; |
1063 | 0 | options[0] = PrefsModel.getInstance().getTranslator().get(ButtonKeys.BUTTON_VOID); |
1064 | 0 | options[1] = PrefsModel.getInstance().getTranslator().get(ButtonKeys.BUTTON_DELETE); |
1065 | 0 | options[2] = PrefsModel.getInstance().getTranslator().get(ButtonKeys.BUTTON_CANCEL); |
1066 | |
|
1067 | 0 | int deleteVoid = JOptionPane.showOptionDialog( |
1068 | |
TransactionFrame.this, |
1069 | |
PrefsModel.getInstance().getTranslator().get(BuddiKeys.DELETE_TRANSACTION_OR_VOID_TRANSACTION), |
1070 | |
PrefsModel.getInstance().getTranslator().get(BuddiKeys.DELETE_TRANSACTION), |
1071 | |
JOptionPane.YES_NO_CANCEL_OPTION, |
1072 | |
JOptionPane.QUESTION_MESSAGE, |
1073 | |
null, |
1074 | |
options, |
1075 | |
options[PrefsModel.getInstance().getLastDeleteOption()]); |
1076 | |
|
1077 | |
|
1078 | 0 | if (deleteVoid == JOptionPane.NO_OPTION){ |
1079 | 0 | PrefsModel.getInstance().setLastDeleteOption(1); |
1080 | 0 | options = new String[2]; |
1081 | 0 | options[0] = PrefsModel.getInstance().getTranslator().get(ButtonKeys.BUTTON_YES); |
1082 | 0 | options[1] = PrefsModel.getInstance().getTranslator().get(ButtonKeys.BUTTON_NO); |
1083 | |
|
1084 | 0 | if (JOptionPane.showOptionDialog( |
1085 | |
TransactionFrame.this, |
1086 | |
PrefsModel.getInstance().getTranslator().get(BuddiKeys.DELETE_TRANSACTION_LOSE_CHANGES), |
1087 | |
PrefsModel.getInstance().getTranslator().get(BuddiKeys.DELETE_TRANSACTION), |
1088 | |
JOptionPane.YES_NO_OPTION, |
1089 | |
JOptionPane.QUESTION_MESSAGE, |
1090 | |
null, |
1091 | |
options, |
1092 | |
options[0]) == JOptionPane.YES_OPTION){ |
1093 | |
|
1094 | 0 | Transaction t = (Transaction) list.getSelectedValue(); |
1095 | 0 | int position = list.getSelectedIndex(); |
1096 | |
try { |
1097 | 0 | ((Document) getDocument()).removeTransaction(t); |
1098 | 0 | ((Document) getDocument()).updateAllBalances(); |
1099 | |
|
1100 | |
|
1101 | |
|
1102 | 0 | updateButtons(); |
1103 | |
|
1104 | |
|
1105 | 0 | list.setSelectedIndex(position); |
1106 | 0 | if (list.getSelectedValue() instanceof Transaction){ |
1107 | 0 | t = (Transaction) list.getSelectedValue(); |
1108 | 0 | transactionEditor.setTransaction(t, true, recordButton); |
1109 | 0 | list.ensureIndexIsVisible(position); |
1110 | |
} |
1111 | |
else{ |
1112 | 0 | transactionEditor.setTransaction(null, true, recordButton); |
1113 | 0 | list.clearSelection(); |
1114 | |
} |
1115 | |
|
1116 | 0 | transactionEditor.setChanged(false); |
1117 | |
} |
1118 | 0 | catch (ModelException me){ |
1119 | 0 | Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Model Exception", me); |
1120 | 0 | } |
1121 | 0 | } |
1122 | |
} |
1123 | |
|
1124 | 0 | else if (deleteVoid == JOptionPane.YES_OPTION){ |
1125 | 0 | PrefsModel.getInstance().setLastDeleteOption(0); |
1126 | 0 | if (list.getSelectedValue() instanceof Transaction){ |
1127 | 0 | Transaction t = (Transaction) list.getSelectedValue(); |
1128 | |
try { |
1129 | 0 | t.setDeleted(true); |
1130 | |
} |
1131 | 0 | catch (InvalidValueException ive){ |
1132 | 0 | Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Invalid Value Exception", ive); |
1133 | 0 | } |
1134 | |
|
1135 | 0 | ((Document) getDocument()).updateAllBalances(); |
1136 | 0 | updateContent(); |
1137 | 0 | this.repaint(); |
1138 | |
} |
1139 | |
} |
1140 | |
} |
1141 | |
} |
1142 | 0 | } |
1143 | |
|
1144 | |
public void doClickRecord(){ |
1145 | 0 | recordButton.doClick(); |
1146 | 0 | } |
1147 | |
|
1148 | |
public void doClickClearAndAdvance(){ |
1149 | 0 | transactionEditor.toggleCleared(); |
1150 | 0 | advanceList(); |
1151 | 0 | } |
1152 | |
|
1153 | |
public void doClickReconcileAndAdvance(){ |
1154 | 0 | transactionEditor.toggleReconciled(); |
1155 | 0 | advanceList(); |
1156 | 0 | } |
1157 | |
|
1158 | |
private void advanceList(){ |
1159 | 0 | int newIndex = Math.min(list.getSelectedIndex() + 1, list.getModel().getSize() - 1); |
1160 | 0 | list.setSelectedIndex(newIndex); |
1161 | 0 | } |
1162 | |
|
1163 | |
public void doClickClear(){ |
1164 | 0 | clearButton.doClick(); |
1165 | 0 | } |
1166 | |
|
1167 | |
public void doClickDelete(){ |
1168 | 0 | deleteButton.doClick(); |
1169 | 0 | } |
1170 | |
|
1171 | |
private Document getDataModel(){ |
1172 | 0 | return (Document) getDocument(); |
1173 | |
} |
1174 | |
|
1175 | |
public void fireStructureChanged(){ |
1176 | 0 | parent.fireStructureChanged(); |
1177 | 0 | } |
1178 | |
|
1179 | |
|
1180 | |
|
1181 | |
|
1182 | |
|
1183 | |
|
1184 | |
|
1185 | |
|
1186 | |
|
1187 | |
public Account getAssociatedAccount(){ |
1188 | 0 | return associatedAccount; |
1189 | |
} |
1190 | |
|
1191 | |
|
1192 | |
|
1193 | |
|
1194 | |
|
1195 | |
|
1196 | |
|
1197 | |
|
1198 | |
|
1199 | |
|
1200 | |
public Source getAssociatedSource(){ |
1201 | 0 | return associatedSource; |
1202 | |
} |
1203 | |
} |