001 /* ======================================================
002 * Orson : a free chart beans library based on JFreeChart
003 * ======================================================
004 *
005 * (C) Copyright 2007, by Object Refinery Limited.
006 *
007 * Project Info: not-yet-released
008 *
009 * This library is free software; you can redistribute it and/or modify it
010 * under the terms of the GNU Lesser General Public License as published by
011 * the Free Software Foundation; either version 2.1 of the License, or
012 * (at your option) any later version.
013 *
014 * This library is distributed in the hope that it will be useful, but
015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
017 * License for more details.
018 *
019 * You should have received a copy of the GNU Lesser General Public
020 * License along with this library; if not, write to the Free Software
021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
022 * USA.
023 *
024 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
025 * in the United States and other countries.]
026 *
027 */
028
029 package org.jfree.beans;
030
031 import java.awt.Font;
032 import java.awt.Insets;
033 import java.awt.Paint;
034 import java.awt.event.MouseEvent;
035 import java.beans.PropertyChangeEvent;
036 import java.beans.PropertyEditorManager;
037
038 import javax.swing.event.EventListenerList;
039
040 import org.jfree.beans.editors.RotationEditor;
041 import org.jfree.beans.events.SectionClickEvent;
042 import org.jfree.beans.events.SectionClickListener;
043 import org.jfree.chart.JFreeChart;
044 import org.jfree.chart.entity.ChartEntity;
045 import org.jfree.chart.entity.EntityCollection;
046 import org.jfree.chart.entity.PieSectionEntity;
047 import org.jfree.chart.labels.PieSectionLabelGenerator;
048 import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
049 import org.jfree.chart.labels.StandardPieToolTipGenerator;
050 import org.jfree.chart.plot.PiePlot;
051 import org.jfree.data.general.DefaultPieDataset;
052 import org.jfree.data.general.PieDataset;
053 import org.jfree.util.Rotation;
054
055 /**
056 * A JavaBean that displays a pie chart.
057 */
058 public class JPieChart extends AbstractChart {
059
060 static {
061 PropertyEditorManager.registerEditor(Rotation.class,
062 RotationEditor.class);
063 }
064
065 /** The section label format string. */
066 private String labelFormat;
067
068 /** Storage for registered sectionClickListeners. */
069 private EventListenerList sectionClickListeners;
070
071 /**
072 * Creates a new pie chart bean.
073 */
074 public JPieChart() {
075 super();
076 this.sectionClickListeners = new EventListenerList();
077 this.labelFormat = "{0}";
078 }
079
080 /**
081 * Creates a default chart.
082 *
083 * @return The default chart.
084 */
085 protected JFreeChart createDefaultChart() {
086 DefaultPieDataset dataset = new DefaultPieDataset();
087 dataset.setValue("A", 5.0);
088 dataset.setValue("B", 7.0);
089 dataset.setValue("C", 6.0);
090 PiePlot plot = new PiePlot(dataset);
091 JFreeChart chart = new JFreeChart(plot);
092 chart.setTitle("JPieChart - Title");
093 plot.setToolTipGenerator(new StandardPieToolTipGenerator());
094 return chart;
095 }
096
097 /**
098 * Returns the direction (clockwise or anti-clockwise) in which the pie
099 * segments are drawn.
100 *
101 * @return The direction.
102 *
103 * @see #setDirection(Rotation)
104 */
105 public Rotation getDirection() {
106 Rotation result = null;
107 PiePlot plot = (PiePlot) this.chart.getPlot();
108 if (plot != null) {
109 result = plot.getDirection();
110 }
111 return result;
112 }
113
114 /**
115 * Sets the direction in which the pie sections are drawn and fires a
116 * {@link PropertyChangeEvent} for the <code>direction</code> property.
117 *
118 * @param direction the new direction (<code>null</code> not permitted).
119 *
120 * @see #getDirection()
121 */
122 public void setDirection(Rotation direction) {
123 PiePlot plot = (PiePlot) this.chart.getPlot();
124 if (plot != null) {
125 Rotation old = plot.getDirection();
126 plot.setDirection(direction);
127 firePropertyChange("direction", old, direction);
128 }
129 }
130
131 /**
132 * Returns the dataset used by the chart.
133 *
134 * @return The dataset (possibly <code>null</code>).
135 *
136 * @see #setDataset(PieDataset)
137 */
138 public PieDataset getDataset() {
139 PieDataset result = null;
140 PiePlot plot = (PiePlot) this.chart.getPlot();
141 if (plot != null) {
142 result = plot.getDataset();
143 }
144 return result;
145 }
146
147 /**
148 * Sets the dataset used by the chart and fires a
149 * {@link PropertyChangeEvent} for the <code>dataset</code> property.
150 *
151 * @param dataset the dataset (<code>null</code> permitted).
152 *
153 * @see #getDataset()
154 */
155 public void setDataset(PieDataset dataset) {
156 PiePlot plot = (PiePlot) this.chart.getPlot();
157 if (plot != null) {
158 PieDataset old = plot.getDataset();
159 plot.setDataset(dataset);
160 firePropertyChange("dataset", old, dataset);
161 }
162 }
163
164 /**
165 * Returns a flag that controls whether the plot is circular or
166 * elliptical.
167 *
168 * @return A flag.
169 *
170 * @see #setCircular(boolean)
171 */
172 public boolean isCircular() {
173 PiePlot plot = (PiePlot) this.chart.getPlot();
174 return plot.isCircular();
175 }
176
177 /**
178 * Sets the flag that controls whether the pie chart is drawn as a circle
179 * or an ellipse and fires a {@link PropertyChangeEvent} for the
180 * <code>circular</code> property.
181 *
182 * @param circular the flag.
183 *
184 * @see #isCircular()
185 */
186 public void setCircular(boolean circular) {
187 PiePlot plot = (PiePlot) this.chart.getPlot();
188 boolean old = plot.isCircular();
189 plot.setCircular(circular);
190 firePropertyChange("circular", old, circular);
191 }
192
193 /**
194 * Returns the angle from which the first pie section starts.
195 *
196 * @return The angle.
197 *
198 * @see #setPieStartingAngle(double)
199 */
200 public double getPieStartingAngle() {
201 PiePlot plot = (PiePlot) this.chart.getPlot();
202 return plot.getStartAngle();
203 }
204
205 /**
206 * Sets the angle at which the first pie section starts and fires a
207 * {@link PropertyChangeEvent} for the <code>pieStartingAngle</code>
208 * property.
209 *
210 * @param angle the angle.
211 *
212 * @see #getPieStartingAngle()
213 */
214 public void setPieStartingAngle(double angle) {
215 PiePlot plot = (PiePlot) this.chart.getPlot();
216 double old = plot.getStartAngle();
217 plot.setStartAngle(angle);
218 firePropertyChange("pieStartingAngle", old, angle);
219 }
220
221 /**
222 * Returns the label format used by the plot.
223 *
224 * @return The label format.
225 *
226 * @see #setLabelFormat(String)
227 */
228 public String getLabelFormat() {
229 String result = null;
230 PiePlot plot = (PiePlot) this.chart.getPlot();
231 PieSectionLabelGenerator g = plot.getLabelGenerator();
232 if (g instanceof StandardPieSectionLabelGenerator) {
233 StandardPieSectionLabelGenerator gg
234 = (StandardPieSectionLabelGenerator) g;
235 result = gg.getLabelFormat();
236 }
237 return result;
238 }
239
240 /**
241 * Returns the format string for the section labels and fires a
242 * {@link PropertyChangeEvent} for the <code>labelFormat</code> property.
243 *
244 * @param format the format string.
245 *
246 * @see #getLabelFormat()
247 */
248 public void setLabelFormat(String format) {
249 PiePlot plot = (PiePlot) this.chart.getPlot();
250 String old = this.labelFormat;
251 this.labelFormat = format;
252 plot.setLabelGenerator(new StandardPieSectionLabelGenerator(format));
253 firePropertyChange("labelFormat", old, format);
254 }
255
256 /**
257 * Returns the font used to display the section labels.
258 *
259 * @return The font.
260 *
261 * @see #setLabelFont(Font)
262 */
263 public Font getLabelFont() {
264 Font result = null;
265 PiePlot plot = (PiePlot) this.chart.getPlot();
266 if (plot != null) {
267 return plot.getLabelFont();
268 }
269 return result;
270 }
271
272 /**
273 * Sets the font used to draw the section labels and fires a
274 * {@link PropertyChangeEvent} for the <code>labelFont</code> property.
275 *
276 * @param font the font.
277 *
278 * @see #getLabelFont()
279 */
280 public void setLabelFont(Font font) {
281 PiePlot plot = (PiePlot) this.chart.getPlot();
282 if (plot != null) {
283 Font old = plot.getLabelFont();
284 plot.setLabelFont(font);
285 firePropertyChange("labelFont", old, font);
286 }
287 }
288
289 /**
290 * Returns the paint used to draw the section labels.
291 *
292 * @return The paint.
293 *
294 * @see #setLabelPaint(Paint)
295 */
296 public Paint getLabelPaint() {
297 Paint result = null;
298 PiePlot plot = (PiePlot) this.chart.getPlot();
299 if (plot != null) {
300 return plot.getLabelPaint();
301 }
302 return result;
303 }
304
305 /**
306 * Sets the paint used to draw the section labels and fires a
307 * {@link PropertyChangeEvent} for the <code>labelPaint</code> property.
308 *
309 * @param paint the paint.
310 *
311 * @see #getLabelPaint()
312 */
313 public void setLabelPaint(Paint paint) {
314 PiePlot plot = (PiePlot) this.chart.getPlot();
315 if (plot != null) {
316 Paint old = plot.getLabelPaint();
317 plot.setLabelPaint(paint);
318 firePropertyChange("labelPaint", old, paint);
319 }
320 }
321
322 /**
323 * Returns the format string for the section tool tips.
324 *
325 * @return The format string.
326 *
327 * @see #setSectionToolTipFormat(String)
328 */
329 public String getSectionToolTipFormat() {
330 PiePlot p = (PiePlot) this.chart.getPlot();
331 if (p == null) {
332 return "";
333 }
334 StandardPieToolTipGenerator g = (StandardPieToolTipGenerator)
335 p.getToolTipGenerator();
336 if (g == null) {
337 return "";
338 }
339 return g.getLabelFormat();
340 }
341
342 /**
343 * Sets the format string for the section tool tips and fires a
344 * {@link PropertyChangeEvent} for the <code>sectionToolTipFormat</code>.
345 *
346 * @param format the format string.
347 *
348 * @see #getSectionToolTipFormat()
349 */
350 public void setSectionToolTipFormat(String format) {
351 PiePlot p = (PiePlot) this.chart.getPlot();
352 if (p == null) {
353 return;
354 }
355 if (format.equals("")) {
356 p.setToolTipGenerator(null);
357 }
358 else {
359 p.setToolTipGenerator(new StandardPieToolTipGenerator(format));
360 }
361 // FIXME: the old value needs to be specified
362 firePropertyChange("sectionToolTipFormat", "", format);
363 }
364
365 /**
366 * Registers a listener to receive notification of section clicks.
367 *
368 * @param listener the listener (<code>null</code> not permitted).
369 */
370 public void addSectionClickListener(SectionClickListener listener) {
371 if (listener == null) {
372 throw new IllegalArgumentException("Null 'listener' argument.");
373 }
374 this.sectionClickListeners.add(SectionClickListener.class, listener);
375 }
376
377 /**
378 * Unregisters a listener so that it no longer receives notification of
379 * section clicks.
380 *
381 * @param listener the listener (<code>null</code> not permitted).
382 */
383 public void removeSectionClickListener(SectionClickListener listener) {
384 if (listener == null) {
385 throw new IllegalArgumentException("Null 'listener' argument.");
386 }
387 this.sectionClickListeners.remove(SectionClickListener.class, listener);
388 }
389
390 /**
391 * Fires a section click event.
392 *
393 * @param event the event.
394 */
395 public void fireSectionClickEvent(SectionClickEvent event) {
396 Object[] listeners = this.sectionClickListeners.getListeners(
397 SectionClickListener.class);
398 for (int i = listeners.length - 1; i >= 0; i -= 1) {
399 ((SectionClickListener) listeners[i]).onSectionClick(event);
400 }
401
402 }
403
404 /**
405 * If the user clicks on the chart, see if that translates into an event
406 * that we report...
407 *
408 * @param event the event.
409 */
410 public void mouseClicked(MouseEvent event) {
411 // if no-one is listening, just return...
412 Object[] listeners = this.sectionClickListeners.getListeners(
413 SectionClickListener.class);
414 if (listeners.length == 0) {
415 super.mouseClicked(event);
416 return;
417 }
418
419 Insets insets = getInsets();
420 int x = event.getX() - insets.left;
421 int y = event.getY() - insets.top;
422
423 ChartEntity entity = null;
424 if (this.info != null) {
425 EntityCollection entities = this.info.getEntityCollection();
426 if (entities != null) {
427 entity = entities.getEntity(x, y);
428 }
429 }
430 if (entity instanceof PieSectionEntity) {
431 PieSectionEntity pse = (PieSectionEntity) entity;
432 SectionClickEvent sce = new SectionClickEvent(this,
433 pse.getSectionKey());
434 fireSectionClickEvent(sce);
435 }
436 else {
437 super.mouseClicked(event);
438 }
439 }
440
441 }