001: /*
002: * Copyright 2004-2007 Gary Bentley
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may
005: * not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: * http://www.apache.org/licenses/LICENSE-2.0
008: *
009: * Unless required by applicable law or agreed to in writing, software
010: * distributed under the License is distributed on an "AS IS" BASIS,
011: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: * See the License for the specific language governing permissions and
013: * limitations under the License.
014: */
015: package org.josql.contrib;
016:
017: import java.util.List;
018: import java.util.ArrayList;
019: import java.util.Map;
020: import java.util.LinkedHashMap;
021: import java.util.Iterator;
022:
023: import org.jfree.data.general.PieDataset;
024:
025: import org.jfree.data.general.DatasetGroup;
026: import org.jfree.data.general.DatasetChangeListener;
027: import org.jfree.data.general.DatasetChangeEvent;
028:
029: import org.josql.Query;
030: import org.josql.QueryResults;
031: import org.josql.QueryExecutionException;
032: import org.josql.QueryParseException;
033:
034: import org.josql.internal.Utilities;
035:
036: import org.josql.expressions.SelectItemExpression;
037:
038: public class JoSQLFreeChartPieDataset extends Query implements
039: PieDataset {
040:
041: private Map values = new LinkedHashMap();
042: private int key = 0;
043: private int value = 0;
044: private List listeners = new ArrayList();
045: private DatasetGroup group = null;
046:
047: public JoSQLFreeChartPieDataset() {
048:
049: }
050:
051: public void addChangeListener(DatasetChangeListener l) {
052:
053: this .listeners.add(l);
054:
055: }
056:
057: public void removeChangeListener(DatasetChangeListener l) {
058:
059: this .listeners.remove(l);
060:
061: }
062:
063: public DatasetGroup getGroup() {
064:
065: return this .group;
066:
067: }
068:
069: public void setGroup(DatasetGroup g) {
070:
071: this .group = g;
072:
073: }
074:
075: public void setKeyValue(int keyCol, int valueCol)
076: throws IllegalArgumentException, IllegalStateException,
077: QueryParseException {
078:
079: if (!this .parsed()) {
080:
081: throw new IllegalStateException(
082: "Cannot specify the key and value columns until a query has been specified and parsed.");
083:
084: }
085:
086: if (keyCol < 1) {
087:
088: throw new IllegalArgumentException(
089: "Key column index must be a minimum of 1.");
090:
091: }
092:
093: if (valueCol < 1) {
094:
095: throw new IllegalArgumentException(
096: "Value column index must be a minimum of 1.");
097:
098: }
099:
100: List cols = this .getColumns();
101:
102: if (keyCol > cols.size()) {
103:
104: throw new IllegalArgumentException(
105: "Key column index must be a minimum of "
106: + cols.size() + ".");
107:
108: }
109:
110: if (valueCol > cols.size()) {
111:
112: throw new IllegalArgumentException(
113: "Value column index must be a minimum of "
114: + cols.size() + ".");
115:
116: }
117:
118: SelectItemExpression vexp = (SelectItemExpression) cols
119: .get(valueCol - 1);
120:
121: Class vc = vexp.getExpectedReturnType(this );
122:
123: if (!Utilities.isNumber(vc)) {
124:
125: throw new IllegalArgumentException(
126: "Value column: "
127: + valueCol
128: + " will evaluate to an instance of type: "
129: + vc.getName()
130: + ", but only columns that return numbers are allowed.");
131:
132: }
133:
134: this .key = keyCol;
135: this .value = valueCol;
136:
137: }
138:
139: /**
140: * Exectute the query and return the results. A reference to the results is also held to
141: * allow them to be iterated over. If you plan on re-using this data source then
142: * you should call: {@link #clearResults()} to free up the references to the results.
143: *
144: * @param l The List of objects to execute the query on.
145: * @return The results.
146: * @throws QueryExecutionException If the query cannot be executed, or if the query
147: * is set to return objects rather than "columns".
148: */
149: public QueryResults executeQuery(List l)
150: throws QueryExecutionException {
151:
152: if (this .isWantObjects()) {
153:
154: throw new QueryExecutionException(
155: "Only SQL statements that return columns (not the objects passed in) can be used.");
156:
157: }
158:
159: if ((this .key == 0) || (this .value == 0)) {
160:
161: throw new IllegalStateException(
162: "Key and/or value columns not specified.");
163:
164: }
165:
166: QueryResults qr = super .execute(l);
167:
168: List res = qr.getResults();
169:
170: Map nValues = new LinkedHashMap();
171:
172: for (int i = 0; i < res.size(); i++) {
173:
174: List resR = (List) res.get(i);
175:
176: // Get the key.
177: Object k = resR.get(this .key - 1);
178:
179: // Get the value.
180: Object v = resR.get(this .value - 1);
181:
182: String kv = null + "";
183:
184: if (k == null) {
185:
186: nValues.put(kv, v);
187:
188: }
189:
190: // See if the key is "comparable".
191: if (k instanceof Comparable) {
192:
193: nValues.put(k, v);
194:
195: } else {
196:
197: kv = k.toString();
198:
199: nValues.put(kv, v);
200:
201: }
202:
203: }
204:
205: // Just switch them, this way enables any client of the data to
206: // still iterate over them without fear of a ConcurrentModificationException
207: // occuring.
208: this .values = nValues;
209:
210: // Notify our listeners.
211: DatasetChangeEvent dce = new DatasetChangeEvent(this , this );
212:
213: for (int i = 0; i < this .listeners.size(); i++) {
214:
215: DatasetChangeListener d = (DatasetChangeListener) this .listeners
216: .get(i);
217:
218: d.datasetChanged(dce);
219:
220: }
221:
222: return qr;
223:
224: }
225:
226: public int getItemCount() {
227:
228: return this .values.size();
229:
230: }
231:
232: public Number getValue(int index) {
233:
234: int c = 0;
235:
236: Iterator iter = this .values.keySet().iterator();
237:
238: while (iter.hasNext()) {
239:
240: Object k = iter.next();
241:
242: if (index == c) {
243:
244: return (Number) this .values.get(k);
245:
246: }
247:
248: c++;
249:
250: }
251:
252: return new Double(-1);
253:
254: }
255:
256: public int getIndex(Comparable k) {
257:
258: int c = 0;
259:
260: Iterator iter = this .values.keySet().iterator();
261:
262: while (iter.hasNext()) {
263:
264: Comparable ko = (Comparable) iter.next();
265:
266: if (ko.compareTo(k) == 0) {
267:
268: return c;
269:
270: }
271:
272: c++;
273:
274: }
275:
276: return -1;
277:
278: }
279:
280: public Comparable getKey(int index) {
281:
282: int c = 0;
283:
284: Iterator iter = this .values.keySet().iterator();
285:
286: while (iter.hasNext()) {
287:
288: Object k = iter.next();
289:
290: if (index == c) {
291:
292: return (Comparable) k;
293:
294: }
295:
296: c++;
297:
298: }
299:
300: return null;
301:
302: }
303:
304: public Number getValue(Comparable key) {
305:
306: return (Number) this .values.get(key);
307:
308: }
309:
310: public List getKeys() {
311:
312: return new ArrayList(this.values.keySet());
313:
314: }
315:
316: }
|