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.text.NumberFormat;
037
038 import org.jfree.beans.events.CategoryItemClickEvent;
039 import org.jfree.beans.events.CategoryItemClickListener;
040 import org.jfree.chart.axis.AxisLocation;
041 import org.jfree.chart.entity.CategoryItemEntity;
042 import org.jfree.chart.entity.ChartEntity;
043 import org.jfree.chart.entity.EntityCollection;
044 import org.jfree.chart.labels.StandardCategoryToolTipGenerator;
045 import org.jfree.chart.plot.CategoryPlot;
046 import org.jfree.chart.plot.PlotOrientation;
047 import org.jfree.chart.renderer.category.CategoryItemRenderer;
048
049 /**
050 * A base class for chart beans that use a {@link CategoryPlot}.
051 */
052 public abstract class AbstractCategoryChart extends AbstractChart {
053
054 /**
055 * Creates a new instance.
056 */
057 public AbstractCategoryChart() {
058 super();
059 }
060
061 /**
062 * Returns the orientation for the plot.
063 *
064 * @return The orientation for the plot.
065 *
066 * @see #setOrientation(PlotOrientation)
067 */
068 public PlotOrientation getOrientation() {
069 PlotOrientation result = null;
070 CategoryPlot plot = (CategoryPlot) this.chart.getPlot();
071 if (plot != null) {
072 result = plot.getOrientation();
073 }
074 return result;
075 }
076
077 /**
078 * Sets the orientation for the plot and fires a
079 * {@link PropertyChangeEvent} for the <code>orientation</code> property.
080 *
081 * @param orientation the orientation (<code>null</code> not permitted).
082 *
083 * @see #getOrientation()
084 */
085 public void setOrientation(PlotOrientation orientation) {
086 if (orientation == null) {
087 throw new IllegalArgumentException("Null 'orientation' argument.");
088 }
089 CategoryPlot plot = (CategoryPlot) this.chart.getPlot();
090 if (plot != null) {
091 PlotOrientation old = plot.getOrientation();
092 plot.setOrientation(orientation);
093 firePropertyChange("orientation", old, orientation);
094 }
095 }
096
097 /**
098 * Returns the category axis label.
099 *
100 * @return The category axis label (possibly <code>null</code>).
101 *
102 * @see #setCategoryAxisLabel(String)
103 */
104 public String getCategoryAxisLabel() {
105 String result = null;
106 CategoryPlot plot = (CategoryPlot) this.chart.getPlot();
107 if (plot != null) {
108 result = plot.getDomainAxis().getLabel();
109 }
110 return result;
111 }
112
113 /**
114 * Sets the category axis label and fires a {@link PropertyChangeEvent} for
115 * the <code>categoryAxisLabel</code> property.
116 *
117 * @param label the label (<code>null</code> permitted).
118 *
119 * @see #getCategoryAxisLabel()
120 */
121 public void setCategoryAxisLabel(String label) {
122 CategoryPlot plot = (CategoryPlot) this.chart.getPlot();
123 if (plot != null) {
124 String old = plot.getDomainAxis().getLabel();
125 plot.getDomainAxis().setLabel(label);
126 firePropertyChange("categoryAxisLabel", old, label);
127 }
128 }
129
130 /**
131 * Returns the font used for the main label on the category axis.
132 *
133 * @return The font.
134 *
135 * @see #setCategoryAxisLabelFont(Font)
136 */
137 public Font getCategoryAxisLabelFont() {
138 CategoryPlot plot = (CategoryPlot) this.chart.getPlot();
139 if (plot != null) {
140 return plot.getDomainAxis().getLabelFont();
141 }
142 return null;
143 }
144
145 /**
146 * Sets the font used for the main label on the category axis and fires a
147 * {@link PropertyChangeEvent} for the <code>categoryAxisLabelFont</code>
148 * property.
149 *
150 * @param font the font (<code>null</code> permitted).
151 */
152 public void setCategoryAxisLabelFont(Font font) {
153 if (font == null) {
154 throw new IllegalArgumentException("Null 'font' argument.");
155 }
156 CategoryPlot plot = (CategoryPlot) this.chart.getPlot();
157 if (plot != null) {
158 Font old = plot.getDomainAxis().getLabelFont();
159 plot.getDomainAxis().setLabelFont(font);
160 firePropertyChange("categoryAxisLabelFont", old, font);
161 }
162
163 }
164
165 /**
166 * Returns the paint used for the main label on the category axis.
167 *
168 * @return The paint.
169 *
170 * @see #setCategoryAxisLabelPaint(Paint)
171 */
172 public Paint getCategoryAxisLabelPaint() {
173 CategoryPlot plot = (CategoryPlot) this.chart.getPlot();
174 if (plot != null) {
175 return plot.getDomainAxis().getLabelPaint();
176 }
177 return null;
178 }
179
180 /**
181 * Sets the paint used for the main label on the category axis and fires a
182 * {@link PropertyChangeEvent} for the <code>categoryAxisLabelPaint</code>
183 * property.
184 *
185 * @param paint the paint (<code>null</code> not permitted).
186 *
187 * @see #getCategoryAxisLabelPaint()
188 */
189 public void setCategoryAxisLabelPaint(Paint paint) {
190 if (paint == null) {
191 throw new IllegalArgumentException("Null 'paint' argument.");
192 }
193 CategoryPlot plot = (CategoryPlot) this.chart.getPlot();
194 if (plot != null) {
195 Paint old = plot.getDomainAxis().getLabelPaint();
196 plot.getDomainAxis().setLabelPaint(paint);
197 firePropertyChange("categoryAxisLabelPaint", old, paint);
198 }
199 }
200
201 /**
202 * Returns the lower margin for the category axis.
203 *
204 * @return The lower margin.
205 *
206 * @see #setCategoryAxisLowerMargin(double)
207 */
208 public double getCategoryAxisLowerMargin() {
209 CategoryPlot plot = (CategoryPlot) this.chart.getPlot();
210 if (plot != null) {
211 return plot.getDomainAxis().getLowerMargin();
212 }
213 return -1.0;
214 }
215
216 /**
217 * Sets the lower margin for the category axis and fires a
218 * {@link PropertyChangeEvent} for the <code>categoryAxisLowerMargin</code>
219 * property.
220 *
221 * @param margin the margin.
222 *
223 * @see #getCategoryAxisLowerMargin()
224 */
225 public void setCategoryAxisLowerMargin(double margin) {
226 CategoryPlot plot = (CategoryPlot) this.chart.getPlot();
227 if (plot != null) {
228 double old = plot.getDomainAxis().getLowerMargin();
229 plot.getDomainAxis().setLowerMargin(margin);
230 firePropertyChange("categoryAxisLowerMargin", old, margin);
231 }
232 }
233
234 /**
235 * Returns the upper margin for the category axis.
236 *
237 * @return The upper margin for the category axis.
238 *
239 * @see #setCategoryAxisUpperMargin(double)
240 */
241 public double getCategoryAxisUpperMargin() {
242 CategoryPlot plot = (CategoryPlot) this.chart.getPlot();
243 if (plot != null) {
244 return plot.getDomainAxis().getUpperMargin();
245 }
246 return -1.0;
247 }
248
249 /**
250 * Sets the upper margin for the category axis and fires a
251 * {@link PropertyChangeEvent} for the <code>categoryAxisUpperMargin</code>
252 * property.
253 *
254 * @param margin the margin.
255 *
256 * @see #getCategoryAxisUpperMargin()
257 */
258 public void setCategoryAxisUpperMargin(double margin) {
259 CategoryPlot plot = (CategoryPlot) this.chart.getPlot();
260 if (plot != null) {
261 double old = plot.getDomainAxis().getUpperMargin();
262 plot.getDomainAxis().setUpperMargin(margin);
263 firePropertyChange("categoryAxisUpperMargin", old, margin);
264 }
265 }
266
267 /**
268 * Returns the margin between categories along the axis.
269 *
270 * @return The margin.
271 *
272 * @see #setCategoryAxisMargin(double)
273 */
274 public double getCategoryAxisMargin() {
275 CategoryPlot plot = (CategoryPlot) this.chart.getPlot();
276 if (plot != null) {
277 return plot.getDomainAxis().getCategoryMargin();
278 }
279 return -1.0;
280 }
281
282 /**
283 * Sets the total space allocated to the margin between categories
284 * along the axis and fires a {@link PropertyChangeEvent} for
285 * the <code>categoryAxisMargin</code> property.
286 *
287 * @param margin the margin.
288 *
289 * @see #getCategoryAxisMargin()
290 */
291 public void setCategoryAxisMargin(double margin) {
292 CategoryPlot plot = (CategoryPlot) this.chart.getPlot();
293 if (plot != null) {
294 double old = plot.getDomainAxis().getCategoryMargin();
295 plot.getDomainAxis().setCategoryMargin(margin);
296 firePropertyChange("categoryAxisMargin", old, margin);
297 }
298 }
299
300 /**
301 * Returns the label for the value axis.
302 *
303 * @return The label for the value axis.
304 *
305 * @see #setValueAxisLabel(String)
306 */
307 public String getValueAxisLabel() {
308 String result = null;
309 CategoryPlot plot = (CategoryPlot) this.chart.getPlot();
310 if (plot != null) {
311 result = plot.getRangeAxis().getLabel();
312 }
313 return result;
314 }
315
316 /**
317 * Sets the label for the value axis and fires a
318 * {@link PropertyChangeEvent} for the <code>valueAxisLabel</code> property.
319 *
320 * @param label the label.
321 *
322 * @see #getValueAxisLabel()
323 */
324 public void setValueAxisLabel(String label) {
325 CategoryPlot plot = (CategoryPlot) this.chart.getPlot();
326 if (plot != null) {
327 String old = plot.getRangeAxis().getLabel();
328 plot.getRangeAxis().setLabel(label);
329 firePropertyChange("valueAxisLabel", old, label);
330 }
331 }
332
333 /**
334 * Returns <code>true</code> if the value axis is inverted, and
335 * <code>false</code> otherwise.
336 *
337 * @return A boolean.
338 *
339 * @see #setValueAxisInverted(boolean)
340 */
341 public boolean isValueAxisInverted() {
342 CategoryPlot plot = (CategoryPlot) this.chart.getPlot();
343 if (plot != null) {
344 return plot.getRangeAxis().isInverted();
345 }
346 return false;
347 }
348
349 /**
350 * Sets a flag that controls whether or not the value axis is inverted and
351 * fires a {@link PropertyChangeEvent} for the
352 * <code>valueAxisInverted</code> property.
353 *
354 * @param inverted the new flag value.
355 *
356 * @see #isValueAxisInverted()
357 */
358 public void setValueAxisInverted(boolean inverted) {
359 CategoryPlot plot = (CategoryPlot) this.chart.getPlot();
360 if (plot != null) {
361 boolean old = plot.getRangeAxis().isInverted();
362 plot.getRangeAxis().setInverted(inverted);
363 firePropertyChange("valueAxisInverted", old, inverted);
364 }
365 }
366
367 /**
368 * Returns the lower margin for the value axis.
369 *
370 * @return The lower margin.
371 *
372 * @see #setValueAxisLowerMargin(double)
373 */
374 public double getValueAxisLowerMargin() {
375 CategoryPlot plot = (CategoryPlot) this.chart.getPlot();
376 if (plot != null) {
377 return plot.getRangeAxis().getLowerMargin();
378 }
379 return -1.0;
380 }
381
382 /**
383 * Sets the lower margin for the value axis and fires a
384 * {@link PropertyChangeEvent} for the <code>valueAxisLowerMargin</code>
385 * property.
386 *
387 * @param margin the margin.
388 *
389 * @see #getValueAxisLowerMargin()
390 */
391 public void setValueAxisLowerMargin(double margin) {
392 CategoryPlot plot = (CategoryPlot) this.chart.getPlot();
393 if (plot != null) {
394 double old = plot.getRangeAxis().getLowerMargin();
395 plot.getRangeAxis().setLowerMargin(margin);
396 firePropertyChange("valueAxisLowerMargin", old, margin);
397 }
398 }
399
400 /**
401 * Returns the upper margin for the value axis.
402 *
403 * @return The upper margin for the value axis.
404 *
405 * @see #setValueAxisUpperMargin(double)
406 */
407 public double getValueAxisUpperMargin() {
408 CategoryPlot plot = (CategoryPlot) this.chart.getPlot();
409 if (plot != null) {
410 return plot.getRangeAxis().getUpperMargin();
411 }
412 return -1.0;
413 }
414
415 /**
416 * Sets the upper margin for the value axis and fires a
417 * {@link PropertyChangeEvent} for the <code>valueAxisUpperMargin</code>
418 * property.
419 *
420 * @param margin the margin.
421 *
422 * @see #getValueAxisUpperMargin()
423 */
424 public void setValueAxisUpperMargin(double margin) {
425 CategoryPlot plot = (CategoryPlot) this.chart.getPlot();
426 if (plot != null) {
427 double old = plot.getRangeAxis().getUpperMargin();
428 plot.getRangeAxis().setUpperMargin(margin);
429 firePropertyChange("valueAxisUpperMargin", old, margin);
430 }
431 }
432
433 /**
434 * Returns <code>true</code> if the value axis gridlines are visible, and
435 * <code>false</code> otherwise.
436 *
437 * @return A boolean.
438 *
439 * @see #setValueAxisGridlinesVisible(boolean)
440 */
441 public boolean isValueAxisGridlinesVisible() {
442 CategoryPlot plot = (CategoryPlot) this.chart.getPlot();
443 if (plot != null) {
444 return plot.isRangeGridlinesVisible();
445 }
446 return false;
447 }
448
449 /**
450 * Sets a flag that controls whether or not the value-axis gridlines are
451 * drawn and fires a {@link PropertyChangeEvent} for the
452 * <code>valueAxisGridlinesVisible</code> property.
453 *
454 * @param visible the new flag value.
455 *
456 * @see #isValueAxisGridlinesVisible()
457 */
458 public void setValueAxisGridlinesVisible(boolean visible) {
459 CategoryPlot plot = (CategoryPlot) this.chart.getPlot();
460 if (plot != null) {
461 boolean old = plot.isRangeGridlinesVisible();
462 plot.setRangeGridlinesVisible(visible);
463 firePropertyChange("valueAxisGridlinesVisible", old, visible);
464 }
465 }
466
467 /**
468 * Returns the flag that controls whether or not the value axis draws a
469 * line running the length of the axis.
470 *
471 * @return A boolean.
472 *
473 * @see #setValueAxisLineVisible(boolean)
474 */
475 public boolean isValueAxisLineVisible() {
476 CategoryPlot plot = (CategoryPlot) this.chart.getPlot();
477 if (plot != null) {
478 return plot.getRangeAxis().isAxisLineVisible();
479 }
480 return false;
481 }
482
483 /**
484 * Sets the flag that controls whether or not the value axis draws a line
485 * running the length of the axis and fires a {@link PropertyChangeEvent}
486 * for the <code>valueAxisLineVisible</code> property.
487 *
488 * @param visible the new flag value.
489 *
490 * @see #isValueAxisLineVisible()
491 */
492 public void setValueAxisLineVisible(boolean visible) {
493 CategoryPlot plot = (CategoryPlot) this.chart.getPlot();
494 if (plot != null) {
495 boolean old = plot.getRangeAxis().isAxisLineVisible();
496 plot.getRangeAxis().setAxisLineVisible(visible);
497 firePropertyChange("valueAxisLineVisible", old, visible);
498 }
499 }
500
501 /**
502 * Returns a flag that conrtols whether or not the category axis
503 * draws a line running the length of the axis.
504 *
505 * @return A boolean.
506 *
507 * @see #setCategoryAxisLineVisible(boolean)
508 */
509 public boolean isCategoryAxisLineVisible() {
510 CategoryPlot plot = (CategoryPlot) this.chart.getPlot();
511 if (plot != null) {
512 return plot.getDomainAxis().isAxisLineVisible();
513 }
514 return false;
515 }
516
517 /**
518 * Sets the flag that controls whether or not the category axis draws a
519 * line running the length of the axis and fires a
520 * {@link PropertyChangeEvent} for the <code>categoryAxisLineVisible</code>
521 * property.
522 *
523 * @param visible the new flag value.
524 *
525 * @see #isCategoryAxisLineVisible()
526 */
527 public void setCategoryAxisLineVisible(boolean visible) {
528 CategoryPlot plot = (CategoryPlot) this.chart.getPlot();
529 if (plot != null) {
530 boolean old = plot.getDomainAxis().isAxisLineVisible();
531 plot.getDomainAxis().setAxisLineVisible(visible);
532 firePropertyChange("categoryAxisLineVisible", old, visible);
533 }
534 }
535
536 /**
537 * Returns the permitted axis locations for the category axis.
538 *
539 * @return The axis location.
540 *
541 * @see #setCategoryAxisLocation(AxisLocation)
542 */
543 public AxisLocation getCategoryAxisLocation() {
544 CategoryPlot plot = (CategoryPlot) this.chart.getPlot();
545 if (plot != null) {
546 return plot.getDomainAxisLocation();
547 }
548 return null;
549 }
550
551 /**
552 * Sets the axis location for the category axis and fires a
553 * {@link PropertyChangeEvent} for the <code>categoryAxisLocation</code>
554 * property.
555 *
556 * @param location the location (<code>null</code> not permitted).
557 *
558 * @see #getCategoryAxisLocation()
559 */
560 public void setCategoryAxisLocation(AxisLocation location) {
561 if (location == null) {
562 throw new IllegalArgumentException("Null 'location' argument.");
563 }
564 CategoryPlot plot = (CategoryPlot) this.chart.getPlot();
565 if (plot != null) {
566 AxisLocation old = plot.getDomainAxisLocation();
567 plot.setDomainAxisLocation(location);
568 firePropertyChange("categoryAxisLocation", old, location);
569 }
570 }
571
572 /**
573 * Returns the permitted axis locations for the value axis.
574 *
575 * @return The axis location.
576 *
577 * @see #setValueAxisLocation(AxisLocation)
578 */
579 public AxisLocation getValueAxisLocation() {
580 CategoryPlot plot = (CategoryPlot) this.chart.getPlot();
581 if (plot != null) {
582 return plot.getRangeAxisLocation();
583 }
584 return null;
585 }
586
587 /**
588 * Sets the axis location for the value axis and fires a
589 * {@link PropertyChangeEvent} for the <code>valueAxisLocation</code>
590 * property.
591 *
592 * @param location the location (<code>null</code> not permitted).
593 */
594 public void setValueAxisLocation(AxisLocation location) {
595 if (location == null) {
596 throw new IllegalArgumentException("Null 'location' argument.");
597 }
598 CategoryPlot plot = (CategoryPlot) this.chart.getPlot();
599 if (plot != null) {
600 AxisLocation old = plot.getRangeAxisLocation();
601 plot.setRangeAxisLocation(location);
602 firePropertyChange("valueAxisLocation", old, location);
603 }
604 }
605
606 /**
607 * Returns the format string for the item tool tips.
608 *
609 * @return The format string.
610 *
611 * @see #setToolTipFormat(String)
612 */
613 public String getToolTipFormat() {
614 CategoryPlot p = (CategoryPlot) this.chart.getPlot();
615 if (p == null) {
616 return "";
617 }
618 CategoryItemRenderer r = p.getRenderer();
619 if (r == null) {
620 return "";
621 }
622 StandardCategoryToolTipGenerator g = (StandardCategoryToolTipGenerator)
623 r.getBaseToolTipGenerator();
624 if (g == null) {
625 return "";
626 }
627 return g.getLabelFormat();
628 }
629
630 /**
631 * Sets the format string for the section tool tips and fires a
632 * {@link PropertyChangeEvent} for the <code>toolTipFormat</code> property.
633 *
634 * @param format the format string.
635 *
636 * @see #getToolTipFormat()
637 */
638 public void setToolTipFormat(String format) {
639 CategoryPlot p = (CategoryPlot) this.chart.getPlot();
640 if (p == null) {
641 return;
642 }
643 CategoryItemRenderer r = p.getRenderer();
644 if (r == null) {
645 return;
646 }
647 if (format.equals("")) {
648 r.setBaseToolTipGenerator(null);
649 }
650 else {
651 r.setBaseToolTipGenerator(new StandardCategoryToolTipGenerator(
652 format, NumberFormat.getInstance()));
653 }
654 // FIXME: what to use for the oldValue
655 firePropertyChange("toolTipFormat", null, format);
656 }
657
658 /**
659 * Registers a listener to receive notification of category item clicks.
660 *
661 * @param listener the listener (<code>null</code> not permitted).
662 */
663 public void addCategoryItemClickListener(
664 CategoryItemClickListener listener) {
665 if (listener == null) {
666 throw new IllegalArgumentException("Null 'listener' argument.");
667 }
668 this.listeners.add(CategoryItemClickListener.class, listener);
669 }
670
671 /**
672 * Unregisters a listener so that it no longer receives notification of
673 * category item clicks.
674 *
675 * @param listener the listener (<code>null</code> not permitted).
676 */
677 public void removeCategoryItemClickListener(CategoryItemClickListener
678 listener) {
679 if (listener == null) {
680 throw new IllegalArgumentException("Null 'listener' argument.");
681 }
682 this.listeners.remove(CategoryItemClickListener.class, listener);
683 }
684
685 /**
686 * Fires a category item click event.
687 *
688 * @param event the event.
689 */
690 public void fireCategoryItemClickEvent(CategoryItemClickEvent event) {
691 Object[] listeners = this.listeners.getListeners(
692 CategoryItemClickListener.class);
693 for (int i = listeners.length - 1; i >= 0; i -= 1) {
694 ((CategoryItemClickListener) listeners[i]).onCategoryItemClick(
695 event);
696 }
697
698 }
699
700 /**
701 * If the user clicks on the chart, see if that translates into an event
702 * that we report...
703 *
704 * @param event the event.
705 */
706 public void mouseClicked(MouseEvent event) {
707 // if no-one is listening, just return...
708 Object[] listeners = this.listeners.getListeners(
709 CategoryItemClickListener.class);
710 if (listeners.length == 0) {
711 super.mouseClicked(event);
712 }
713
714 Insets insets = getInsets();
715 int x = event.getX() - insets.left;
716 int y = event.getY() - insets.top;
717
718 ChartEntity entity = null;
719 if (this.info != null) {
720 EntityCollection entities = this.info.getEntityCollection();
721 if (entities != null) {
722 entity = entities.getEntity(x, y);
723 }
724 }
725 if (entity instanceof CategoryItemEntity) {
726 CategoryItemEntity cie = (CategoryItemEntity) entity;
727 CategoryItemClickEvent lce = new CategoryItemClickEvent(this,
728 cie.getDataset(), cie.getRowKey(), cie.getColumnKey());
729 fireCategoryItemClickEvent(lce);
730 }
731 else {
732 super.mouseClicked(event);
733 }
734
735 }
736
737 }