001: /*
002: *
003: * JMoney - A Personal Finance Manager
004: * Copyright (c) 2007 Nigel Westbury <westbury@users.sf.net>
005: *
006: *
007: * This program is free software; you can redistribute it and/or modify
008: * it under the terms of the GNU General Public License as published by
009: * the Free Software Foundation; either version 2 of the License, or
010: * (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
020: *
021: */
022:
023: package net.sf.jmoney.entrytable;
024:
025: import net.sf.jmoney.model2.Commodity;
026: import net.sf.jmoney.model2.Entry;
027: import net.sf.jmoney.model2.EntryInfo;
028: import net.sf.jmoney.model2.ExtendableObject;
029: import net.sf.jmoney.model2.ScalarPropertyAccessor;
030: import net.sf.jmoney.model2.SessionChangeAdapter;
031: import net.sf.jmoney.model2.SessionChangeListener;
032:
033: import org.eclipse.swt.SWT;
034: import org.eclipse.swt.events.DisposeEvent;
035: import org.eclipse.swt.events.DisposeListener;
036: import org.eclipse.swt.events.FocusListener;
037: import org.eclipse.swt.events.TraverseEvent;
038: import org.eclipse.swt.events.TraverseListener;
039: import org.eclipse.swt.widgets.Composite;
040: import org.eclipse.swt.widgets.Control;
041: import org.eclipse.swt.widgets.Text;
042:
043: /**
044: * Represents a table column that is either the debit or the credit column.
045: * Use two instances of this class instead of a single instance of the
046: * above <code>EntriesSectionProperty</code> class if you want the amount to be
047: * displayed in separate debit and credit columns.
048: */
049: public class DebitAndCreditColumns extends
050: IndividualBlock<EntryData, BaseEntryRowControl> {
051:
052: private class DebitAndCreditCellControl implements
053: ICellControl<EntryData> {
054: private Text textControl;
055: private Entry entry = null;
056:
057: private SessionChangeListener amountChangeListener = new SessionChangeAdapter() {
058: @Override
059: public void objectChanged(ExtendableObject changedObject,
060: ScalarPropertyAccessor changedProperty,
061: Object oldValue, Object newValue) {
062: if (changedObject.equals(entry)
063: && changedProperty == EntryInfo
064: .getAmountAccessor()) {
065: setControlContent();
066: }
067: }
068: };
069:
070: public DebitAndCreditCellControl(Text textControl) {
071: this .textControl = textControl;
072:
073: textControl.addDisposeListener(new DisposeListener() {
074: public void widgetDisposed(DisposeEvent e) {
075: if (entry != null) {
076: entry.getDataManager().removeChangeListener(
077: amountChangeListener);
078: }
079: }
080: });
081: }
082:
083: public Control getControl() {
084: return textControl;
085: }
086:
087: public void load(EntryData data) {
088: if (entry != null) {
089: entry.getDataManager().removeChangeListener(
090: amountChangeListener);
091: }
092:
093: entry = data.getEntry();
094:
095: /*
096: * We must listen to the model for changes in the value
097: * of this property.
098: */
099: entry.getDataManager().addChangeListener(
100: amountChangeListener);
101:
102: setControlContent();
103: }
104:
105: private void setControlContent() {
106: long amount = entry.getAmount();
107:
108: /*
109: * We need a currency so that we can format the amount. Get the
110: * currency from this entry if possible. However, the user may
111: * not have yet entered enough information to determine the
112: * currency for this entry, in which case use the default
113: * currency for this entry table.
114: */
115: Commodity commodityForFormatting = entry.getCommodity();
116: if (commodityForFormatting == null) {
117: commodityForFormatting = commodity;
118: }
119:
120: if (isDebit) {
121: // Debit column
122: textControl.setText(amount < 0 ? commodityForFormatting
123: .format(-amount) : "");
124: } else {
125: // Credit column
126: textControl.setText(amount > 0 ? commodityForFormatting
127: .format(amount) : "");
128: }
129: }
130:
131: public void save() {
132: /*
133: * We need a currency so that we can parse the amount. Get the
134: * currency from this entry if possible. However, the user may
135: * not have yet entered enough information to determine the
136: * currency for this entry, in which case use the default
137: * currency for this entry table.
138: */
139: Commodity commodityForFormatting = entry.getCommodity();
140: if (commodityForFormatting == null) {
141: commodityForFormatting = commodity;
142: }
143:
144: String amountString = textControl.getText();
145: long amount = commodityForFormatting.parse(amountString);
146:
147: long previousEntryAmount = entry.getAmount();
148: long newEntryAmount;
149:
150: if (isDebit) {
151: if (amount != 0) {
152: newEntryAmount = -amount;
153: } else {
154: if (previousEntryAmount < 0) {
155: newEntryAmount = 0;
156: } else {
157: newEntryAmount = previousEntryAmount;
158: }
159: }
160: } else {
161: if (amount != 0) {
162: newEntryAmount = amount;
163: } else {
164: if (previousEntryAmount > 0) {
165: newEntryAmount = 0;
166: } else {
167: newEntryAmount = previousEntryAmount;
168: }
169: }
170: }
171:
172: entry.setAmount(newEntryAmount);
173:
174: // If there are two entries in the transaction and
175: // if both entries have accounts in the same currency or
176: // one or other account is not known or one or other account
177: // is a multi-currency account then we set the amount in
178: // the other entry to be the same but opposite signed amount.
179:
180: if (entry.getTransaction().hasTwoEntries()) {
181: Entry otherEntry = entry.getTransaction().getOther(
182: entry);
183: Commodity commodity1 = entry.getCommodity();
184: Commodity commodity2 = otherEntry.getCommodity();
185: if (commodity1 == null || commodity2 == null
186: || commodity1.equals(commodity2)) {
187: otherEntry.setAmount(-newEntryAmount);
188: }
189: }
190: }
191:
192: public void setFocusListener(FocusListener controlFocusListener) {
193: // Nothing to do
194: }
195: }
196:
197: private String id;
198: private Commodity commodity;
199: private boolean isDebit;
200:
201: public static DebitAndCreditColumns createCreditColumn(
202: Commodity commodityForFormatting) {
203: return new DebitAndCreditColumns(
204: "credit", "Credit", commodityForFormatting, false); //$NON-NLS-2$
205: }
206:
207: public static DebitAndCreditColumns createDebitColumn(
208: Commodity commodityForFormatting) {
209: return new DebitAndCreditColumns(
210: "debit", "Debit", commodityForFormatting, true); //$NON-NLS-2$
211: }
212:
213: private DebitAndCreditColumns(String id, String name,
214: Commodity commodity, boolean isDebit) {
215: super (name, 70, 2);
216: this .id = id;
217: this .commodity = commodity;
218: this .isDebit = isDebit;
219: }
220:
221: public String getId() {
222: return id;
223: }
224:
225: @Override
226: public ICellControl<EntryData> createCellControl(Composite parent,
227: BaseEntryRowControl rowControl) {
228: final Text textControl = new Text(parent, SWT.TRAIL);
229: textControl.addTraverseListener(new TraverseListener() {
230: public void keyTraversed(TraverseEvent e) {
231: switch (e.detail) {
232: case SWT.TRAVERSE_ARROW_PREVIOUS:
233: if (e.keyCode == SWT.ARROW_UP) {
234: e.doit = false;
235: e.detail = SWT.TRAVERSE_NONE;
236: }
237: break;
238: case SWT.TRAVERSE_ARROW_NEXT:
239: if (e.keyCode == SWT.ARROW_DOWN) {
240: e.doit = true;
241: }
242: break;
243: }
244: }
245: });
246:
247: return new DebitAndCreditCellControl(textControl);
248: }
249:
250: public int compare(EntryData entryData1, EntryData entryData2) {
251: long amount1 = entryData1.getEntry().getAmount();
252: long amount2 = entryData2.getEntry().getAmount();
253:
254: int result;
255: if (amount1 < amount2) {
256: result = -1;
257: } else if (amount1 > amount2) {
258: result = 1;
259: } else {
260: result = 0;
261: }
262:
263: // If debit column then reverse. Ascending sort should
264: // result in the user seeing ascending numbers in the
265: // sorted column.
266: if (isDebit) {
267: result = -result;
268: }
269:
270: return result;
271: }
272: }
|