001/*
002 * Copyright (c) 2009 The openGion Project.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
013 * either express or implied. See the License for the specific language
014 * governing permissions and limitations under the License.
015 */
016package org.opengion.hayabusa.io;
017
018import java.awt.Graphics2D;
019import java.awt.Stroke;
020import java.awt.Paint;
021import java.awt.geom.Rectangle2D;
022import java.util.List;
023import java.util.Map;
024import java.util.HashMap;
025import java.util.Iterator;
026
027import org.jfree.chart.plot.CategoryPlot;
028import org.jfree.chart.plot.PlotRenderingInfo;
029import org.jfree.chart.urls.CategoryURLGenerator;
030import org.jfree.chart.axis.CategoryAxis;
031import org.jfree.chart.axis.ValueAxis;
032import org.jfree.chart.axis.ValueTick;
033import org.jfree.chart.renderer.category.CategoryItemRenderer;
034import org.jfree.chart.renderer.category.CategoryItemRendererState;
035import org.jfree.chart.renderer.category.StackedBarRenderer;
036import org.jfree.data.category.CategoryDataset;
037import org.jfree.data.general.DatasetUtilities;
038
039/**
040 * HybsCategoryPlot は、CategoryPlot を拡張したカスタマイズクラスです。
041 * これは、シリーズの表示色を変更する箇所で、描画順により、きれいに表示されない
042 * 現象への対応案です。
043 * 描画順を、最も最後に行うように、修正しています。
044 *
045 * renders each data item using a {@link CategoryItemRenderer}.
046 *
047 * @og.rev 3.8.9.2 (2007/07/28) 新規作成
048 *
049 * @version  0.9.0  2001/05/05
050 * @author   Kazuhiko Hasegawa
051 * @since    JDK1.1,
052 */
053public class HybsCategoryPlot extends CategoryPlot {
054        private static final long serialVersionUID = 519020100801L ;
055
056        private final Map<Integer,Double> barWidths = new HashMap<Integer,Double>();    // 4.3.1.1 (2008/08/23) final化
057        private int             serNo     = -1;
058        private int             rangeSkip = 1;                  // 4.1.1.0 (2008/02/04) 縦軸のグリッドをスキップする間隔
059        private final int hsCode = Long.valueOf( System.nanoTime() ).hashCode() ;       // 5.1.9.0 (2010/08/01) equals,hashCode
060
061        /**
062         * デフォルトコンストラクター
063         * シリーズ番号を、初期化しておきます。
064         *
065         **/
066        public HybsCategoryPlot() {
067                // 4.3.4.4 (2009/01/01)
068                this( -1 );
069        }
070
071        /**
072         * シリーズ番号 を、指定して、オブジェクトを作成するコンストラクター
073         *
074         * @param       serNo   ピックアップするシリーズ番号
075         **/
076        protected HybsCategoryPlot( final int serNo ) {
077                // 4.3.4.4 (2009/01/01)
078                this.serNo = serNo;
079        }
080
081        /**
082         * ピックアップするシリーズ番号を設定します。
083         *
084         * @og.rev 4.1.1.0 (2008/02/04) データの値(itemText)表示の継承
085         *
086         * @param       newSerNo        ピックアップするシリーズ番号
087         **/
088        protected void setSeriesPikup( final int newSerNo ) {
089                int oldSerNo = serNo ;
090                serNo = newSerNo;
091                CategoryItemRenderer rend = getRenderer();
092                CategoryURLGenerator urlGen = rend.getSeriesItemURLGenerator( oldSerNo );
093                if( urlGen != null ) {
094                        rend.setSeriesItemURLGenerator( oldSerNo,null );
095                        rend.setSeriesItemURLGenerator( serNo   ,urlGen );
096                }
097
098                // 4.1.1.0 (2008/02/04) データの値(itemText)表示の継承
099                if( rend.isSeriesItemLabelsVisible( oldSerNo ) ) {
100                        rend.setSeriesItemLabelsVisible( oldSerNo,false );
101                        rend.setSeriesItemLabelsVisible( serNo   ,true  );
102                }
103        }
104
105        /**
106         * 縦軸のグリッド線(水平線)をスキップする間隔を指定します。
107         *
108         * 縦軸のグリッド線を表示する際に、スキップする間隔を指定します。
109         * 通常は、ラベルと同じだけのグリッド線が掛かれますが、ラベルよりも
110         * 少ない数のグリッド線(例えば、2つおき)を出す場合に、値を設定します。
111         * "1" (初期値)では、1つづつ表示(つまり、すべて表示する)します。
112         * "2" とすると、1つおきに、"3" とすると、2つおきに表示します。
113         * 初期値は、"1" (すべて表示)です。
114         * なお、先頭から表示を開始します。
115         *
116         * @og.rev 4.1.1.0 (2008/02/04) 新規追加
117         *
118         * @param       rngSkip 縦軸のグリッド線(水平線)をスキップする間隔
119         */
120        protected void setRangeSkip( final int rngSkip ) {
121                rangeSkip = rngSkip;
122        }
123
124        /**
125         * BarChart のバーの幅を直接指定します。
126         * 通常は、maxBarWidth や itemMargin で比率指定しますが、
127         * ここでは、CategoryItemRendererState オブジェクトに直接設定する為の
128         * データセット単位のマップを作成します。
129         *
130         * @param       index   データセット番号
131         * @param       width   バーの幅
132         **/
133        protected void setBarWidth( final int index,final Double width ) {
134                barWidths.put( index,width );
135        }
136
137        /**
138         * Draws a representation of a dataset within the dataArea region using the
139         * appropriate renderer.
140         *
141         * @param g2  the graphics device.
142         * @param dataArea      the region in which the data is to be drawn.
143         * @param index  the dataset and renderer index.
144         * @param info  an optional object for collection dimension information.
145         *
146         * @return      描画するデータが見つかった場合は、true
147         */
148        public boolean render( final Graphics2D g2, final Rectangle2D dataArea, final int index,
149                                                  final PlotRenderingInfo info ) {
150                boolean foundData = false;
151                CategoryDataset currentDataset = getDataset(index);
152                CategoryItemRenderer renderer = getRenderer(index);
153                // 4.3.1.0 (2008/08/19) 軸とデータセットのマッピング
154                this.mapDatasetToRangeAxis( index, index );
155
156                CategoryAxis domainAxis = null ;
157                if( renderer instanceof StackedBarRenderer ) {
158                        domainAxis = getDomainAxis(index);
159                }
160                else {
161                        domainAxis = getDomainAxisForDataset(index);
162                }
163
164                ValueAxis rangeAxis = getRangeAxis(index);
165                boolean hasData = !DatasetUtilities.isEmptyOrNull(currentDataset);
166                if(hasData && renderer != null) {
167                        foundData = true;
168                        CategoryItemRendererState state = renderer.initialise(g2, dataArea,
169                                        this, index, info);
170
171                        // 4.0.3.0 (2008/01/07) 棒グラフのバー幅指定
172                        Double bwidth = barWidths.get( index );
173                        if( bwidth != null ) { state.setBarWidth( bwidth.doubleValue() ); }
174
175                        if( renderer instanceof HybsDrawItem ) {
176                                ((HybsDrawItem)renderer).drawItem2(g2, state, dataArea, this,
177                                                domainAxis, rangeAxis, currentDataset , serNo );
178                        }
179                        else {
180                                int columnCount = currentDataset.getColumnCount();
181                                int rowCount = currentDataset.getRowCount();
182                                int passCount = renderer.getPassCount();
183                                for( int pass=0; pass<passCount; pass++ ) {
184                                        for( int column=0; column<columnCount; column++ ) {
185                                                for( int row=0; row<rowCount; row++ ) {
186                                                        if( row == serNo ) { continue; }        // Mis Add 2007/07/23
187                                                        renderer.drawItem(g2, state, dataArea, this,
188                                                                        domainAxis, rangeAxis, currentDataset,
189                                                                        row, column, pass);
190                                                }
191                                                // 指定のシリーズと一致する場合は、最後に描画する。 Mis Add 2007/07/23
192                                                if( serNo >= 0 ) {
193                                                        renderer.drawItem(g2, state, dataArea, this,
194                                                                        domainAxis, rangeAxis, currentDataset,
195                                                                        serNo, column, pass);
196                                                }
197                                        }
198                                }
199                        }
200                }
201                return foundData;
202        }
203
204        /**
205         * Draws the gridlines for the plot.
206         *
207         * @param g2  the graphics device.
208         * @param dataArea      the area inside the axes.
209         * @param ticks  the ticks.
210         *
211         * @see #drawDomainGridlines(Graphics2D, Rectangle2D)
212         */
213        @SuppressWarnings("rawtypes")
214        protected void drawRangeGridlines( final Graphics2D g2, final Rectangle2D dataArea,
215                                                                           final List ticks ) {
216                // draw the range grid lines, if any...
217
218                if (isRangeGridlinesVisible()) {
219                        Stroke gridStroke = getRangeGridlineStroke();
220                        Paint gridPaint = getRangeGridlinePaint();
221                        if ( gridStroke != null && gridPaint != null ) {
222                                ValueAxis axis = getRangeAxis();
223                                CategoryItemRenderer renderer1 = getRenderer();
224                                if (axis != null && renderer1 != null) {
225                                        Iterator<?> iterator = ticks.iterator();
226                                        int cnt = 0;
227                                        while (iterator.hasNext()) {
228                                                ValueTick tick = (ValueTick) iterator.next();
229                                                if( cnt % rangeSkip == 0 ) {
230                                                        renderer1.drawRangeGridline(g2, this,
231                                                                                axis, dataArea, tick.getValue());
232                                                }
233                                                cnt++ ;
234                                        }
235                                }
236                        }
237                }
238        }
239
240        /**
241         * この文字列と指定されたオブジェクトを比較します。
242         *
243         * 親クラスで、equals メソッドが実装されているため、警告がでます。
244         *
245         * @og.rev 5.1.8.0 (2010/07/01) findbug対応
246         * @og.rev 5.1.9.0 (2010/08/01) findbug対応
247         *
248         * @param       object  比較するオブジェクト
249         *
250         * @return      Objectが等しい場合は true、そうでない場合は false
251         */
252        @Override
253        public boolean equals( final Object object ) {
254                if( super.equals( object ) ) {
255                        return hsCode == ((HybsCategoryPlot)object).hsCode;
256                }
257                return false;
258        }
259
260        /**
261         * このオブジェクトのハッシュコードを取得します。
262         *
263         * @og.rev 5.1.8.0 (2010/07/01) findbug対応
264         * @og.rev 5.1.9.0 (2010/08/01) findbug対応
265         *
266         * @return      ハッシュコード
267         */
268        @Override
269        public int hashCode() { return hsCode ; }
270}