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
018
019import java.util.List;
020import java.util.ArrayList;
021import java.awt.Graphics2D;
022import java.awt.geom.Rectangle2D;
023import org.jfree.ui.RectangleEdge;
024import org.jfree.text.TextBlock;
025import org.jfree.chart.axis.AxisState;
026import org.jfree.chart.axis.CategoryAxis;
027import org.jfree.chart.axis.CategoryAnchor;
028
029/**
030 * HybsCategoryAxis は、CategoryAxis クラスを継承した、横軸管理クラスです。
031 * 横軸ラベルの表示制御を、主に行っています。
032 * 横軸表示には、3つの制御機能がカスタマイズされています。
033 *
034 *  1."_" ラベルのスキップ(非表示)
035 *  2.cutNo 属性による、ラベル文字位置指定のキーブレイク
036 *  3.skip 属性による、ラベルをスキップする間隔の指定
037 *
038 * 上記、1,2,3 の順番で優先的に処理されます。
039 *
040 * @version  0.9.0      2007/06/21
041 * @author       Kazuhiko Hasegawa
042 * @since        JDK1.1,
043 */
044public class HybsCategoryAxis extends CategoryAxis {
045        private static final long serialVersionUID = 519020100801L ;
046
047        private static final TextBlock NULL_LABEL = new TextBlock() ;
048
049        // 4.1.2.0 (2008/03/12) 新規追加
050        private enum LabelVisible { TRUE(true) , FALSE(false) , UNDER(true) ;
051                private final boolean flag ;
052                LabelVisible( boolean flag ) { this.flag = flag; }
053                public boolean booleanValue() { return flag; }
054        };
055
056        /** For serialization. */
057        private int skip  = 1;                          // skip数
058        private int count = 0;                          // skip 時の現在位置のカウント
059
060        private transient List<LabelVisible> labelBreak = null;
061        private int             cutNo                   = -1;           // 4.1.1.0 (2008/02/04) ラベルブレイクのsubstring 位置
062        private String  breakKey                = null;         // 4.1.1.0 (2008/02/04) ラベルブレイクの前回キー
063        private boolean isItemLabelLastVisible = false; // 4.1.2.0 (2008/03/12)
064        private final int hsCode = Long.valueOf( System.nanoTime() ).hashCode() ;       // 5.1.9.0 (2010/08/01) equals,hashCode
065
066        /**
067         * 引数を指定して作成する コンストラクター
068         *
069         * skip(ラベルの表示間隔) = 1 , cutNo(ラベルブレイクのsubstring 位置) = -1 で初期化します。
070         *
071         * @param       label   ラベル
072         */
073        public HybsCategoryAxis( final String label ) {
074                this( label,1,-1 );
075        }
076
077        /**
078         * 引数を指定して作成する コンストラクター
079         *
080         * @og.rev 4.1.1.0 (2008/02/04) cutNo 新規追加
081         *
082         * @param       label   ラベル
083         * @param       skip    ラベルの表示間隔
084         * @param       cutNo   ラベルブレイクのsubstring 位置
085         */
086        protected HybsCategoryAxis( final String label,final int skip,final int cutNo ) {
087                super( label );
088                this.skip       = skip ;
089                this.cutNo      = cutNo ;
090        }
091
092        /**
093         * itemLabelVisible 時に、最後の値のみ表示するかどうか[true/false]を指定します。
094         *
095         * これは、itemLabelVisible 属性に、"last" という設定値を指定した場合は、
096         * 最後のみラベル表示します。
097         * このメソッドでは、true が指定された場合は、"last" 属性が有効になったと
098         * 判断します。
099         *
100         * @og.rev 4.1.2.0 (2008/03/12) 新規追加
101         *
102         * @param       flag            最後の値のみ表示するかどうか[true/false]
103         */
104        protected void setItemLabelLastVisible( final boolean flag ) {
105                isItemLabelLastVisible = flag;
106        }
107
108        /**
109         * 軸を引く場合、使用することができるチックの一時的リストを作成します。
110         *
111         * @og.rev 4.1.1.0 (2008/02/04) labelBreak 新規追加
112         *
113         * @param       g2                      Graphics2Dオブジェクト(フォント測定に使用)
114         * @param       state           AxisStateオブジェクト
115         * @param       dataArea        インサイドエリアを示すRectangle2Dオブジェクト
116         * @param       edge            ロケーションを指定するRectangleEdgeオブジェクト
117         *
118         * @return      チックのリスト
119         */
120        @Override
121        public List<?> refreshTicks( final Graphics2D g2,
122                                                          final AxisState state,
123                                                          final Rectangle2D dataArea,
124                                                          final RectangleEdge edge) {
125                count = 0;
126                labelBreak = new ArrayList<LabelVisible>();
127
128                return super.refreshTicks( g2, state, dataArea, edge);
129        }
130
131        /**
132         * TextBlock オブジェクトを作成します。
133         *
134         * このメソッドでは、3つの拡張機能を実現しています。
135         *  1."_" ラベルのスキップ(非表示)
136         *  2.cutNo 属性による、ラベル文字位置指定のキーブレイク
137         *  3.skip 属性による、ラベルをスキップする間隔の指定
138         * cutNo が指定された場合は、skip 処理は行われません。また、
139         * その場合のラベルは、cutNoで指定された先頭文字列のみ表示されます。
140         * 文字列が、cutNoで指定された数より小さい場合は、そのまま使用されます。
141         *
142         * @og.rev 4.1.1.0 (2008/02/04) cutNo,labelBreak 追加
143         * @og.rev 4.1.2.0 (2008/03/12) LabelVisible.UNDER 処理を追加
144         * @og.rev 4.3.1.1 (2008/08/23) lbl の null参照はずしの対応
145         *
146         * @param       category        カテゴリ名
147         * @param       width           幅
148         * @param       edge            表示範囲を示すRectangleEdgeオブジェクト
149         * @param       g2                      Graphics2Dオブジェクト
150         *
151         * @return      TextBlockオブジェクト
152         */
153        @SuppressWarnings("rawtypes")
154        protected TextBlock createLabel( final Comparable category, final float width,
155                                                                        final RectangleEdge edge, final Graphics2D g2) {
156                TextBlock label = null ;
157                String    lbl   = null;
158                if( category instanceof String ) {      // 4.3.1.1 (2008/08/23) instanceof チェックは、nullチェック不要
159                        lbl = (String)category;
160                        if( lbl.startsWith( "_" ) ) {
161                                label = NULL_LABEL;
162                        }
163                }
164
165                if( cutNo > 0 && lbl != null ) {
166                        if( lbl.length() >= cutNo ) {
167                                lbl = lbl.substring( 0,cutNo );
168                        }
169
170                        if( ! lbl.equals( breakKey ) ) {
171                                label = super.createLabel( lbl, width, edge,  g2);
172                                breakKey = lbl ;
173                        }
174                }
175                else {
176                        if( count % skip == 0 ) {
177                                label = super.createLabel( category, width, edge,  g2);
178                        }
179                        count++;
180                }
181
182                if( label == null ) {
183                        label = NULL_LABEL;
184                        labelBreak.add( LabelVisible.FALSE );
185                }
186                else if( label.equals( NULL_LABEL ) ) {
187                        labelBreak.add( LabelVisible.UNDER );
188                }
189                else {
190                        labelBreak.add( LabelVisible.TRUE );
191                }
192
193                return label;
194        }
195
196        /**
197         * ラベルブレイクするかどうかを返します。
198         *
199         * skip または、cutNo によるラベルの間引き処理で、指定のCategoryAxis
200         * に対するカラム番号を指定する事で、判定値を返します。
201         * 処理が、Label の作成済みかどうかに依存する為、その判定を先に行います。
202         *
203         * @og.rev 4.1.1.0 (2008/02/04) 新規追加
204         *
205         * @param column カラム番号
206         *
207         * @return      ラベルブレイクするかどうか(true:する)
208         */
209        protected boolean isLabelBreak( final int column ) {
210                return labelBreak == null ||
211                                labelBreak.size() <= column ||
212                                labelBreak.get( column ).booleanValue() ;
213        }
214
215        /**
216         * ITEM ラベル(各データの設定値の説明用の値)を表示するかどうかを返します。
217         *
218         * ラベルの先頭に、アンダースコアがついたラベルは、ラベルの表示と
219         * ItemLabel の表示を抑止します。(false)
220         * それ以外のラベルは、表示する(true) を返します。
221         * 処理が、Label の作成済みかどうかに依存する為、その判定を先に行います。
222         *
223         * @og.rev 4.1.2.0 (2008/03/12) 新規追加
224         *
225         * @param       column  カラム番号
226         *
227         * @return      ITEMラベルを表示するかどうか(true:する)
228         */
229        protected boolean isViewItemLabel( final int column ) {
230                boolean flag = labelBreak == null ||
231                                                labelBreak.size() <= column ||
232                                                labelBreak.get( column ) != LabelVisible.UNDER ;
233
234                if( flag && isItemLabelLastVisible && labelBreak.size() -1 != column ) {
235                        flag = false;
236                }
237
238                return flag;
239        }
240
241        /**
242         * ドメイン(横軸)のカテゴリ単位のライン(縦線)の描画位置を返します。
243         *
244         * この位置は、labelBreak が存在しないか、または、ブレークするときのみ
245         * 値を返します。これにより、ライン(縦線)の位置を、グラフの中心から
246         * ずらす事が可能になります。
247         * また、labelBreak により、ラベルを描画しない場合は、線の位置を、0 に
248         * 設定する事で、画面から見えなくします。
249         *
250         * @param       anchor                  CategoryAnchorオブジェクト
251         * @param       category                カテゴリ番号
252         * @param       categoryCount   カテゴリ数
253         * @param       area                    範囲を表すRectangle2Dオブジェクト
254         * @param       edge                    ロケーションを指定するRectangleEdgeオブジェクト
255         *
256         * @return      ライン(縦線)の描画位置
257         */
258        @Override
259        public double getCategoryJava2DCoordinate( final CategoryAnchor anchor,
260                                                                                           final int category,
261                                                                                           final int categoryCount,
262                                                                                           final Rectangle2D area,
263                                                                                           final RectangleEdge edge) {
264
265                final double result ;
266
267                // labelBreak が存在しないか、または、ブレークするときのみ値を返す。
268                if( isLabelBreak( category ) ) {
269                        result = super.getCategoryJava2DCoordinate(
270                                                        anchor,category,categoryCount,area,edge
271                                        ) ;
272                }
273                else {
274                        result = 0;
275                }
276                return result ;
277        }
278
279        /**
280         * この文字列と指定されたオブジェクトを比較します。
281         *
282         * 親クラスで、equals メソッドが実装されているため、警告がでます。
283         *
284         * @og.rev 5.1.8.0 (2010/07/01) findbug対応
285         * @og.rev 5.1.9.0 (2010/08/01) findbug対応
286         *
287         * @param       object  比較するオブジェクト
288         *
289         * @return      Objectが等しい場合は true、そうでない場合は false
290         */
291        @Override
292        public boolean equals( final Object object ) {
293                if( super.equals( object ) ) {
294                        return hsCode == ((HybsCategoryAxis)object).hsCode;
295                }
296                return false;
297        }
298
299        /**
300         * このオブジェクトのハッシュコードを取得します。
301         *
302         * @og.rev 5.1.8.0 (2010/07/01) findbug対応
303         * @og.rev 5.1.9.0 (2010/08/01) findbug対応
304         *
305         * @return      ハッシュコード
306         */
307        @Override
308        public int hashCode() { return hsCode ; }
309}