| 1 83 84 package org.jfree.chart; 85 86 import java.awt.BasicStroke ; 87 import java.awt.Color ; 88 import java.awt.Font ; 89 import java.awt.FontMetrics ; 90 import java.awt.Graphics2D ; 91 import java.awt.Paint ; 92 import java.awt.Shape ; 93 import java.awt.Stroke ; 94 import java.awt.font.LineMetrics ; 95 import java.awt.geom.AffineTransform ; 96 import java.awt.geom.Line2D ; 97 import java.awt.geom.Point2D ; 98 import java.awt.geom.Rectangle2D ; 99 import java.awt.geom.RectangularShape ; 100 import java.awt.geom.RoundRectangle2D ; 101 import java.io.IOException ; 102 import java.io.ObjectInputStream ; 103 import java.io.ObjectOutputStream ; 104 import java.io.Serializable ; 105 import java.util.ArrayList ; 106 import java.util.Iterator ; 107 import java.util.List ; 108 109 import org.jfree.chart.entity.EntityCollection; 110 import org.jfree.chart.entity.LegendItemEntity; 111 import org.jfree.chart.event.LegendChangeEvent; 112 import org.jfree.io.SerialUtilities; 113 import org.jfree.text.TextUtilities; 114 import org.jfree.ui.RectangleInsets; 115 import org.jfree.ui.TextAnchor; 116 import org.jfree.util.ObjectUtilities; 117 118 123 public class DefaultOldLegend extends OldLegend implements Serializable { 124 125 126 private static final long serialVersionUID = -5466149184220837922L; 127 128 129 public static final RectangleInsets DEFAULT_MARGIN 130 = new RectangleInsets(3, 3, 3, 3); 131 132 133 public static final RectangleInsets DEFAULT_PADDING 134 = new RectangleInsets(2, 2, 2, 2); 135 136 137 public static final Stroke DEFAULT_OUTLINE_STROKE = new BasicStroke (); 138 139 140 public static final Paint DEFAULT_OUTLINE_PAINT = Color.gray; 141 142 143 public static final Paint DEFAULT_BACKGROUND_PAINT = Color.white; 144 145 146 public static final Font DEFAULT_TITLE_FONT 147 = new Font ("SansSerif", Font.BOLD, 11); 148 149 150 public static final Font DEFAULT_ITEM_FONT 151 = new Font ("SansSerif", Font.PLAIN, 10); 152 153 157 public static final double NO_PREFERRED_WIDTH = Double.MAX_VALUE; 158 159 160 private static final String UNEXPECTED_LEGEND_ANCHOR 161 = "Unexpected legend anchor"; 162 163 164 private RectangleInsets margin; 165 166 167 private transient Stroke outlineStroke; 168 169 170 private transient Paint outlinePaint; 171 172 173 private transient Paint backgroundPaint; 174 175 176 private RectangleInsets padding; 177 178 179 private String title; 180 181 182 private Font titleFont; 183 184 185 private Font itemFont; 186 187 188 private transient Paint itemPaint; 189 190 191 private double shapeScaleX = 1.0; 192 193 194 private double shapeScaleY = 1.0; 195 196 197 private LegendRenderingOrder renderingOrder = LegendRenderingOrder.STANDARD; 198 199 202 private int boundingBoxArcWidth = 0; 203 204 207 private int boundingBoxArcHeight = 0; 208 209 210 private double preferredWidth = NO_PREFERRED_WIDTH; 211 212 215 public DefaultOldLegend() { 216 this.margin = DEFAULT_MARGIN; 217 this.padding = DEFAULT_PADDING; 218 this.backgroundPaint = DEFAULT_BACKGROUND_PAINT; 219 this.outlineStroke = DEFAULT_OUTLINE_STROKE; 220 this.outlinePaint = DEFAULT_OUTLINE_PAINT; 221 this.title = null; 222 this.titleFont = DEFAULT_TITLE_FONT; 223 this.itemFont = DEFAULT_ITEM_FONT; 224 this.itemPaint = Color.black; 225 } 226 227 233 public RectangleInsets getMargin() { 234 return this.margin; 235 } 236 237 243 public void setMargin(RectangleInsets margin) { 244 if (margin == null) { 245 throw new NullPointerException ("Null 'margin' argument."); 246 } 247 this.margin = margin; 248 notifyListeners(new LegendChangeEvent(this)); 249 } 250 251 257 public RectangleInsets getPadding() { 258 return this.padding; 259 } 260 261 267 public void setPadding(RectangleInsets padding) { 268 if (padding == null) { 269 throw new NullPointerException ("Null 'padding' argument."); 270 } 271 this.padding = padding; 272 notifyListeners(new LegendChangeEvent(this)); 273 } 274 275 280 public Paint getBackgroundPaint() { 281 return this.backgroundPaint; 282 } 283 284 290 public void setBackgroundPaint(Paint paint) { 291 if (paint == null) { 292 throw new IllegalArgumentException ("Null 'paint' argument."); 293 } 294 this.backgroundPaint = paint; 295 notifyListeners(new LegendChangeEvent(this)); 296 } 297 298 303 public Stroke getOutlineStroke() { 304 return this.outlineStroke; 305 } 306 307 313 public void setOutlineStroke(Stroke stroke) { 314 if (stroke == null) { 315 throw new NullPointerException ("Null 'stroke' argument."); 316 } 317 this.outlineStroke = stroke; 318 notifyListeners(new LegendChangeEvent(this)); 319 } 320 321 326 public Paint getOutlinePaint() { 327 return this.outlinePaint; 328 } 329 330 336 public void setOutlinePaint(Paint paint) { 337 if (paint == null) { 338 throw new IllegalArgumentException ("Null 'paint' argument."); 339 } 340 this.outlinePaint = paint; 341 notifyListeners(new LegendChangeEvent(this)); 342 } 343 344 349 public String getTitle() { 350 return this.title; 351 } 352 353 359 public void setTitle(String title) { 360 this.title = title; 361 notifyListeners(new LegendChangeEvent(this)); 362 } 363 364 369 public Font getTitleFont() { 370 return this.titleFont; 371 } 372 373 379 public void setTitleFont(Font font) { 380 if (font == null) { 381 throw new IllegalArgumentException ("Null 'font' argument."); 382 } 383 this.titleFont = font; 384 notifyListeners(new LegendChangeEvent(this)); 385 } 386 387 392 public Font getItemFont() { 393 return this.itemFont; 394 } 395 396 402 public void setItemFont(Font font) { 403 if (font == null) { 404 throw new IllegalArgumentException ("Null 'font' argument."); 405 } 406 this.itemFont = font; 407 notifyListeners(new LegendChangeEvent(this)); 408 } 409 410 415 public Paint getItemPaint() { 416 return this.itemPaint; 417 } 418 419 425 public void setItemPaint(Paint paint) { 426 if (paint == null) { 427 throw new IllegalArgumentException ("Null 'paint' argument."); 428 } 429 this.itemPaint = paint; 430 notifyListeners(new LegendChangeEvent(this)); 431 } 432 433 438 public double getShapeScaleX() { 439 return this.shapeScaleX; 440 } 441 442 448 public void setShapeScaleX(double factor) { 449 this.shapeScaleX = factor; 450 notifyListeners(new LegendChangeEvent(this)); 451 } 452 453 458 public double getShapeScaleY() { 459 return this.shapeScaleY; 460 } 461 462 468 public void setShapeScaleY(double factor) { 469 this.shapeScaleY = factor; 470 notifyListeners(new LegendChangeEvent(this)); 471 } 472 473 478 public LegendRenderingOrder getRenderingOrder() { 479 return this.renderingOrder; 480 } 481 482 488 public void setRenderingOrder(LegendRenderingOrder order) { 489 if (order == null) { 490 throw new IllegalArgumentException ("Null 'order' argument."); 491 } 492 this.renderingOrder = order; 493 notifyListeners(new LegendChangeEvent(this)); 494 } 495 496 497 504 public int getBoundingBoxArcWidth() { 505 return this.boundingBoxArcWidth; 506 } 507 508 515 public void setBoundingBoxArcWidth(int arcWidth) { 516 this.boundingBoxArcWidth = arcWidth; 517 notifyListeners(new LegendChangeEvent(this)); 518 } 519 520 527 public int getBoundingBoxArcHeight() { 528 return this.boundingBoxArcHeight; 529 } 530 531 538 public void setBoundingBoxArcHeight(int arcHeight) { 539 this.boundingBoxArcHeight = arcHeight; 540 notifyListeners(new LegendChangeEvent(this)); 541 } 542 543 551 public double getPreferredWidth() { 552 return this.preferredWidth; 553 } 554 555 570 public void setPreferredWidth(double width) { 571 this.preferredWidth = width; 572 notifyListeners(new LegendChangeEvent(this)); 573 } 574 575 586 public Rectangle2D draw(Graphics2D g2, Rectangle2D available, 587 ChartRenderingInfo info) { 588 589 return draw( 590 g2, available, (getAnchor() & HORIZONTAL) != 0, 591 (getAnchor() & INVERTED) != 0, info 592 ); 593 594 } 595 596 608 protected Rectangle2D draw(Graphics2D g2, Rectangle2D available, 609 boolean horizontal, boolean inverted, 610 ChartRenderingInfo info) { 611 612 LegendItemCollection legendItems 613 = getChart().getPlot().getLegendItems(); 614 615 if (legendItems == null || legendItems.getItemCount() == 0) { 616 return available; 617 } 618 620 DrawableLegendItem legendTitle = null; 621 LegendItem titleItem = null; 622 623 if (this.title != null && !this.title.equals("")) { 624 titleItem = new LegendItem( 625 this.title, this.title, null, null, (Shape ) null, Color.black 626 ); 627 } 628 629 RectangularShape legendArea; 630 double availableWidth = available.getWidth(); 631 Point2D translation; 633 634 List items = new ArrayList (); 636 637 if (horizontal) { 640 double xstart = available.getX() 641 + getMargin().calculateLeftOutset(availableWidth); 642 double xlimit = available.getMaxX() 643 - getMargin().calculateRightOutset(availableWidth); 644 double maxRowWidth = 0; 645 double xoffset = 0; 646 double rowHeight = 0; 647 double totalHeight = 0; 648 boolean wrappingAllowed = true; 649 650 if (titleItem != null) { 651 g2.setFont(getTitleFont()); 652 653 legendTitle = createDrawableLegendItem( 654 g2, titleItem, xoffset, totalHeight 655 ); 656 657 rowHeight = Math.max(0, legendTitle.getHeight()); 658 xoffset += legendTitle.getWidth(); 659 } 660 661 g2.setFont(this.itemFont); 662 for (int i = 0; i < legendItems.getItemCount(); i++) { 663 DrawableLegendItem item; 664 665 if (this.renderingOrder == LegendRenderingOrder.STANDARD) { 666 item = createDrawableLegendItem( 667 g2, legendItems.get(i), xoffset, totalHeight 668 ); 669 } 670 else if (this.renderingOrder == LegendRenderingOrder.REVERSE) { 671 item = createDrawableLegendItem( 672 g2, legendItems.get(legendItems.getItemCount() - i - 1), 673 xoffset, totalHeight 674 ); 675 } 676 else { 677 item = null; 680 } 681 682 if (item.getMaxX() + xstart > xlimit && wrappingAllowed) { 683 maxRowWidth = Math.max(maxRowWidth, xoffset); 685 xoffset = 0; 686 totalHeight += rowHeight; 687 i--; wrappingAllowed = false; 692 } 693 else { 694 rowHeight = Math.max(rowHeight, item.getHeight()); 696 xoffset += item.getWidth(); 697 wrappingAllowed = true; 700 items.add(item); 701 } 702 } 703 704 maxRowWidth = Math.max(maxRowWidth, xoffset); 705 totalHeight += rowHeight; 706 707 legendArea = new RoundRectangle2D.Double ( 709 0, 0, maxRowWidth, totalHeight, this.boundingBoxArcWidth, 710 this.boundingBoxArcHeight 711 ); 712 713 translation = createTranslationPointForHorizontalDraw( 714 available, inverted, maxRowWidth, totalHeight 715 ); 716 } 717 else { double totalHeight = 0; 719 double maxWidth = (this.preferredWidth == NO_PREFERRED_WIDTH) 720 ? 0 : this.preferredWidth; 721 722 if (titleItem != null) { 723 g2.setFont(getTitleFont()); 724 725 legendTitle = createDrawableLegendItem( 726 g2, titleItem, 0, totalHeight 727 ); 728 729 totalHeight += legendTitle.getHeight(); 730 maxWidth = Math.max(maxWidth, legendTitle.getWidth()); 731 } 732 733 g2.setFont(this.itemFont); 734 735 int legendItemsLength = legendItems.getItemCount(); 736 for (int i = 0; i < legendItemsLength; i++) { 737 List drawableParts; 738 739 if (this.renderingOrder == LegendRenderingOrder.STANDARD) { 740 drawableParts = createAllDrawableLinesForItem(g2, 741 legendItems.get(i), 0, totalHeight, maxWidth); 742 } 743 else if (this.renderingOrder == LegendRenderingOrder.REVERSE) { 744 drawableParts = createAllDrawableLinesForItem( 745 g2, legendItems.get(legendItemsLength - i - 1), 0, 746 totalHeight, maxWidth 747 ); 748 } 749 else { 750 drawableParts = null; 753 } 754 755 for (Iterator j = drawableParts.iterator(); j.hasNext();) { 756 DrawableLegendItem item = (DrawableLegendItem) j.next(); 757 758 totalHeight += item.getHeight(); 759 maxWidth = Math.max(maxWidth, item.getWidth()); 760 761 items.add(item); 762 } 763 } 764 765 legendArea = new RoundRectangle2D.Float ( 767 0, 0, (float) maxWidth, (float) totalHeight, 768 this.boundingBoxArcWidth, this.boundingBoxArcHeight 769 ); 770 771 translation = createTranslationPointForVerticalDraw( 772 available, inverted, totalHeight, maxWidth 773 ); 774 } 775 776 g2.translate(translation.getX(), translation.getY()); 778 drawLegendBox(g2, legendArea); 779 drawLegendTitle(g2, legendTitle); 780 drawSeriesElements(g2, items, translation, info); 781 782 g2.translate(-translation.getX(), -translation.getY()); 784 785 return calcRemainingDrawingArea( 786 available, horizontal, inverted, legendArea 787 ); 788 } 789 790 800 private Point2D createTranslationPointForHorizontalDraw( 801 Rectangle2D available, boolean inverted, double maxRowWidth, 802 double totalHeight) { 803 double yloc = (inverted) 806 ? available.getMaxY() - totalHeight 807 - getMargin().calculateBottomOutset(available.getHeight()) 808 : available.getY() 809 + getMargin().calculateTopOutset(available.getHeight()); 810 double xloc; 811 if (isAnchoredToLeft()) { 812 xloc = available.getX() 813 + getMargin().calculateLeftOutset(available.getWidth()); 814 } 815 else if (isAnchoredToCenter()) { 816 xloc = available.getX() + available.getWidth() / 2 817 - maxRowWidth / 2; 818 } 819 else if (isAnchoredToRight()) { 820 xloc = available.getX() + available.getWidth() 821 - maxRowWidth - getChart().getPlot().getInsets().getLeft(); 822 } 823 else { 824 throw new IllegalStateException (UNEXPECTED_LEGEND_ANCHOR); 825 } 826 827 return new Point2D.Double (xloc, yloc); 829 } 830 831 841 private Point2D createTranslationPointForVerticalDraw(Rectangle2D available, 842 boolean inverted, double totalHeight, double maxWidth) { 843 double xloc = (inverted) 846 ? available.getMaxX() - maxWidth 847 - getMargin().calculateRightOutset(available.getWidth()) 848 : available.getX() 849 + getMargin().calculateLeftOutset(available.getWidth()); 850 double yloc; 851 if (isAnchoredToTop()) { 852 yloc = available.getY() + getChart().getPlot().getInsets().getTop(); 853 } 854 else if (isAnchoredToMiddle()) { 855 yloc = available.getY() + (available.getHeight() / 2) 856 - (totalHeight / 2); 857 } 858 else if (isAnchoredToBottom()) { 859 yloc = available.getY() + available.getHeight() 860 - getChart().getPlot().getInsets().getBottom() - totalHeight; 861 } 862 else { 863 throw new IllegalStateException (UNEXPECTED_LEGEND_ANCHOR); 864 } 865 return new Point2D.Double (xloc, yloc); 867 } 868 869 876 private void drawLegendTitle(Graphics2D g2, 877
|