1 /*
2 * Copyright (C) 2000 Bill Bereza
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * Author: Bill Bereza
19 * email : bereza@pobox.com
20 * url : http://www.pobox.com/~bereza/
21 */
22 package net.bereza.money.gui;
23
24 //import net.bereza.util.*;
25 //import net.bereza.db.*;
26 import net.bereza.db.DatabaseException;
27 import net.bereza.db.DatabaseItem;
28 import net.bereza.db.DatabaseItemFactory;
29 import net.bereza.money.db;
30 import net.bereza.gui.CalendarSpinner;
31 import net.bereza.gui.ActionPanel;
32
33 //import java.io.*;
34 import java.util;
35 //import java.text.*;
36 import java.math.BigDecimal;
37
38 import java.awt;
39 import java.awt.event;
40 import javax.swing;
41 import javax.swing.event;
42 //import javax.swing.text.*;
43 //import javax.swing.border.*;
44 import javax.swing.table.TableModel;
45
46 import kiwi.ui;
47 import kiwi.util.KiwiUtils;
48 import kiwi.ui.dialog.DialogSet;
49
50
51 /**
52 * CheckBook is a Panel which contains a LedgerPanel and a TransactionPanel
53 * in a SplitPane. It handles the interaction between the two panels.
54 *
55 * @author $Author: bereza $
56 * @version $Revision: 1.4 $
57 * <p>
58 * $Log: CheckBook.java,v $
59 * Revision 1.4 2001/07/27 15:40:00 bereza
60 * jikes complaint fixes
61 *
62 * Revision 1.3 2000/08/25 15:18:22 bereza
63 * *** empty log message ***
64 *
65 * Revision 1.2 2000/03/30 01:57:33 bereza
66 * Added copyright header
67 *
68 * Revision 1.1 2000/03/29 02:12:30 bereza
69 * Initial revision
70 *
71 * <p>
72 * $Id: CheckBook.java,v 1.4 2001/07/27 15:40:00 bereza Exp $
73 */
74 public class CheckBook extends KPanel
75 {
76 class UndoAction extends AbstractAction
77 {
78 ResourceBundle guiRes;
79
80 public UndoAction(ResourceBundle guiRes)
81 {
82 this.guiRes=guiRes;
83
84 putValue(NAME, guiRes.getString(
85 "panel.checkbook.action.undo.name"));
86 putValue(SHORT_DESCRIPTION,
87 guiRes.getString(
88 "panel.checkbook.action.undo.description"));
89 putValue(SMALL_ICON, KiwiUtils.getResourceManager()
90 .getIcon(guiRes.getString(
91 "panel.checkbook.action.undo.icon")));
92 this.setEnabled(false);
93 }
94
95 public void actionPerformed(ActionEvent e)
96 {
97 if(this.isEnabled() && restorableTransactions.size() > 0)
98 {
99 EventQueue.invokeLater(new Runnable()
100 {
101 public void run()
102 {
103 synchronized(CheckBook.this)
104 {
105 Vector restoreTransactions=
106 (Vector)restorableTransactions.lastElement();
107
108 Transaction tranny;
109 for(Enumeration el=restoreTransactions.elements();
110 el.hasMoreElements();)
111 {
112 tranny=(Transaction)el.nextElement();
113 try
114 {
115 tranny.updateToDatabase();
116 }
117 catch(DatabaseException dbe)
118 {
119 dbe.printStackTrace(System.err);
120 DialogSet.getInstance().showMessageDialog(guiRes.getString(
121 "panel.checkbook.message.error.undo")+"\n\n"+
122 dbe.getMessage());
123 return;
124 }
125 }
126
127 restorableTransactions.removeElementAt(
128 restorableTransactions.size()-1);
129
130 if(restorableTransactions.isEmpty())
131 {
132 CheckBook.this.setEnabled(false);
133 }
134 }
135
136 ledger.reloadTable();
137 }
138 });
139 }
140 }
141 }
142
143 class SaveAndClearAction extends AbstractAction
144 {
145 public SaveAndClearAction(ResourceBundle guiRes)
146 {
147 putValue(NAME, guiRes.getString(
148 "panel.checkbook.button.saveandclear"));
149 putValue(SHORT_DESCRIPTION,
150 guiRes.getString(
151 "panel.checkbook.button.saveandclear.description"));
152 putValue(SMALL_ICON, KiwiUtils.getResourceManager()
153 .getIcon(guiRes.getString(
154 "panel.checkbook.kiwi.icon.save")));
155 }
156
157 public void actionPerformed(ActionEvent e)
158 {
159 if(this.isEnabled())
160 {
161 EventQueue.invokeLater(new Runnable()
162 {
163 public void run()
164 {
165 if(saveCheck())
166 {
167 clearCheck();
168 }
169 }
170 });
171 }
172 }
173 }
174
175 class SaveAction extends AbstractAction
176 {
177 public SaveAction(ResourceBundle guiRes)
178 {
179 putValue(NAME, guiRes.getString(
180 "panel.checkbook.button.save"));
181 putValue(SHORT_DESCRIPTION,
182 guiRes.getString(
183 "panel.checkbook.button.save.description"));
184 putValue(SMALL_ICON, KiwiUtils.getResourceManager()
185 .getIcon(guiRes.getString(
186 "panel.checkbook.kiwi.icon.save")));
187 }
188
189 public void actionPerformed(ActionEvent e)
190 {
191 if(this.isEnabled())
192 {
193 EventQueue.invokeLater(new Runnable()
194 {
195 public void run()
196 {
197 saveCheck();
198 }
199 });
200 }
201 }
202 }
203
204 class ClearAction extends AbstractAction
205 {
206 public ClearAction(ResourceBundle guiRes)
207 {
208 putValue(NAME, guiRes.getString(
209 "panel.checkbook.button.clear"));
210 putValue(SHORT_DESCRIPTION,
211 guiRes.getString(
212 "panel.checkbook.button.clear.description"));
213 putValue(SMALL_ICON, KiwiUtils.getResourceManager()
214 .getIcon(guiRes.getString(
215 "panel.checkbook.kiwi.icon.clear")));
216 }
217
218 public void actionPerformed(ActionEvent e)
219 {
220 if(this.isEnabled())
221 {
222 EventQueue.invokeLater(new Runnable()
223 {
224 public void run()
225 {
226 clearCheck();
227 }
228 });
229 }
230 }
231 }
232
233 class DeleteAction extends AbstractAction
234 {
235 public DeleteAction(ResourceBundle guiRes)
236 {
237 putValue(NAME, guiRes.getString(
238 "panel.checkbook.button.delete"));
239 putValue(SHORT_DESCRIPTION,
240 guiRes.getString(
241 "panel.checkbook.button.delete.description"));
242 putValue(SMALL_ICON, KiwiUtils.getResourceManager()
243 .getIcon(guiRes.getString(
244 "panel.checkbook.kiwi.icon.delete")));
245 }
246
247 public void actionPerformed(ActionEvent e)
248 {
249 if(this.isEnabled())
250 {
251 EventQueue.invokeLater
252 //Thread t=new Thread
253 (new Runnable()
254 {
255 public void run()
256 {
257 deleteCheck();
258 }
259 });
260 //t.start();
261 }
262 }
263 }
264
265 class LedgerSelectionActor implements Runnable
266 {
267 ListSelectionEvent e;
268 //Thread z;
269
270 LedgerSelectionActor(ListSelectionEvent lsa)
271 {
272 e=lsa;
273 //z=new Thread(this);
274 //z.start();
275 }
276
277 public void run()
278 {
279 if(!e.getValueIsAdjusting())
280 {
281 if(ledger.getTransactionTable().getSelectedRow() >= 0)
282 {
283 Transaction t=ledger.getTransactionTable().
284 getTransactions().getTransactionAt(
285 ledger.getTransactionTable()
286 .getSelectedRow());
287 boolean confirmed=t.getConfirmed();
288 check.setEditable(!confirmed);
289 check.setTransaction(t);
290 deleteAction.setEnabled(!confirmed);
291 saveAction.setEnabled(!confirmed);
292 saveAction.putValue(Action.NAME,
293 guiRes.getString(
294 "panel.checkbook.button.change"));
295 saveAction.putValue(Action.SHORT_DESCRIPTION,
296 guiRes.getString(
297 "panel.checkbook.button.change.description"));
298 }
299 }
300 }
301 }
302
303 class LedgerEventActor implements Runnable
304 {
305 TableModelEvent e;
306 //Thread z;
307
308 LedgerEventActor(TableModelEvent tme)
309 {
310 e=tme;
311 //z=new Thread(this);
312 //z.start();
313 }
314
315 public void run()
316 {
317 /** posted check mark change */
318 if((e.getType() == TableModelEvent.UPDATE)
319 && (e.getColumn() == TransactionTableModel.POSTED_COLUMN)
320 && (e.getLastRow() == ledger.getTransactionTable()
321 .getSelectedRow()))
322 {
323 Transaction t=ledger.getTransactionTable().
324 getTransactions().getTransactionAt(
325 e.getLastRow());
326 boolean confirmed=t.getConfirmed();
327 check.setEditable(!confirmed);
328 saveAction.setEnabled(!confirmed);
329 deleteAction.setEnabled(!confirmed);
330 }
331 }
332 }
333
334 /** LedgerPanel. */
335 protected LedgerPanel ledger;
336
337 /** TransactionPanel. */
338 protected TransactionPanel check;
339
340 /** SplitPanel */
341 protected JSplitPane splitPane;
342
343 /** parent frame */
344 protected Frame parentFrame;
345
346 /** button/status panel */
347 protected KPanel buttonStatusPanel;
348
349 /** transaction tool bar */
350 protected ActionPanel toolBar;
351
352 /** undo action */
353 protected Action undoAction;
354
355 /** save action */
356 protected Action saveAction;
357
358 /** clear action */
359 protected Action clearAction;
360
361 /** save and clear action */
362 protected Action saveAndClearAction;
363
364 /** delete action */
365 protected Action deleteAction;
366
367 /** Transactions which can be put back into the database,
368 * after having been deleted or modified.
369 */
370 protected Vector restorableTransactions=new Vector();
371
372 protected ResourceBundle guiRes;
373
374 protected Image texture;
375
376 protected StatusBar status;
377
378 /** Construct the CheckBook. */
379 public CheckBook(Frame parent)
380 {
381 super(new BorderLayout());
382
383 //setBackground(Color);
384
385 guiRes=ResourceBundle.getBundle("net.bereza.money.gui.gui");
386
387 parentFrame=parent;
388
389 texture=kiwi.util.KiwiUtils.getResourceManager()
390 .getTexture(guiRes.getString(
391 "panel.checkbook.kiwi.texture"));
392
393 setTexture(texture);
394
395 status=new StatusBar(true);
396
397 check=new TransactionPanel(parent);
398
399 ledger=new LedgerPanel(parent);
400
401 ledger.setStatusBar(status);
402
403 //ledger.getTransactionTable()
404 //.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
405
406 ledger.getTransactionTable().getTransactions()
407 .addTableModelListener(new TableModelListener()
408 {
409 public void tableChanged(TableModelEvent e)
410 {
411 /** complete table change. clear selection and transaction panel. */
412 if((e.getType() == TableModelEvent.UPDATE)
413 && e.getLastRow() == Integer.MAX_VALUE
414 && e.getFirstRow() == 0
415 && e.getColumn() == TableModelEvent.ALL_COLUMNS)
416 {
417 clearCheck();
418 }
419 EventQueue.invokeLater(new LedgerEventActor(e));
420 }
421 });
422
423 ledger.getTransactionTable()
424 .getSelectionModel().addListSelectionListener(new ListSelectionListener()
425 {
426 public void valueChanged(ListSelectionEvent e)
427 {
428 EventQueue.invokeLater(new LedgerSelectionActor(e));
429 }
430 });
431
432 splitPane=new JSplitPane(JSplitPane.VERTICAL_SPLIT,
433 true,
434 ledger,
435 check);
436 splitPane.setOneTouchExpandable(true);
437 splitPane.resetToPreferredSizes();
438
439 undoAction=new UndoAction(guiRes);
440
441 saveAndClearAction=new SaveAndClearAction(guiRes);
442
443 saveAction=new SaveAction(guiRes);
444
445 clearAction=new ClearAction(guiRes);
446
447 deleteAction=new DeleteAction(guiRes);
448
449 KeyStroke deleteStroke=KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0);
450 ledger.getTransactionTable().registerKeyboardAction(deleteAction,
451 "delete",
452 deleteStroke,
453 JComponent.WHEN_FOCUSED);
454
455 toolBar=new ActionPanel();
456
457 toolBar.addAction(deleteAction);
458 toolBar.addAction(clearAction);
459 toolBar.addAction(saveAction);
460
461 buttonStatusPanel=new KPanel();
462 buttonStatusPanel.setLayout(new BoxLayout(buttonStatusPanel,
463 BoxLayout.X_AXIS));
464
465 buttonStatusPanel.add(status);
466 buttonStatusPanel.add(toolBar);
467
468 clearCheck();
469
470 add("Center", splitPane);
471 add("South", buttonStatusPanel);
472 }
473
474 /**
475 * Get the Action for our save button.
476 */
477 public Action getSaveAction()
478 {
479 return saveAction;
480 }
481
482 /**
483 * Get the Action for our undo button.
484 */
485 public Action getUndoAction()
486 {
487 return undoAction;
488 }
489
490 /**
491 * Get the Action for our new button.
492 */
493 public Action getClearAction()
494 {
495 return clearAction;
496 }
497
498 /**
499 * Get the Action for our saveAndClear button.
500 */
501 public Action getSaveAndClearAction()
502 {
503 return saveAndClearAction;
504 }
505
506 /**
507 * Get the Action for our delete button.
508 */
509 public Action getDeleteAction()
510 {
511 return deleteAction;
512 }
513
514 /**
515 * Get the LedgerPanel we contain.
516 */
517 public LedgerPanel getLedger()
518 {
519 return ledger;
520 }
521
522 /**
523 * Delete the currently selected Transaction.
524 * @return <code>true</code> if successful
525 */
526 protected boolean deleteCheck()
527 {
528 int oldsel=ledger.getTransactionTable().getSelectedRow();
529 boolean deleted=false;
530 int sel;
531 int min=ledger.getTransactionTable().getSelectionModel()
532 .getMinSelectionIndex();
533 int max=ledger.getTransactionTable().getSelectionModel()
534 .getMaxSelectionIndex();
535 int selectedRows=ledger.getTransactionTable().getSelectedRowCount();
536 Transaction trans;
537 double count=0D;
538 double inc=(100D)/((double)(max - min))/2D;
539 Vector deletedTransactions=new Vector();
540 String deleteMessage=" "+guiRes.getString(
541 "panel.checkbook.message.delete");
542 Vector restoreTransactions=new Vector();
543
544 if(min < 0)
545 {
546 return false;
547 }
548 for(sel=min;sel<=max;sel++)
549 {
550 if(ledger.getTransactionTable().isRowSelected(sel))
551 {
552 status.setText(selectedRows+deleteMessage);
553
554 selectedRows--;
555
556 try
557 {
558 trans=ledger.getTransactionTable().getTransactions()
559 .getTransactionAt(sel);
560
561 if(!trans.getConfirmed())
562 {
563 trans.deleteFromDatabase();
564
565 deletedTransactions.addElement(new Integer(sel));
566 restoreTransactions.addElement(trans);
567
568 deleted=true;
569 }
570 }
571 catch(DatabaseException dbe)
572 {
573 deleted=false;
574 dbe.printStackTrace(System.err);
575 DialogSet.getInstance().showMessageDialog(guiRes.getString(
576 "panel.checkbook.message.error.delete")+"\n\n"+dbe.getMessage());
577 break;
578 //return false;
579 }
580 }
581 count+=inc;
582 status.setProgress((int)count);
583 }
584
585 //status.setBusy(true);
586
587 Integer ie;
588 for(int i=deletedTransactions.size()-1;i>=0;i--)
589 {
590 ie=(Integer)deletedTransactions.elementAt(i);
591
592 status.setText(ie.toString());
593
594 ledger.getTransactionTable().getTransactions().removeTransactionAt(
595 ie.intValue());
596 count+=inc;
597 status.setProgress((int)count);
598 }
599
600 restorableTransactions.addElement(restoreTransactions);
601 undoAction.setEnabled(true);
602
603 //status.setBusy(false);
604 status.setText("");
605 status.setProgress(0);
606
607 sel=oldsel;
608 if(sel >= ledger.getTransactionTable().getRowCount())
609 {
610 sel=ledger.getTransactionTable().getRowCount() - 1;
611 }
612
613 if(sel >= 0)
614 {
615 ledger.getTransactionTable().getSelectionModel()
616 .setSelectionInterval(sel, sel);
617 }
618 else
619 {
620 clearCheck();
621 }
622
623 return deleted;
624 }
625
626 /**
627 * Save the transaction currently displayed in the TransactionPanel.
628 * <p>This also adds the transaction to the ledger, and changes
629 * the ledger display to show the account and month of the just
630 * entered transaction.
631 * @return <code>true</code> if the save worked.
632 */
633 protected synchronized boolean saveCheck()
634 {
635 Transaction t;
636
637 try
638 {
639 Vector restoreTransactions=new Vector();
640
641 try
642 {
643 restoreTransactions.addElement(
644 ledger.getTransactionTable().
645 getTransactions().getTransactionAt(
646 ledger.getTransactionTable()
647 .getSelectedRow())
648 );
649 restorableTransactions.addElement(restoreTransactions);
650 undoAction.setEnabled(true);
651 }
652 catch(Exception e)
653 {
654 // when saving, nothing will be selected
655 }
656
657 t=check.buildTransaction();
658
659 if(t != null)
660 {
661 ledger.setFromTransaction(t);
662
663 //int i=ledger.getTransactionTable().getTransactions().indexOf(t);
664 //System.err.println("Selection: "+i);
665
666 //ledger.getTransactionTable().getSelectionModel()
667 // .setSelectionInterval(i, i);
668
669 clearCheck();
670
671 return true;
672 }
673 }
674 catch(DatabaseException e)
675 {
676 e.printStackTrace(System.err);
677 DialogSet.getInstance().showMessageDialog(guiRes.getString(
678 "panel.checkbook.message.error.save")+"\n\n"+e.getMessage());
679 }
680 return false;
681 }
682
683 /**
684 * Reset the Transaction panel for a new transaction.
685 * <p>This can happen when new/clear is pressed, or when
686 * the account or time frame changes.
687 */
688 protected synchronized void clearCheck()
689 {
690 System.err.println("CLEARCHECK ====================");
691 if(check.getAccountFrom() == null)
692 {
693 check.setAccountFrom(ledger.getAccount());
694 }
695 check.resetTransaction();
696 check.setEditable(true);
697 ledger.getTransactionTable().clearSelection();
698
699 deleteAction.setEnabled(false);
700 saveAction.setEnabled(true);
701 saveAction.putValue(Action.NAME,
702 guiRes.getString(
703 "panel.checkbook.button.save"));
704 saveAction.putValue(Action.SHORT_DESCRIPTION,
705 guiRes.getString(
706 "panel.checkbook.button.save.description"));
707 }
708
709 public static void main(String argv[])
710 {
711 BookFrame.main(argv);
712 }
713 }