001    /* ===========================================================
002     * JFreeChart : a free chart library for the Java(tm) platform
003     * ===========================================================
004     *
005     * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
006     *
007     * Project Info:  http://www.jfree.org/jfreechart/index.html
008     *
009     * This library is free software; you can redistribute it and/or modify it 
010     * under the terms of the GNU Lesser General Public License as published by 
011     * the Free Software Foundation; either version 2.1 of the License, or 
012     * (at your option) any later version.
013     *
014     * This library is distributed in the hope that it will be useful, but 
015     * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
016     * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
017     * License for more details.
018     *
019     * You should have received a copy of the GNU Lesser General Public
020     * License along with this library; if not, write to the Free Software
021     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
022     * USA.  
023     *
024     * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
025     * in the United States and other countries.]
026     *
027     * ------------------------
028     * IntervalBarRenderer.java
029     * ------------------------
030     * (C) Copyright 2002-2005, by Jeremy Bowman.
031     *
032     * Original Author:  Jeremy Bowman;
033     * Contributor(s):   David Gilbert (for Object Refinery Limited);
034     *                   Christian W. Zuckschwerdt;
035     *
036     * $Id: IntervalBarRenderer.java,v 1.6.2.2 2005/12/01 20:33:26 mungady Exp $
037     *
038     * Changes
039     * -------
040     * 29-Apr-2002 : Version 1, contributed by Jeremy Bowman (DG);
041     * 11-May-2002 : Use CategoryPlot.getLabelsVisible() (JB);
042     * 29-May-2002 : Added constructors (DG);
043     * 26-Jun-2002 : Added axis to initialise method (DG);
044     * 20-Sep-2002 : Added basic support for chart entities (DG);
045     * 24-Oct-2002 : Amendments for changes in CategoryDataset interface and 
046     *               CategoryToolTipGenerator interface (DG);
047     * 05-Nov-2002 : Base dataset is now TableDataset not CategoryDataset (DG);
048     * 25-Mar-2003 : Implemented Serializable (DG);
049     * 30-Jul-2003 : Modified entity constructor (CZ);
050     * 19-Aug-2003 : Implemented Cloneable and PublicCloneable (DG);
051     * 08-Sep-2003 : Added checks for null values (DG);
052     * 07-Oct-2003 : Added renderer state (DG);
053     * 21-Oct-2003 : Bar width moved into renderer state (DG);
054     * 23-Dec-2003 : Removed the deprecated MultiIntervalCategoryDataset 
055     *               interface (DG);
056     * 05-Nov-2004 : Modified drawItem() signature (DG);
057     * 20-Apr-2005 : Renamed CategoryLabelGenerator 
058     *               --> CategoryItemLabelGenerator (DG);
059     * 
060     */
061    
062    package org.jfree.chart.renderer.category;
063    
064    import java.awt.Graphics2D;
065    import java.awt.Paint;
066    import java.awt.Stroke;
067    import java.awt.geom.Rectangle2D;
068    import java.io.Serializable;
069    
070    import org.jfree.chart.axis.CategoryAxis;
071    import org.jfree.chart.axis.ValueAxis;
072    import org.jfree.chart.entity.CategoryItemEntity;
073    import org.jfree.chart.entity.EntityCollection;
074    import org.jfree.chart.labels.CategoryItemLabelGenerator;
075    import org.jfree.chart.labels.CategoryToolTipGenerator;
076    import org.jfree.chart.plot.CategoryPlot;
077    import org.jfree.chart.plot.PlotOrientation;
078    import org.jfree.data.category.CategoryDataset;
079    import org.jfree.data.category.IntervalCategoryDataset;
080    import org.jfree.ui.RectangleEdge;
081    import org.jfree.util.PublicCloneable;
082    
083    /**
084     * A renderer that handles the drawing of bars for a bar plot where
085     * each bar has a high and low value.
086     * <p>
087     * For use with the {@link CategoryPlot} class.
088     *
089     * @author Jeremy Bowman
090     */
091    public class IntervalBarRenderer extends BarRenderer
092                                     implements CategoryItemRenderer, 
093                                                Cloneable, 
094                                                PublicCloneable, 
095                                                Serializable {
096    
097        /** For serialization. */
098        private static final long serialVersionUID = -5068857361615528725L;
099        
100        /**
101         * Constructs a new renderer.
102         */
103        public IntervalBarRenderer() {
104            super();
105        }
106    
107        /**
108         * Draws the bar for a single (series, category) data item.
109         *
110         * @param g2  the graphics device.
111         * @param state  the renderer state.
112         * @param dataArea  the data area.
113         * @param plot  the plot.
114         * @param domainAxis  the domain axis.
115         * @param rangeAxis  the range axis.
116         * @param dataset  the dataset.
117         * @param row  the row index (zero-based).
118         * @param column  the column index (zero-based).
119         * @param pass  the pass index.
120         */
121        public void drawItem(Graphics2D g2,
122                             CategoryItemRendererState state,
123                             Rectangle2D dataArea,
124                             CategoryPlot plot,
125                             CategoryAxis domainAxis,
126                             ValueAxis rangeAxis,
127                             CategoryDataset dataset,
128                             int row,
129                             int column,
130                             int pass) {
131    
132             if (dataset instanceof IntervalCategoryDataset) {
133                 IntervalCategoryDataset d = (IntervalCategoryDataset) dataset;
134                 drawInterval(
135                     g2, state, dataArea, plot, domainAxis, rangeAxis, 
136                     d, row, column
137                 );
138             }
139             else {
140                 super.drawItem(
141                     g2, state, dataArea, plot, domainAxis, rangeAxis, 
142                     dataset, row, column, pass
143                 );
144             } 
145             
146         }
147                              
148         /**
149          * Draws a single interval.
150          *
151          * @param g2  the graphics device.
152          * @param state  the renderer state.
153          * @param dataArea  the data plot area.
154          * @param plot  the plot.
155          * @param domainAxis  the domain axis.
156          * @param rangeAxis  the range axis.
157          * @param dataset  the data.
158          * @param row  the row index (zero-based).
159          * @param column  the column index (zero-based).
160          */
161         protected void drawInterval(Graphics2D g2,
162                                     CategoryItemRendererState state,
163                                     Rectangle2D dataArea,
164                                     CategoryPlot plot,
165                                     CategoryAxis domainAxis,
166                                     ValueAxis rangeAxis,
167                                     IntervalCategoryDataset dataset,
168                                     int row,
169                                     int column) {
170    
171            int seriesCount = getRowCount();
172            int categoryCount = getColumnCount();
173    
174            PlotOrientation orientation = plot.getOrientation();
175            
176            double rectX = 0.0;
177            double rectY = 0.0;
178    
179            RectangleEdge domainAxisLocation = plot.getDomainAxisEdge();
180            RectangleEdge rangeAxisLocation = plot.getRangeAxisEdge();
181            
182            // Y0
183            Number value0 = dataset.getEndValue(row, column);
184            if (value0 == null) {
185                return;
186            }
187            double java2dValue0 = rangeAxis.valueToJava2D(
188                value0.doubleValue(), dataArea, rangeAxisLocation
189            );
190    
191            // Y1
192            Number value1 = dataset.getStartValue(row, column);
193            if (value1 == null) {
194                return;
195            }
196            double java2dValue1 = rangeAxis.valueToJava2D(
197                value1.doubleValue(), dataArea, rangeAxisLocation
198            );
199    
200            if (java2dValue1 < java2dValue0) {
201                double temp = java2dValue1;
202                java2dValue1 = java2dValue0;
203                java2dValue0 = temp;
204                Number tempNum = value1;
205                value1 = value0;
206                value0 = tempNum;
207            }
208    
209            // BAR WIDTH
210            double rectWidth = state.getBarWidth();
211    
212            // BAR HEIGHT
213            double rectHeight = Math.abs(java2dValue1 - java2dValue0);
214    
215            if (orientation == PlotOrientation.HORIZONTAL) {
216                // BAR Y
217                rectY = domainAxis.getCategoryStart(
218                    column, getColumnCount(), dataArea, domainAxisLocation
219                );
220                if (seriesCount > 1) {
221                    double seriesGap = dataArea.getHeight() * getItemMargin()
222                                       / (categoryCount * (seriesCount - 1));
223                    rectY = rectY + row * (state.getBarWidth() + seriesGap);
224                }
225                else {
226                    rectY = rectY + row * state.getBarWidth();
227                }
228                
229                rectX = java2dValue0;
230    
231                rectHeight = state.getBarWidth();
232                rectWidth = Math.abs(java2dValue1 - java2dValue0);
233    
234            }
235            else if (orientation == PlotOrientation.VERTICAL) {
236                // BAR X
237                rectX = domainAxis.getCategoryStart(
238                    column, getColumnCount(), dataArea, domainAxisLocation
239                );
240    
241                if (seriesCount > 1) {
242                    double seriesGap = dataArea.getWidth() * getItemMargin()
243                                       / (categoryCount * (seriesCount - 1));
244                    rectX = rectX + row * (state.getBarWidth() + seriesGap);
245                }
246                else {
247                    rectX = rectX + row * state.getBarWidth();
248                }
249    
250                rectY = java2dValue0;
251    
252            }
253            Rectangle2D bar = new Rectangle2D.Double(
254                rectX, rectY, rectWidth, rectHeight
255            );
256            Paint seriesPaint = getItemPaint(row, column);
257            g2.setPaint(seriesPaint);
258            g2.fill(bar);
259            
260            // draw the outline...
261            if (state.getBarWidth() > BAR_OUTLINE_WIDTH_THRESHOLD) {
262                Stroke stroke = getItemOutlineStroke(row, column);
263                Paint paint = getItemOutlinePaint(row, column);
264                if (stroke != null && paint != null) {
265                    g2.setStroke(stroke);
266                    g2.setPaint(paint);
267                    g2.draw(bar);
268                }
269            }
270            
271            CategoryItemLabelGenerator generator 
272                = getItemLabelGenerator(row, column);
273            if (generator != null && isItemLabelVisible(row, column)) {
274                drawItemLabel(
275                    g2, dataset, row, column, plot, generator, bar, false
276                );
277            }        
278    
279            // collect entity and tool tip information...
280            if (state.getInfo() != null) {
281                EntityCollection entities = state.getEntityCollection();
282                if (entities != null) {
283                    String tip = null;
284                    CategoryToolTipGenerator tipster 
285                        = getToolTipGenerator(row, column);
286                    if (tipster != null) {
287                        tip = tipster.generateToolTip(dataset, row, column);
288                    }
289                    String url = null;
290                    if (getItemURLGenerator(row, column) != null) {
291                        url = getItemURLGenerator(row, column).generateURL(
292                            dataset, row, column
293                        );
294                    }
295                    CategoryItemEntity entity = new CategoryItemEntity(
296                        bar, tip, url, dataset, row, 
297                        dataset.getColumnKey(column), column
298                    );
299                    entities.add(entity);
300                }
301            }
302    
303        }
304    
305    }