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