001: /*
002: * Created on 6 sept. 2004
003: */
004: package net.sf.jmoney.charts;
005:
006: import java.awt.Color;
007: import java.awt.Container;
008: import java.awt.GridBagConstraints;
009: import java.awt.GridBagLayout;
010: import java.security.InvalidParameterException;
011: import java.text.DateFormat;
012: import java.text.ParseException;
013: import java.text.SimpleDateFormat;
014: import java.util.Date;
015: import java.util.Iterator;
016: import java.util.LinkedList;
017: import java.util.List;
018: import java.util.NoSuchElementException;
019: import java.util.TreeSet;
020:
021: import net.sf.jmoney.JMoneyPlugin;
022: import net.sf.jmoney.model2.Account;
023: import net.sf.jmoney.model2.CapitalAccount;
024: import net.sf.jmoney.model2.CurrencyAccount;
025: import net.sf.jmoney.model2.Session;
026:
027: import org.jfree.chart.ChartMouseEvent;
028: import org.jfree.chart.ChartPanel;
029: import org.jfree.chart.entity.PieSectionEntity;
030: import org.jfree.chart.plot.PiePlot;
031: import org.jfree.chart.title.TextTitle;
032: import org.jfree.data.DefaultPieDataset;
033:
034: public class ExpensePieChart extends PieChart {
035:
036: private static final long serialVersionUID = -4298533800978851837L;
037:
038: protected Date fromDate;
039: protected Date toDate;
040: protected int maxLevel;
041: String[] accounts;
042: Container containerForSeveralGraphics;
043:
044: public ExpensePieChart(String title, Session session, int maxLevel,
045: String[] accounts) {
046: super (title, session);
047: this .accounts = accounts;
048: this .maxLevel = maxLevel;
049: }
050:
051: public ExpensePieChart(String title, Session session, int maxLevel,
052: String account) {
053: this (title, session, maxLevel, new String[1]);
054: accounts[0] = account;
055: }
056:
057: public ExpensePieChart(String title, Session session, int maxLevel) {
058: this (title, session, maxLevel, "Dépenses");
059: }
060:
061: public void setAccount(String account) {
062: accounts[0] = account;
063: }
064:
065: public void setDates(Date from, Date to) {
066: fromDate = from;
067: toDate = to;
068: }
069:
070: public void setMaxLevel(String newMaxLevel) {
071: try {
072: maxLevel = Integer.parseInt(newMaxLevel);
073: } catch (NumberFormatException e) {
074: }
075: }
076:
077: protected void createValues() {
078:
079: // TODO: Faucheux - der gewählte Level sollte parametrisierbar sein.
080: long totalBalance = 0;
081:
082: // collect the values
083: TreeSet values = new TreeSet();
084:
085: // TODO: Faucheux - The list of accounts should be parametrisabled.
086: List listAccounts = new LinkedList();
087: for (int i = 0; i < accounts.length; i++) {
088: CapitalAccount theAccount = (CapitalAccount) Util
089: .getAccountByFullName(session, accounts[i]);
090: listAccounts.add(theAccount);
091: if (maxLevel > theAccount.getLevel())
092: listAccounts.addAll(Util.getSubAccountsUntilLevel(
093: theAccount, maxLevel));
094: else
095: listAccounts.addAll(Util.getSubAccounts(theAccount));
096: }
097: Iterator aIt = listAccounts.iterator();
098: // Iterator aIt = util.getAccountsUntilLevel(session,maxLevel).iterator();
099: while (aIt.hasNext()) {
100: Account currentAccount = (Account) aIt.next();
101: // TODO: Konten, die mehrere Währung enthalten,
102: // mussen auch gezeigt sind.
103: if (currentAccount instanceof CurrencyAccount) {
104: CurrencyAccount currentCapitalAccount = (CurrencyAccount) currentAccount;
105: long balance;
106:
107: if (currentAccount.getLevel() < maxLevel) {
108: // If the account has sub accounts, they will have their own entry -> we don't have to include them here
109: balance = currentCapitalAccount.getBalance(session,
110: fromDate, toDate);
111: } else {
112: // If the account has sub accounts, they won't have their own entry -> we have to include them here
113: balance = currentCapitalAccount
114: .getBalanceWithSubAccounts(session,
115: fromDate, toDate);
116: }
117:
118: if (balance >= 0) {
119: if (ChartsPlugin.DEBUG)
120: System.out.println(currentAccount.getName()
121: + " : " + balance / 100 + ".");
122: values.add(new CoupleStringNumber(currentAccount
123: .getFullAccountName(), currentAccount
124: .getName(), balance / 100));
125: totalBalance += balance / 100;
126: }
127: }
128: }
129:
130: // Calculate the 5 % of the graph and group the values which generate it.
131: long smallBalance = 0;
132: boolean finished = false;
133: String nameRest = new String();
134: while (!finished) {
135: CoupleStringNumber csn = null;
136: try {
137: csn = (CoupleStringNumber) values.last();
138: } catch (NoSuchElementException e) {
139: }
140: ;
141: if (csn != null
142: && smallBalance + csn.n < (totalBalance * 0.05)) {
143: nameRest = nameRest + " + " + csn.s;
144: smallBalance += csn.n;
145: values.remove(csn);
146: } else {
147: finished = true;
148: }
149: }
150: if (nameRest.length() > 3)
151: nameRest = nameRest.substring(3); // to avoid to begin with a +
152: if (nameRest.length() > 60)
153: nameRest = nameRest.substring(0, 60) + "...";
154: nameRest = "Reste";
155:
156: // create a new Dataset
157: data = new DefaultPieDataset();
158: if (chart != null)
159: ((PiePlot) chart.getPlot()).setDataset(data);
160:
161: // set the (sorted) values in the graph
162: Iterator it = values.iterator();
163: // TODO: Variant -> Do not display the value for the all time, but per day
164: long intervallInDays = (toDate.getTime() - fromDate.getTime())
165: / 1000 / 60 / 60 / 24;
166: intervallInDays = intervallInDays / 100; // To have Cent and not Euro
167: while (it.hasNext()) {
168: CoupleStringNumber csn = (CoupleStringNumber) it.next();
169: // data.setValue(csn, new Long(csn.n));
170: data.setValue(csn, new Long(csn.n / intervallInDays));
171: }
172: if (smallBalance > 0)
173: // data.setValue(nameRest, smallBalance);
174: data.setValue(nameRest, smallBalance / intervallInDays);
175:
176: // set the title
177: DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
178: title = accounts[0];
179: subTitle = new String(" from " + df.format(fromDate) + " to "
180: + df.format(toDate));
181: if (chart != null) {
182: chart.setTitle(title);
183: chart.addSubtitle(new TextTitle(subTitle));
184: }
185:
186: }
187:
188: protected void initParameters() {
189: DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
190: try {
191: fromDate = df.parse("2004-01-01");
192: title = title + "\n" + fromDate + " - " + toDate;
193: } catch (ParseException e) {
194: JMoneyPlugin.log(e);
195: }
196: toDate = new Date();
197: }
198:
199: /**
200: * Object to stock the String and Number the time to sort them in a TreeSet
201: * @author Faucheux
202: */
203: private class CoupleStringNumber implements Comparable {
204: public String s;
205: public String longName;
206: public long n;
207:
208: public CoupleStringNumber(String s, long n) {
209: this .s = s;
210: this .n = n;
211: this .longName = s;
212: }
213:
214: public CoupleStringNumber(String longName, String s, long n) {
215: this (s, n);
216: this .longName = longName;
217: }
218:
219: public String toString() {
220: return s;
221: }
222:
223: public int compareTo(Object csn2) {
224: // Compare first the values, than the names.
225: // If the names are the same too, then compare the hash codes: two objects
226: // should be considered as equal iff they really are the same.
227: // Caution: to have the display well-displayed, we have to say "bigger first"
228: // and therefore inverse the results;
229: if (csn2 instanceof CoupleStringNumber) {
230: String s2 = ((CoupleStringNumber) csn2).s;
231: long n2 = ((CoupleStringNumber) csn2).n;
232: int difference = (new Long(n)).compareTo(new Long(n2));
233: if (difference == 0)
234: difference = s.compareTo(s2);
235: if (difference == 0)
236: difference = s.hashCode() - s2.hashCode();
237: return -difference;
238: } else {
239: throw new InvalidParameterException(
240: "A CoupleStringNumber object can't be compared to an other typ of object.");
241: }
242:
243: }
244:
245: }
246:
247: public void chartMouseClicked(ChartMouseEvent e) {
248: if (ChartsPlugin.DEBUG)
249: System.out.println("in chartMouseClicked");
250: if (e.getEntity() != null) {
251: PieSectionEntity pieSection = (PieSectionEntity) e
252: .getEntity();
253: String accountClicked = ((CoupleStringNumber) pieSection
254: .getSectionKey()).longName;
255: if (ChartsPlugin.DEBUG)
256: System.out.println("Im Entity : " + accountClicked);
257: PieChart newChart = new ExpensePieChart(accountClicked,
258: this .session, this .maxLevel + 1, accountClicked);
259: newChart.run();
260: ChartPanel chartPanel = newChart.getChartPanel();
261: if (containerForSeveralGraphics != null) {
262: GridBagConstraints gbConstraints = new GridBagConstraints();
263: gbConstraints.fill = GridBagConstraints.BOTH;
264: gbConstraints.weightx = 1;
265: gbConstraints.weighty = 1;
266: gbConstraints.gridy = 2;
267: ((GridBagLayout) containerForSeveralGraphics
268: .getLayout()).setConstraints(chartPanel,
269: gbConstraints);
270: containerForSeveralGraphics.add(chartPanel);
271: containerForSeveralGraphics
272: .setBackground(Color.MAGENTA);
273: containerForSeveralGraphics.validate();
274: }
275: }
276: }
277:
278: /**
279: * @param containerForSeveralGraphics The containerForSeveralGraphics to set.
280: */
281: public void setContainerForSeveralGraphics(
282: Container containerForSeveralGraphics) {
283: this.containerForSeveralGraphics = containerForSeveralGraphics;
284: }
285: }
|