    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 * 横軸表示には、３つの制御機能がカスタマイズされています。
    033 *
    034 *  １．"_" ラベルのスキップ(非表示)
    035 *  ２．cutNo 属性による、ラベル文字位置指定のキーブレイク
    036 *  ３．skip 属性による、ラベルをスキップする間隔の指定
    037 *
    038 * 上記、１，２，３ の順番で優先的に処理されます。
    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         * このメソッドでは、３つの拡張機能を実現しています。
    135         *  １．"_" ラベルのスキップ(非表示)
    136         *  ２．cutNo 属性による、ラベル文字位置指定のキーブレイク
    137         *  ３．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 != null && category instanceof String ) {
    159                if( category instanceof String ) {      // 4.3.1.1 (2008/08/23) instanceof チェックは、nullチェック不要
    160                        lbl = (String)category;
    161                        if( lbl.startsWith( "_" ) ) {
    162                                label = NULL_LABEL;
    163                        }
    164                }
    165
    166//              if( lbl.startsWith( "_" ) ) {
    167//                      label = NULL_LABEL;
    168//              }
    169//              else if( cutNo > 0 && lbl != null ) {
    170                if( cutNo > 0 && lbl != null ) {
    171                        if( lbl.length() >= cutNo ) {
    172                                lbl = lbl.substring( 0,cutNo );
    173                        }
    174
    175                        if( ! lbl.equals( breakKey ) ) {
    176                                label = super.createLabel( lbl, width, edge,  g2);
    177                                breakKey = lbl ;
    178                        }
    179                }
    180                else {
    181                        if( count % skip == 0 ) {
    182                                label = super.createLabel( category, width, edge,  g2);
    183                        }
    184                        count++;
    185                }
    186
    187                if( label == null ) {
    188                        label = NULL_LABEL;
    189                        labelBreak.add( LabelVisible.FALSE );
    190                }
    191                else if( label.equals( NULL_LABEL ) ) {
    192                        labelBreak.add( LabelVisible.UNDER );
    193                }
    194                else {
    195                        labelBreak.add( LabelVisible.TRUE );
    196                }
    197
    198                return label;
    199        }
    200
    201        /**
    202         * ラベルブレイクするかどうかを返します。
    203         *
    204         * skip または、cutNo によるラベルの間引き処理で、指定のCategoryAxis
    205         * に対するカラム番号を指定する事で、判定値を返します。
    206         * 処理が、Label の作成済みかどうかに依存する為、その判定を先に行います。
    207         *
    208         * @og.rev 4.1.1.0 (2008/02/04) 新規追加
    209         *
    210         * @param column カラム番号
    211         *
    212         * @return      ラベルブレイクするかどうか(true:する)
    213         */
    214        protected boolean isLabelBreak( final int column ) {
    215                return labelBreak == null ||
    216                                labelBreak.size() <= column ||
    217                                labelBreak.get( column ).booleanValue() ;
    218        }
    219
    220        /**
    221         * ITEM ラベル(各データの設定値の説明用の値)を表示するかどうかを返します。
    222         *
    223         * ラベルの先頭に、アンダースコアがついたラベルは、ラベルの表示と
    224         * ItemLabel の表示を抑止します。(false)
    225         * それ以外のラベルは、表示する(true) を返します。
    226         * 処理が、Label の作成済みかどうかに依存する為、その判定を先に行います。
    227         *
    228         * @og.rev 4.1.2.0 (2008/03/12) 新規追加
    229         *
    230         * @param       column  カラム番号
    231         *
    232         * @return      ITEMラベルを表示するかどうか(true:する)
    233         */
    234        protected boolean isViewItemLabel( final int column ) {
    235                boolean flag = labelBreak == null ||
    236                                                labelBreak.size() <= column ||
    237                                                labelBreak.get( column ) != LabelVisible.UNDER ;
    238
    239                if( flag && isItemLabelLastVisible && labelBreak.size() -1 != column ) {
    240                        flag = false;
    241                }
    242
    243                return flag;
    244        }
    245
    246        /**
    247         * ドメイン(横軸)のカテゴリ単位のライン(縦線)の描画位置を返します。
    248         *
    249         * この位置は、labelBreak が存在しないか、または、ブレークするときのみ
    250         * 値を返します。これにより、ライン(縦線)の位置を、グラフの中心から
    251         * ずらす事が可能になります。
    252         * また、labelBreak により、ラベルを描画しない場合は、線の位置を、０ に
    253         * 設定する事で、画面から見えなくします。
    254         *
    255         * @param       anchor                  CategoryAnchorオブジェクト
    256         * @param       category                カテゴリ番号
    257         * @param       categoryCount   カテゴリ数
    258         * @param       area                    範囲を表すRectangle2Dオブジェクト
    259         * @param       edge                    ロケーションを指定するRectangleEdgeオブジェクト
    260         *
    261         * @return      ライン(縦線)の描画位置
    262         */
    263        @Override
    264        public double getCategoryJava2DCoordinate( final CategoryAnchor anchor,
    265                                                                                           final int category,
    266                                                                                           final int categoryCount,
    267                                                                                           final Rectangle2D area,
    268                                                                                           final RectangleEdge edge) {
    269
    270                final double result ;
    271
    272                // labelBreak が存在しないか、または、ブレークするときのみ値を返す。
    273                if( isLabelBreak( category ) ) {
    274                        result = super.getCategoryJava2DCoordinate(
    275                                                        anchor,category,categoryCount,area,edge
    276                                        ) ;
    277                }
    278                else {
    279                        result = 0;
    280                }
    281                return result ;
    282        }
    283
    284        /**
    285         * この文字列と指定されたオブジェクトを比較します。
    286         *
    287         * 親クラスで、equals メソッドが実装されているため、警告がでます。
    288         *
    289         * @og.rev 5.1.8.0 (2010/07/01) findbug対応
    290         * @og.rev 5.1.9.0 (2010/08/01) findbug対応
    291         *
    292         * @param       object  比較するオブジェクト
    293         *
    294         * @return      Objectが等しい場合は true、そうでない場合は false
    295         */
    296        @Override
    297        public boolean equals( final Object object ) {
    298//              return super.equals( object );
    299                if( super.equals( object ) ) {
    300                        return hsCode == ((HybsCategoryAxis)object).hsCode;
    301                }
    302                return false;
    303        }
    304
    305        /**
    306         * このオブジェクトのハッシュコードを取得します。
    307         *
    308         * @og.rev 5.1.8.0 (2010/07/01) findbug対応
    309         * @og.rev 5.1.9.0 (2010/08/01) findbug対応
    310         *
    311         * @return      ハッシュコード
    312         */
    313//      public int hashCode() { return super.hashCode() ; }
    314        @Override
    315        public int hashCode() { return hsCode ; }
    316
    317        /**
    318         * Tests this axis for equality with an arbitrary object.
    319         *
    320         * @og.rev 4.1.0.1(2008/01/19) 新規追加
    321         * @og.rev 5.1.8.0 (2010/07/01) 廃止
    322         *
    323         * @param obj  the object (<code>null</code> permitted).
    324         *
    325         * @return A boolean.
    326         */
    327//      public boolean equals( final Object obj ) {
    328//              if( obj == null ) {
    329//                      return false;
    330//              }
    331//              if( obj == this ) {
    332//                      return true;
    333//              }
    334//              if( !(obj instanceof HybsCategoryAxis) ) {
    335//                      return false;
    336//              }
    337//              if( !super.equals(obj) ) {
    338//                      return false;
    339//              }
    340//              HybsCategoryAxis that = (HybsCategoryAxis) obj;
    341//              if( that.count != count || that.skip != skip || that.cutNo != cutNo ) {
    342//                      return false;
    343//              }
    344//
    345//              return true;
    346//      }
    347
    348        /**
    349         * Returns a hash code for this object.
    350         *
    351         * @og.rev 4.1.0.1(2008/01/19) 新規追加
    352         * @og.rev 5.1.8.0 (2010/07/01) 廃止
    353         *
    354         * @return A hash code.
    355         */
    356//      public int hashCode() {
    357//              return ( getLabel() + ":" + count + ":" + skip + ":" + cutNo ).hashCode();
    358//      }
    359}