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 boolean isNotify  = false;
059        private int             rangeSkip = 1;                  // 4.1.1.0 (2008/02/04) 縦軸のグリッドをスキップする間隔
060        private final int hsCode = Long.valueOf( System.nanoTime() ).hashCode() ;       // 5.1.9.0 (2010/08/01) equals,hashCode
061
062        /**
063         * デフォルトコンストラクター
064         * シリーズ番号を、初期化しておきます。
065         *
066         **/
067        public HybsCategoryPlot() {
068                // 4.3.4.4 (2009/01/01)
069                this( -1 );
070        }
071
072        /**
073         * シリーズ番号 を、指定して、オブジェクトを作成するコンストラクター
074         *
075         * @param       serNo   ピックアップするシリーズ番号
076         **/
077        protected HybsCategoryPlot( final int serNo ) {
078                // 4.3.4.4 (2009/01/01)
079//              super();
080                this.serNo = serNo;
081        }
082
083        /**
084         * ピックアップするシリーズ番号を設定します。
085         *
086         * @og.rev 4.1.1.0 (2008/02/04) データの値(itemText)表示の継承
087         *
088         * @param       newSerNo        ピックアップするシリーズ番号
089         **/
090        protected void setSeriesPikup( final int newSerNo ) {
091                int oldSerNo = serNo ;
092                serNo = newSerNo;
093                CategoryItemRenderer rend = getRenderer();
094                CategoryURLGenerator urlGen = rend.getSeriesItemURLGenerator( oldSerNo );
095                if( urlGen != null ) {
096                        rend.setSeriesItemURLGenerator( oldSerNo,null );
097                        rend.setSeriesItemURLGenerator( serNo   ,urlGen );
098                }
099
100                // 4.1.1.0 (2008/02/04) データの値(itemText)表示の継承
101                if( rend.isSeriesItemLabelsVisible( oldSerNo ) ) {
102                        rend.setSeriesItemLabelsVisible( oldSerNo,false );
103                        rend.setSeriesItemLabelsVisible( serNo   ,true  );
104                }
105        }
106
107        /**
108         * Notifyを設定します。
109         *
110         * @og.rev 5.1.4.0 (2010/03/01) 継承元の Plot クラスに public で追加された対応
111         * @og.rev 5.1.8.0 (2010/07/01) 実質的に使用されていないので、削除
112         *
113         * @param   isNotify boolean
114         **/
115//      protected void setNotify( final boolean isNotify ) {
116//      public void setNotify( final boolean isNotify ) {
117//              this.isNotify = isNotify;
118//      }
119
120        /**
121         * 縦軸のグリッド線(水平線)をスキップする間隔を指定します。
122         *
123         * 縦軸のグリッド線を表示する際に、スキップする間隔を指定します。
124         * 通常は、ラベルと同じだけのグリッド線が掛かれますが、ラベルよりも
125         * 少ない数のグリッド線(例えば、2つおき)を出す場合に、値を設定します。
126         * "1" (初期値)では、1つづつ表示(つまり、すべて表示する)します。
127         * "2" とすると、1つおきに、"3" とすると、2つおきに表示します。
128         * 初期値は、"1" (すべて表示)です。
129         * なお、先頭から表示を開始します。
130         *
131         * @og.rev 4.1.1.0 (2008/02/04) 新規追加
132         *
133         * @param       rngSkip 縦軸のグリッド線(水平線)をスキップする間隔
134         */
135        protected void setRangeSkip( final int rngSkip ) {
136                rangeSkip = rngSkip;
137        }
138
139        /**
140         * BarChart のバーの幅を直接指定します。
141         * 通常は、maxBarWidth や itemMargin で比率指定しますが、
142         * ここでは、CategoryItemRendererState オブジェクトに直接設定する為の
143         * データセット単位のマップを作成します。
144         *
145         * @param       index   データセット番号
146         * @param       width   バーの幅
147         **/
148        protected void setBarWidth( final int index,final Double width ) {
149                barWidths.put( index,width );
150        }
151
152        /**
153         * Draws a representation of a dataset within the dataArea region using the
154         * appropriate renderer.
155         *
156         * @param g2  the graphics device.
157         * @param dataArea      the region in which the data is to be drawn.
158         * @param index  the dataset and renderer index.
159         * @param info  an optional object for collection dimension information.
160         *
161         * @return      描画するデータが見つかった場合は、true
162         */
163        public boolean render( final Graphics2D g2, final Rectangle2D dataArea, final int index,
164                                                  final PlotRenderingInfo info ) {
165                boolean foundData = false;
166                CategoryDataset currentDataset = getDataset(index);
167                CategoryItemRenderer renderer = getRenderer(index);
168                // 4.3.1.0 (2008/08/19) 軸とデータセットのマッピング
169                this.mapDatasetToRangeAxis( index, index );
170
171                CategoryAxis domainAxis = null ;
172                if( renderer instanceof StackedBarRenderer ) {
173                        domainAxis = getDomainAxis(index);
174                }
175                else {
176                        domainAxis = getDomainAxisForDataset(index);
177                }
178
179                ValueAxis rangeAxis = getRangeAxis(index);
180                boolean hasData = !DatasetUtilities.isEmptyOrNull(currentDataset);
181                if(hasData && renderer != null) {
182                        foundData = true;
183                        CategoryItemRendererState state = renderer.initialise(g2, dataArea,
184                                        this, index, info);
185
186                        // 4.0.3.0 (2008/01/07) 棒グラフのバー幅指定
187                        Double bwidth = barWidths.get( index );
188                        if( bwidth != null ) { state.setBarWidth( bwidth.doubleValue() ); }
189
190                        if( renderer instanceof HybsDrawItem ) {
191                                ((HybsDrawItem)renderer).drawItem2(g2, state, dataArea, this,
192                                                domainAxis, rangeAxis, currentDataset , serNo );
193                        }
194                        else {
195                                int columnCount = currentDataset.getColumnCount();
196                                int rowCount = currentDataset.getRowCount();
197                                int passCount = renderer.getPassCount();
198                                for( int pass=0; pass<passCount; pass++ ) {
199                                        for( int column=0; column<columnCount; column++ ) {
200                                                for( int row=0; row<rowCount; row++ ) {
201                                                        if( row == serNo ) { continue; }        // Mis Add 2007/07/23
202                                                        renderer.drawItem(g2, state, dataArea, this,
203                                                                        domainAxis, rangeAxis, currentDataset,
204                                                                        row, column, pass);
205                                                }
206                                                // 指定のシリーズと一致する場合は、最後に描画する。 Mis Add 2007/07/23
207                                                if( serNo >= 0 ) {
208                                                        renderer.drawItem(g2, state, dataArea, this,
209                                                                        domainAxis, rangeAxis, currentDataset,
210                                                                        serNo, column, pass);
211                                                }
212                                        }
213                                }
214                        }
215                }
216                return foundData;
217        }
218
219        /**
220         * Draws the gridlines for the plot.
221         *
222         * @param g2  the graphics device.
223         * @param dataArea      the area inside the axes.
224         * @param ticks  the ticks.
225         *
226         * @see #drawDomainGridlines(Graphics2D, Rectangle2D)
227         */
228        @SuppressWarnings("rawtypes")
229        protected void drawRangeGridlines( final Graphics2D g2, final Rectangle2D dataArea,
230                                                                           final List ticks ) {
231                // draw the range grid lines, if any...
232
233                if (isRangeGridlinesVisible()) {
234                        Stroke gridStroke = getRangeGridlineStroke();
235                        Paint gridPaint = getRangeGridlinePaint();
236                        if ((gridStroke != null) && (gridPaint != null)) {
237                                ValueAxis axis = getRangeAxis();
238                                CategoryItemRenderer renderer1 = getRenderer();
239                                if (axis != null && renderer1 != null) {
240                                        Iterator<?> iterator = ticks.iterator();
241                                        int cnt = 0;
242                                        while (iterator.hasNext()) {
243                                                ValueTick tick = (ValueTick) iterator.next();
244                                                if( cnt % rangeSkip == 0 ) {
245                                                        renderer1.drawRangeGridline(g2, this,
246                                                                                axis, dataArea, tick.getValue());
247                                                }
248                                                cnt++ ;
249                                        }
250                                }
251                        }
252                }
253        }
254
255        /**
256         * この文字列と指定されたオブジェクトを比較します。
257         *
258         * 親クラスで、equals メソッドが実装されているため、警告がでます。
259         *
260         * @og.rev 5.1.8.0 (2010/07/01) findbug対応
261         * @og.rev 5.1.9.0 (2010/08/01) findbug対応
262         *
263         * @param       object  比較するオブジェクト
264         *
265         * @return      Objectが等しい場合は true、そうでない場合は false
266         */
267        @Override
268        public boolean equals( final Object object ) {
269                if( super.equals( object ) ) {
270                        return hsCode == ((HybsCategoryPlot)object).hsCode;
271                }
272                return false;
273        }
274
275        /**
276         * このオブジェクトのハッシュコードを取得します。
277         *
278         * @og.rev 5.1.8.0 (2010/07/01) findbug対応
279         * @og.rev 5.1.9.0 (2010/08/01) findbug対応
280         *
281         * @return      ハッシュコード
282         */
283//      public int hashCode() { return super.hashCode() ; }
284        @Override
285        public int hashCode() { return hsCode ; }
286
287        /**
288         * このオブジェクトと指定されたオブジェクトを比較します。
289         *
290         * @og.rev 4.0.0.0 (2007/11/28) 新規追加
291         * @og.rev 5.1.4.0 (2010/03/01) 削除します。
292         *
293         * @param anObject Object 比較されるオブジェクト
294         *
295         * @return      指定されたオブジェクトが等しい場合は true、そうでない場合は false
296         */
297//      public boolean equals( final Object anObject ) {
298//              if( super.equals( anObject ) ) {
299//                      HybsCategoryPlot other = ((HybsCategoryPlot)anObject);
300////                    if( other.serNo == serNo && other.isNotify == isNotify ) {
301//                      if( other.serNo == serNo ) {
302//                              return true;
303//                      }
304//              }
305//              return false;
306//      }
307
308        /**
309         * このオブジェクトのハッシュコードを返します。
310         *
311         * @og.rev 4.0.0.0 (2007/11/28) 新規追加
312         * @og.rev 5.1.4.0 (2010/03/01) 削除します。
313         *
314         * @return      このオブジェクトのハッシュコード値
315         */
316//      public int hashCode() {
317////            return super.hashCode() + serNo + Boolean.valueOf( isNotify ).hashCode() ;
318//              return super.hashCode() + serNo ;
319//      }
320}