85 } 86 if (!result.getNestedRows().isEmpty()) { 87 subdivision = result.getNestedRows(); 88 } 89 } 90 return new RenderedRowBase(subdivision, height, text, description, payload) { 91 92 @Override 93 public void infoAt(IChartInfoVisitor visitor, int x, int y, Point offset) { 94 for (IRenderedRow rr : results) { 95 rr.infoAt(visitor, x, y, offset); 96 } 97 } 98 }; 99 } 100 101 } 102 103 private static class CompositeRenderer implements IXDataRenderer { 104 105 private static final Color TOO_MUCH_CONTENT_BG = new Color(240, 240, 240, 190); 106 private static final String TOO_MUCH_CONTENT_MSG = Messages 107 .getString(Messages.RendererToolkit_TOO_MUCH_CONTENT); 108 private final List<IXDataRenderer> children; 109 private final List<Double> weights; 110 private final String text; 111 private final double totalWeight; 112 113 CompositeRenderer(List<IXDataRenderer> children, String text, List<Double> weights) { 114 this.children = children; 115 this.text = text; 116 this.weights = weights; 117 if (weights == null) { 118 totalWeight = children.size(); 119 } else { 120 double sum = 0; 121 for (Double w : weights) { 122 sum += w; 123 } 124 totalWeight = sum; 125 } 126 } 127 128 @Override 129 public IRenderedRow render(Graphics2D context, SubdividedQuantityRange xRange, int height) { 130 List<IRenderedRow> result = new ArrayList<>(children.size()); 131 AffineTransform oldTransform = context.getTransform(); 132 int heightLeft = height; 133 double weightLeft = totalWeight; 134 for (int i = 0; i < children.size(); i++) { 135 double rowWeight = weights == null ? 1 : weights.get(i); 136 int rowHeight = (int) Math.round(heightLeft / weightLeft * rowWeight); 137 weightLeft -= rowWeight; 138 if (rowHeight > 0) { 139 heightLeft -= rowHeight; 140 result.add(children.get(i).render(context, xRange, rowHeight)); 141 context.translate(0, rowHeight); 142 } 143 } 144 context.setTransform(oldTransform); 145 if (result.size() != children.size()) { 146 result = Collections.emptyList(); 147 context.setPaint(TOO_MUCH_CONTENT_BG); 148 context.fillRect(0, 0, xRange.getPixelExtent(), height); 149 // FIXME: Draw something nice. 150 Font orgFont = context.getFont(); 151 Font italicFont = orgFont.deriveFont(Font.ITALIC); 152 FontMetrics fm = context.getFontMetrics(italicFont); 153 int msgWidth = fm.stringWidth(TOO_MUCH_CONTENT_MSG); 154 if (height > fm.getHeight() && xRange.getPixelExtent() > msgWidth) { 155 context.setFont(italicFont); 156 context.setPaint(Color.BLACK); 157 context.drawString(TOO_MUCH_CONTENT_MSG, (xRange.getPixelExtent() - msgWidth) / 2, 158 (height - fm.getHeight()) / 2 + fm.getAscent()); 159 context.setFont(orgFont); 160 } 161 } 162 163 return new RenderedRowBase(result, height, text, null, null) { 164 165 @Override 166 public void infoAt(IChartInfoVisitor visitor, int x, int y, Point offset) { 167 boolean notifyLeave = false; 168 if (text != null) { 169 // FIXME: Use stored state for fullyShown? 170 notifyLeave = visitor.enterScope(text, (getHeight() > 20) && (text.length() <= 26)); 171 } 172 int yRowStart = 0; 173 for (IRenderedRow nestedRow : getNestedRows()) { 174 int yRowEnd = yRowStart + nestedRow.getHeight(); 175 if (yRowStart > y) { 176 break; 177 } else if (yRowEnd > y) { | 85 } 86 if (!result.getNestedRows().isEmpty()) { 87 subdivision = result.getNestedRows(); 88 } 89 } 90 return new RenderedRowBase(subdivision, height, text, description, payload) { 91 92 @Override 93 public void infoAt(IChartInfoVisitor visitor, int x, int y, Point offset) { 94 for (IRenderedRow rr : results) { 95 rr.infoAt(visitor, x, y, offset); 96 } 97 } 98 }; 99 } 100 101 } 102 103 private static class CompositeRenderer implements IXDataRenderer { 104 105 private static final Color MISMATCH_CONTENT_BG = new Color(240, 240, 240, 190); 106 private static final String TOO_MUCH_CONTENT_MSG = Messages 107 .getString(Messages.RendererToolkit_TOO_MUCH_CONTENT); 108 private static final String NO_CONTENT_MSG = Messages 109 .getString(Messages.RendererToolkit_NO_CONTENT); 110 private final List<IXDataRenderer> children; 111 private final List<Double> weights; 112 private final String text; 113 private final double totalWeight; 114 115 CompositeRenderer(List<IXDataRenderer> children, String text, List<Double> weights) { 116 this.children = children; 117 this.text = text; 118 this.weights = weights; 119 if (weights == null) { 120 totalWeight = children.size(); 121 } else { 122 double sum = 0; 123 for (Double w : weights) { 124 sum += w; 125 } 126 totalWeight = sum; 127 } 128 } 129 130 @Override 131 public IRenderedRow render(Graphics2D context, SubdividedQuantityRange xRange, int height) { 132 List<IRenderedRow> result = new ArrayList<>(children.size()); 133 AffineTransform oldTransform = context.getTransform(); 134 int heightLeft = height; 135 double weightLeft = totalWeight; 136 for (int i = 0; i < children.size(); i++) { 137 double rowWeight = weights == null ? 1 : weights.get(i); 138 int rowHeight = (int) Math.round(heightLeft / weightLeft * rowWeight); 139 weightLeft -= rowWeight; 140 if (rowHeight > 0) { 141 heightLeft -= rowHeight; 142 result.add(children.get(i).render(context, xRange, rowHeight)); 143 context.translate(0, rowHeight); 144 } 145 } 146 context.setTransform(oldTransform); 147 if (result.size() != children.size()) { 148 String displayMessage = result.size() == 0 ? NO_CONTENT_MSG : TOO_MUCH_CONTENT_MSG; 149 result = Collections.emptyList(); 150 context.setPaint(MISMATCH_CONTENT_BG); 151 context.fillRect(0, 0, xRange.getPixelExtent(), height); 152 // FIXME: Draw something nice. 153 Font orgFont = context.getFont(); 154 Font italicFont = orgFont.deriveFont(Font.ITALIC); 155 FontMetrics fm = context.getFontMetrics(italicFont); 156 int msgWidth = fm.stringWidth(displayMessage); 157 if (height > fm.getHeight() && xRange.getPixelExtent() > msgWidth) { 158 context.setFont(italicFont); 159 context.setPaint(Color.BLACK); 160 context.drawString(displayMessage, (xRange.getPixelExtent() - msgWidth) / 2, 161 (height - fm.getHeight()) / 2 + fm.getAscent()); 162 context.setFont(orgFont); 163 } 164 } 165 166 return new RenderedRowBase(result, height, text, null, null) { 167 168 @Override 169 public void infoAt(IChartInfoVisitor visitor, int x, int y, Point offset) { 170 boolean notifyLeave = false; 171 if (text != null) { 172 // FIXME: Use stored state for fullyShown? 173 notifyLeave = visitor.enterScope(text, (getHeight() > 20) && (text.length() <= 26)); 174 } 175 int yRowStart = 0; 176 for (IRenderedRow nestedRow : getNestedRows()) { 177 int yRowEnd = yRowStart + nestedRow.getHeight(); 178 if (yRowStart > y) { 179 break; 180 } else if (yRowEnd > y) { |