001    /* ===========================================================
002     * JFreeChart : a free chart library for the Java(tm) platform
003     * ===========================================================
004     *
005     * (C) Copyright 2000-2007, 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-2007, by Jeremy Bowman.
031     *
032     * Original Author:  Jeremy Bowman;
033     * Contributor(s):   David Gilbert (for Object Refinery Limited);
034     *                   Christian W. Zuckschwerdt;
035     *
036     * Changes
037     * -------
038     * 29-Apr-2002 : Version 1, contributed by Jeremy Bowman (DG);
039     * 11-May-2002 : Use CategoryPlot.getLabelsVisible() (JB);
040     * 29-May-2002 : Added constructors (DG);
041     * 26-Jun-2002 : Added axis to initialise method (DG);
042     * 20-Sep-2002 : Added basic support for chart entities (DG);
043     * 24-Oct-2002 : Amendments for changes in CategoryDataset interface and 
044     *               CategoryToolTipGenerator interface (DG);
045     * 05-Nov-2002 : Base dataset is now TableDataset not CategoryDataset (DG);
046     * 25-Mar-2003 : Implemented Serializable (DG);
047     * 30-Jul-2003 : Modified entity constructor (CZ);
048     * 19-Aug-2003 : Implemented Cloneable and PublicCloneable (DG);
049     * 08-Sep-2003 : Added checks for null values (DG);
050     * 07-Oct-2003 : Added renderer state (DG);
051     * 21-Oct-2003 : Bar width moved into renderer state (DG);
052     * 23-Dec-2003 : Removed the deprecated MultiIntervalCategoryDataset 
053     *               interface (DG);
054     * 05-Nov-2004 : Modified drawItem() signature (DG);
055     * 20-Apr-2005 : Renamed CategoryLabelGenerator 
056     *               --> CategoryItemLabelGenerator (DG);
057     * 02-Feb-2007 : Removed author tags all over JFreeChart sources (DG);
058     * 
059     */
060    
061    package org.jfree.chart.renderer.category;
062    
063    import java.awt.Graphics2D;
064    import java.awt.Paint;
065    import java.awt.Stroke;
066    import java.awt.geom.Rectangle2D;
067    import java.io.Serializable;
068    
069    import org.jfree.chart.axis.CategoryAxis;
070    import org.jfree.chart.axis.ValueAxis;
071    import org.jfree.chart.entity.CategoryItemEntity;
072    import org.jfree.chart.entity.EntityCollection;
073    import org.jfree.chart.labels.CategoryItemLabelGenerator;
074    import org.jfree.chart.labels.CategoryToolTipGenerator;
075    import org.jfree.chart.plot.CategoryPlot;
076    import org.jfree.chart.plot.PlotOrientation;
077    import org.jfree.data.category.CategoryDataset;
078    import org.jfree.data.category.IntervalCategoryDataset;
079    import org.jfree.ui.RectangleEdge;
080    import org.jfree.util.PublicCloneable;
081    
082    /**
083     * A renderer that handles the drawing of bars for a bar plot where
084     * each bar has a high and low value.
085     * <p>
086     * For use with the {@link CategoryPlot} class.
087     */
088    public class IntervalBarRenderer extends BarRenderer
089                                     implements CategoryItemRenderer, 
090                                                Cloneable, 
091                                                PublicCloneable, 
092                                                Serializable {
093    
094        /** For serialization. */
095        private static final long serialVersionUID = -5068857361615528725L;
096        
097        /**
098         * Constructs a new renderer.
099         */
100        public IntervalBarRenderer() {
101            super();
102        }
103    
104        /**
105         * Draws the bar for a single (series, category) data item.
106         *
107         * @param g2  the graphics device.
108         * @param state  the renderer state.
109         * @param dataArea  the data area.
110         * @param plot  the plot.
111         * @param domainAxis  the domain axis.
112         * @param rangeAxis  the range axis.
113         * @param dataset  the dataset.
114         * @param row  the row index (zero-based).
115         * @param column  the column index (zero-based).
116         * @param pass  the pass index.
117         */
118        public void drawItem(Graphics2D g2,
119                             CategoryItemRendererState state,
120                             Rectangle2D dataArea,
121                             CategoryPlot plot,
122                             CategoryAxis domainAxis,
123                             ValueAxis rangeAxis,
124                             CategoryDataset dataset,
125                             int row,
126                             int column,
127                             int pass) {
128    
129             if (dataset instanceof IntervalCategoryDataset) {
130                 IntervalCategoryDataset d = (IntervalCategoryDataset) dataset;
131                 drawInterval(g2, state, dataArea, plot, domainAxis, rangeAxis, 
132                         d, row, column);
133             }
134             else {
135                 super.drawItem(g2, state, dataArea, plot, domainAxis, rangeAxis, 
136                         dataset, row, column, pass);
137             } 
138             
139         }
140                              
141         /**
142          * Draws a single interval.
143          *
144          * @param g2  the graphics device.
145          * @param state  the renderer state.
146          * @param dataArea  the data plot area.
147          * @param plot  the plot.
148          * @param domainAxis  the domain axis.
149          * @param rangeAxis  the range axis.
150          * @param dataset  the data.
151          * @param row  the row index (zero-based).
152          * @param column  the column index (zero-based).
153          */
154         protected void drawInterval(Graphics2D g2,
155                                     CategoryItemRendererState state,
156                                     Rectangle2D dataArea,
157                                     CategoryPlot plot,
158                                     CategoryAxis domainAxis,
159                                     ValueAxis rangeAxis,
160                                     IntervalCategoryDataset dataset,
161                                     int row,
162                                     int column) {
163    
164            int seriesCount = getRowCount();
165            int categoryCount = getColumnCount();
166    
167            PlotOrientation orientation = plot.getOrientation();
168            
169            double rectX = 0.0;
170            double rectY = 0.0;
171    
172            RectangleEdge domainAxisLocation = plot.getDomainAxisEdge();
173            RectangleEdge rangeAxisLocation = plot.getRangeAxisEdge();
174            
175            // Y0
176            Number value0 = dataset.getEndValue(row, column);
177            if (value0 == null) {
178                return;
179            }
180            double java2dValue0 = rangeAxis.valueToJava2D(
181                value0.doubleValue(), dataArea, rangeAxisLocation
182            );
183    
184            // Y1
185            Number value1 = dataset.getStartValue(row, column);
186            if (value1 == null) {
187                return;
188            }
189            double java2dValue1 = rangeAxis.valueToJava2D(
190                    value1.doubleValue(), dataArea, rangeAxisLocation);
191    
192            if (java2dValue1 < java2dValue0) {
193                double temp = java2dValue1;
194                java2dValue1 = java2dValue0;
195                java2dValue0 = temp;
196                Number tempNum = value1;
197                value1 = value0;
198                value0 = tempNum;
199            }
200    
201            // BAR WIDTH
202            double rectWidth = state.getBarWidth();
203    
204            // BAR HEIGHT
205            double rectHeight = Math.abs(java2dValue1 - java2dValue0);
206    
207            if (orientation == PlotOrientation.HORIZONTAL) {
208                // BAR Y
209                rectY = domainAxis.getCategoryStart(
210                    column, getColumnCount(), dataArea, domainAxisLocation
211                );
212                if (seriesCount > 1) {
213                    double seriesGap = dataArea.getHeight() * getItemMargin()
214                                       / (categoryCount * (seriesCount - 1));
215                    rectY = rectY + row * (state.getBarWidth() + seriesGap);
216                }
217                else {
218                    rectY = rectY + row * state.getBarWidth();
219                }
220                
221                rectX = java2dValue0;
222    
223                rectHeight = state.getBarWidth();
224                rectWidth = Math.abs(java2dValue1 - java2dValue0);
225    
226            }
227            else if (orientation == PlotOrientation.VERTICAL) {
228                // BAR X
229                rectX = domainAxis.getCategoryStart(column, getColumnCount(), 
230                        dataArea, domainAxisLocation);
231    
232                if (seriesCount > 1) {
233                    double seriesGap = dataArea.getWidth() * getItemMargin()
234                                       / (categoryCount * (seriesCount - 1));
235                    rectX = rectX + row * (state.getBarWidth() + seriesGap);
236                }
237                else {
238                    rectX = rectX + row * state.getBarWidth();
239                }
240    
241                rectY = java2dValue0;
242    
243            }
244            Rectangle2D bar = new Rectangle2D.Double(rectX, rectY, rectWidth, 
245                    rectHeight);
246            Paint seriesPaint = getItemPaint(row, column);
247            g2.setPaint(seriesPaint);
248            g2.fill(bar);
249            
250            // draw the outline...
251            if (state.getBarWidth() > BAR_OUTLINE_WIDTH_THRESHOLD) {
252                Stroke stroke = getItemOutlineStroke(row, column);
253                Paint paint = getItemOutlinePaint(row, column);
254                if (stroke != null && paint != null) {
255                    g2.setStroke(stroke);
256                    g2.setPaint(paint);
257                    g2.draw(bar);
258                }
259            }
260            
261            CategoryItemLabelGenerator generator = getItemLabelGenerator(row,
262                    column);
263            if (generator != null && isItemLabelVisible(row, column)) {
264                drawItemLabel(g2, dataset, row, column, plot, generator, bar, 
265                        false);
266            }        
267    
268            // collect entity and tool tip information...
269            if (state.getInfo() != null) {
270                EntityCollection entities = state.getEntityCollection();
271                if (entities != null) {
272                    String tip = null;
273                    CategoryToolTipGenerator tipster 
274                            = getToolTipGenerator(row, column);
275                    if (tipster != null) {
276                        tip = tipster.generateToolTip(dataset, row, column);
277                    }
278                    String url = null;
279                    if (getItemURLGenerator(row, column) != null) {
280                        url = getItemURLGenerator(row, column).generateURL(
281                                dataset, row, column);
282                    }
283                    CategoryItemEntity entity = new CategoryItemEntity(bar, tip, 
284                            url, dataset, dataset.getRowKey(row), 
285                            dataset.getColumnKey(column));
286                    entities.add(entity);
287                }
288            }
289    
290        }
291    
292    }