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 }