diff -burN jfreechart-original/pom.xml jfreechart-after-maintenance/pom.xml --- jfreechart-original/pom.xml 2022-03-07 09:23:25.000000000 +0100 +++ jfreechart-after-maintenance/pom.xml 2022-04-17 18:12:48.000000000 +0200 @@ -66,6 +66,16 @@ 4.11 test + + + + org.mockito + mockito-core + 4.4.0 + test + + + diff -burN jfreechart-original/src/main/java/org/jfree/chart/axis/DateAxis.java jfreechart-after-maintenance/src/main/java/org/jfree/chart/axis/DateAxis.java --- jfreechart-original/src/main/java/org/jfree/chart/axis/DateAxis.java 2022-03-07 09:23:25.000000000 +0100 +++ jfreechart-after-maintenance/src/main/java/org/jfree/chart/axis/DateAxis.java 2022-04-17 18:12:48.000000000 +0200 @@ -181,7 +181,7 @@ * For example, this allows you to create a date axis that only contains * working days. */ -public class DateAxis extends ValueAxis implements Cloneable, Serializable { +public class DateAxis extends DatePeriodCommon implements Cloneable, Serializable { /** For serialization. */ private static final long serialVersionUID = -1013460999649007604L; @@ -758,32 +758,7 @@ DateRange range = (DateRange) getRange(); double axisMin = this.timeline.toTimelineValue(range.getLowerMillis()); double axisMax = this.timeline.toTimelineValue(range.getUpperMillis()); - double result = 0.0; - if (RectangleEdge.isTopOrBottom(edge)) { - double minX = area.getX(); - double maxX = area.getMaxX(); - if (isInverted()) { - result = maxX + ((value - axisMin) / (axisMax - axisMin)) - * (minX - maxX); - } - else { - result = minX + ((value - axisMin) / (axisMax - axisMin)) - * (maxX - minX); - } - } - else if (RectangleEdge.isLeftOrRight(edge)) { - double minY = area.getMinY(); - double maxY = area.getMaxY(); - if (isInverted()) { - result = minY + (((value - axisMin) / (axisMax - axisMin)) - * (maxY - minY)); - } - else { - result = maxY - (((value - axisMin) / (axisMax - axisMin)) - * (maxY - minY)); - } - } - return result; + return getCoordinates(value, area, edge, axisMin, axisMax); } /** @@ -1399,21 +1374,21 @@ * just look at two values: the lower bound and the upper bound for the * axis. These two values will usually be representative. * + * @param resultInitialValue * @param g2 the graphics device. * @param unit the tick unit to use for calculation. * * @return The estimated maximum width of the tick labels. */ - private double estimateMaximumTickLabelWidth(Graphics2D g2, - DateTickUnit unit) { + private double estimateMaximumTickLabelDimension(Graphics2D g2, + DateTickUnit unit, boolean verticalOrHorizontal, double resultInitialValue) { - RectangleInsets tickLabelInsets = getTickLabelInsets(); - double result = tickLabelInsets.getLeft() + tickLabelInsets.getRight(); + double result = resultInitialValue; Font tickLabelFont = getTickLabelFont(); FontRenderContext frc = g2.getFontRenderContext(); LineMetrics lm = tickLabelFont.getLineMetrics("ABCxyz", frc); - if (isVerticalTickLabels()) { + if (verticalOrHorizontal) { // all tick labels have the same width (equal to the height of // the font)... result += lm.getHeight(); @@ -1456,42 +1431,32 @@ * * @return The estimated maximum width of the tick labels. */ - private double estimateMaximumTickLabelHeight(Graphics2D g2, + private double estimateMaximumTickLabelWidth(Graphics2D g2, DateTickUnit unit) { RectangleInsets tickLabelInsets = getTickLabelInsets(); - double result = tickLabelInsets.getTop() + tickLabelInsets.getBottom(); + return estimateMaximumTickLabelDimension(g2, unit, isVerticalTickLabels(), tickLabelInsets.getLeft() + tickLabelInsets.getRight()); - Font tickLabelFont = getTickLabelFont(); - FontRenderContext frc = g2.getFontRenderContext(); - LineMetrics lm = tickLabelFont.getLineMetrics("ABCxyz", frc); - if (!isVerticalTickLabels()) { - // all tick labels have the same width (equal to the height of - // the font)... - result += lm.getHeight(); - } - else { - // look at lower and upper bounds... - DateRange range = (DateRange) getRange(); - Date lower = range.getLowerDate(); - Date upper = range.getUpperDate(); - String lowerStr, upperStr; - DateFormat formatter = getDateFormatOverride(); - if (formatter != null) { - lowerStr = formatter.format(lower); - upperStr = formatter.format(upper); - } - else { - lowerStr = unit.dateToString(lower); - upperStr = unit.dateToString(upper); - } - FontMetrics fm = g2.getFontMetrics(tickLabelFont); - double w1 = fm.stringWidth(lowerStr); - double w2 = fm.stringWidth(upperStr); - result += Math.max(w1, w2); } - return result; + /** + * Estimates the maximum width of the tick labels, assuming the specified + * tick unit is used. + *

+ * Rather than computing the string bounds of every tick on the axis, we + * just look at two values: the lower bound and the upper bound for the + * axis. These two values will usually be representative. + * + * @param g2 the graphics device. + * @param unit the tick unit to use for calculation. + * + * @return The estimated maximum width of the tick labels. + */ + private double estimateMaximumTickLabelHeight(Graphics2D g2, + DateTickUnit unit) { + + RectangleInsets tickLabelInsets = getTickLabelInsets(); + return estimateMaximumTickLabelDimension(g2, unit, !isVerticalTickLabels(), tickLabelInsets.getTop() + tickLabelInsets.getBottom()); } @@ -1555,6 +1520,30 @@ protected List refreshTicksHorizontal(Graphics2D g2, Rectangle2D dataArea, RectangleEdge edge) { + DateTickUnit unit = getTickUnit(); + Date tickDate = calculateLowestVisibleTickValue(unit); + return refreshTicksRefactored(g2, dataArea, edge, unit, tickDate, TextAnchor.CENTER_RIGHT, RectangleEdge.TOP, Math.PI, - Math.PI, TextAnchor.BOTTOM_CENTER, TextAnchor.TOP_CENTER); + + } + + /** + * Recalculates the ticks for the date axis. + * + * @param g2 the graphics device. + * @param dataArea the area in which the plot should be drawn. + * @param edge the location of the axis. + * + * @return A list of ticks. + */ + protected List refreshTicksVertical(Graphics2D g2, + Rectangle2D dataArea, RectangleEdge edge) { + + DateTickUnit unit = getTickUnit(); + Date tickDate = calculateLowestVisibleTickValue(unit); + return refreshTicksRefactored(g2, dataArea, edge, unit, tickDate, TextAnchor.BOTTOM_CENTER, RectangleEdge.LEFT, - Math.PI, Math.PI, TextAnchor.CENTER_RIGHT, TextAnchor.CENTER_LEFT); + } + + private List refreshTicksRefactored(Graphics2D g2, Rectangle2D dataArea, RectangleEdge edge, DateTickUnit unit, Date tickDate, TextAnchor originAnchor, RectangleEdge rectangleEdge, double pi, double pi1, TextAnchor oneCenter, TextAnchor otherCenter) { List result = new java.util.ArrayList(); Font tickLabelFont = getTickLabelFont(); @@ -1564,8 +1553,6 @@ selectAutoTickUnit(g2, dataArea, edge); } - DateTickUnit unit = getTickUnit(); - Date tickDate = calculateLowestVisibleTickValue(unit); Date upperDate = getMaximumDate(); boolean hasRolled = false; @@ -1596,39 +1583,7 @@ if (!isHiddenValue(tickDate.getTime())) { // work out the value, label and position - String tickLabel; - DateFormat formatter = getDateFormatOverride(); - if (formatter != null) { - tickLabel = formatter.format(tickDate); - } - else { - tickLabel = this.tickUnit.dateToString(tickDate); - } - TextAnchor anchor, rotationAnchor; - double angle = 0.0; - if (isVerticalTickLabels()) { - anchor = TextAnchor.CENTER_RIGHT; - rotationAnchor = TextAnchor.CENTER_RIGHT; - if (edge == RectangleEdge.TOP) { - angle = Math.PI / 2.0; - } - else { - angle = -Math.PI / 2.0; - } - } - else { - if (edge == RectangleEdge.TOP) { - anchor = TextAnchor.BOTTOM_CENTER; - rotationAnchor = TextAnchor.BOTTOM_CENTER; - } - else { - anchor = TextAnchor.TOP_CENTER; - rotationAnchor = TextAnchor.TOP_CENTER; - } - } - - Tick tick = new DateTick(tickDate, tickLabel, anchor, - rotationAnchor, angle); + Tick tick = getTickRefreshed(originAnchor, edge, rectangleEdge, pi, pi1, oneCenter, otherCenter, tickDate); result.add(tick); hasRolled = false; @@ -1658,61 +1613,9 @@ } return result; - - } - - /** - * Recalculates the ticks for the date axis. - * - * @param g2 the graphics device. - * @param dataArea the area in which the plot should be drawn. - * @param edge the location of the axis. - * - * @return A list of ticks. - */ - protected List refreshTicksVertical(Graphics2D g2, - Rectangle2D dataArea, RectangleEdge edge) { - - List result = new java.util.ArrayList(); - - Font tickLabelFont = getTickLabelFont(); - g2.setFont(tickLabelFont); - - if (isAutoTickUnitSelection()) { - selectAutoTickUnit(g2, dataArea, edge); - } - DateTickUnit unit = getTickUnit(); - Date tickDate = calculateLowestVisibleTickValue(unit); - Date upperDate = getMaximumDate(); - - boolean hasRolled = false; - while (tickDate.before(upperDate)) { - - // could add a flag to make the following correction optional... - if (!hasRolled) { - tickDate = correctTickDateForPosition(tickDate, unit, - this.tickMarkPosition); } - long lowestTickTime = tickDate.getTime(); - long distance = unit.addToDate(tickDate, this.timeZone).getTime() - - lowestTickTime; - int minorTickSpaces = getMinorTickCount(); - if (minorTickSpaces <= 0) { - minorTickSpaces = unit.getMinorTickCount(); - } - for (int minorTick = 1; minorTick < minorTickSpaces; minorTick++) { - long minorTickTime = lowestTickTime - distance - * minorTick / minorTickSpaces; - if (minorTickTime > 0 && getRange().contains(minorTickTime) - && (!isHiddenValue(minorTickTime))) { - result.add(new DateTick(TickType.MINOR, - new Date(minorTickTime), "", TextAnchor.TOP_CENTER, - TextAnchor.CENTER, 0.0)); - } - } - if (!isHiddenValue(tickDate.getTime())) { - // work out the value, label and position + private Tick getTickRefreshed(TextAnchor originAnchor, RectangleEdge edge, RectangleEdge top, double pi, double PI, TextAnchor oneCenter, TextAnchor otherCenter, Date tickDate) { String tickLabel; DateFormat formatter = getDateFormatOverride(); if (formatter != null) { @@ -1724,54 +1627,29 @@ TextAnchor anchor, rotationAnchor; double angle = 0.0; if (isVerticalTickLabels()) { - anchor = TextAnchor.BOTTOM_CENTER; - rotationAnchor = TextAnchor.BOTTOM_CENTER; - if (edge == RectangleEdge.LEFT) { - angle = -Math.PI / 2.0; + anchor = originAnchor; + rotationAnchor = originAnchor; + if (edge == top) { + angle = pi / 2.0; } else { - angle = Math.PI / 2.0; + angle = PI / 2.0; } } else { - if (edge == RectangleEdge.LEFT) { - anchor = TextAnchor.CENTER_RIGHT; - rotationAnchor = TextAnchor.CENTER_RIGHT; + if (edge == top) { + anchor = oneCenter; + rotationAnchor = oneCenter; } else { - anchor = TextAnchor.CENTER_LEFT; - rotationAnchor = TextAnchor.CENTER_LEFT; + anchor = otherCenter; + rotationAnchor = otherCenter; } } Tick tick = new DateTick(tickDate, tickLabel, anchor, rotationAnchor, angle); - result.add(tick); - hasRolled = false; - - long currentTickTime = tickDate.getTime(); - tickDate = unit.addToDate(tickDate, this.timeZone); - long nextTickTime = tickDate.getTime(); - for (int minorTick = 1; minorTick < minorTickSpaces; - minorTick++) { - long minorTickTime = currentTickTime - + (nextTickTime - currentTickTime) - * minorTick / minorTickSpaces; - if (getRange().contains(minorTickTime) - && (!isHiddenValue(minorTickTime))) { - result.add(new DateTick(TickType.MINOR, - new Date(minorTickTime), "", - TextAnchor.TOP_CENTER, TextAnchor.CENTER, - 0.0)); - } - } - } - else { - tickDate = unit.rollDate(tickDate, this.timeZone); - hasRolled = true; - } - } - return result; + return tick; } /** diff -burN jfreechart-original/src/main/java/org/jfree/chart/axis/DatePeriodCommon.java jfreechart-after-maintenance/src/main/java/org/jfree/chart/axis/DatePeriodCommon.java --- jfreechart-original/src/main/java/org/jfree/chart/axis/DatePeriodCommon.java 1970-01-01 01:00:00.000000000 +0100 +++ jfreechart-after-maintenance/src/main/java/org/jfree/chart/axis/DatePeriodCommon.java 2022-04-17 18:12:48.000000000 +0200 @@ -0,0 +1,49 @@ +package org.jfree.chart.axis; + +import org.jfree.chart.ui.RectangleEdge; + +import java.awt.geom.Rectangle2D; + +public abstract class DatePeriodCommon extends ValueAxis { + + /** + * Constructs a value axis. + * + * @param label the axis label ({@code null} permitted). + * @param standardTickUnits the source for standard tick units + * ({@code null} permitted). + */ + protected DatePeriodCommon(String label, TickUnitSource standardTickUnits) { + super(label, standardTickUnits); + } + + protected double getCoordinates(double value, Rectangle2D area, RectangleEdge edge, double axisMin, double axisMax) { + double result = 0.0; + if (RectangleEdge.isTopOrBottom(edge)) { + double minX = area.getX(); + double maxX = area.getMaxX(); + if (isInverted()) { + result = maxX + ((value - axisMin) / (axisMax - axisMin)) + * (minX - maxX); + } + else { + result = minX + ((value - axisMin) / (axisMax - axisMin)) + * (maxX - minX); + } + } + else if (RectangleEdge.isLeftOrRight(edge)) { + double minY = area.getMinY(); + double maxY = area.getMaxY(); + double v = ((value - axisMin) / (axisMax - axisMin)) + * (maxY - minY); + if (isInverted()) { + result = minY + v; + } + else { + result = maxY - v; + } + } + return result; + } + +} diff -burN jfreechart-original/src/main/java/org/jfree/chart/axis/LogarithmicAxis.java jfreechart-after-maintenance/src/main/java/org/jfree/chart/axis/LogarithmicAxis.java --- jfreechart-original/src/main/java/org/jfree/chart/axis/LogarithmicAxis.java 2022-03-07 09:23:25.000000000 +0100 +++ jfreechart-after-maintenance/src/main/java/org/jfree/chart/axis/LogarithmicAxis.java 2022-04-17 18:12:48.000000000 +0200 @@ -836,32 +836,7 @@ if (currentTickValue >= lowerBoundVal - SMALL_LOG_VALUE) { //tick value not below lowest data value - TextAnchor anchor; - TextAnchor rotationAnchor; - double angle = 0.0; - if (isVerticalTickLabels()) { - anchor = TextAnchor.CENTER_RIGHT; - rotationAnchor = TextAnchor.CENTER_RIGHT; - if (edge == RectangleEdge.TOP) { - angle = Math.PI / 2.0; - } - else { - angle = -Math.PI / 2.0; - } - } - else { - if (edge == RectangleEdge.TOP) { - anchor = TextAnchor.BOTTOM_CENTER; - rotationAnchor = TextAnchor.BOTTOM_CENTER; - } - else { - anchor = TextAnchor.TOP_CENTER; - rotationAnchor = TextAnchor.TOP_CENTER; - } - } - - Tick tick = new NumberTick(new Double(currentTickValue), - tickLabel, anchor, rotationAnchor, angle); + Tick tick = getTickHorizontallyRefreshed(edge, currentTickValue, tickLabel); ticks.add(tick); } } @@ -1026,34 +1001,8 @@ if (tickVal >= lowerBoundVal - SMALL_LOG_VALUE) { //tick value not below lowest data value - TextAnchor anchor; - TextAnchor rotationAnchor; - double angle = 0.0; - if (isVerticalTickLabels()) { - if (edge == RectangleEdge.LEFT) { - anchor = TextAnchor.BOTTOM_CENTER; - rotationAnchor = TextAnchor.BOTTOM_CENTER; - angle = -Math.PI / 2.0; - } - else { - anchor = TextAnchor.BOTTOM_CENTER; - rotationAnchor = TextAnchor.BOTTOM_CENTER; - angle = Math.PI / 2.0; - } - } - else { - if (edge == RectangleEdge.LEFT) { - anchor = TextAnchor.CENTER_RIGHT; - rotationAnchor = TextAnchor.CENTER_RIGHT; - } - else { - anchor = TextAnchor.CENTER_LEFT; - rotationAnchor = TextAnchor.CENTER_LEFT; - } - } //create tick object and add to list: - ticks.add(new NumberTick(new Double(tickVal), tickLabel, - anchor, rotationAnchor, angle)); + ticks.add(getTickVerticallyRefreshed(edge, tickVal, tickLabel)); } } } diff -burN jfreechart-original/src/main/java/org/jfree/chart/axis/LogAxis.java jfreechart-after-maintenance/src/main/java/org/jfree/chart/axis/LogAxis.java --- jfreechart-original/src/main/java/org/jfree/chart/axis/LogAxis.java 2022-03-07 09:23:25.000000000 +0100 +++ jfreechart-after-maintenance/src/main/java/org/jfree/chart/axis/LogAxis.java 2022-04-17 18:12:48.000000000 +0200 @@ -97,7 +97,7 @@ * * @since 1.0.7 */ -public class LogAxis extends ValueAxis { +public class LogAxis extends NumberLogCommon { /** The logarithm base. */ private double base = 10.0; @@ -120,9 +120,6 @@ /** The smallest value permitted on the axis. */ private double smallestValue = 1E-100; - /** The current tick unit. */ - private NumberTickUnit tickUnit; - /** The override number format. */ private NumberFormat numberFormatOverride; @@ -254,57 +251,6 @@ fireChangeEvent(); } - /** - * Returns the current tick unit. - * - * @return The current tick unit. - * - * @see #setTickUnit(NumberTickUnit) - */ - public NumberTickUnit getTickUnit() { - return this.tickUnit; - } - - /** - * Sets the tick unit for the axis and sends an {@link AxisChangeEvent} to - * all registered listeners. A side effect of calling this method is that - * the "auto-select" feature for tick units is switched off (you can - * restore it using the {@link ValueAxis#setAutoTickUnitSelection(boolean)} - * method). - * - * @param unit the new tick unit ({@code null} not permitted). - * - * @see #getTickUnit() - */ - public void setTickUnit(NumberTickUnit unit) { - // defer argument checking... - setTickUnit(unit, true, true); - } - - /** - * Sets the tick unit for the axis and, if requested, sends an - * {@link AxisChangeEvent} to all registered listeners. In addition, an - * option is provided to turn off the "auto-select" feature for tick units - * (you can restore it using the - * {@link ValueAxis#setAutoTickUnitSelection(boolean)} method). - * - * @param unit the new tick unit ({@code null} not permitted). - * @param notify notify listeners? - * @param turnOffAutoSelect turn off the auto-tick selection? - * - * @see #getTickUnit() - */ - public void setTickUnit(NumberTickUnit unit, boolean notify, - boolean turnOffAutoSelect) { - Args.nullNotPermitted(unit, "unit"); - this.tickUnit = unit; - if (turnOffAutoSelect) { - setAutoTickUnitSelection(false, false); - } - if (notify) { - fireChangeEvent(); - } - } /** * Returns the number format override. If this is non-{@code null}, @@ -513,47 +459,6 @@ } /** - * Draws the axis on a Java 2D graphics device (such as the screen or a - * printer). - * - * @param g2 the graphics device ({@code null} not permitted). - * @param cursor the cursor location (determines where to draw the axis). - * @param plotArea the area within which the axes and plot should be drawn. - * @param dataArea the area within which the data should be drawn. - * @param edge the axis location ({@code null} not permitted). - * @param plotState collects information about the plot ({@code null} - * permitted). - * - * @return The axis state (never {@code null}). - */ - @Override - public AxisState draw(Graphics2D g2, double cursor, Rectangle2D plotArea, - Rectangle2D dataArea, RectangleEdge edge, - PlotRenderingInfo plotState) { - - AxisState state; - // if the axis is not visible, don't draw it... - if (!isVisible()) { - state = new AxisState(cursor); - // even though the axis is not visible, we need ticks for the - // gridlines... - List ticks = refreshTicks(g2, state, dataArea, edge); - state.setTicks(ticks); - return state; - } - state = drawTickMarksAndLabels(g2, cursor, plotArea, dataArea, edge); - if (getAttributedLabel() != null) { - state = drawAttributedLabel(getAttributedLabel(), g2, plotArea, - dataArea, edge, state); - - } else { - state = drawLabel(getLabel(), g2, plotArea, dataArea, edge, state); - } - createAndAddEntity(cursor, state, dataArea, edge, plotState); - return state; - } - - /** * Calculates the positions of the tick labels for the axis, storing the * results in the tick label list (ready for drawing). * @@ -863,25 +768,6 @@ } /** - * Estimates the maximum tick label height. - * - * @param g2 the graphics device. - * - * @return The maximum height. - * - * @since 1.0.7 - */ - protected double estimateMaximumTickLabelHeight(Graphics2D g2) { - RectangleInsets tickLabelInsets = getTickLabelInsets(); - double result = tickLabelInsets.getTop() + tickLabelInsets.getBottom(); - - Font tickLabelFont = getTickLabelFont(); - FontRenderContext frc = g2.getFontRenderContext(); - result += tickLabelFont.getLineMetrics("123", frc).getHeight(); - return result; - } - - /** * Estimates the maximum width of the tick labels, assuming the specified * tick unit is used. *

diff -burN jfreechart-original/src/main/java/org/jfree/chart/axis/NumberAxis.java jfreechart-after-maintenance/src/main/java/org/jfree/chart/axis/NumberAxis.java --- jfreechart-original/src/main/java/org/jfree/chart/axis/NumberAxis.java 2022-03-07 09:23:25.000000000 +0100 +++ jfreechart-after-maintenance/src/main/java/org/jfree/chart/axis/NumberAxis.java 2022-04-17 18:12:48.000000000 +0200 @@ -119,7 +119,6 @@ import org.jfree.chart.event.AxisChangeEvent; import org.jfree.chart.plot.Plot; -import org.jfree.chart.plot.PlotRenderingInfo; import org.jfree.chart.plot.ValueAxisPlot; import org.jfree.chart.ui.RectangleEdge; import org.jfree.chart.ui.RectangleInsets; @@ -140,7 +139,7 @@ * The {@code NumberAxis} class has a mechanism for automatically * selecting a tick unit that is appropriate for the current axis range. */ -public class NumberAxis extends ValueAxis implements Cloneable, Serializable { +public class NumberAxis extends NumberLogCommon implements Cloneable, Serializable { /** For serialization. */ private static final long serialVersionUID = 2805933088476185789L; @@ -178,9 +177,6 @@ */ private boolean autoRangeStickyZero; - /** The tick unit for the axis. */ - private NumberTickUnit tickUnit; - /** The override number format. */ private NumberFormat numberFormatOverride; @@ -204,7 +200,6 @@ this.rangeType = RangeType.FULL; this.autoRangeIncludesZero = DEFAULT_AUTO_RANGE_INCLUDES_ZERO; this.autoRangeStickyZero = DEFAULT_AUTO_RANGE_STICKY_ZERO; - this.tickUnit = DEFAULT_TICK_UNIT; this.numberFormatOverride = null; this.markerBand = null; } @@ -297,65 +292,6 @@ } /** - * Returns the tick unit for the axis. - *

- * Note: if the {@code autoTickUnitSelection} flag is - * {@code true} the tick unit may be changed while the axis is being - * drawn, so in that case the return value from this method may be - * irrelevant if the method is called before the axis has been drawn. - * - * @return The tick unit for the axis. - * - * @see #setTickUnit(NumberTickUnit) - * @see ValueAxis#isAutoTickUnitSelection() - */ - public NumberTickUnit getTickUnit() { - return this.tickUnit; - } - - /** - * Sets the tick unit for the axis and sends an {@link AxisChangeEvent} to - * all registered listeners. A side effect of calling this method is that - * the "auto-select" feature for tick units is switched off (you can - * restore it using the {@link ValueAxis#setAutoTickUnitSelection(boolean)} - * method). - * - * @param unit the new tick unit ({@code null} not permitted). - * - * @see #getTickUnit() - * @see #setTickUnit(NumberTickUnit, boolean, boolean) - */ - public void setTickUnit(NumberTickUnit unit) { - // defer argument checking... - setTickUnit(unit, true, true); - } - - /** - * Sets the tick unit for the axis and, if requested, sends an - * {@link AxisChangeEvent} to all registered listeners. In addition, an - * option is provided to turn off the "auto-select" feature for tick units - * (you can restore it using the - * {@link ValueAxis#setAutoTickUnitSelection(boolean)} method). - * - * @param unit the new tick unit ({@code null} not permitted). - * @param notify notify listeners? - * @param turnOffAutoSelect turn off the auto-tick selection? - */ - public void setTickUnit(NumberTickUnit unit, boolean notify, - boolean turnOffAutoSelect) { - - Args.nullNotPermitted(unit, "unit"); - this.tickUnit = unit; - if (turnOffAutoSelect) { - setAutoTickUnitSelection(false, false); - } - if (notify) { - notifyListeners(new AxisChangeEvent(this)); - } - - } - - /** * Returns the number format override. If this is non-null, then it will * be used to format the numbers on the axis. * @@ -632,53 +568,6 @@ } /** - * Draws the axis on a Java 2D graphics device (such as the screen or a - * printer). - * - * @param g2 the graphics device ({@code null} not permitted). - * @param cursor the cursor location. - * @param plotArea the area within which the axes and data should be drawn - * ({@code null} not permitted). - * @param dataArea the area within which the data should be drawn - * ({@code null} not permitted). - * @param edge the location of the axis ({@code null} not permitted). - * @param plotState collects information about the plot - * ({@code null} permitted). - * - * @return The axis state (never {@code null}). - */ - @Override - public AxisState draw(Graphics2D g2, double cursor, Rectangle2D plotArea, - Rectangle2D dataArea, RectangleEdge edge, - PlotRenderingInfo plotState) { - - AxisState state; - // if the axis is not visible, don't draw it... - if (!isVisible()) { - state = new AxisState(cursor); - // even though the axis is not visible, we need ticks for the - // gridlines... - List ticks = refreshTicks(g2, state, dataArea, edge); - state.setTicks(ticks); - return state; - } - - // draw the tick marks and labels... - state = drawTickMarksAndLabels(g2, cursor, plotArea, dataArea, edge); - - if (getAttributedLabel() != null) { - state = drawAttributedLabel(getAttributedLabel(), g2, plotArea, - dataArea, edge, state); - - } else { - state = drawLabel(getLabel(), g2, plotArea, dataArea, edge, state); - } - createAndAddEntity(cursor, state, dataArea, edge, plotState); - return state; - - } - - /** * Creates the standard tick units. *

* If you don't like these defaults, create your own instance of TickUnits @@ -742,23 +631,6 @@ } /** - * Estimates the maximum tick label height. - * - * @param g2 the graphics device. - * - * @return The maximum height. - */ - protected double estimateMaximumTickLabelHeight(Graphics2D g2) { - RectangleInsets tickLabelInsets = getTickLabelInsets(); - double result = tickLabelInsets.getTop() + tickLabelInsets.getBottom(); - - Font tickLabelFont = getTickLabelFont(); - FontRenderContext frc = g2.getFontRenderContext(); - result += tickLabelFont.getLineMetrics("123", frc).getHeight(); - return result; - } - - /** * Estimates the maximum width of the tick labels, assuming the specified * tick unit is used. *

@@ -942,10 +814,39 @@ * * @return A list of ticks. */ - protected List refreshTicksHorizontal(Graphics2D g2, - Rectangle2D dataArea, RectangleEdge edge) { + protected List refreshTicksHorizontal(Graphics2D g2, Rectangle2D dataArea, RectangleEdge edge) { + return refreshTicksRefactored(g2, dataArea, edge, false); + } + + /** + * Calculates the positions of the tick labels for the axis, storing the + * results in the tick label list (ready for drawing). + * + * @param g2 the graphics device. + * @param dataArea the area in which the plot should be drawn. + * @param edge the location of the axis. + * + * @return A list of ticks. + */ + protected List refreshTicksVertical(Graphics2D g2, Rectangle2D dataArea, RectangleEdge edge) { + return refreshTicksRefactored(g2, dataArea, edge, true); + } + + /** + * Calculates the positions of the tick labels for the axis, storing the + * results in the tick label list (ready for drawing). + * + * @param g2 the graphics device. + * @param dataArea the area in which the data should be drawn. + * @param edge the location of the axis. + * @param vertical boolean, true if vertical refresh, false if horizontal + * + * @return A list of ticks. + */ + protected List refreshTicksRefactored(Graphics2D g2, Rectangle2D dataArea, RectangleEdge edge, boolean vertical) { List result = new java.util.ArrayList(); + if(vertical) result.clear(); Font tickLabelFont = getTickLabelFont(); g2.setFont(tickLabelFont); @@ -983,31 +884,7 @@ else { tickLabel = getTickUnit().valueToString(currentTickValue); } - TextAnchor anchor, rotationAnchor; - double angle = 0.0; - if (isVerticalTickLabels()) { - anchor = TextAnchor.CENTER_RIGHT; - rotationAnchor = TextAnchor.CENTER_RIGHT; - if (edge == RectangleEdge.TOP) { - angle = Math.PI / 2.0; - } - else { - angle = -Math.PI / 2.0; - } - } - else { - if (edge == RectangleEdge.TOP) { - anchor = TextAnchor.BOTTOM_CENTER; - rotationAnchor = TextAnchor.BOTTOM_CENTER; - } - else { - anchor = TextAnchor.TOP_CENTER; - rotationAnchor = TextAnchor.TOP_CENTER; - } - } - - Tick tick = new NumberTick(new Double(currentTickValue), - tickLabel, anchor, rotationAnchor, angle); + Tick tick = refreshTick(edge, vertical, currentTickValue, tickLabel); result.add(tick); double nextTickValue = lowestTickValue + ((i + 1) * size); for (int minorTick = 1; minorTick < minorTickSpaces; @@ -1027,61 +904,46 @@ } - /** - * Calculates the positions of the tick labels for the axis, storing the - * results in the tick label list (ready for drawing). - * - * @param g2 the graphics device. - * @param dataArea the area in which the plot should be drawn. - * @param edge the location of the axis. - * - * @return A list of ticks. - */ - protected List refreshTicksVertical(Graphics2D g2, - Rectangle2D dataArea, RectangleEdge edge) { - List result = new java.util.ArrayList(); - result.clear(); - Font tickLabelFont = getTickLabelFont(); - g2.setFont(tickLabelFont); - if (isAutoTickUnitSelection()) { - selectAutoTickUnit(g2, dataArea, edge); + private Tick refreshTick(RectangleEdge edge, boolean vertical, double currentTickValue, String tickLabel) { + if(vertical) { + return getTickVerticallyRefreshed(edge, currentTickValue, tickLabel); + } else { + return getTickHorizontallyRefreshed(edge, currentTickValue, tickLabel); + } } - TickUnit tu = getTickUnit(); - double size = tu.getSize(); - int count = calculateVisibleTickCount(); - double lowestTickValue = calculateLowestVisibleTickValue(); - - if (count <= ValueAxis.MAXIMUM_TICK_COUNT) { - int minorTickSpaces = getMinorTickCount(); - if (minorTickSpaces <= 0) { - minorTickSpaces = tu.getMinorTickCount(); + protected Tick getTickHorizontallyRefreshed(RectangleEdge edge, double currentTickValue, String tickLabel) { + TextAnchor anchor, rotationAnchor; + double angle = 0.0; + if (isVerticalTickLabels()) { + anchor = TextAnchor.CENTER_RIGHT; + rotationAnchor = TextAnchor.CENTER_RIGHT; + if (edge == RectangleEdge.TOP) { + angle = Math.PI / 2.0; } - for (int minorTick = 1; minorTick < minorTickSpaces; minorTick++) { - double minorTickValue = lowestTickValue - - size * minorTick / minorTickSpaces; - if (getRange().contains(minorTickValue)) { - result.add(new NumberTick(TickType.MINOR, minorTickValue, - "", TextAnchor.TOP_CENTER, TextAnchor.CENTER, - 0.0)); + else { + angle = -Math.PI / 2.0; } } - - for (int i = 0; i < count; i++) { - double currentTickValue = lowestTickValue + (i * size); - String tickLabel; - NumberFormat formatter = getNumberFormatOverride(); - if (formatter != null) { - tickLabel = formatter.format(currentTickValue); + else { + if (edge == RectangleEdge.TOP) { + anchor = TextAnchor.BOTTOM_CENTER; + rotationAnchor = TextAnchor.BOTTOM_CENTER; } else { - tickLabel = getTickUnit().valueToString(currentTickValue); + anchor = TextAnchor.TOP_CENTER; + rotationAnchor = TextAnchor.TOP_CENTER; + } + } + Tick tick = new NumberTick(new Double(currentTickValue), + tickLabel, anchor, rotationAnchor, angle); + return tick; } - TextAnchor anchor; - TextAnchor rotationAnchor; + protected Tick getTickVerticallyRefreshed(RectangleEdge edge, double currentTickValue, String tickLabel) { + TextAnchor anchor, rotationAnchor; double angle = 0.0; if (isVerticalTickLabels()) { if (edge == RectangleEdge.LEFT) { @@ -1105,27 +967,9 @@ rotationAnchor = TextAnchor.CENTER_LEFT; } } - Tick tick = new NumberTick(new Double(currentTickValue), tickLabel, anchor, rotationAnchor, angle); - result.add(tick); - - double nextTickValue = lowestTickValue + ((i + 1) * size); - for (int minorTick = 1; minorTick < minorTickSpaces; - minorTick++) { - double minorTickValue = currentTickValue - + (nextTickValue - currentTickValue) - * minorTick / minorTickSpaces; - if (getRange().contains(minorTickValue)) { - result.add(new NumberTick(TickType.MINOR, - minorTickValue, "", TextAnchor.TOP_CENTER, - TextAnchor.CENTER, 0.0)); - } - } - } - } - return result; - + return tick; } /** diff -burN jfreechart-original/src/main/java/org/jfree/chart/axis/NumberLogCommon.java jfreechart-after-maintenance/src/main/java/org/jfree/chart/axis/NumberLogCommon.java --- jfreechart-original/src/main/java/org/jfree/chart/axis/NumberLogCommon.java 1970-01-01 01:00:00.000000000 +0100 +++ jfreechart-after-maintenance/src/main/java/org/jfree/chart/axis/NumberLogCommon.java 2022-04-17 18:12:48.000000000 +0200 @@ -0,0 +1,150 @@ +package org.jfree.chart.axis; + +import org.jfree.chart.event.AxisChangeEvent; +import org.jfree.chart.plot.PlotRenderingInfo; +import org.jfree.chart.ui.RectangleEdge; +import org.jfree.chart.ui.RectangleInsets; +import org.jfree.chart.util.Args; + +import java.awt.*; +import java.awt.font.FontRenderContext; +import java.awt.geom.Rectangle2D; +import java.util.List; + +import static org.jfree.chart.axis.NumberAxis.DEFAULT_TICK_UNIT; + +public abstract class NumberLogCommon extends ValueAxis { + + /** The tick unit for the axis. */ + protected TickUnit tickUnit; + + /** + * Constructs a value axis. + * + * @param label the axis label ({@code null} permitted). + * @param standardTickUnits the source for standard tick units + * ({@code null} permitted). + */ + protected NumberLogCommon(String label, TickUnitSource standardTickUnits) { + super(label, standardTickUnits); + this.tickUnit = DEFAULT_TICK_UNIT; + } + + /** + * Returns the current tick unit. + * + * @return The current tick unit. + * + * @see #setTickUnit(NumberTickUnit) + */ + public TickUnit getTickUnit() { + return this.tickUnit; + } + + /** + * Sets the tick unit for the axis and sends an {@link AxisChangeEvent} to + * all registered listeners. A side effect of calling this method is that + * the "auto-select" feature for tick units is switched off (you can + * restore it using the {@link ValueAxis#setAutoTickUnitSelection(boolean)} + * method). + * + * @param unit the new tick unit ({@code null} not permitted). + * + * @see #getTickUnit() + */ + public void setTickUnit(NumberTickUnit unit) { + // defer argument checking... + setTickUnit(unit, true, true); + } + + /** + * Sets the tick unit for the axis and, if requested, sends an + * {@link AxisChangeEvent} to all registered listeners. In addition, an + * option is provided to turn off the "auto-select" feature for tick units + * (you can restore it using the + * {@link ValueAxis#setAutoTickUnitSelection(boolean)} method). + * + * @param unit the new tick unit ({@code null} not permitted). + * @param notify notify listeners? + * @param turnOffAutoSelect turn off the auto-tick selection? + * + * @see #getTickUnit() + */ + public void setTickUnit(NumberTickUnit unit, boolean notify, + boolean turnOffAutoSelect) { + Args.nullNotPermitted(unit, "unit"); + this.tickUnit = unit; + if (turnOffAutoSelect) { + setAutoTickUnitSelection(false, false); + } + if (notify) { + fireChangeEvent(); + } + } + + /** + * Draws the axis on a Java 2D graphics device (such as the screen or a + * printer). + * + * @param g2 the graphics device ({@code null} not permitted). + * @param cursor the cursor location. + * @param plotArea the area within which the axes and data should be drawn + * ({@code null} not permitted). + * @param dataArea the area within which the data should be drawn + * ({@code null} not permitted). + * @param edge the location of the axis ({@code null} not permitted). + * @param plotState collects information about the plot + * ({@code null} permitted). + * + * @return The axis state (never {@code null}). + */ + @Override + public AxisState draw(Graphics2D g2, double cursor, Rectangle2D plotArea, + Rectangle2D dataArea, RectangleEdge edge, + PlotRenderingInfo plotState) { + + AxisState state; + // if the axis is not visible, don't draw it... + if (!isVisible()) { + state = new AxisState(cursor); + // even though the axis is not visible, we need ticks for the + // gridlines... + List ticks = refreshTicks(g2, state, dataArea, edge); + state.setTicks(ticks); + return state; + } + + // draw the tick marks and labels... + state = drawTickMarksAndLabels(g2, cursor, plotArea, dataArea, edge); + + if (getAttributedLabel() != null) { + state = drawAttributedLabel(getAttributedLabel(), g2, plotArea, + dataArea, edge, state); + + } else { + state = drawLabel(getLabel(), g2, plotArea, dataArea, edge, state); + } + createAndAddEntity(cursor, state, dataArea, edge, plotState); + return state; + + } + + /** + * Estimates the maximum tick label height. + * + * @param g2 the graphics device. + * + * @return The maximum height. + * + * @since 1.0.7 + */ + protected double estimateMaximumTickLabelHeight(Graphics2D g2) { + RectangleInsets tickLabelInsets = getTickLabelInsets(); + double result = tickLabelInsets.getTop() + tickLabelInsets.getBottom(); + + Font tickLabelFont = getTickLabelFont(); + FontRenderContext frc = g2.getFontRenderContext(); + result += tickLabelFont.getLineMetrics("123", frc).getHeight(); + return result; + } +} diff -burN jfreechart-original/src/main/java/org/jfree/chart/axis/PeriodAxis.java jfreechart-after-maintenance/src/main/java/org/jfree/chart/axis/PeriodAxis.java --- jfreechart-original/src/main/java/org/jfree/chart/axis/PeriodAxis.java 2022-03-07 09:23:25.000000000 +0100 +++ jfreechart-after-maintenance/src/main/java/org/jfree/chart/axis/PeriodAxis.java 2022-04-17 18:12:48.000000000 +0200 @@ -111,7 +111,7 @@ * displayed across the bottom or top of a plot, but is broken for display at * the left or right of charts. */ -public class PeriodAxis extends ValueAxis +public class PeriodAxis extends DatePeriodCommon implements Cloneable, PublicCloneable, Serializable { /** For serialization. */ @@ -966,35 +966,9 @@ public double valueToJava2D(double value, Rectangle2D area, RectangleEdge edge) { - double result = Double.NaN; double axisMin = this.first.getFirstMillisecond(); double axisMax = this.last.getLastMillisecond(); - if (RectangleEdge.isTopOrBottom(edge)) { - double minX = area.getX(); - double maxX = area.getMaxX(); - if (isInverted()) { - result = maxX + ((value - axisMin) / (axisMax - axisMin)) - * (minX - maxX); - } - else { - result = minX + ((value - axisMin) / (axisMax - axisMin)) - * (maxX - minX); - } - } - else if (RectangleEdge.isLeftOrRight(edge)) { - double minY = area.getMinY(); - double maxY = area.getMaxY(); - if (isInverted()) { - result = minY + (((value - axisMin) / (axisMax - axisMin)) - * (maxY - minY)); - } - else { - result = maxY - (((value - axisMin) / (axisMax - axisMin)) - * (maxY - minY)); - } - } - return result; - + return getCoordinates(value, area, edge, axisMin, axisMax); } /** diff -burN jfreechart-original/src/main/java/org/jfree/chart/ChartPanel.java jfreechart-after-maintenance/src/main/java/org/jfree/chart/ChartPanel.java --- jfreechart-original/src/main/java/org/jfree/chart/ChartPanel.java 2022-03-07 09:23:25.000000000 +0100 +++ jfreechart-after-maintenance/src/main/java/org/jfree/chart/ChartPanel.java 2022-04-17 18:12:48.000000000 +0200 @@ -219,7 +219,6 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.EventListener; -import java.util.Iterator; import java.util.List; import java.util.ResourceBundle; @@ -1403,7 +1402,7 @@ String result = null; if (this.info != null) { EntityCollection entities = this.info.getEntityCollection(); - if (entities != null) { + if ((entities != null) && (entities.getEntityCount() > 0)) { Insets insets = getInsets(); ChartEntity entity = entities.getEntity( (int) ((e.getX() - insets.left) / this.scaleX), @@ -1761,6 +1760,10 @@ */ @Override public void mouseEntered(MouseEvent e) { + mouseEnteredAction(); + } + + void mouseEnteredAction() { if (!this.ownToolTipDelaysActive) { ToolTipManager ttm = ToolTipManager.sharedInstance(); @@ -1786,6 +1789,10 @@ */ @Override public void mouseExited(MouseEvent e) { + mouseExitedAction(); + } + + void mouseExitedAction() { if (this.ownToolTipDelaysActive) { // restore original tooltip dealys ToolTipManager ttm = ToolTipManager.sharedInstance(); @@ -1806,23 +1813,27 @@ */ @Override public void mousePressed(MouseEvent e) { + mousePressedAction(e.getX(), e.getY(), e.getPoint(), e.isPopupTrigger(), e.getModifiers()); + } + + void mousePressedAction(int cursorX, int cursorY, Point cursorPoint, boolean popupTrigger, int cursorModifiers) { if (this.chart == null) { return; } Plot plot = this.chart.getPlot(); - int mods = e.getModifiers(); + int mods = cursorModifiers; if ((mods & this.panMask) == this.panMask) { // can we pan this plot? if (plot instanceof Pannable) { Pannable pannable = (Pannable) plot; if (pannable.isDomainPannable() || pannable.isRangePannable()) { - Rectangle2D screenDataArea = getScreenDataArea(e.getX(), - e.getY()); + Rectangle2D screenDataArea = getScreenDataArea(cursorX, + cursorY); if (screenDataArea != null && screenDataArea.contains( - e.getPoint())) { + cursorPoint)) { this.panW = screenDataArea.getWidth(); this.panH = screenDataArea.getHeight(); - this.panLast = e.getPoint(); + this.panLast = cursorPoint; setCursor(Cursor.getPredefinedCursor( Cursor.MOVE_CURSOR)); } @@ -1832,17 +1843,17 @@ } } else if (this.zoomRectangle == null) { - Rectangle2D screenDataArea = getScreenDataArea(e.getX(), e.getY()); + Rectangle2D screenDataArea = getScreenDataArea(cursorX, cursorY); if (screenDataArea != null) { - this.zoomPoint = getPointInRectangle(e.getX(), e.getY(), + this.zoomPoint = getPointInRectangle(cursorX, cursorY, screenDataArea); } else { this.zoomPoint = null; } - if (e.isPopupTrigger()) { + if (popupTrigger) { if (this.popup != null) { - displayPopupMenu(e.getX(), e.getY()); + displayPopupMenu(cursorX, cursorY); } } } @@ -1858,7 +1869,7 @@ * * @return A point within the rectangle. */ - private Point2D getPointInRectangle(int x, int y, Rectangle2D area) { + Point2D getPointInRectangle(int x, int y, Rectangle2D area) { double xx = Math.max(area.getMinX(), Math.min(x, area.getMaxX())); double yy = Math.max(area.getMinY(), Math.min(y, area.getMaxY())); return new Point2D.Double(xx, yy); @@ -1879,30 +1890,7 @@ // handle panning if we have a start point if (this.panLast != null) { - double dx = e.getX() - this.panLast.getX(); - double dy = e.getY() - this.panLast.getY(); - if (dx == 0.0 && dy == 0.0) { - return; - } - double wPercent = -dx / this.panW; - double hPercent = dy / this.panH; - boolean old = this.chart.getPlot().isNotify(); - this.chart.getPlot().setNotify(false); - Pannable p = (Pannable) this.chart.getPlot(); - if (p.getOrientation() == PlotOrientation.VERTICAL) { - p.panDomainAxes(wPercent, this.info.getPlotInfo(), - this.panLast); - p.panRangeAxes(hPercent, this.info.getPlotInfo(), - this.panLast); - } - else { - p.panDomainAxes(hPercent, this.info.getPlotInfo(), - this.panLast); - p.panRangeAxes(wPercent, this.info.getPlotInfo(), - this.panLast); - } - this.panLast = e.getPoint(); - this.chart.getPlot().setNotify(old); + mouseDraggedHandlePanning(e.getX(), e.getY(), e.getPoint()); return; } @@ -1920,6 +1908,22 @@ drawZoomRectangle(g2, true); } + setZoomRectangle(e.getX(), e.getY(), this.zoomPoint); + + // Draw the new zoom rectangle... + if (this.useBuffer) { + repaint(); + } + else { + // with no buffer, we use XOR to draw the rectangle "over" the + // chart... + drawZoomRectangle(g2, true); + } + g2.dispose(); + + } + + void setZoomRectangle(int x, int y, Point2D zoomPoint) { boolean hZoom, vZoom; if (this.orientation == PlotOrientation.HORIZONTAL) { hZoom = this.rangeZoomable; @@ -1930,39 +1934,54 @@ vZoom = this.rangeZoomable; } Rectangle2D scaledDataArea = getScreenDataArea( - (int) this.zoomPoint.getX(), (int) this.zoomPoint.getY()); + (int) zoomPoint.getX(), (int) zoomPoint.getY()); if (hZoom && vZoom) { // selected rectangle shouldn't extend outside the data area... - double xmax = Math.min(e.getX(), scaledDataArea.getMaxX()); - double ymax = Math.min(e.getY(), scaledDataArea.getMaxY()); + double xmax = Math.min(x, scaledDataArea.getMaxX()); + double ymax = Math.min(y, scaledDataArea.getMaxY()); this.zoomRectangle = new Rectangle2D.Double( - this.zoomPoint.getX(), this.zoomPoint.getY(), - xmax - this.zoomPoint.getX(), ymax - this.zoomPoint.getY()); + zoomPoint.getX(), zoomPoint.getY(), + xmax - zoomPoint.getX(), ymax - zoomPoint.getY()); } else if (hZoom) { - double xmax = Math.min(e.getX(), scaledDataArea.getMaxX()); + double xmax = Math.min(x, scaledDataArea.getMaxX()); this.zoomRectangle = new Rectangle2D.Double( - this.zoomPoint.getX(), scaledDataArea.getMinY(), - xmax - this.zoomPoint.getX(), scaledDataArea.getHeight()); + zoomPoint.getX(), scaledDataArea.getMinY(), + xmax - zoomPoint.getX(), scaledDataArea.getHeight()); } else if (vZoom) { - double ymax = Math.min(e.getY(), scaledDataArea.getMaxY()); + double ymax = Math.min(y, scaledDataArea.getMaxY()); this.zoomRectangle = new Rectangle2D.Double( - scaledDataArea.getMinX(), this.zoomPoint.getY(), - scaledDataArea.getWidth(), ymax - this.zoomPoint.getY()); + scaledDataArea.getMinX(), zoomPoint.getY(), + scaledDataArea.getWidth(), ymax - zoomPoint.getY()); + } } - // Draw the new zoom rectangle... - if (this.useBuffer) { - repaint(); + void mouseDraggedHandlePanning(int x, int y, Point point) { + double dx = x - this.panLast.getX(); + double dy = y - this.panLast.getY(); + if (dx == 0.0 && dy == 0.0) { + return; + } + double wPercent = -dx / this.panW; + double hPercent = dy / this.panH; + boolean old = this.chart.getPlot().isNotify(); + this.chart.getPlot().setNotify(false); + Pannable p = (Pannable) this.chart.getPlot(); + if (p.getOrientation() == PlotOrientation.VERTICAL) { + p.panDomainAxes(wPercent, this.info.getPlotInfo(), + this.panLast); + p.panRangeAxes(hPercent, this.info.getPlotInfo(), + this.panLast); } else { - // with no buffer, we use XOR to draw the rectangle "over" the - // chart... - drawZoomRectangle(g2, true); + p.panDomainAxes(hPercent, this.info.getPlotInfo(), + this.panLast); + p.panRangeAxes(wPercent, this.info.getPlotInfo(), + this.panLast); } - g2.dispose(); - + this.panLast = point; + this.chart.getPlot().setNotify(old); } /** @@ -1975,6 +1994,11 @@ @Override public void mouseReleased(MouseEvent e) { + mouseReleasedAction(e.getX(), e.getY(), e.isPopupTrigger(), this.zoomPoint); + + } + + void mouseReleasedAction(int x, int y, boolean popupTrigger, Point2D zoomPoint) { // if we've been panning, we need to reset now that the mouse is // released... if (this.panLast != null) { @@ -1993,48 +2017,17 @@ vZoom = this.rangeZoomable; } - boolean zoomTrigger1 = hZoom && Math.abs(e.getX() - - this.zoomPoint.getX()) >= this.zoomTriggerDistance; - boolean zoomTrigger2 = vZoom && Math.abs(e.getY() - - this.zoomPoint.getY()) >= this.zoomTriggerDistance; + boolean zoomTrigger1 = hZoom && Math.abs(x + - zoomPoint.getX()) >= this.zoomTriggerDistance; + boolean zoomTrigger2 = vZoom && Math.abs(y + - zoomPoint.getY()) >= this.zoomTriggerDistance; if (zoomTrigger1 || zoomTrigger2) { - if ((hZoom && (e.getX() < this.zoomPoint.getX())) - || (vZoom && (e.getY() < this.zoomPoint.getY()))) { + if ((hZoom && (x < zoomPoint.getX())) + || (vZoom && (y < zoomPoint.getY()))) { restoreAutoBounds(); } else { - double x, y, w, h; - Rectangle2D screenDataArea = getScreenDataArea( - (int) this.zoomPoint.getX(), - (int) this.zoomPoint.getY()); - double maxX = screenDataArea.getMaxX(); - double maxY = screenDataArea.getMaxY(); - // for mouseReleased event, (horizontalZoom || verticalZoom) - // will be true, so we can just test for either being false; - // otherwise both are true - if (!vZoom) { - x = this.zoomPoint.getX(); - y = screenDataArea.getMinY(); - w = Math.min(this.zoomRectangle.getWidth(), - maxX - this.zoomPoint.getX()); - h = screenDataArea.getHeight(); - } - else if (!hZoom) { - x = screenDataArea.getMinX(); - y = this.zoomPoint.getY(); - w = screenDataArea.getWidth(); - h = Math.min(this.zoomRectangle.getHeight(), - maxY - this.zoomPoint.getY()); - } - else { - x = this.zoomPoint.getX(); - y = this.zoomPoint.getY(); - w = Math.min(this.zoomRectangle.getWidth(), - maxX - this.zoomPoint.getX()); - h = Math.min(this.zoomRectangle.getHeight(), - maxY - this.zoomPoint.getY()); - } - Rectangle2D zoomArea = new Rectangle2D.Double(x, y, w, h); + Rectangle2D zoomArea = getZoomArea(hZoom, vZoom, zoomPoint, this.zoomRectangle); zoom(zoomArea); } this.zoomPoint = null; @@ -2056,12 +2049,47 @@ } - else if (e.isPopupTrigger()) { + else if (popupTrigger) { if (this.popup != null) { - displayPopupMenu(e.getX(), e.getY()); + displayPopupMenu(x, y); + } } } + Rectangle2D getZoomArea(boolean hZoom, boolean vZoom, Point2D zoomPoint, Rectangle2D zoomRectangle) { + double x, y, w, h; + Rectangle2D screenDataArea = getScreenDataArea( + (int) zoomPoint.getX(), + (int) zoomPoint.getY()); + double maxX = screenDataArea.getMaxX(); + double maxY = screenDataArea.getMaxY(); + // for mouseReleased event, (horizontalZoom || verticalZoom) + // will be true, so we can just test for either being false; + // otherwise both are true + if (! vZoom) { + x = zoomPoint.getX(); + y = screenDataArea.getMinY(); + w = Math.min(zoomRectangle.getWidth(), + maxX - zoomPoint.getX()); + h = screenDataArea.getHeight(); + } + else if (! hZoom) { + x = screenDataArea.getMinX(); + y = zoomPoint.getY(); + w = screenDataArea.getWidth(); + h = Math.min(zoomRectangle.getHeight(), + maxY - zoomPoint.getY()); + } + else { + x = zoomPoint.getX(); + y = zoomPoint.getY(); + w = Math.min(zoomRectangle.getWidth(), + maxX - zoomPoint.getX()); + h = Math.min(zoomRectangle.getHeight(), + maxY - zoomPoint.getY()); + } + Rectangle2D zoomArea = new Rectangle2D.Double(x, y, w, h); + return zoomArea; } /** @@ -2685,12 +2713,7 @@ * @throws IOException if there is an I/O error. */ public void doSaveAs() throws IOException { - JFileChooser fileChooser = new JFileChooser(); - fileChooser.setCurrentDirectory(this.defaultDirectoryForSaveAs); - FileNameExtensionFilter filter = new FileNameExtensionFilter( - localizationResources.getString("PNG_Image_Files"), "png"); - fileChooser.addChoosableFileFilter(filter); - fileChooser.setFileFilter(filter); + JFileChooser fileChooser = createFileChooser("PNG_Image_Files", "png"); int option = fileChooser.showSaveDialog(this); if (option == JFileChooser.APPROVE_OPTION) { @@ -2711,37 +2734,13 @@ * if the JFreeSVG library is on the classpath...if this library is not * present, the method will fail. */ - private void saveAsSVG(File f) throws IOException { + void saveAsSVG(File f) throws IOException { File file = f; if (file == null) { - JFileChooser fileChooser = new JFileChooser(); - fileChooser.setCurrentDirectory(this.defaultDirectoryForSaveAs); - FileNameExtensionFilter filter = new FileNameExtensionFilter( - localizationResources.getString("SVG_Files"), "svg"); - fileChooser.addChoosableFileFilter(filter); - fileChooser.setFileFilter(filter); + JFileChooser fileChooser = createFileChooser("SVG_Files", "svg"); int option = fileChooser.showSaveDialog(this); - if (option == JFileChooser.APPROVE_OPTION) { - String filename = fileChooser.getSelectedFile().getPath(); - if (isEnforceFileExtensions()) { - if (!filename.endsWith(".svg")) { - filename = filename + ".svg"; - } - } - file = new File(filename); - if (file.exists()) { - String fileExists = localizationResources.getString( - "FILE_EXISTS_CONFIRM_OVERWRITE"); - int response = JOptionPane.showConfirmDialog(this, - fileExists, - localizationResources.getString("Save_as_SVG"), - JOptionPane.OK_CANCEL_OPTION); - if (response == JOptionPane.CANCEL_OPTION) { - file = null; - } - } - } + file = saveFile(option, fileChooser, ".svg", file, "Save_as_SVG"); } if (file != null) { @@ -2766,6 +2765,43 @@ } } + File saveFile(int option, JFileChooser fileChooser, String suffix, File file, String saveAs) { + if (option == JFileChooser.APPROVE_OPTION) { + String filename = fileChooser.getSelectedFile().getPath(); + if (isEnforceFileExtensions()) { + if (!filename.endsWith(suffix)) { + filename = filename + suffix; + } + } + file = new File(filename); + if (file.exists()) { + file = dealWithExistingFile(file, JOptionPane.showConfirmDialog(this, + localizationResources.getString( + "FILE_EXISTS_CONFIRM_OVERWRITE"), + localizationResources.getString(saveAs), + JOptionPane.OK_CANCEL_OPTION)); + } + } + return file; + } + + File dealWithExistingFile(File file, int response) { + if (response == JOptionPane.CANCEL_OPTION) { + file = null; + } + return file; + } + + JFileChooser createFileChooser(String description, String extension) { + JFileChooser fileChooser = new JFileChooser(); + fileChooser.setCurrentDirectory(this.defaultDirectoryForSaveAs); + FileNameExtensionFilter filter = new FileNameExtensionFilter( + localizationResources.getString(description), extension); + fileChooser.addChoosableFileFilter(filter); + fileChooser.setFileFilter(filter); + return fileChooser; + } + /** * Generates a string containing a rendering of the chart in SVG format. * This feature is only supported if the JFreeSVG library is included on @@ -2775,7 +2811,7 @@ * {@code null} if there is a problem with the method invocation * by reflection. */ - private String generateSVG(int width, int height) { + String generateSVG(int width, int height) { Graphics2D g2 = createSVGGraphics2D(width, height); if (g2 == null) { throw new IllegalStateException("JFreeSVG library is not present."); @@ -2834,34 +2870,10 @@ private void saveAsPDF(File f) { File file = f; if (file == null) { - JFileChooser fileChooser = new JFileChooser(); - fileChooser.setCurrentDirectory(this.defaultDirectoryForSaveAs); - FileNameExtensionFilter filter = new FileNameExtensionFilter( - localizationResources.getString("PDF_Files"), "pdf"); - fileChooser.addChoosableFileFilter(filter); - fileChooser.setFileFilter(filter); + JFileChooser fileChooser = createFileChooser("PDF_Files", "pdf"); int option = fileChooser.showSaveDialog(this); - if (option == JFileChooser.APPROVE_OPTION) { - String filename = fileChooser.getSelectedFile().getPath(); - if (isEnforceFileExtensions()) { - if (!filename.endsWith(".pdf")) { - filename = filename + ".pdf"; - } - } - file = new File(filename); - if (file.exists()) { - String fileExists = localizationResources.getString( - "FILE_EXISTS_CONFIRM_OVERWRITE"); - int response = JOptionPane.showConfirmDialog(this, - fileExists, - localizationResources.getString("Save_as_PDF"), - JOptionPane.OK_CANCEL_OPTION); - if (response == JOptionPane.CANCEL_OPTION) { - file = null; - } - } - } + file = saveFile(option, fileChooser, ".pdf", file, "Save_as_PDF"); } if (file != null) { @@ -3320,4 +3332,24 @@ } + public boolean isOwnToolTipDelaysActive() { + return ownToolTipDelaysActive; + } + + public Point getPanLast() { + return panLast; + } + + public void setPanLast(Point panLast) { + this.panLast = panLast; + } + + public Point2D getZoomPoint() { + return zoomPoint; + } + + public Rectangle2D getZoomRectangle() { + return zoomRectangle; + } + } diff -burN jfreechart-original/src/main/java/org/jfree/chart/plot/CategoryPlot.java jfreechart-after-maintenance/src/main/java/org/jfree/chart/plot/CategoryPlot.java --- jfreechart-original/src/main/java/org/jfree/chart/plot/CategoryPlot.java 2022-03-07 09:23:25.000000000 +0100 +++ jfreechart-after-maintenance/src/main/java/org/jfree/chart/plot/CategoryPlot.java 2022-04-17 18:12:48.000000000 +0200 @@ -219,6 +219,7 @@ import java.util.TreeMap; import org.jfree.chart.JFreeChart; import org.jfree.chart.LegendItemCollection; +import org.jfree.chart.LegendItemSource; import org.jfree.chart.annotations.Annotation; import org.jfree.chart.annotations.CategoryAnnotation; import org.jfree.chart.axis.Axis; @@ -233,11 +234,9 @@ import org.jfree.chart.axis.ValueTick; import org.jfree.chart.event.AnnotationChangeEvent; import org.jfree.chart.event.AnnotationChangeListener; -import org.jfree.chart.event.ChartChangeEventType; import org.jfree.chart.event.PlotChangeEvent; import org.jfree.chart.event.RendererChangeEvent; import org.jfree.chart.event.RendererChangeListener; -import org.jfree.chart.renderer.category.AbstractCategoryItemRenderer; import org.jfree.chart.renderer.category.CategoryItemRenderer; import org.jfree.chart.renderer.category.CategoryItemRendererState; import org.jfree.chart.ui.Layer; @@ -262,7 +261,7 @@ * A general plotting class that uses data from a {@link CategoryDataset} and * renders each data item using a {@link CategoryItemRenderer}. */ -public class CategoryPlot extends Plot implements ValueAxisPlot, Pannable, +public class CategoryPlot extends CategoryXYCommon implements ValueAxisPlot, Pannable, Zoomable, AnnotationChangeListener, RendererChangeListener, Cloneable, PublicCloneable, Serializable { @@ -320,29 +319,15 @@ = ResourceBundleWrapper.getBundle( "org.jfree.chart.plot.LocalizationBundle"); - /** The plot orientation. */ - private PlotOrientation orientation; - - /** The offset between the data area and the axes. */ - private RectangleInsets axisOffset; - /** Storage for the domain axes. */ private Map domainAxes; - /** Storage for the domain axis locations. */ - private Map domainAxisLocations; - /** * A flag that controls whether or not the shared domain axis is drawn * (only relevant when the plot is being used as a subplot). */ private boolean drawSharedDomainAxis; - /** Storage for the range axes. */ - private Map rangeAxes; - - /** Storage for the range axis locations. */ - private Map rangeAxisLocations; /** Storage for the datasets. */ private Map datasets; @@ -417,40 +402,6 @@ */ private transient Paint rangeZeroBaselinePaint; - /** - * A flag that controls whether the grid-lines for the range axis are - * visible. - */ - private boolean rangeGridlinesVisible; - - /** The stroke used to draw the range axis grid-lines. */ - private transient Stroke rangeGridlineStroke; - - /** The paint used to draw the range axis grid-lines. */ - private transient Paint rangeGridlinePaint; - - /** - * A flag that controls whether or not gridlines are shown for the minor - * tick values on the primary range axis. - * - * @since 1.0.13 - */ - private boolean rangeMinorGridlinesVisible; - - /** - * The stroke used to draw the range minor grid-lines. - * - * @since 1.0.13 - */ - private transient Stroke rangeMinorGridlineStroke; - - /** - * The paint used to draw the range minor grid-lines. - * - * @since 1.0.13 - */ - private transient Paint rangeMinorGridlinePaint; - /** The anchor value. */ private double anchorValue; @@ -515,17 +466,6 @@ */ private boolean rangeCrosshairLockedOnData = true; - /** A map containing lists of markers for the domain axes. */ - private Map foregroundDomainMarkers; - - /** A map containing lists of markers for the domain axes. */ - private Map backgroundDomainMarkers; - - /** A map containing lists of markers for the range axes. */ - private Map foregroundRangeMarkers; - - /** A map containing lists of markers for the range axes. */ - private Map backgroundRangeMarkers; /** * A (possibly empty) list of annotations for the plot. The list should @@ -859,100 +799,6 @@ } /** - * Returns the domain axis location for the primary domain axis. - * - * @return The location (never {@code null}). - * - * @see #getRangeAxisLocation() - */ - public AxisLocation getDomainAxisLocation() { - return getDomainAxisLocation(0); - } - - /** - * Returns the location for a domain axis. - * - * @param index the axis index. - * - * @return The location. - * - * @see #setDomainAxisLocation(int, AxisLocation) - */ - public AxisLocation getDomainAxisLocation(int index) { - AxisLocation result = this.domainAxisLocations.get(index); - if (result == null) { - result = AxisLocation.getOpposite(getDomainAxisLocation(0)); - } - return result; - } - - /** - * Sets the location of the domain axis and sends a {@link PlotChangeEvent} - * to all registered listeners. - * - * @param location the axis location ({@code null} not permitted). - * - * @see #getDomainAxisLocation() - * @see #setDomainAxisLocation(int, AxisLocation) - */ - public void setDomainAxisLocation(AxisLocation location) { - // delegate... - setDomainAxisLocation(0, location, true); - } - - /** - * Sets the location of the domain axis and, if requested, sends a - * {@link PlotChangeEvent} to all registered listeners. - * - * @param location the axis location ({@code null} not permitted). - * @param notify a flag that controls whether listeners are notified. - */ - public void setDomainAxisLocation(AxisLocation location, boolean notify) { - // delegate... - setDomainAxisLocation(0, location, notify); - } - - /** - * Sets the location for a domain axis and sends a {@link PlotChangeEvent} - * to all registered listeners. - * - * @param index the axis index. - * @param location the location. - * - * @see #getDomainAxisLocation(int) - * @see #setRangeAxisLocation(int, AxisLocation) - */ - public void setDomainAxisLocation(int index, AxisLocation location) { - // delegate... - setDomainAxisLocation(index, location, true); - } - - /** - * Sets the location for a domain axis and sends a {@link PlotChangeEvent} - * to all registered listeners. - * - * @param index the axis index. - * @param location the location. - * @param notify notify listeners? - * - * @since 1.0.5 - * - * @see #getDomainAxisLocation(int) - * @see #setRangeAxisLocation(int, AxisLocation, boolean) - */ - public void setDomainAxisLocation(int index, AxisLocation location, - boolean notify) { - if (index == 0 && location == null) { - throw new IllegalArgumentException( - "Null 'location' for index 0 not permitted."); - } - this.domainAxisLocations.put(index, location); - if (notify) { - fireChangeEvent(); - } - } - - /** * Returns the domain axis edge. This is derived from the axis location * and the plot orientation. * @@ -1014,16 +860,6 @@ } } - /** - * Returns the range axis for the plot. If the range axis for this plot is - * null, then the method will return the parent plot's range axis (if there - * is a parent plot). - * - * @return The range axis (possibly {@code null}). - */ - public ValueAxis getRangeAxis() { - return getRangeAxis(0); - } /** * Returns a range axis. @@ -1032,6 +868,7 @@ * * @return The axis ({@code null} possible). */ + @Override public ValueAxis getRangeAxis(int index) { ValueAxis result = this.rangeAxes.get(index); if (result == null) { @@ -1050,6 +887,7 @@ * * @param axis the axis ({@code null} permitted). */ + @Override public void setRangeAxis(ValueAxis axis) { setRangeAxis(0, axis); } @@ -1065,31 +903,6 @@ setRangeAxis(index, axis, true); } - /** - * Sets a range axis and, if requested, sends a {@link PlotChangeEvent} to - * all registered listeners. - * - * @param index the axis index. - * @param axis the axis. - * @param notify notify listeners? - */ - public void setRangeAxis(int index, ValueAxis axis, boolean notify) { - ValueAxis existing = this.rangeAxes.get(index); - if (existing != null) { - existing.removeChangeListener(this); - } - if (axis != null) { - axis.setPlot(this); - } - this.rangeAxes.put(index, axis); - if (axis != null) { - axis.configure(); - axis.addChangeListener(this); - } - if (notify) { - fireChangeEvent(); - } - } /** * Sets the range axes for this plot and sends a {@link PlotChangeEvent} @@ -1132,104 +945,6 @@ return result; } - private int findRangeAxisIndex(ValueAxis axis) { - for (Entry entry : this.rangeAxes.entrySet()) { - if (entry.getValue() == axis) { - return entry.getKey(); - } - } - return -1; - } - - /** - * Returns the range axis location. - * - * @return The location (never {@code null}). - */ - public AxisLocation getRangeAxisLocation() { - return getRangeAxisLocation(0); - } - - /** - * Returns the location for a range axis. - * - * @param index the axis index. - * - * @return The location. - * - * @see #setRangeAxisLocation(int, AxisLocation) - */ - public AxisLocation getRangeAxisLocation(int index) { - AxisLocation result = this.rangeAxisLocations.get(index); - if (result == null) { - result = AxisLocation.getOpposite(getRangeAxisLocation(0)); - } - return result; - } - - /** - * Sets the location of the range axis and sends a {@link PlotChangeEvent} - * to all registered listeners. - * - * @param location the location ({@code null} not permitted). - * - * @see #setRangeAxisLocation(AxisLocation, boolean) - * @see #setDomainAxisLocation(AxisLocation) - */ - public void setRangeAxisLocation(AxisLocation location) { - // defer argument checking... - setRangeAxisLocation(location, true); - } - - /** - * Sets the location of the range axis and, if requested, sends a - * {@link PlotChangeEvent} to all registered listeners. - * - * @param location the location ({@code null} not permitted). - * @param notify notify listeners? - * - * @see #setDomainAxisLocation(AxisLocation, boolean) - */ - public void setRangeAxisLocation(AxisLocation location, boolean notify) { - setRangeAxisLocation(0, location, notify); - } - - /** - * Sets the location for a range axis and sends a {@link PlotChangeEvent} - * to all registered listeners. - * - * @param index the axis index. - * @param location the location. - * - * @see #getRangeAxisLocation(int) - * @see #setRangeAxisLocation(int, AxisLocation, boolean) - */ - public void setRangeAxisLocation(int index, AxisLocation location) { - setRangeAxisLocation(index, location, true); - } - - /** - * Sets the location for a range axis and sends a {@link PlotChangeEvent} - * to all registered listeners. - * - * @param index the axis index. - * @param location the location. - * @param notify notify listeners? - * - * @see #getRangeAxisLocation(int) - * @see #setDomainAxisLocation(int, AxisLocation, boolean) - */ - public void setRangeAxisLocation(int index, AxisLocation location, - boolean notify) { - if (index == 0 && location == null) { - throw new IllegalArgumentException( - "Null 'location' for index 0 not permitted."); - } - this.rangeAxisLocations.put(index, location); - if (notify) { - fireChangeEvent(); - } - } /** * Returns the edge where the primary range axis is located. @@ -1252,39 +967,6 @@ return Plot.resolveRangeAxisLocation(location, this.orientation); } - /** - * Returns the number of range axes. - * - * @return The axis count. - */ - public int getRangeAxisCount() { - return this.rangeAxes.size(); - } - - /** - * Clears the range axes from the plot and sends a {@link PlotChangeEvent} - * to all registered listeners. - */ - public void clearRangeAxes() { - for (ValueAxis yAxis : this.rangeAxes.values()) { - if (yAxis != null) { - yAxis.removeChangeListener(this); - } - } - this.rangeAxes.clear(); - fireChangeEvent(); - } - - /** - * Configures the range axes. - */ - public void configureRangeAxes() { - for (ValueAxis yAxis : this.rangeAxes.values()) { - if (yAxis != null) { - yAxis.configure(); - } - } - } /** * Returns the primary dataset for the plot. @@ -1973,177 +1655,6 @@ } /** - * Returns the flag that controls whether the range grid-lines are visible. - * - * @return The flag. - * - * @see #setRangeGridlinesVisible(boolean) - */ - public boolean isRangeGridlinesVisible() { - return this.rangeGridlinesVisible; - } - - /** - * Sets the flag that controls whether or not grid-lines are drawn against - * the range axis. If the flag changes value, a {@link PlotChangeEvent} is - * sent to all registered listeners. - * - * @param visible the new value of the flag. - * - * @see #isRangeGridlinesVisible() - */ - public void setRangeGridlinesVisible(boolean visible) { - if (this.rangeGridlinesVisible != visible) { - this.rangeGridlinesVisible = visible; - fireChangeEvent(); - } - } - - /** - * Returns the stroke used to draw the grid-lines against the range axis. - * - * @return The stroke (never {@code null}). - * - * @see #setRangeGridlineStroke(Stroke) - */ - public Stroke getRangeGridlineStroke() { - return this.rangeGridlineStroke; - } - - /** - * Sets the stroke used to draw the grid-lines against the range axis and - * sends a {@link PlotChangeEvent} to all registered listeners. - * - * @param stroke the stroke ({@code null} not permitted). - * - * @see #getRangeGridlineStroke() - */ - public void setRangeGridlineStroke(Stroke stroke) { - Args.nullNotPermitted(stroke, "stroke"); - this.rangeGridlineStroke = stroke; - fireChangeEvent(); - } - - /** - * Returns the paint used to draw the grid-lines against the range axis. - * - * @return The paint (never {@code null}). - * - * @see #setRangeGridlinePaint(Paint) - */ - public Paint getRangeGridlinePaint() { - return this.rangeGridlinePaint; - } - - /** - * Sets the paint used to draw the grid lines against the range axis and - * sends a {@link PlotChangeEvent} to all registered listeners. - * - * @param paint the paint ({@code null} not permitted). - * - * @see #getRangeGridlinePaint() - */ - public void setRangeGridlinePaint(Paint paint) { - Args.nullNotPermitted(paint, "paint"); - this.rangeGridlinePaint = paint; - fireChangeEvent(); - } - - /** - * Returns {@code true} if the range axis minor grid is visible, and - * {@code false} otherwise. - * - * @return A boolean. - * - * @see #setRangeMinorGridlinesVisible(boolean) - * - * @since 1.0.13 - */ - public boolean isRangeMinorGridlinesVisible() { - return this.rangeMinorGridlinesVisible; - } - - /** - * Sets the flag that controls whether or not the range axis minor grid - * lines are visible. - *

- * If the flag value is changed, a {@link PlotChangeEvent} is sent to all - * registered listeners. - * - * @param visible the new value of the flag. - * - * @see #isRangeMinorGridlinesVisible() - * - * @since 1.0.13 - */ - public void setRangeMinorGridlinesVisible(boolean visible) { - if (this.rangeMinorGridlinesVisible != visible) { - this.rangeMinorGridlinesVisible = visible; - fireChangeEvent(); - } - } - - /** - * Returns the stroke for the minor grid lines (if any) plotted against the - * range axis. - * - * @return The stroke (never {@code null}). - * - * @see #setRangeMinorGridlineStroke(Stroke) - * - * @since 1.0.13 - */ - public Stroke getRangeMinorGridlineStroke() { - return this.rangeMinorGridlineStroke; - } - - /** - * Sets the stroke for the minor grid lines plotted against the range axis, - * and sends a {@link PlotChangeEvent} to all registered listeners. - * - * @param stroke the stroke ({@code null} not permitted). - * - * @see #getRangeMinorGridlineStroke() - * - * @since 1.0.13 - */ - public void setRangeMinorGridlineStroke(Stroke stroke) { - Args.nullNotPermitted(stroke, "stroke"); - this.rangeMinorGridlineStroke = stroke; - fireChangeEvent(); - } - - /** - * Returns the paint for the minor grid lines (if any) plotted against the - * range axis. - * - * @return The paint (never {@code null}). - * - * @see #setRangeMinorGridlinePaint(Paint) - * - * @since 1.0.13 - */ - public Paint getRangeMinorGridlinePaint() { - return this.rangeMinorGridlinePaint; - } - - /** - * Sets the paint for the minor grid lines plotted against the range axis - * and sends a {@link PlotChangeEvent} to all registered listeners. - * - * @param paint the paint ({@code null} not permitted). - * - * @see #getRangeMinorGridlinePaint() - * - * @since 1.0.13 - */ - public void setRangeMinorGridlinePaint(Paint paint) { - Args.nullNotPermitted(paint, "paint"); - this.rangeMinorGridlinePaint = paint; - fireChangeEvent(); - } - - /** * Returns the fixed legend items, if any. * * @return The legend items (possibly {@code null}). @@ -2273,18 +1784,8 @@ */ @Override public void datasetChanged(DatasetChangeEvent event) { - for (ValueAxis yAxis : this.rangeAxes.values()) { - if (yAxis != null) { - yAxis.configure(); - } - } - if (getParent() != null) { - getParent().datasetChanged(event); - } else { - PlotChangeEvent e = new PlotChangeEvent(this); - e.setType(ChartChangeEventType.DATASET_UPDATED); - notifyListeners(e); - } + configureRangeAxes(); + dealWithEventWhenDatasetChanges(event); } @@ -2361,261 +1862,6 @@ } /** - * Adds a marker for display by a particular renderer and, if requested, - * sends a {@link PlotChangeEvent} to all registered listeners. - *

- * Typically a marker will be drawn by the renderer as a line perpendicular - * to a domain axis, however this is entirely up to the renderer. - * - * @param index the renderer index. - * @param marker the marker ({@code null} not permitted). - * @param layer the layer ({@code null} not permitted). - * @param notify notify listeners? - * - * @since 1.0.10 - * - * @see #removeDomainMarker(int, Marker, Layer, boolean) - */ - public void addDomainMarker(int index, CategoryMarker marker, Layer layer, - boolean notify) { - Args.nullNotPermitted(marker, "marker"); - Args.nullNotPermitted(layer, "layer"); - Collection markers; - if (layer == Layer.FOREGROUND) { - markers = (Collection) this.foregroundDomainMarkers.get( - new Integer(index)); - if (markers == null) { - markers = new java.util.ArrayList(); - this.foregroundDomainMarkers.put(new Integer(index), markers); - } - markers.add(marker); - } else if (layer == Layer.BACKGROUND) { - markers = (Collection) this.backgroundDomainMarkers.get( - new Integer(index)); - if (markers == null) { - markers = new java.util.ArrayList(); - this.backgroundDomainMarkers.put(new Integer(index), markers); - } - markers.add(marker); - } - marker.addChangeListener(this); - if (notify) { - fireChangeEvent(); - } - } - - /** - * Clears all the domain markers for the plot and sends a - * {@link PlotChangeEvent} to all registered listeners. - * - * @see #clearRangeMarkers() - */ - public void clearDomainMarkers() { - if (this.backgroundDomainMarkers != null) { - Set keys = this.backgroundDomainMarkers.keySet(); - Iterator iterator = keys.iterator(); - while (iterator.hasNext()) { - Integer key = (Integer) iterator.next(); - clearDomainMarkers(key.intValue()); - } - this.backgroundDomainMarkers.clear(); - } - if (this.foregroundDomainMarkers != null) { - Set keys = this.foregroundDomainMarkers.keySet(); - Iterator iterator = keys.iterator(); - while (iterator.hasNext()) { - Integer key = (Integer) iterator.next(); - clearDomainMarkers(key.intValue()); - } - this.foregroundDomainMarkers.clear(); - } - fireChangeEvent(); - } - - /** - * Returns the list of domain markers (read only) for the specified layer. - * - * @param layer the layer (foreground or background). - * - * @return The list of domain markers. - */ - public Collection getDomainMarkers(Layer layer) { - return getDomainMarkers(0, layer); - } - - /** - * Returns a collection of domain markers for a particular renderer and - * layer. - * - * @param index the renderer index. - * @param layer the layer. - * - * @return A collection of markers (possibly {@code null}). - */ - public Collection getDomainMarkers(int index, Layer layer) { - Collection result = null; - Integer key = new Integer(index); - if (layer == Layer.FOREGROUND) { - result = (Collection) this.foregroundDomainMarkers.get(key); - } - else if (layer == Layer.BACKGROUND) { - result = (Collection) this.backgroundDomainMarkers.get(key); - } - if (result != null) { - result = Collections.unmodifiableCollection(result); - } - return result; - } - - /** - * Clears all the domain markers for the specified renderer. - * - * @param index the renderer index. - * - * @see #clearRangeMarkers(int) - */ - public void clearDomainMarkers(int index) { - Integer key = new Integer(index); - if (this.backgroundDomainMarkers != null) { - Collection markers - = (Collection) this.backgroundDomainMarkers.get(key); - if (markers != null) { - Iterator iterator = markers.iterator(); - while (iterator.hasNext()) { - Marker m = (Marker) iterator.next(); - m.removeChangeListener(this); - } - markers.clear(); - } - } - if (this.foregroundDomainMarkers != null) { - Collection markers - = (Collection) this.foregroundDomainMarkers.get(key); - if (markers != null) { - Iterator iterator = markers.iterator(); - while (iterator.hasNext()) { - Marker m = (Marker) iterator.next(); - m.removeChangeListener(this); - } - markers.clear(); - } - } - fireChangeEvent(); - } - - /** - * Removes a marker for the domain axis and sends a {@link PlotChangeEvent} - * to all registered listeners. - * - * @param marker the marker. - * - * @return A boolean indicating whether or not the marker was actually - * removed. - * - * @since 1.0.7 - */ - public boolean removeDomainMarker(Marker marker) { - return removeDomainMarker(marker, Layer.FOREGROUND); - } - - /** - * Removes a marker for the domain axis in the specified layer and sends a - * {@link PlotChangeEvent} to all registered listeners. - * - * @param marker the marker ({@code null} not permitted). - * @param layer the layer (foreground or background). - * - * @return A boolean indicating whether or not the marker was actually - * removed. - * - * @since 1.0.7 - */ - public boolean removeDomainMarker(Marker marker, Layer layer) { - return removeDomainMarker(0, marker, layer); - } - - /** - * Removes a marker for a specific dataset/renderer and sends a - * {@link PlotChangeEvent} to all registered listeners. - * - * @param index the dataset/renderer index. - * @param marker the marker. - * @param layer the layer (foreground or background). - * - * @return A boolean indicating whether or not the marker was actually - * removed. - * - * @since 1.0.7 - */ - public boolean removeDomainMarker(int index, Marker marker, Layer layer) { - return removeDomainMarker(index, marker, layer, true); - } - - /** - * Removes a marker for a specific dataset/renderer and, if requested, - * sends a {@link PlotChangeEvent} to all registered listeners. - * - * @param index the dataset/renderer index. - * @param marker the marker. - * @param layer the layer (foreground or background). - * @param notify notify listeners? - * - * @return A boolean indicating whether or not the marker was actually - * removed. - * - * @since 1.0.10 - */ - public boolean removeDomainMarker(int index, Marker marker, Layer layer, - boolean notify) { - ArrayList markers; - if (layer == Layer.FOREGROUND) { - markers = (ArrayList) this.foregroundDomainMarkers.get(new Integer( - index)); - } else { - markers = (ArrayList) this.backgroundDomainMarkers.get(new Integer( - index)); - } - if (markers == null) { - return false; - } - boolean removed = markers.remove(marker); - if (removed && notify) { - fireChangeEvent(); - } - return removed; - } - - /** - * Adds a marker for display (in the foreground) against the range axis and - * sends a {@link PlotChangeEvent} to all registered listeners. Typically a - * marker will be drawn by the renderer as a line perpendicular to the - * range axis, however this is entirely up to the renderer. - * - * @param marker the marker ({@code null} not permitted). - * - * @see #removeRangeMarker(Marker) - */ - public void addRangeMarker(Marker marker) { - addRangeMarker(marker, Layer.FOREGROUND); - } - - /** - * Adds a marker for display against the range axis and sends a - * {@link PlotChangeEvent} to all registered listeners. Typically a marker - * will be drawn by the renderer as a line perpendicular to the range axis, - * however this is entirely up to the renderer. - * - * @param marker the marker ({@code null} not permitted). - * @param layer the layer (foreground or background) ({@code null} - * not permitted). - * - * @see #removeRangeMarker(Marker, Layer) - */ - public void addRangeMarker(Marker marker, Layer layer) { - addRangeMarker(0, marker, layer); - } - - /** * Adds a marker for display by a particular renderer and sends a * {@link PlotChangeEvent} to all registered listeners. *

@@ -2675,34 +1921,6 @@ } /** - * Clears all the range markers for the plot and sends a - * {@link PlotChangeEvent} to all registered listeners. - * - * @see #clearDomainMarkers() - */ - public void clearRangeMarkers() { - if (this.backgroundRangeMarkers != null) { - Set keys = this.backgroundRangeMarkers.keySet(); - Iterator iterator = keys.iterator(); - while (iterator.hasNext()) { - Integer key = (Integer) iterator.next(); - clearRangeMarkers(key.intValue()); - } - this.backgroundRangeMarkers.clear(); - } - if (this.foregroundRangeMarkers != null) { - Set keys = this.foregroundRangeMarkers.keySet(); - Iterator iterator = keys.iterator(); - while (iterator.hasNext()) { - Integer key = (Integer) iterator.next(); - clearRangeMarkers(key.intValue()); - } - this.foregroundRangeMarkers.clear(); - } - fireChangeEvent(); - } - - /** * Returns the list of range markers (read only) for the specified layer. * * @param layer the layer (foreground or background). @@ -2740,96 +1958,6 @@ } /** - * Clears all the range markers for the specified renderer. - * - * @param index the renderer index. - * - * @see #clearDomainMarkers(int) - */ - public void clearRangeMarkers(int index) { - Integer key = new Integer(index); - if (this.backgroundRangeMarkers != null) { - Collection markers - = (Collection) this.backgroundRangeMarkers.get(key); - if (markers != null) { - Iterator iterator = markers.iterator(); - while (iterator.hasNext()) { - Marker m = (Marker) iterator.next(); - m.removeChangeListener(this); - } - markers.clear(); - } - } - if (this.foregroundRangeMarkers != null) { - Collection markers - = (Collection) this.foregroundRangeMarkers.get(key); - if (markers != null) { - Iterator iterator = markers.iterator(); - while (iterator.hasNext()) { - Marker m = (Marker) iterator.next(); - m.removeChangeListener(this); - } - markers.clear(); - } - } - fireChangeEvent(); - } - - /** - * Removes a marker for the range axis and sends a {@link PlotChangeEvent} - * to all registered listeners. - * - * @param marker the marker. - * - * @return A boolean indicating whether or not the marker was actually - * removed. - * - * @since 1.0.7 - * - * @see #addRangeMarker(Marker) - */ - public boolean removeRangeMarker(Marker marker) { - return removeRangeMarker(marker, Layer.FOREGROUND); - } - - /** - * Removes a marker for the range axis in the specified layer and sends a - * {@link PlotChangeEvent} to all registered listeners. - * - * @param marker the marker ({@code null} not permitted). - * @param layer the layer (foreground or background). - * - * @return A boolean indicating whether or not the marker was actually - * removed. - * - * @since 1.0.7 - * - * @see #addRangeMarker(Marker, Layer) - */ - public boolean removeRangeMarker(Marker marker, Layer layer) { - return removeRangeMarker(0, marker, layer); - } - - /** - * Removes a marker for a specific dataset/renderer and sends a - * {@link PlotChangeEvent} to all registered listeners. - * - * @param index the dataset/renderer index. - * @param marker the marker. - * @param layer the layer (foreground or background). - * - * @return A boolean indicating whether or not the marker was actually - * removed. - * - * @since 1.0.7 - * - * @see #addRangeMarker(int, Marker, Layer) - */ - public boolean removeRangeMarker(int index, Marker marker, Layer layer) { - return removeRangeMarker(index, marker, layer, true); - } - - /** * Removes a marker for a specific dataset/renderer and sends a * {@link PlotChangeEvent} to all registered listeners. * @@ -3425,13 +2553,7 @@ } } else { // reserve space for the range axes (if any)... - for (ValueAxis yAxis : this.rangeAxes.values()) { - if (yAxis != null) { - int i = findRangeAxisIndex(yAxis); - RectangleEdge edge = getRangeAxisEdge(i); - space = yAxis.reserveSpace(g2, this, plotArea, edge, space); - } - } + space = reserveSpaceForTheRangeAxes(g2, plotArea, space); } return space; @@ -3511,7 +2633,7 @@ // calculate the data area... AxisSpace space = calculateAxisSpace(g2, area); Rectangle2D dataArea = space.shrink(area, null); - this.axisOffset.trim(dataArea); + trimAxisOffset(dataArea); dataArea = integerise(dataArea); if (dataArea.isEmpty()) { return; @@ -3769,7 +2891,7 @@ * * @return A map containing the axis states. */ - protected Map drawAxes(Graphics2D g2, Rectangle2D plotArea, + protected Map drawAxes(Graphics2D g2, Rectangle2D plotArea, Rectangle2D dataArea, PlotRenderingInfo plotState) { AxisCollection axisCollection = new AxisCollection(); @@ -3782,73 +2904,7 @@ } } - // add range axes to lists... - for (ValueAxis yAxis : this.rangeAxes.values()) { - if (yAxis != null) { - int index = findRangeAxisIndex(yAxis); - axisCollection.add(yAxis, getRangeAxisEdge(index)); - } - } - - Map axisStateMap = new HashMap(); - - // draw the top axes - double cursor = dataArea.getMinY() - this.axisOffset.calculateTopOutset( - dataArea.getHeight()); - Iterator iterator = axisCollection.getAxesAtTop().iterator(); - while (iterator.hasNext()) { - Axis axis = (Axis) iterator.next(); - if (axis != null) { - AxisState axisState = axis.draw(g2, cursor, plotArea, dataArea, - RectangleEdge.TOP, plotState); - cursor = axisState.getCursor(); - axisStateMap.put(axis, axisState); - } - } - - // draw the bottom axes - cursor = dataArea.getMaxY() - + this.axisOffset.calculateBottomOutset(dataArea.getHeight()); - iterator = axisCollection.getAxesAtBottom().iterator(); - while (iterator.hasNext()) { - Axis axis = (Axis) iterator.next(); - if (axis != null) { - AxisState axisState = axis.draw(g2, cursor, plotArea, dataArea, - RectangleEdge.BOTTOM, plotState); - cursor = axisState.getCursor(); - axisStateMap.put(axis, axisState); - } - } - - // draw the left axes - cursor = dataArea.getMinX() - - this.axisOffset.calculateLeftOutset(dataArea.getWidth()); - iterator = axisCollection.getAxesAtLeft().iterator(); - while (iterator.hasNext()) { - Axis axis = (Axis) iterator.next(); - if (axis != null) { - AxisState axisState = axis.draw(g2, cursor, plotArea, dataArea, - RectangleEdge.LEFT, plotState); - cursor = axisState.getCursor(); - axisStateMap.put(axis, axisState); - } - } - - // draw the right axes - cursor = dataArea.getMaxX() - + this.axisOffset.calculateRightOutset(dataArea.getWidth()); - iterator = axisCollection.getAxesAtRight().iterator(); - while (iterator.hasNext()) { - Axis axis = (Axis) iterator.next(); - if (axis != null) { - AxisState axisState = axis.draw(g2, cursor, plotArea, dataArea, - RectangleEdge.RIGHT, plotState); - cursor = axisState.getCursor(); - axisStateMap.put(axis, axisState); - } - } - - return axisStateMap; + return extractedDraw(g2, plotArea, dataArea, plotState, axisCollection); } @@ -4689,24 +3745,8 @@ public void zoomRangeAxes(double factor, PlotRenderingInfo info, Point2D source, boolean useAnchor) { - // perform the zoom on each range axis - for (ValueAxis rangeAxis : this.rangeAxes.values()) { - if (rangeAxis == null) { - continue; - } - if (useAnchor) { - // get the relevant source coordinate given the plot orientation - double sourceY = source.getY(); - if (this.orientation.isHorizontal()) { - sourceY = source.getX(); - } - double anchorY = rangeAxis.java2DToValue(sourceY, - info.getDataArea(), getRangeAxisEdge()); - rangeAxis.resizeRange2(factor, anchorY); - } else { - rangeAxis.resizeRange(factor); - } - } + zoomRangeAxesWithFactor(factor, info, source, useAnchor); + } /** @@ -4720,13 +3760,10 @@ @Override public void zoomRangeAxes(double lowerPercent, double upperPercent, PlotRenderingInfo state, Point2D source) { - for (ValueAxis yAxis : this.rangeAxes.values()) { - if (yAxis != null) { - yAxis.zoomRange(lowerPercent, upperPercent); - } - } + zoomRangeAxesDefault(lowerPercent, upperPercent); } + /** * Returns the anchor value. * diff -burN jfreechart-original/src/main/java/org/jfree/chart/plot/CategoryXYCommon.java jfreechart-after-maintenance/src/main/java/org/jfree/chart/plot/CategoryXYCommon.java --- jfreechart-original/src/main/java/org/jfree/chart/plot/CategoryXYCommon.java 1970-01-01 01:00:00.000000000 +0100 +++ jfreechart-after-maintenance/src/main/java/org/jfree/chart/plot/CategoryXYCommon.java 2022-04-17 18:12:48.000000000 +0200 @@ -0,0 +1,1026 @@ +package org.jfree.chart.plot; + +import org.jfree.chart.axis.*; +import org.jfree.chart.event.ChartChangeEventType; +import org.jfree.chart.event.PlotChangeEvent; +import org.jfree.chart.ui.Layer; +import org.jfree.chart.ui.RectangleEdge; +import org.jfree.chart.ui.RectangleInsets; +import org.jfree.chart.util.Args; +import org.jfree.data.general.DatasetChangeEvent; + +import java.awt.*; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.util.*; + +public abstract class CategoryXYCommon extends Plot { + + + /** Storage for the range axes. */ + protected Map rangeAxes; + + /** Storage for the range axis locations. */ + protected Map rangeAxisLocations; + + /** The offset between the data area and the axes. */ + protected RectangleInsets axisOffset; + + /** The plot orientation. */ + protected PlotOrientation orientation; + + /** Storage for the domain axis locations. */ + protected Map domainAxisLocations; + /** + * The stroke used to draw the range minor grid-lines. + * + * @since 1.0.13 + */ + protected transient Stroke rangeMinorGridlineStroke; + /** + * The paint used to draw the range minor grid-lines. + * + * @since 1.0.13 + */ + protected transient Paint rangeMinorGridlinePaint; + /** + * A flag that controls whether the grid-lines for the range axis are + * visible. + */ + protected boolean rangeGridlinesVisible; + + /** A map containing lists of markers for the domain axes. */ + protected Map foregroundDomainMarkers; + + /** A map containing lists of markers for the domain axes. */ + protected Map backgroundDomainMarkers; + + /** A map containing lists of markers for the range axes. */ + protected Map foregroundRangeMarkers; + + /** A map containing lists of markers for the range axes. */ + protected Map backgroundRangeMarkers; + + /** + * A flag that controls whether or not gridlines are shown for the minor + * tick values on the primary range axis. + * + * @since 1.0.13 + */ + protected boolean rangeMinorGridlinesVisible; + + /** The stroke used to draw the range axis grid-lines. */ + protected transient Stroke rangeGridlineStroke; + + /** The paint used to draw the range axis grid-lines. */ + protected transient Paint rangeGridlinePaint; + + + /** + * Returns the range axis for the plot. If the range axis for this plot is + * null, then the method will return the parent plot's range axis (if there + * is a parent plot). + * + * @return The range axis (possibly {@code null}). + */ + public ValueAxis getRangeAxis() { + return getRangeAxis(0); + } + + public abstract ValueAxis getRangeAxis(int index); + public abstract void setRangeAxis(ValueAxis axis); + + + /** + * Returns the number of range axes. + * + * @return The axis count. + */ + public int getRangeAxisCount() { + return this.rangeAxes.size(); + } + + + /** + * Clears the range axes from the plot and sends a {@link PlotChangeEvent} + * to all registered listeners. + */ + public void clearRangeAxes() { + for (ValueAxis axis : this.rangeAxes.values()) { + if (axis != null) { + axis.removeChangeListener(this); + } + } + this.rangeAxes.clear(); + fireChangeEvent(); + } + + /** + * Configures the range axes. + */ + public void configureRangeAxes() { + for (ValueAxis axis : this.rangeAxes.values()) { + if (axis != null) { + axis.configure(); + } + } + } + + + protected void dealWithEventWhenDatasetChanges(DatasetChangeEvent event) { + if (getParent() != null) { + getParent().datasetChanged(event); + } else { + PlotChangeEvent e = new PlotChangeEvent(this); + e.setType(ChartChangeEventType.DATASET_UPDATED); + notifyListeners(e); + } + } + + /** + * Sets a range axis and, if requested, sends a {@link PlotChangeEvent} to + * all registered listeners. + * + * @param index the axis index. + * @param axis the axis. + * @param notify notify listeners? + */ + public void setRangeAxis(int index, ValueAxis axis, boolean notify) { + ValueAxis existing = this.rangeAxes.get(index); + if (existing != null) { + existing.removeChangeListener(this); + } + if (axis != null) { + axis.setPlot(this); + } + this.rangeAxes.put(index, axis); + if (axis != null) { + axis.configure(); + axis.addChangeListener(this); + } + if (notify) { + fireChangeEvent(); + } + } + + /** + * Sets the location for a range axis and sends a {@link PlotChangeEvent} + * to all registered listeners. + * + * @param index the axis index. + * @param location the location. + * + * @see #getRangeAxisLocation(int) + * @see #setRangeAxisLocation(int, AxisLocation, boolean) + */ + public void setRangeAxisLocation(int index, AxisLocation location) { + setRangeAxisLocation(index, location, true); + } + + /** + * Sets the location for a range axis and sends a {@link PlotChangeEvent} + * to all registered listeners. + * + * @param index the axis index. + * @param location the location. + * @param notify notify listeners? + * + * @see #getRangeAxisLocation(int) + * @see #setDomainAxisLocation(int, AxisLocation, boolean) + */ + public void setRangeAxisLocation(int index, AxisLocation location, + boolean notify) { + if (index == 0 && location == null) { + throw new IllegalArgumentException( + "Null 'location' for index 0 not permitted."); + } + this.rangeAxisLocations.put(index, location); + if (notify) { + fireChangeEvent(); + } + } + /** + * Sets the location of the range axis and sends a {@link PlotChangeEvent} + * to all registered listeners. + * + * @param location the location ({@code null} not permitted). + * + * @see #setRangeAxisLocation(AxisLocation, boolean) + * @see #setDomainAxisLocation(AxisLocation) + */ + public void setRangeAxisLocation(AxisLocation location) { + // defer argument checking... + setRangeAxisLocation(location, true); + } + + /** + * Sets the location of the range axis and, if requested, sends a + * {@link PlotChangeEvent} to all registered listeners. + * + * @param location the location ({@code null} not permitted). + * @param notify notify listeners? + * + * @see #setDomainAxisLocation(AxisLocation, boolean) + */ + public void setRangeAxisLocation(AxisLocation location, boolean notify) { + setRangeAxisLocation(0, location, notify); + } + + /** + * Returns the location for a range axis. + * + * @param index the axis index. + * + * @return The location. + * + * @see #setRangeAxisLocation(int, AxisLocation) + */ + public AxisLocation getRangeAxisLocation(int index) { + AxisLocation result = this.rangeAxisLocations.get(index); + if (result == null) { + result = AxisLocation.getOpposite(getRangeAxisLocation(0)); + } + return result; + } + + protected int findRangeAxisIndex(ValueAxis axis) { + for (Map.Entry entry : this.rangeAxes.entrySet()) { + if (entry.getValue() == axis) { + return entry.getKey(); + } + } + return -1; + } + + /** + * Returns the range axis location. + * + * @return The location (never {@code null}). + */ + public AxisLocation getRangeAxisLocation() { + return getRangeAxisLocation(0); + } + + + /** + * Sets the location of the domain axis and sends a {@link PlotChangeEvent} + * to all registered listeners. + * + * @param location the axis location ({@code null} not permitted). + * + * @see #getDomainAxisLocation() + * @see #setDomainAxisLocation(int, AxisLocation) + */ + public void setDomainAxisLocation(AxisLocation location) { + // delegate... + setDomainAxisLocation(0, location, true); + } + + /** + * Sets the location of the domain axis and, if requested, sends a + * {@link PlotChangeEvent} to all registered listeners. + * + * @param location the axis location ({@code null} not permitted). + * @param notify a flag that controls whether listeners are notified. + */ + public void setDomainAxisLocation(AxisLocation location, boolean notify) { + // delegate... + setDomainAxisLocation(0, location, notify); + } + + + /** + * Sets the location for a domain axis and sends a {@link PlotChangeEvent} + * to all registered listeners. + * + * @param index the axis index. + * @param location the location. + * + * @see #getDomainAxisLocation(int) + * @see #setRangeAxisLocation(int, AxisLocation) + */ + public void setDomainAxisLocation(int index, AxisLocation location) { + // delegate... + setDomainAxisLocation(index, location, true); + } + + /** + * Returns the location for a domain axis. If this hasn't been set + * explicitly, the method returns the location that is opposite to the + * primary domain axis location. + * + * @param index the axis index (must be >= 0). + * + * @return The location (never {@code null}). + * + * @see #setDomainAxisLocation(int, AxisLocation) + */ + public AxisLocation getDomainAxisLocation(int index) { + AxisLocation result = this.domainAxisLocations.get(index); + if (result == null) { + result = AxisLocation.getOpposite(getDomainAxisLocation()); + } + return result; + } + + + /** + * Returns the domain axis location for the primary domain axis. + * + * @return The location (never {@code null}). + * + * @see #getRangeAxisLocation() + */ + public AxisLocation getDomainAxisLocation() { + return getDomainAxisLocation(0); + } + + /** + * Sets the location for a domain axis and sends a {@link PlotChangeEvent} + * to all registered listeners. + * + * @param index the axis index. + * @param location the location. + * @param notify notify listeners? + * + * @since 1.0.5 + * + * @see #getDomainAxisLocation(int) + * @see #setRangeAxisLocation(int, AxisLocation, boolean) + */ + public void setDomainAxisLocation(int index, AxisLocation location, + boolean notify) { + if (index == 0 && location == null) { + throw new IllegalArgumentException( + "Null 'location' for index 0 not permitted."); + } + this.domainAxisLocations.put(index, location); + if (notify) { + fireChangeEvent(); + } + } + + protected AxisSpace reserveSpaceForTheRangeAxes(Graphics2D g2, Rectangle2D plotArea, AxisSpace space) { + for (ValueAxis yAxis : this.rangeAxes.values()) { + if (yAxis != null) { + int i = findRangeAxisIndex(yAxis); + RectangleEdge edge = getRangeAxisEdge(i); + space = yAxis.reserveSpace(g2, this, plotArea, edge, space); + } + } + return space; + } + + protected abstract RectangleEdge getRangeAxisEdge(int i); + + + protected void addRangesToList(AxisCollection axisCollection) { + for (ValueAxis axis : this.rangeAxes.values()) { + if (axis != null) { + int index = findRangeAxisIndex(axis); + axisCollection.add(axis, getRangeAxisEdge(index)); + } + } + } + + protected Map extractedDraw(Graphics2D g2, Rectangle2D plotArea, Rectangle2D dataArea, PlotRenderingInfo plotState, AxisCollection axisCollection) { + // add range axes to lists... + addRangesToList(axisCollection); + + Map axisStateMap = new HashMap(); + + // draw the top axes + Iterator iterator = axisCollection.getAxesAtTop().iterator(); + double cursor = dataArea.getMinY() - this.axisOffset.calculateTopOutset(dataArea.getHeight()); + drawTheAxes(iterator, cursor, g2, plotArea, dataArea, plotState, axisStateMap, RectangleEdge.TOP); + + // draw the bottom axes + iterator = axisCollection.getAxesAtBottom().iterator(); + cursor = dataArea.getMaxY() + this.axisOffset.calculateBottomOutset(dataArea.getHeight()); + drawTheAxes(iterator, cursor, g2, plotArea, dataArea, plotState, axisStateMap, RectangleEdge.BOTTOM); + + // draw the left axes + iterator = axisCollection.getAxesAtLeft().iterator(); + cursor = dataArea.getMinX() - this.axisOffset.calculateLeftOutset(dataArea.getWidth()); + drawTheAxes(iterator, cursor, g2, plotArea, dataArea, plotState, axisStateMap, RectangleEdge.LEFT); + + // draw the right axes + iterator = axisCollection.getAxesAtRight().iterator(); + cursor = dataArea.getMaxX() + this.axisOffset.calculateRightOutset(dataArea.getWidth()); + drawTheAxes(iterator, cursor, g2, plotArea, dataArea, plotState, axisStateMap, RectangleEdge.RIGHT); + + return axisStateMap; + } + + + private void drawTheAxes(Iterator iterator, double cursor, Graphics2D g2, Rectangle2D plotArea, Rectangle2D dataArea, PlotRenderingInfo plotState, Map axisStateMap, RectangleEdge rectangleEdge) { + while (iterator.hasNext()) { + Axis axis = (Axis) iterator.next(); + if (axis != null) { + AxisState axisState = axis.draw(g2, cursor, plotArea, dataArea, + rectangleEdge, plotState); + cursor = axisState.getCursor(); + axisStateMap.put(axis, axisState); + } + } + } + + protected void trimAxisOffset(Rectangle2D dataArea) { + this.axisOffset.trim(dataArea); + } + + protected void zoomRangeAxesWithFactor(double factor, PlotRenderingInfo info, Point2D source, boolean useAnchor) { + // perform the zoom on each range axis + for (ValueAxis rangeAxis : this.rangeAxes.values()) { + if (rangeAxis == null) { + continue; + } + if (useAnchor) { + // get the relevant source coordinate given the plot orientation + double sourceY = source.getY(); + if (this.orientation.isHorizontal()) { + sourceY = source.getX(); + } + double anchorY = rangeAxis.java2DToValue(sourceY, + info.getDataArea(), getRangeAxisEdge()); + rangeAxis.resizeRange2(factor, anchorY); + } else { + rangeAxis.resizeRange(factor); + } + } + } + + protected abstract RectangleEdge getRangeAxisEdge(); + + protected void zoomRangeAxesDefault(double lowerPercent, double upperPercent) { + for (ValueAxis yAxis : this.rangeAxes.values()) { + if (yAxis != null) { + yAxis.zoomRange(lowerPercent, upperPercent); + } + } + } + + /** + * Returns the stroke used to draw the grid-lines against the range axis. + * + * @return The stroke (never {@code null}). + * + * @see #setRangeGridlineStroke(Stroke) + */ + public Stroke getRangeGridlineStroke() { + return this.rangeGridlineStroke; + } + + /** + * Sets the stroke used to draw the grid-lines against the range axis and + * sends a {@link PlotChangeEvent} to all registered listeners. + * + * @param stroke the stroke ({@code null} not permitted). + * + * @see #getRangeGridlineStroke() + */ + public void setRangeGridlineStroke(Stroke stroke) { + Args.nullNotPermitted(stroke, "stroke"); + this.rangeGridlineStroke = stroke; + fireChangeEvent(); + } + + /** + * Returns the paint used to draw the grid-lines against the range axis. + * + * @return The paint (never {@code null}). + * + * @see #setRangeGridlinePaint(Paint) + */ + public Paint getRangeGridlinePaint() { + return this.rangeGridlinePaint; + } + + /** + * Sets the paint used to draw the grid lines against the range axis and + * sends a {@link PlotChangeEvent} to all registered listeners. + * + * @param paint the paint ({@code null} not permitted). + * + * @see #getRangeGridlinePaint() + */ + public void setRangeGridlinePaint(Paint paint) { + Args.nullNotPermitted(paint, "paint"); + this.rangeGridlinePaint = paint; + fireChangeEvent(); + } + + /** + * Returns {@code true} if the range axis minor grid is visible, and + * {@code false} otherwise. + * + * @return A boolean. + * + * @see #setRangeMinorGridlinesVisible(boolean) + * + * @since 1.0.13 + */ + public boolean isRangeMinorGridlinesVisible() { + return this.rangeMinorGridlinesVisible; + } + + /** + * Sets the flag that controls whether or not the range axis minor grid + * lines are visible. + *

+ * If the flag value is changed, a {@link PlotChangeEvent} is sent to all + * registered listeners. + * + * @param visible the new value of the flag. + * + * @see #isRangeMinorGridlinesVisible() + * + * @since 1.0.13 + */ + public void setRangeMinorGridlinesVisible(boolean visible) { + if (this.rangeMinorGridlinesVisible != visible) { + this.rangeMinorGridlinesVisible = visible; + fireChangeEvent(); + } + } + + /** + * Returns the stroke for the minor grid lines (if any) plotted against the + * range axis. + * + * @return The stroke (never {@code null}). + * + * @see #setRangeMinorGridlineStroke(Stroke) + * + * @since 1.0.13 + */ + public Stroke getRangeMinorGridlineStroke() { + return this.rangeMinorGridlineStroke; + } + + /** + * Sets the stroke for the minor grid lines plotted against the range axis, + * and sends a {@link PlotChangeEvent} to all registered listeners. + * + * @param stroke the stroke ({@code null} not permitted). + * + * @see #getRangeMinorGridlineStroke() + * + * @since 1.0.13 + */ + public void setRangeMinorGridlineStroke(Stroke stroke) { + Args.nullNotPermitted(stroke, "stroke"); + this.rangeMinorGridlineStroke = stroke; + fireChangeEvent(); + } + + /** + * Returns the paint for the minor grid lines (if any) plotted against the + * range axis. + * + * @return The paint (never {@code null}). + * + * @see #setRangeMinorGridlinePaint(Paint) + * + * @since 1.0.13 + */ + public Paint getRangeMinorGridlinePaint() { + return this.rangeMinorGridlinePaint; + } + + /** + * Sets the paint for the minor grid lines plotted against the range axis + * and sends a {@link PlotChangeEvent} to all registered listeners. + * + * @param paint the paint ({@code null} not permitted). + * + * @see #getRangeMinorGridlinePaint() + * + * @since 1.0.13 + */ + public void setRangeMinorGridlinePaint(Paint paint) { + Args.nullNotPermitted(paint, "paint"); + this.rangeMinorGridlinePaint = paint; + fireChangeEvent(); + } + + + /** + * Clears all the domain markers for the plot and sends a + * {@link PlotChangeEvent} to all registered listeners. + * + * @see #clearRangeMarkers() + */ + public void clearDomainMarkers() { + if (this.backgroundDomainMarkers != null) { + Set keys = this.backgroundDomainMarkers.keySet(); + Iterator iterator = keys.iterator(); + while (iterator.hasNext()) { + Integer key = (Integer) iterator.next(); + clearDomainMarkers(key.intValue()); + } + this.backgroundDomainMarkers.clear(); + } + if (this.foregroundDomainMarkers != null) { + Set keys = this.foregroundDomainMarkers.keySet(); + Iterator iterator = keys.iterator(); + while (iterator.hasNext()) { + Integer key = (Integer) iterator.next(); + clearDomainMarkers(key.intValue()); + } + this.foregroundDomainMarkers.clear(); + } + fireChangeEvent(); + } + /** + * Clears all the domain markers for the specified renderer. + * + * @param index the renderer index. + * + * @see #clearRangeMarkers(int) + */ + public void clearDomainMarkers(int index) { + Integer key = new Integer(index); + if (this.backgroundDomainMarkers != null) { + Collection markers + = (Collection) this.backgroundDomainMarkers.get(key); + if (markers != null) { + Iterator iterator = markers.iterator(); + while (iterator.hasNext()) { + Marker m = (Marker) iterator.next(); + m.removeChangeListener(this); + } + markers.clear(); + } + } + if (this.foregroundDomainMarkers != null) { + Collection markers + = (Collection) this.foregroundDomainMarkers.get(key); + if (markers != null) { + Iterator iterator = markers.iterator(); + while (iterator.hasNext()) { + Marker m = (Marker) iterator.next(); + m.removeChangeListener(this); + } + markers.clear(); + } + } + fireChangeEvent(); + } + + /** + * Adds a marker for display by a particular renderer and, if requested, + * sends a {@link PlotChangeEvent} to all registered listeners. + *

+ * Typically a marker will be drawn by the renderer as a line perpendicular + * to a domain axis, however this is entirely up to the renderer. + * + * @param index the renderer index. + * @param marker the marker ({@code null} not permitted). + * @param layer the layer ({@code null} not permitted). + * @param notify notify listeners? + * + * @since 1.0.10 + * + * @see #removeDomainMarker(int, Marker, Layer, boolean) + */ + public void addDomainMarker(int index, CategoryMarker marker, Layer layer, + boolean notify) { + Args.nullNotPermitted(marker, "marker"); + Args.nullNotPermitted(layer, "layer"); + Collection markers; + if (layer == Layer.FOREGROUND) { + markers = (Collection) this.foregroundDomainMarkers.get( + new Integer(index)); + if (markers == null) { + markers = new java.util.ArrayList(); + this.foregroundDomainMarkers.put(new Integer(index), markers); + } + markers.add(marker); + } else if (layer == Layer.BACKGROUND) { + markers = (Collection) this.backgroundDomainMarkers.get( + new Integer(index)); + if (markers == null) { + markers = new java.util.ArrayList(); + this.backgroundDomainMarkers.put(new Integer(index), markers); + } + markers.add(marker); + } + marker.addChangeListener(this); + if (notify) { + fireChangeEvent(); + } + } + + + /** + * Returns the list of domain markers (read only) for the specified layer. + * + * @param layer the layer (foreground or background). + * + * @return The list of domain markers. + */ + public Collection getDomainMarkers(Layer layer) { + return getDomainMarkers(0, layer); + } + + /** + * Returns a collection of domain markers for a particular renderer and + * layer. + * + * @param index the renderer index. + * @param layer the layer. + * + * @return A collection of markers (possibly {@code null}). + */ + public Collection getDomainMarkers(int index, Layer layer) { + Collection result = null; + Integer key = new Integer(index); + if (layer == Layer.FOREGROUND) { + result = (Collection) this.foregroundDomainMarkers.get(key); + } + else if (layer == Layer.BACKGROUND) { + result = (Collection) this.backgroundDomainMarkers.get(key); + } + if (result != null) { + result = Collections.unmodifiableCollection(result); + } + return result; + } + + /** + * Removes a marker for the domain axis and sends a {@link PlotChangeEvent} + * to all registered listeners. + * + * @param marker the marker. + * + * @return A boolean indicating whether or not the marker was actually + * removed. + * + * @since 1.0.7 + */ + public boolean removeDomainMarker(Marker marker) { + return removeDomainMarker(marker, Layer.FOREGROUND); + } + + /** + * Removes a marker for the domain axis in the specified layer and sends a + * {@link PlotChangeEvent} to all registered listeners. + * + * @param marker the marker ({@code null} not permitted). + * @param layer the layer (foreground or background). + * + * @return A boolean indicating whether or not the marker was actually + * removed. + * + * @since 1.0.7 + */ + public boolean removeDomainMarker(Marker marker, Layer layer) { + return removeDomainMarker(0, marker, layer); + } + + /** + * Removes a marker for a specific dataset/renderer and sends a + * {@link PlotChangeEvent} to all registered listeners. + * + * @param index the dataset/renderer index. + * @param marker the marker. + * @param layer the layer (foreground or background). + * + * @return A boolean indicating whether or not the marker was actually + * removed. + * + * @since 1.0.7 + */ + public boolean removeDomainMarker(int index, Marker marker, Layer layer) { + return removeDomainMarker(index, marker, layer, true); + } + + /** + * Removes a marker for a specific dataset/renderer and, if requested, + * sends a {@link PlotChangeEvent} to all registered listeners. + * + * @param index the dataset/renderer index. + * @param marker the marker. + * @param layer the layer (foreground or background). + * @param notify notify listeners? + * + * @return A boolean indicating whether or not the marker was actually + * removed. + * + * @since 1.0.10 + */ + public boolean removeDomainMarker(int index, Marker marker, Layer layer, + boolean notify) { + ArrayList markers; + if (layer == Layer.FOREGROUND) { + markers = (ArrayList) this.foregroundDomainMarkers.get(new Integer( + index)); + } else { + markers = (ArrayList) this.backgroundDomainMarkers.get(new Integer( + index)); + } + if (markers == null) { + return false; + } + boolean removed = markers.remove(marker); + if (removed && notify) { + fireChangeEvent(); + } + return removed; + } + + /** + * Adds a marker for display (in the foreground) against the range axis and + * sends a {@link PlotChangeEvent} to all registered listeners. Typically a + * marker will be drawn by the renderer as a line perpendicular to the + * range axis, however this is entirely up to the renderer. + * + * @param marker the marker ({@code null} not permitted). + * + * @see #removeRangeMarker(Marker) + */ + public void addRangeMarker(Marker marker) { + addRangeMarker(marker, Layer.FOREGROUND); + } + + /** + * Adds a marker for display against the range axis and sends a + * {@link PlotChangeEvent} to all registered listeners. Typically a marker + * will be drawn by the renderer as a line perpendicular to the range axis, + * however this is entirely up to the renderer. + * + * @param marker the marker ({@code null} not permitted). + * @param layer the layer (foreground or background) ({@code null} + * not permitted). + * + * @see #removeRangeMarker(Marker, Layer) + */ + public void addRangeMarker(Marker marker, Layer layer) { + addRangeMarker(0, marker, layer); + } + + /** + * Adds a marker for a specific dataset/renderer and sends a + * {@link PlotChangeEvent} to all registered listeners. + *

+ * Typically a marker will be drawn by the renderer as a line perpendicular + * to the range axis, however this is entirely up to the renderer. + * + * @param index the dataset/renderer index. + * @param marker the marker. + * @param layer the layer (foreground or background). + * + * @see #clearRangeMarkers(int) + * @see #addDomainMarker(int, Marker, Layer) + */ + public void addRangeMarker(int index, Marker marker, Layer layer) { + addRangeMarker(index, marker, layer, true); + } + + protected abstract void addRangeMarker(int index, Marker marker, Layer layer, boolean notify); + + /** + * Clears all the range markers and sends a {@link PlotChangeEvent} to all + * registered listeners. + * + * @see #clearRangeMarkers() + */ + public void clearRangeMarkers() { + if (this.backgroundRangeMarkers != null) { + Set keys = this.backgroundRangeMarkers.keySet(); + for (Integer key : keys) { + clearRangeMarkers(key); + } + this.backgroundRangeMarkers.clear(); + } + if (this.foregroundRangeMarkers != null) { + Set keys = this.foregroundRangeMarkers.keySet(); + for (Integer key : keys) { + clearRangeMarkers(key); + } + this.foregroundRangeMarkers.clear(); + } + fireChangeEvent(); + } + + /** + * Clears all the range markers for the specified renderer. + * + * @param index the renderer index. + * + * @see #clearDomainMarkers(int) + */ + public void clearRangeMarkers(int index) { + Integer key = new Integer(index); + if (this.backgroundRangeMarkers != null) { + Collection markers + = (Collection) this.backgroundRangeMarkers.get(key); + if (markers != null) { + Iterator iterator = markers.iterator(); + while (iterator.hasNext()) { + Marker m = (Marker) iterator.next(); + m.removeChangeListener(this); + } + markers.clear(); + } + } + if (this.foregroundRangeMarkers != null) { + Collection markers + = (Collection) this.foregroundRangeMarkers.get(key); + if (markers != null) { + Iterator iterator = markers.iterator(); + while (iterator.hasNext()) { + Marker m = (Marker) iterator.next(); + m.removeChangeListener(this); + } + markers.clear(); + } + } + fireChangeEvent(); + } + + /** + * Removes a marker for the range axis and sends a {@link PlotChangeEvent} + * to all registered listeners. + * + * @param marker the marker. + * + * @return A boolean indicating whether or not the marker was actually + * removed. + * + * @since 1.0.7 + * + * @see #addRangeMarker(Marker) + */ + public boolean removeRangeMarker(Marker marker) { + return removeRangeMarker(marker, Layer.FOREGROUND); + } + + /** + * Removes a marker for the range axis in the specified layer and sends a + * {@link PlotChangeEvent} to all registered listeners. + * + * @param marker the marker ({@code null} not permitted). + * @param layer the layer (foreground or background). + * + * @return A boolean indicating whether or not the marker was actually + * removed. + * + * @since 1.0.7 + * + * @see #addRangeMarker(Marker, Layer) + */ + public boolean removeRangeMarker(Marker marker, Layer layer) { + return removeRangeMarker(0, marker, layer); + } + + /** + * Removes a marker for a specific dataset/renderer and sends a + * {@link PlotChangeEvent} to all registered listeners. + * + * @param index the dataset/renderer index. + * @param marker the marker. + * @param layer the layer (foreground or background). + * + * @return A boolean indicating whether or not the marker was actually + * removed. + * + * @since 1.0.7 + * + * @see #addRangeMarker(int, Marker, Layer) + */ + public boolean removeRangeMarker(int index, Marker marker, Layer layer) { + return removeRangeMarker(index, marker, layer, true); + } + + protected abstract boolean removeRangeMarker(int index, Marker marker, Layer layer, boolean notify); + + /** + * Returns {@code true} if the range axis grid is visible, and + * {@code false} otherwise. + * + * @return A boolean. + * + * @see #setRangeGridlinesVisible(boolean) + */ + public boolean isRangeGridlinesVisible() { + return this.rangeGridlinesVisible; + } + + /** + * Sets the flag that controls whether or not grid-lines are drawn against + * the range axis. If the flag changes value, a {@link PlotChangeEvent} is + * sent to all registered listeners. + * + * @param visible the new value of the flag. + * + * @see #isRangeGridlinesVisible() + */ + public void setRangeGridlinesVisible(boolean visible) { + if (this.rangeGridlinesVisible != visible) { + this.rangeGridlinesVisible = visible; + fireChangeEvent(); + } + } +} diff -burN jfreechart-original/src/main/java/org/jfree/chart/plot/XYPlot.java jfreechart-after-maintenance/src/main/java/org/jfree/chart/plot/XYPlot.java --- jfreechart-original/src/main/java/org/jfree/chart/plot/XYPlot.java 2022-03-07 09:23:25.000000000 +0100 +++ jfreechart-after-maintenance/src/main/java/org/jfree/chart/plot/XYPlot.java 2022-04-17 18:12:48.000000000 +0200 @@ -281,7 +281,6 @@ import org.jfree.chart.axis.ValueAxis; import org.jfree.chart.axis.ValueTick; import org.jfree.chart.event.AnnotationChangeEvent; -import org.jfree.chart.event.ChartChangeEventType; import org.jfree.chart.event.PlotChangeEvent; import org.jfree.chart.event.RendererChangeEvent; import org.jfree.chart.event.RendererChangeListener; @@ -316,7 +315,7 @@ * The {@link org.jfree.chart.ChartFactory} class contains static methods for * creating pre-configured charts. */ -public class XYPlot extends Plot implements ValueAxisPlot, Pannable, Zoomable, +public class XYPlot extends CategoryXYCommon implements ValueAxisPlot, Pannable, Zoomable, RendererChangeListener, Cloneable, PublicCloneable, Serializable { /** For serialization. */ @@ -345,24 +344,9 @@ = ResourceBundleWrapper.getBundle( "org.jfree.chart.plot.LocalizationBundle"); - /** The plot orientation. */ - private PlotOrientation orientation; - - /** The offset between the data area and the axes. */ - private RectangleInsets axisOffset; - /** The domain axis / axes (used for the x-values). */ private Map domainAxes; - /** The domain axis locations. */ - private Map domainAxisLocations; - - /** The range axis (used for the y-values). */ - private Map rangeAxes; - - /** The range axis location. */ - private Map rangeAxisLocations; - /** Storage for the datasets. */ private Map datasets; @@ -405,15 +389,6 @@ /** The paint used to draw the domain grid-lines. */ private transient Paint domainGridlinePaint; - /** A flag that controls whether the range grid-lines are visible. */ - private boolean rangeGridlinesVisible; - - /** The stroke used to draw the range grid-lines. */ - private transient Stroke rangeGridlineStroke; - - /** The paint used to draw the range grid-lines. */ - private transient Paint rangeGridlinePaint; - /** * A flag that controls whether the domain minor grid-lines are visible. * @@ -436,27 +411,6 @@ private transient Paint domainMinorGridlinePaint; /** - * A flag that controls whether the range minor grid-lines are visible. - * - * @since 1.0.12 - */ - private boolean rangeMinorGridlinesVisible; - - /** - * The stroke used to draw the range minor grid-lines. - * - * @since 1.0.12 - */ - private transient Stroke rangeMinorGridlineStroke; - - /** - * The paint used to draw the range minor grid-lines. - * - * @since 1.0.12 - */ - private transient Paint rangeMinorGridlinePaint; - - /** * A flag that controls whether or not the zero baseline against the domain * axis is visible. * @@ -526,18 +480,6 @@ */ private boolean rangeCrosshairLockedOnData = true; - /** A map of lists of foreground markers (optional) for the domain axes. */ - private Map foregroundDomainMarkers; - - /** A map of lists of background markers (optional) for the domain axes. */ - private Map backgroundDomainMarkers; - - /** A map of lists of foreground markers (optional) for the range axes. */ - private Map foregroundRangeMarkers; - - /** A map of lists of background markers (optional) for the range axes. */ - private Map backgroundRangeMarkers; - /** * A (possibly empty) list of annotations for the plot. The list should * be initialised in the constructor and never allowed to be @@ -887,44 +829,6 @@ } /** - * Returns the location of the primary domain axis. - * - * @return The location (never {@code null}). - * - * @see #setDomainAxisLocation(AxisLocation) - */ - public AxisLocation getDomainAxisLocation() { - return (AxisLocation) this.domainAxisLocations.get(0); - } - - /** - * Sets the location of the primary domain axis and sends a - * {@link PlotChangeEvent} to all registered listeners. - * - * @param location the location ({@code null} not permitted). - * - * @see #getDomainAxisLocation() - */ - public void setDomainAxisLocation(AxisLocation location) { - // delegate... - setDomainAxisLocation(0, location, true); - } - - /** - * Sets the location of the domain axis and, if requested, sends a - * {@link PlotChangeEvent} to all registered listeners. - * - * @param location the location ({@code null} not permitted). - * @param notify notify listeners? - * - * @see #getDomainAxisLocation() - */ - public void setDomainAxisLocation(AxisLocation location, boolean notify) { - // delegate... - setDomainAxisLocation(0, location, notify); - } - - /** * Returns the edge for the primary domain axis (taking into account the * plot's orientation). * @@ -977,66 +881,6 @@ } /** - * Returns the location for a domain axis. If this hasn't been set - * explicitly, the method returns the location that is opposite to the - * primary domain axis location. - * - * @param index the axis index (must be >= 0). - * - * @return The location (never {@code null}). - * - * @see #setDomainAxisLocation(int, AxisLocation) - */ - public AxisLocation getDomainAxisLocation(int index) { - AxisLocation result = this.domainAxisLocations.get(index); - if (result == null) { - result = AxisLocation.getOpposite(getDomainAxisLocation()); - } - return result; - } - - /** - * Sets the location for a domain axis and sends a {@link PlotChangeEvent} - * to all registered listeners. - * - * @param index the axis index. - * @param location the location ({@code null} not permitted for index - * 0). - * - * @see #getDomainAxisLocation(int) - */ - public void setDomainAxisLocation(int index, AxisLocation location) { - // delegate... - setDomainAxisLocation(index, location, true); - } - - /** - * Sets the axis location for a domain axis and, if requested, sends a - * {@link PlotChangeEvent} to all registered listeners. - * - * @param index the axis index (must be >= 0). - * @param location the location ({@code null} not permitted for - * index 0). - * @param notify notify listeners? - * - * @since 1.0.5 - * - * @see #getDomainAxisLocation(int) - * @see #setRangeAxisLocation(int, AxisLocation, boolean) - */ - public void setDomainAxisLocation(int index, AxisLocation location, - boolean notify) { - if (index == 0 && location == null) { - throw new IllegalArgumentException( - "Null 'location' for index 0 not permitted."); - } - this.domainAxisLocations.put(index, location); - if (notify) { - fireChangeEvent(); - } - } - - /** * Returns the edge for a domain axis. * * @param index the axis index. @@ -1073,6 +917,7 @@ * @see #getRangeAxis() * @see #setRangeAxis(int, ValueAxis) */ + @Override public void setRangeAxis(ValueAxis axis) { if (axis != null) { axis.setPlot(this); @@ -1091,43 +936,17 @@ } /** - * Returns the location of the primary range axis. + * Returns the location for a range axis. * - * @return The location (never {@code null}). - * - * @see #setRangeAxisLocation(AxisLocation) - */ - public AxisLocation getRangeAxisLocation() { - return (AxisLocation) this.rangeAxisLocations.get(0); - } - - /** - * Sets the location of the primary range axis and sends a - * {@link PlotChangeEvent} to all registered listeners. - * - * @param location the location ({@code null} not permitted). - * - * @see #getRangeAxisLocation() - */ - public void setRangeAxisLocation(AxisLocation location) { - // delegate... - setRangeAxisLocation(0, location, true); - } - - /** - * Sets the location of the primary range axis and, if requested, sends a - * {@link PlotChangeEvent} to all registered listeners. + * @param index the axis index. * - * @param location the location ({@code null} not permitted). - * @param notify notify listeners? + * @return The location. * - * @see #getRangeAxisLocation() + * @see #setRangeAxisLocation(int, AxisLocation) */ - public void setRangeAxisLocation(AxisLocation location, boolean notify) { - // delegate... - setRangeAxisLocation(0, location, notify); + public AxisLocation getRangeAxisLocation(int index) { + return this.rangeAxisLocations.get(0); } - /** * Returns the edge for the primary range axis. * @@ -1151,6 +970,7 @@ * * @see #setRangeAxis(int, ValueAxis) */ + @Override public ValueAxis getRangeAxis(int index) { ValueAxis result = this.rangeAxes.get(index); if (result == null) { @@ -1220,105 +1040,6 @@ } /** - * Returns the number of range axes. - * - * @return The axis count. - * - * @see #getDomainAxisCount() - */ - public int getRangeAxisCount() { - return this.rangeAxes.size(); - } - - /** - * Clears the range axes from the plot and sends a {@link PlotChangeEvent} - * to all registered listeners. - * - * @see #clearDomainAxes() - */ - public void clearRangeAxes() { - for (ValueAxis axis: this.rangeAxes.values()) { - if (axis != null) { - axis.removeChangeListener(this); - } - } - this.rangeAxes.clear(); - fireChangeEvent(); - } - - /** - * Configures the range axes. - * - * @see #configureDomainAxes() - */ - public void configureRangeAxes() { - for (ValueAxis axis: this.rangeAxes.values()) { - if (axis != null) { - axis.configure(); - } - } - } - - /** - * Returns the location for a range axis. If this hasn't been set - * explicitly, the method returns the location that is opposite to the - * primary range axis location. - * - * @param index the axis index (must be >= 0). - * - * @return The location (never {@code null}). - * - * @see #setRangeAxisLocation(int, AxisLocation) - */ - public AxisLocation getRangeAxisLocation(int index) { - AxisLocation result = this.rangeAxisLocations.get(index); - if (result == null) { - result = AxisLocation.getOpposite(getRangeAxisLocation()); - } - return result; - } - - /** - * Sets the location for a range axis and sends a {@link PlotChangeEvent} - * to all registered listeners. - * - * @param index the axis index. - * @param location the location ({@code null} permitted). - * - * @see #getRangeAxisLocation(int) - */ - public void setRangeAxisLocation(int index, AxisLocation location) { - // delegate... - setRangeAxisLocation(index, location, true); - } - - /** - * Sets the axis location for a domain axis and, if requested, sends a - * {@link PlotChangeEvent} to all registered listeners. - * - * @param index the axis index. - * @param location the location ({@code null} not permitted for - * index 0). - * @param notify notify listeners? - * - * @since 1.0.5 - * - * @see #getRangeAxisLocation(int) - * @see #setDomainAxisLocation(int, AxisLocation, boolean) - */ - public void setRangeAxisLocation(int index, AxisLocation location, - boolean notify) { - if (index == 0 && location == null) { - throw new IllegalArgumentException( - "Null 'location' for index 0 not permitted."); - } - this.rangeAxisLocations.put(index, location); - if (notify) { - fireChangeEvent(); - } - } - - /** * Returns the edge for a range axis. * * @param index the axis index. @@ -1930,183 +1651,6 @@ this.domainMinorGridlinePaint = paint; fireChangeEvent(); } - - /** - * Returns {@code true} if the range axis grid is visible, and - * {@code false} otherwise. - * - * @return A boolean. - * - * @see #setRangeGridlinesVisible(boolean) - */ - public boolean isRangeGridlinesVisible() { - return this.rangeGridlinesVisible; - } - - /** - * Sets the flag that controls whether or not the range axis grid lines - * are visible. - *

- * If the flag value is changed, a {@link PlotChangeEvent} is sent to all - * registered listeners. - * - * @param visible the new value of the flag. - * - * @see #isRangeGridlinesVisible() - */ - public void setRangeGridlinesVisible(boolean visible) { - if (this.rangeGridlinesVisible != visible) { - this.rangeGridlinesVisible = visible; - fireChangeEvent(); - } - } - - /** - * Returns the stroke for the grid lines (if any) plotted against the - * range axis. - * - * @return The stroke (never {@code null}). - * - * @see #setRangeGridlineStroke(Stroke) - */ - public Stroke getRangeGridlineStroke() { - return this.rangeGridlineStroke; - } - - /** - * Sets the stroke for the grid lines plotted against the range axis, - * and sends a {@link PlotChangeEvent} to all registered listeners. - * - * @param stroke the stroke ({@code null} not permitted). - * - * @see #getRangeGridlineStroke() - */ - public void setRangeGridlineStroke(Stroke stroke) { - Args.nullNotPermitted(stroke, "stroke"); - this.rangeGridlineStroke = stroke; - fireChangeEvent(); - } - - /** - * Returns the paint for the grid lines (if any) plotted against the range - * axis. - * - * @return The paint (never {@code null}). - * - * @see #setRangeGridlinePaint(Paint) - */ - public Paint getRangeGridlinePaint() { - return this.rangeGridlinePaint; - } - - /** - * Sets the paint for the grid lines plotted against the range axis and - * sends a {@link PlotChangeEvent} to all registered listeners. - * - * @param paint the paint ({@code null} not permitted). - * - * @see #getRangeGridlinePaint() - */ - public void setRangeGridlinePaint(Paint paint) { - Args.nullNotPermitted(paint, "paint"); - this.rangeGridlinePaint = paint; - fireChangeEvent(); - } - - /** - * Returns {@code true} if the range axis minor grid is visible, and - * {@code false} otherwise. - * - * @return A boolean. - * - * @see #setRangeMinorGridlinesVisible(boolean) - * - * @since 1.0.12 - */ - public boolean isRangeMinorGridlinesVisible() { - return this.rangeMinorGridlinesVisible; - } - - /** - * Sets the flag that controls whether or not the range axis minor grid - * lines are visible. - *

- * If the flag value is changed, a {@link PlotChangeEvent} is sent to all - * registered listeners. - * - * @param visible the new value of the flag. - * - * @see #isRangeMinorGridlinesVisible() - * - * @since 1.0.12 - */ - public void setRangeMinorGridlinesVisible(boolean visible) { - if (this.rangeMinorGridlinesVisible != visible) { - this.rangeMinorGridlinesVisible = visible; - fireChangeEvent(); - } - } - - /** - * Returns the stroke for the minor grid lines (if any) plotted against the - * range axis. - * - * @return The stroke (never {@code null}). - * - * @see #setRangeMinorGridlineStroke(Stroke) - * - * @since 1.0.12 - */ - public Stroke getRangeMinorGridlineStroke() { - return this.rangeMinorGridlineStroke; - } - - /** - * Sets the stroke for the minor grid lines plotted against the range axis, - * and sends a {@link PlotChangeEvent} to all registered listeners. - * - * @param stroke the stroke ({@code null} not permitted). - * - * @see #getRangeMinorGridlineStroke() - * - * @since 1.0.12 - */ - public void setRangeMinorGridlineStroke(Stroke stroke) { - Args.nullNotPermitted(stroke, "stroke"); - this.rangeMinorGridlineStroke = stroke; - fireChangeEvent(); - } - - /** - * Returns the paint for the minor grid lines (if any) plotted against the - * range axis. - * - * @return The paint (never {@code null}). - * - * @see #setRangeMinorGridlinePaint(Paint) - * - * @since 1.0.12 - */ - public Paint getRangeMinorGridlinePaint() { - return this.rangeMinorGridlinePaint; - } - - /** - * Sets the paint for the minor grid lines plotted against the range axis - * and sends a {@link PlotChangeEvent} to all registered listeners. - * - * @param paint the paint ({@code null} not permitted). - * - * @see #getRangeMinorGridlinePaint() - * - * @since 1.0.12 - */ - public void setRangeMinorGridlinePaint(Paint paint) { - Args.nullNotPermitted(paint, "paint"); - this.rangeMinorGridlinePaint = paint; - fireChangeEvent(); - } - /** * Returns a flag that controls whether or not a zero baseline is * displayed for the domain axis. @@ -2654,48 +2198,6 @@ } /** - * Clears all the range markers and sends a {@link PlotChangeEvent} to all - * registered listeners. - * - * @see #clearRangeMarkers() - */ - public void clearRangeMarkers() { - if (this.backgroundRangeMarkers != null) { - Set keys = this.backgroundRangeMarkers.keySet(); - for (Integer key : keys) { - clearRangeMarkers(key); - } - this.backgroundRangeMarkers.clear(); - } - if (this.foregroundRangeMarkers != null) { - Set keys = this.foregroundRangeMarkers.keySet(); - for (Integer key : keys) { - clearRangeMarkers(key); - } - this.foregroundRangeMarkers.clear(); - } - fireChangeEvent(); - } - - /** - * Adds a marker for a specific dataset/renderer and sends a - * {@link PlotChangeEvent} to all registered listeners. - *

- * Typically a marker will be drawn by the renderer as a line perpendicular - * to the range axis, however this is entirely up to the renderer. - * - * @param index the dataset/renderer index. - * @param marker the marker. - * @param layer the layer (foreground or background). - * - * @see #clearRangeMarkers(int) - * @see #addDomainMarker(int, Marker, Layer) - */ - public void addRangeMarker(int index, Marker marker, Layer layer) { - addRangeMarker(index, marker, layer, true); - } - - /** * Adds a marker for a specific dataset/renderer and, if requested, sends a * {@link PlotChangeEvent} to all registered listeners. *

@@ -2736,103 +2238,6 @@ } } - /** - * Clears the (foreground and background) range markers for a particular - * renderer. - * - * @param index the renderer index. - */ - public void clearRangeMarkers(int index) { - Integer key = new Integer(index); - if (this.backgroundRangeMarkers != null) { - Collection markers - = (Collection) this.backgroundRangeMarkers.get(key); - if (markers != null) { - Iterator iterator = markers.iterator(); - while (iterator.hasNext()) { - Marker m = (Marker) iterator.next(); - m.removeChangeListener(this); - } - markers.clear(); - } - } - if (this.foregroundRangeMarkers != null) { - Collection markers - = (Collection) this.foregroundRangeMarkers.get(key); - if (markers != null) { - Iterator iterator = markers.iterator(); - while (iterator.hasNext()) { - Marker m = (Marker) iterator.next(); - m.removeChangeListener(this); - } - markers.clear(); - } - } - fireChangeEvent(); - } - - /** - * Removes a marker for the range axis and sends a {@link PlotChangeEvent} - * to all registered listeners. - * - * @param marker the marker. - * - * @return A boolean indicating whether or not the marker was actually - * removed. - * - * @since 1.0.7 - */ - public boolean removeRangeMarker(Marker marker) { - return removeRangeMarker(marker, Layer.FOREGROUND); - } - - /** - * Removes a marker for the range axis in the specified layer and sends a - * {@link PlotChangeEvent} to all registered listeners. - * - * @param marker the marker ({@code null} not permitted). - * @param layer the layer (foreground or background). - * - * @return A boolean indicating whether or not the marker was actually - * removed. - * - * @since 1.0.7 - */ - public boolean removeRangeMarker(Marker marker, Layer layer) { - return removeRangeMarker(0, marker, layer); - } - - /** - * Removes a marker for a specific dataset/renderer and sends a - * {@link PlotChangeEvent} to all registered listeners. - * - * @param index the dataset/renderer index. - * @param marker the marker ({@code null} not permitted). - * @param layer the layer (foreground or background). - * - * @return A boolean indicating whether or not the marker was actually - * removed. - * - * @since 1.0.7 - */ - public boolean removeRangeMarker(int index, Marker marker, Layer layer) { - return removeRangeMarker(index, marker, layer, true); - } - - /** - * Removes a marker for a specific dataset/renderer and sends a - * {@link PlotChangeEvent} to all registered listeners. - * - * @param index the dataset/renderer index. - * @param marker the marker ({@code null} not permitted). - * @param layer the layer (foreground or background) ({@code null} not permitted). - * @param notify notify listeners? - * - * @return A boolean indicating whether or not the marker was actually - * removed. - * - * @since 1.0.10 - */ public boolean removeRangeMarker(int index, Marker marker, Layer layer, boolean notify) { Args.nullNotPermitted(marker, "marker"); @@ -3070,13 +2475,7 @@ } else { // reserve space for the range axes... - for (ValueAxis axis: this.rangeAxes.values()) { - if (axis != null) { - RectangleEdge edge = getRangeAxisEdge( - findRangeAxisIndex(axis)); - space = axis.reserveSpace(g2, this, plotArea, edge, space); - } - } + space = reserveSpaceForTheRangeAxes(g2, plotArea, space); } return space; @@ -3131,7 +2530,7 @@ AxisSpace space = calculateAxisSpace(g2, area); Rectangle2D dataArea = space.shrink(area, null); - this.axisOffset.trim(dataArea); + trimAxisOffset(dataArea); dataArea = integerise(dataArea); if (dataArea.isEmpty()) { @@ -3614,65 +3013,8 @@ } } - // add range axes to lists... - for (ValueAxis axis : this.rangeAxes.values()) { - if (axis != null) { - int axisIndex = findRangeAxisIndex(axis); - axisCollection.add(axis, getRangeAxisEdge(axisIndex)); - } - } - - Map axisStateMap = new HashMap(); - - // draw the top axes - double cursor = dataArea.getMinY() - this.axisOffset.calculateTopOutset( - dataArea.getHeight()); - Iterator iterator = axisCollection.getAxesAtTop().iterator(); - while (iterator.hasNext()) { - ValueAxis axis = (ValueAxis) iterator.next(); - AxisState info = axis.draw(g2, cursor, plotArea, dataArea, - RectangleEdge.TOP, plotState); - cursor = info.getCursor(); - axisStateMap.put(axis, info); - } - - // draw the bottom axes - cursor = dataArea.getMaxY() - + this.axisOffset.calculateBottomOutset(dataArea.getHeight()); - iterator = axisCollection.getAxesAtBottom().iterator(); - while (iterator.hasNext()) { - ValueAxis axis = (ValueAxis) iterator.next(); - AxisState info = axis.draw(g2, cursor, plotArea, dataArea, - RectangleEdge.BOTTOM, plotState); - cursor = info.getCursor(); - axisStateMap.put(axis, info); - } + return extractedDraw(g2, plotArea, dataArea, plotState, axisCollection); - // draw the left axes - cursor = dataArea.getMinX() - - this.axisOffset.calculateLeftOutset(dataArea.getWidth()); - iterator = axisCollection.getAxesAtLeft().iterator(); - while (iterator.hasNext()) { - ValueAxis axis = (ValueAxis) iterator.next(); - AxisState info = axis.draw(g2, cursor, plotArea, dataArea, - RectangleEdge.LEFT, plotState); - cursor = info.getCursor(); - axisStateMap.put(axis, info); - } - - // draw the right axes - cursor = dataArea.getMaxX() - + this.axisOffset.calculateRightOutset(dataArea.getWidth()); - iterator = axisCollection.getAxesAtRight().iterator(); - while (iterator.hasNext()) { - ValueAxis axis = (ValueAxis) iterator.next(); - AxisState info = axis.draw(g2, cursor, plotArea, dataArea, - RectangleEdge.RIGHT, plotState); - cursor = info.getCursor(); - axisStateMap.put(axis, info); - } - - return axisStateMap; } /** @@ -4389,14 +3731,6 @@ return result; } - private int findRangeAxisIndex(ValueAxis axis) { - for (Map.Entry entry : this.rangeAxes.entrySet()) { - if (entry.getValue() == axis) { - return entry.getKey(); - } - } - return -1; - } /** * Returns the range for the specified axis. @@ -4532,14 +3866,7 @@ public void datasetChanged(DatasetChangeEvent event) { configureDomainAxes(); configureRangeAxes(); - if (getParent() != null) { - getParent().datasetChanged(event); - } - else { - PlotChangeEvent e = new PlotChangeEvent(this); - e.setType(ChartChangeEventType.DATASET_UPDATED); - notifyListeners(e); - } + dealWithEventWhenDatasetChanges(event); } /** @@ -5154,24 +4481,8 @@ public void zoomRangeAxes(double factor, PlotRenderingInfo info, Point2D source, boolean useAnchor) { - // perform the zoom on each range axis - for (ValueAxis yAxis : this.rangeAxes.values()) { - if (yAxis == null) { - continue; - } - if (useAnchor) { - // get the relevant source coordinate given the plot orientation - double sourceY = source.getY(); - if (this.orientation == PlotOrientation.HORIZONTAL) { - sourceY = source.getX(); - } - double anchorY = yAxis.java2DToValue(sourceY, - info.getDataArea(), getRangeAxisEdge()); - yAxis.resizeRange2(factor, anchorY); - } else { - yAxis.resizeRange(factor); - } - } + zoomRangeAxesWithFactor(factor, info, source, useAnchor); + } /** @@ -5187,11 +4498,7 @@ @Override public void zoomRangeAxes(double lowerPercent, double upperPercent, PlotRenderingInfo info, Point2D source) { - for (ValueAxis yAxis : this.rangeAxes.values()) { - if (yAxis != null) { - yAxis.zoomRange(lowerPercent, upperPercent); - } - } + zoomRangeAxesDefault(lowerPercent, upperPercent); } /** diff -burN jfreechart-original/src/test/java/org/jfree/chart/ChartPanelTest.java jfreechart-after-maintenance/src/test/java/org/jfree/chart/ChartPanelTest.java --- jfreechart-original/src/test/java/org/jfree/chart/ChartPanelTest.java 2022-03-07 09:23:25.000000000 +0100 +++ jfreechart-after-maintenance/src/test/java/org/jfree/chart/ChartPanelTest.java 2022-04-17 18:12:48.000000000 +0200 @@ -41,22 +41,37 @@ package org.jfree.chart; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.assertFalse; -import java.awt.geom.Rectangle2D; -import java.util.EventListener; -import java.util.List; - -import javax.swing.event.CaretListener; - import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.event.ChartChangeEvent; import org.jfree.chart.event.ChartChangeListener; +import org.jfree.chart.event.PlotChangeEvent; +import org.jfree.chart.event.PlotChangeListener; +import org.jfree.chart.panel.CrosshairOverlay; +import org.jfree.chart.plot.Crosshair; import org.jfree.chart.plot.PlotOrientation; +import org.jfree.chart.plot.ThermometerPlot; import org.jfree.chart.plot.XYPlot; +import org.jfree.data.general.DefaultPieDataset; import org.jfree.data.xy.DefaultXYDataset; import org.junit.Test; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import javax.swing.*; +import javax.swing.event.CaretListener; +import java.awt.*; +import java.awt.datatransfer.Clipboard; +import java.awt.event.ActionEvent; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.io.File; +import java.util.EventListener; +import java.util.List; + +import static org.jfree.chart.ChartPanel.*; +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; /** * Tests for the {@link ChartPanel} class. @@ -117,8 +132,7 @@ boolean pass = false; try { listeners = p.getListeners((Class) null); - } - catch (NullPointerException e) { + } catch (NullPointerException e) { pass = true; } assertTrue(pass); @@ -127,8 +141,7 @@ pass = false; try { listeners = p.getListeners(Integer.class); - } - catch (ClassCastException e) { + } catch (ClassCastException e) { pass = true; } assertTrue(pass); @@ -343,4 +356,523 @@ panel.setMouseWheelEnabled(false); assertFalse(panel.isMouseWheelEnabled()); } + + @Test + public void testGetToolTipText() { + DefaultXYDataset dataset = new DefaultXYDataset(); + JFreeChart chart = ChartFactory.createXYLineChart("TestChart", "X", + "Y", dataset, PlotOrientation.VERTICAL, false, false, false); + ChartPanel panel = new ChartPanel(chart); + assertEquals(null, panel.getToolTipText(null)); + // TODO test with a real MouseEvent + } + + @Test + public void testScale() { + DefaultXYDataset dataset = new DefaultXYDataset(); + JFreeChart chart = ChartFactory.createXYLineChart("TestChart", "X", + "Y", dataset, PlotOrientation.VERTICAL, false, false, false); + ChartPanel panel = new ChartPanel(chart); + // scale is 0.0 by default and is only set by paintComponent + BufferedImage bi = new BufferedImage(300, 200, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2 = bi.createGraphics(); + panel.setSize(300, 200); + panel.paintComponent(g2); + // Insets are (0,0,0,0) + assertEquals(1.0, panel.getScaleX(), 0.1); + assertEquals(1.0, panel.getScaleY(), 0.1); + assertEquals(new Rectangle2D.Double(10.0, 20.0, 30.0, 40.0), + panel.scale(new Rectangle2D.Double(10.0, 20.0, 30.0, 40.0))); + panel.setSize(150, 50); + panel.paintComponent(g2); + assertEquals(0.5, panel.getScaleX(), 0.1); + assertEquals(0.25, panel.getScaleY(), 0.1); + assertEquals(new Rectangle2D.Double(5.0, 5.0, 15.0, 10.0), + panel.scale(new Rectangle2D.Double(10.0, 20.0, 30.0, 40.0))); + panel.setMaximumDrawWidth(500); + panel.setSize(600, 400); + panel.paintComponent(g2); + assertEquals(1.2, panel.getScaleX(), 0.1); + assertEquals(1.0, panel.getScaleY(), 0.1); + assertEquals(new Rectangle2D.Double(12.0, 20.0, 36.0, 40.0), + panel.scale(new Rectangle2D.Double(10.0, 20.0, 30.0, 40.0))); + panel.setMaximumDrawHeight(200); + panel.setSize(600, 400); + panel.paintComponent(g2); + assertEquals(1.2, panel.getScaleX(), 0.1); + assertEquals(2.0, panel.getScaleY(), 0.1); + assertEquals(new Rectangle2D.Double(12.0, 40.0, 36.0, 80.0), + panel.scale(new Rectangle2D.Double(10.0, 20.0, 30.0, 40.0))); + g2.dispose(); + } + + /** + * Same test as the previous one, but specifying no buffer to check that it has the same behaviour. + */ + @Test + public void testPaintComponentNoBuffer() { + DefaultXYDataset dataset = new DefaultXYDataset(); + JFreeChart chart = ChartFactory.createXYLineChart("TestChart", "X", + "Y", dataset, PlotOrientation.VERTICAL, false, false, false); + ChartPanel panel = new ChartPanel(chart, false); + // scale is 0.0 by default and is only set by paintComponent + BufferedImage bi = new BufferedImage(300, 200, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2 = bi.createGraphics(); + panel.setSize(300, 200); + panel.paintComponent(g2); + // Insets are (0,0,0,0) + assertEquals(1.0, panel.getScaleX(), 0.1); + assertEquals(1.0, panel.getScaleY(), 0.1); + assertEquals(new Rectangle2D.Double(10.0, 20.0, 30.0, 40.0), + panel.scale(new Rectangle2D.Double(10.0, 20.0, 30.0, 40.0))); + panel.setSize(150, 50); + panel.paintComponent(g2); + assertEquals(0.5, panel.getScaleX(), 0.1); + assertEquals(0.25, panel.getScaleY(), 0.1); + assertEquals(new Rectangle2D.Double(5.0, 5.0, 15.0, 10.0), + panel.scale(new Rectangle2D.Double(10.0, 20.0, 30.0, 40.0))); + panel.setMaximumDrawWidth(500); + panel.setSize(600, 400); + panel.paintComponent(g2); + assertEquals(1.2, panel.getScaleX(), 0.1); + assertEquals(1.0, panel.getScaleY(), 0.1); + assertEquals(new Rectangle2D.Double(12.0, 20.0, 36.0, 40.0), + panel.scale(new Rectangle2D.Double(10.0, 20.0, 30.0, 40.0))); + panel.setMaximumDrawHeight(200); + panel.setSize(600, 400); + panel.paintComponent(g2); + assertEquals(1.2, panel.getScaleX(), 0.1); + assertEquals(2.0, panel.getScaleY(), 0.1); + assertEquals(new Rectangle2D.Double(12.0, 40.0, 36.0, 80.0), + panel.scale(new Rectangle2D.Double(10.0, 20.0, 30.0, 40.0))); + g2.dispose(); + } + + @Test + public void testPaintComponentNullChart() { + ChartPanel panel = new ChartPanel(null); + // scale is 0.0 by default and is only set by paintComponent + BufferedImage bi = new BufferedImage(300, 200, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2 = bi.createGraphics(); + panel.setSize(300, 200); + panel.paintComponent(g2); + + } + + /** + * Same test as the previous one, but specifying no buffer to check that it has the same behaviour. + */ + @Test + public void testPaintComponentWithOverlays() { + CrosshairOverlay overlay = new CrosshairOverlay(); + overlay.addDomainCrosshair(new Crosshair()); + overlay.addRangeCrosshair(new Crosshair()); + DefaultXYDataset dataset = new DefaultXYDataset(); + JFreeChart chart = ChartFactory.createXYLineChart("TestChart", "X", + "Y", dataset, PlotOrientation.VERTICAL, false, false, false); + ChartPanel panel = new ChartPanel(chart, false); + panel.addOverlay(overlay); + // scale is 0.0 by default and is only set by paintComponent + BufferedImage bi = new BufferedImage(300, 200, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2 = bi.createGraphics(); + panel.setSize(300, 200); + panel.paintComponent(g2); + // Insets are (0,0,0,0) + assertEquals(1.0, panel.getScaleX(), 0.1); + assertEquals(1.0, panel.getScaleY(), 0.1); + assertEquals(new Rectangle2D.Double(10.0, 20.0, 30.0, 40.0), + panel.scale(new Rectangle2D.Double(10.0, 20.0, 30.0, 40.0))); + panel.setSize(150, 50); + panel.paintComponent(g2); + assertEquals(0.5, panel.getScaleX(), 0.1); + assertEquals(0.25, panel.getScaleY(), 0.1); + assertEquals(new Rectangle2D.Double(5.0, 5.0, 15.0, 10.0), + panel.scale(new Rectangle2D.Double(10.0, 20.0, 30.0, 40.0))); + panel.setMaximumDrawWidth(500); + panel.setSize(600, 400); + panel.paintComponent(g2); + assertEquals(1.2, panel.getScaleX(), 0.1); + assertEquals(1.0, panel.getScaleY(), 0.1); + assertEquals(new Rectangle2D.Double(12.0, 20.0, 36.0, 40.0), + panel.scale(new Rectangle2D.Double(10.0, 20.0, 30.0, 40.0))); + panel.setMaximumDrawHeight(200); + panel.setSize(600, 400); + panel.paintComponent(g2); + assertEquals(1.2, panel.getScaleX(), 0.1); + assertEquals(2.0, panel.getScaleY(), 0.1); + assertEquals(new Rectangle2D.Double(12.0, 40.0, 36.0, 80.0), + panel.scale(new Rectangle2D.Double(10.0, 20.0, 30.0, 40.0))); + g2.dispose(); + } + + @Test + public void testActionPerformed() { + final boolean[] plotChanged = {false}; + + DefaultXYDataset dataset = new DefaultXYDataset(); + JFreeChart chart = ChartFactory.createXYLineChart("TestChart", "X", + "Y", dataset, PlotOrientation.VERTICAL, false, false, false); + chart.getPlot().addChangeListener(new PlotChangeListener() { + @Override + public void plotChanged(PlotChangeEvent event) { + plotChanged[0] = true; + } + }); + + ChartPanel panel = new ChartPanel(chart); + + ActionEvent event = new ActionEvent(new Object(), 0, ZOOM_IN_BOTH_COMMAND); + panel.actionPerformed(event); + assertTrue(plotChanged[0]); + + plotChanged[0] = false; + event = new ActionEvent(new Object(), 0, ZOOM_IN_DOMAIN_COMMAND); + panel.actionPerformed(event); + assertTrue(plotChanged[0]); + + plotChanged[0] = false; + event = new ActionEvent(new Object(), 0, ZOOM_IN_RANGE_COMMAND); + panel.actionPerformed(event); + assertTrue(plotChanged[0]); + + event = new ActionEvent(new Object(), 0, ZOOM_OUT_BOTH_COMMAND); + panel.actionPerformed(event); + assertTrue(plotChanged[0]); + + plotChanged[0] = false; + event = new ActionEvent(new Object(), 0, ZOOM_OUT_DOMAIN_COMMAND); + panel.actionPerformed(event); + assertTrue(plotChanged[0]); + + plotChanged[0] = false; + event = new ActionEvent(new Object(), 0, ZOOM_OUT_RANGE_COMMAND); + panel.actionPerformed(event); + assertTrue(plotChanged[0]); + + event = new ActionEvent(new Object(), 0, ZOOM_RESET_BOTH_COMMAND); + panel.actionPerformed(event); + assertTrue(plotChanged[0]); + + plotChanged[0] = false; + event = new ActionEvent(new Object(), 0, ZOOM_RESET_BOTH_COMMAND); + panel.actionPerformed(event); + assertTrue(plotChanged[0]); + + plotChanged[0] = false; + event = new ActionEvent(new Object(), 0, ZOOM_RESET_BOTH_COMMAND); + panel.actionPerformed(event); + assertTrue(plotChanged[0]); + + event = new ActionEvent(new Object(), 0, COPY_COMMAND); + panel.actionPerformed(event); + Clipboard systemClipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + assertEquals("image/x-java-image; class=java.awt.Image", systemClipboard.getContents(this).getTransferDataFlavors()[0].getMimeType()); + + } + + @Test + public void testMouseEnteredExitedInteractions() { + DefaultXYDataset dataset = new DefaultXYDataset(); + JFreeChart chart = ChartFactory.createXYLineChart("TestChart", "X", + "Y", dataset, PlotOrientation.VERTICAL, false, false, false); + ChartPanel panel = new ChartPanel(chart); + panel.mouseEnteredAction(); + assertTrue(panel.isOwnToolTipDelaysActive()); + panel.mouseExitedAction(); + assertFalse(panel.isOwnToolTipDelaysActive()); + } + + @Test + public void testMousePressedPannableButNotDomainNorRange() { + DefaultXYDataset dataset = new DefaultXYDataset(); + JFreeChart chart = ChartFactory.createXYLineChart("TestChart", "X", + "Y", dataset, PlotOrientation.VERTICAL, false, false, false); + ChartPanel panel = new ChartPanel(chart); + Point cursorPoint = new Point(10, 20); + panel.mousePressedAction(10, 20, cursorPoint, false, 2); + assertNull(panel.getPanLast()); + } + + @Test + public void testMousePressedPannable() { + XYPlot plot = mock(XYPlot.class); + when(plot.isDomainPannable()).thenReturn(true); + when(plot.isRangePannable()).thenReturn(true); + JFreeChart chart = new JFreeChart(plot); + ChartPanel panel = spy(new ChartPanel(chart)); + when(panel.getScreenDataArea(anyInt(),anyInt())).thenReturn(new Rectangle(10,10)); + Point cursorPoint = new Point(0, 0); + panel.mousePressedAction(0, 0, cursorPoint, false, 2); + assertEquals(cursorPoint, panel.getPanLast()); + } + + @Test + public void testMousePressedNonPannable() { + DefaultPieDataset dataset = new DefaultPieDataset(); + JFreeChart chart = ChartFactory.createPieChart("TestChart", dataset); + ChartPanel panel = new ChartPanel(chart); + panel.mouseEnteredAction(); + assertTrue(panel.isOwnToolTipDelaysActive()); + panel.mouseExitedAction(); + assertFalse(panel.isOwnToolTipDelaysActive()); + } + + @Test + public void testMousePressedNoModifiersZoomRectangle() { + DefaultPieDataset dataset = new DefaultPieDataset(); + JFreeChart chart = ChartFactory.createPieChart("TestChart", dataset); + ChartPanel panel = spy(new ChartPanel(chart)); + when(panel.getScreenDataArea(anyInt(), anyInt())).thenReturn(new Rectangle(10,10)); + Point cursorPoint = new Point(0, 0); + panel.mousePressedAction(0, 0, cursorPoint, false, 1); + assertEquals(cursorPoint, panel.getZoomPoint()); + } + + @Test + public void testMousePressedNoModifiersZoomRectangleNullScreenDataArea() { + DefaultPieDataset dataset = new DefaultPieDataset(); + JFreeChart chart = ChartFactory.createPieChart("TestChart", dataset); + ChartPanel panel = spy(new ChartPanel(chart)); + when(panel.getScreenDataArea(anyInt(), anyInt())).thenReturn(null); + Point cursorPoint = new Point(0, 0); + panel.mousePressedAction(0, 0, cursorPoint, false, 1); + assertNull(panel.getZoomPoint()); + } + + @Test + public void testMousePressedNoModifiersPopupTrigger() { + DefaultPieDataset dataset = new DefaultPieDataset(); + JFreeChart chart = ChartFactory.createPieChart("TestChart", dataset); + ChartPanel panel = spy(new ChartPanel(chart)); + when(panel.getScreenDataArea(anyInt(), anyInt())).thenReturn(new Rectangle(10,10)); + final boolean[] displayPopupCalled = {false}; + doAnswer(new Answer() { + @Override + public Void answer(InvocationOnMock invocationOnMock) { + displayPopupCalled[0] = true; + return null; + } + }).when(panel).displayPopupMenu(anyInt(), anyInt()); + Point cursorPoint = new Point(0, 0); + panel.mousePressedAction(0, 0, cursorPoint, true, 1); + assertTrue(displayPopupCalled[0]); + } + + @Test + public void testGetPointInRectangle() { + DefaultPieDataset dataset = new DefaultPieDataset(); + JFreeChart chart = ChartFactory.createPieChart("TestChart", dataset); + ChartPanel panel = new ChartPanel(chart); + Rectangle2D r2d = mock(Rectangle2D.class); + when(r2d.getMaxX()).thenReturn(100d); + when(r2d.getMaxY()).thenReturn(50d); + + Point2D pointInRectangle = panel.getPointInRectangle(10, 20, r2d); + assertEquals(pointInRectangle.getX(), 10, 0.1); + assertEquals(pointInRectangle.getY(), 20, 0.1); + + pointInRectangle = panel.getPointInRectangle(100, 200, r2d); + assertEquals(pointInRectangle.getX(), 100, 0.1); + assertEquals(pointInRectangle.getY(), 50, 0.1); + + pointInRectangle = panel.getPointInRectangle(200, 200, r2d); + assertEquals(pointInRectangle.getX(), 100, 0.1); + assertEquals(pointInRectangle.getY(), 50, 0.1); + } + + @Test + public void testSetZoomRectangleNoZoomable() { + DefaultPieDataset dataset = new DefaultPieDataset(); + JFreeChart chart = ChartFactory.createPieChart("TestChart", dataset); + ChartPanel panel = new ChartPanel(chart); + panel.setZoomRectangle(10, 20, new Point(10, 20)); + assertNull(panel.getZoomRectangle()); + } + + @Test + public void testSetZoomRectangleVerticalPlotZoomable() { + DefaultXYDataset dataset = new DefaultXYDataset(); + JFreeChart chart = ChartFactory.createXYLineChart("TestChart", "X", + "Y", dataset, PlotOrientation.VERTICAL, false, false, false); + ChartPanel panel = new ChartPanel(chart); + panel.setZoomRectangle(10, 20, new Point(10, 20)); + assertEquals(new Rectangle2D.Double(10d, 20d, -10d, -20d), panel.getZoomRectangle()); + } + + @Test + public void testSetZoomRectangleHorizontalPlotZoomable() { + DefaultXYDataset dataset = new DefaultXYDataset(); + JFreeChart chart = ChartFactory.createXYLineChart("TestChart", "X", + "Y", dataset, PlotOrientation.HORIZONTAL, false, false, false); + ChartPanel panel = new ChartPanel(chart); + panel.setZoomRectangle(10, 20, new Point(10, 20)); + assertEquals(new Rectangle2D.Double(10d, 20d, -10d, -20d), panel.getZoomRectangle()); + } + + @Test + public void testSetZoomRectanglePlotZoomableRange() { + JFreeChart chart = new JFreeChart(new ThermometerPlot()); + ChartPanel panel = new ChartPanel(chart); + panel.setZoomRectangle(10, 20, new Point(10, 20)); + assertEquals(new Rectangle2D.Double(0d, 20d, 0d, -20d), panel.getZoomRectangle()); + } + + @Test + public void testhandlePanningVertical() { + DefaultXYDataset dataset = new DefaultXYDataset(); + JFreeChart chart = ChartFactory.createXYLineChart("TestChart", "X", + "Y", dataset, PlotOrientation.VERTICAL, false, false, false); + ChartPanel panel = new ChartPanel(chart); + panel.setPanLast(new Point(15, 15)); + Point point = new Point(20, 30); + panel.mouseDraggedHandlePanning(10, 20, point); + assertEquals(point, panel.getPanLast()); + } + + @Test + public void testhandlePanningHorizontal() { + DefaultXYDataset dataset = new DefaultXYDataset(); + JFreeChart chart = ChartFactory.createXYLineChart("TestChart", "X", + "Y", dataset, PlotOrientation.HORIZONTAL, false, false, false); + ChartPanel panel = new ChartPanel(chart); + panel.setPanLast(new Point(15, 15)); + Point point = new Point(20, 30); + panel.mouseDraggedHandlePanning(10, 20, point); + assertEquals(point, panel.getPanLast()); + } + + @Test + public void testMouseReleasedNotNullPanLast() { + DefaultXYDataset dataset = new DefaultXYDataset(); + JFreeChart chart = ChartFactory.createXYLineChart("TestChart", "X", + "Y", dataset, PlotOrientation.HORIZONTAL, false, false, false); + ChartPanel panel = new ChartPanel(chart); + panel.setPanLast(new Point(15, 15)); + Point point = new Point(20, 30); + panel.mouseDraggedHandlePanning(10, 20, point); + assertEquals(point, panel.getPanLast()); + } + + @Test + public void testGetZoomAreaDoubleZoom() { + JFreeChart chart = new JFreeChart(new ThermometerPlot()); + ChartPanel panel = new ChartPanel(chart); + Rectangle2D zoomArea = panel.getZoomArea(true, true, new Point(10, 10), new Rectangle(15, 30)); + assertEquals(new Rectangle2D.Double(10d, 10d, -10d, -10d), zoomArea); + } + + @Test + public void testGetZoomAreaHZoom() { + JFreeChart chart = new JFreeChart(new ThermometerPlot()); + ChartPanel panel = new ChartPanel(chart); + Rectangle2D zoomArea = panel.getZoomArea(true, false, new Point(10, 10), new Rectangle(15, 30)); +// when(panel.getScreenDataArea(anyInt(),anyInt())).thenReturn(new Rectangle(10,10)); + assertEquals(new Rectangle2D.Double(10d, 0d, -10d, 0d), zoomArea); + } + + @Test + public void testGetZoomAreaVZoom() { + JFreeChart chart = new JFreeChart(new ThermometerPlot()); + ChartPanel panel = new ChartPanel(chart); + Rectangle2D zoomArea = panel.getZoomArea(false, true, new Point(10, 10), new Rectangle(15, 30)); +// when(panel.getScreenDataArea(anyInt(),anyInt())).thenReturn(new Rectangle(10,10)); + assertEquals(new Rectangle2D.Double(0d, 10d, 0d, -10d), zoomArea); + } + + @Test + public void testMouseReleasedPopupTrigger() { + DefaultPieDataset dataset = new DefaultPieDataset(); + JFreeChart chart = ChartFactory.createPieChart("TestChart", dataset); + ChartPanel panel = spy(new ChartPanel(chart)); + when(panel.getScreenDataArea(anyInt(), anyInt())).thenReturn(new Rectangle(10,10)); + final boolean[] displayPopupCalled = {false}; + doAnswer(new Answer() { + @Override + public Void answer(InvocationOnMock invocationOnMock) { + displayPopupCalled[0] = true; + return null; + } + }).when(panel).displayPopupMenu(anyInt(), anyInt()); + panel.mouseReleasedAction(0, 0, true, new Point(10, 10)); + assertTrue(displayPopupCalled[0]); + } + + @Test + public void testMouseReleasedPanLast() { + DefaultPieDataset dataset = new DefaultPieDataset(); + JFreeChart chart = ChartFactory.createPieChart("TestChart", dataset); + ChartPanel panel = spy(new ChartPanel(chart)); + panel.setPanLast(new Point(15, 15)); + panel.mouseReleasedAction(0, 0, true, new Point(10, 10)); + assertNull(panel.getPanLast()); + } + + @Test + public void testMouseReleasedZoomRectangle() { + DefaultXYDataset dataset = new DefaultXYDataset(); + JFreeChart chart = ChartFactory.createXYLineChart("TestChart", "X", + "Y", dataset, PlotOrientation.VERTICAL, false, false, false); + ChartPanel panel = spy(new ChartPanel(chart)); + panel.setPanLast(null); + panel.setZoomRectangle(10, 20, new Point(10, 20)); + doNothing().when(panel).displayPopupMenu(anyInt(), anyInt()); + panel.mouseReleasedAction(0, 0, true, new Point(10, 10)); + assertNull(panel.getZoomRectangle()); + } + + @Test(expected = IllegalStateException.class) + public void testGenerateSVGNull() { + DefaultXYDataset dataset = new DefaultXYDataset(); + JFreeChart chart = ChartFactory.createXYLineChart("TestChart", "X", + "Y", dataset, PlotOrientation.VERTICAL, false, false, false); + ChartPanel panel = spy(new ChartPanel(chart)); + panel.generateSVG(100, 200); + } + + @Test + public void testSaveNullFile() { + DefaultXYDataset dataset = new DefaultXYDataset(); + JFreeChart chart = ChartFactory.createXYLineChart("TestChart", "X", + "Y", dataset, PlotOrientation.VERTICAL, false, false, false); + ChartPanel panel = spy(new ChartPanel(chart)); + JFileChooser jFileChooser = mock(JFileChooser.class); + when(jFileChooser.getSelectedFile()).thenReturn(new File("/test/path")); + File file = panel.saveFile(JFileChooser.APPROVE_OPTION, jFileChooser, ".ext", null, "save_as"); + assertEquals("/test/path.ext", file.getPath()); + } + + @Test + public void testDealWithExistingFileCancel() { + DefaultXYDataset dataset = new DefaultXYDataset(); + JFreeChart chart = ChartFactory.createXYLineChart("TestChart", "X", + "Y", dataset, PlotOrientation.VERTICAL, false, false, false); + ChartPanel panel = spy(new ChartPanel(chart)); + File file = mock(File.class); + File fileToSave = panel.dealWithExistingFile(file, JOptionPane.CANCEL_OPTION); + assertNull(fileToSave); + } + + @Test + public void testDealWithExistingFileNotCancel() { + DefaultXYDataset dataset = new DefaultXYDataset(); + JFreeChart chart = ChartFactory.createXYLineChart("TestChart", "X", + "Y", dataset, PlotOrientation.VERTICAL, false, false, false); + ChartPanel panel = spy(new ChartPanel(chart)); + File file = mock(File.class); + File fileToSave = panel.dealWithExistingFile(file, JOptionPane.OK_OPTION); + assertEquals(file, fileToSave); + } + + @Test + public void testCreateFileChooser() { + DefaultXYDataset dataset = new DefaultXYDataset(); + JFreeChart chart = ChartFactory.createXYLineChart("TestChart", "X", + "Y", dataset, PlotOrientation.VERTICAL, false, false, false); + ChartPanel panel = spy(new ChartPanel(chart)); + JFileChooser fileChooser = panel.createFileChooser("PDF_Files", "ext"); + assertTrue(fileChooser.getFileFilter().accept(new File("test.ext"))); + assertFalse(fileChooser.getFileFilter().accept(new File("test.other"))); + } + + } diff -burN jfreechart-original/src/test/java/org/jfree/chart/entity/ChartEntityTest.java jfreechart-after-maintenance/src/test/java/org/jfree/chart/entity/ChartEntityTest.java --- jfreechart-original/src/test/java/org/jfree/chart/entity/ChartEntityTest.java 1970-01-01 01:00:00.000000000 +0100 +++ jfreechart-after-maintenance/src/test/java/org/jfree/chart/entity/ChartEntityTest.java 2022-04-17 18:12:48.000000000 +0200 @@ -0,0 +1,76 @@ +package org.jfree.chart.entity; + +import org.jfree.chart.imagemap.StandardToolTipTagFragmentGenerator; +import org.jfree.chart.imagemap.StandardURLTagFragmentGenerator; +import org.junit.Before; +import org.junit.Test; + +import java.awt.*; + +import static org.junit.Assert.*; + +public class ChartEntityTest { + + private ChartEntity chartEntityRect, chartEntityPoly; + + @Before + public void setUp() throws Exception { + chartEntityRect = new ChartEntity(new Rectangle(1, 2, 3, 4)); + chartEntityPoly = new ChartEntity(new Polygon(new int[]{1, 2, 3, 4, 5}, new int[]{1, 2, 3, 4, 5},5)); + } + + @Test + public void testgetShapeType() { + assertEquals("rect", chartEntityRect.getShapeType()); + assertEquals("poly", chartEntityPoly.getShapeType()); + } + + @Test + public void testgetShapeCoords() { + assertEquals("1,2,4,6", chartEntityRect.getShapeCoords()); + assertEquals("1,1,2,2,3,3,4,4,5,5,5,5", chartEntityPoly.getShapeCoords()); + } + + @Test + public void testgetImageMapAreaTag() { + StandardToolTipTagFragmentGenerator toolTipGenerator = new StandardToolTipTagFragmentGenerator(); + StandardURLTagFragmentGenerator urlTagGenerator = new StandardURLTagFragmentGenerator(); + assertEquals("", chartEntityRect.getImageMapAreaTag(toolTipGenerator, urlTagGenerator)); + chartEntityRect.setToolTipText(" a nice rectangle"); + assertEquals("\"\"", + chartEntityRect.getImageMapAreaTag(toolTipGenerator, urlTagGenerator)); + chartEntityRect.setURLText("http://www.example.com/jfreechart"); + assertEquals("\"\"", + chartEntityRect.getImageMapAreaTag(toolTipGenerator, urlTagGenerator)); + chartEntityPoly.setURLText("http://www.example.com/jfreechart"); + assertEquals("\"\"/", + chartEntityPoly.getImageMapAreaTag(toolTipGenerator, urlTagGenerator)); + } + + @Test + public void testToString() { + assertEquals("ChartEntity: tooltip = null", chartEntityRect.toString()); + chartEntityRect.setToolTipText(" a nice rectangle"); + assertEquals("ChartEntity: tooltip = a nice rectangle", chartEntityRect.toString()); + } + + @Test + public void testEquals() { + assertNotEquals(chartEntityRect,null); + assertEquals(chartEntityRect,chartEntityRect); + assertNotEquals(chartEntityRect,chartEntityPoly); + assertEquals(chartEntityRect, new ChartEntity(new Rectangle(1, 2, 3, 4))); + assertNotEquals(chartEntityRect, new ChartEntity(new Rectangle(2, 2, 3, 4))); + assertNotEquals(chartEntityRect, new ChartEntity(new Rectangle(1, 2, 3, 5))); + assertNotEquals(chartEntityPoly, new ChartEntity(new Polygon(new int[]{1, 2, 3, 4}, new int[]{1, 2, 3, 4},4))); + assertNotEquals(chartEntityPoly, new ChartEntity(new Polygon(new int[]{1, 2, 3, 4, 6}, new int[]{1, 2, 3, 4, 6},5))); + ChartEntity rectToolTip = new ChartEntity(new Rectangle(1, 2, 3, 4),"toolTip"); + assertNotEquals(chartEntityRect, rectToolTip); + assertEquals(rectToolTip, new ChartEntity(new Rectangle(1, 2, 3, 4),"toolTip")); + ChartEntity rectToolUrl = new ChartEntity(new Rectangle(1, 2, 3, 4),"toolTip", "http://www.example.com/jfreechart"); + assertNotEquals(chartEntityRect, rectToolUrl); + assertNotEquals(rectToolTip,rectToolUrl); + } + + +} \ No newline at end of file