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.html; 017 018import org.opengion.hayabusa.common.HybsSystem; 019import org.opengion.hayabusa.common.HybsSystemException; 020import org.opengion.hayabusa.db.DBTableModel; 021import org.opengion.fukurou.util.StringUtil; 022import org.opengion.fukurou.model.Formatter; 023 024import java.util.regex.Pattern; 025import java.util.regex.Matcher; 026 027/** 028 * [PN],[OYA] などの [] で指定されたカラムで表されたフォーマットデータに対して、 029 * DBTableModelオブジェクトを適用して 各カラムに実データを割り当てるオブジェクトです。 030 * 031 * 特に、[XXXX]に対して、[#XXXX]、[$XXXX]、[$XXXX]などの特殊記号が使用できます。 032 * 特殊記号の解釈は、HTMLFormatTextField系とHTMLFormatTable系で異なりますので 033 * ご注意ください。 034 * 035 * @og.rev 3.5.4.0 (2003/11/25) 新規追加 036 * @og.group 画面表示 037 * 038 * @version 4.0 039 * @author Kazuhiko Hasegawa 040 * @since JDK5.0, 041 */ 042public class TableFormatter { 043 044 /** フォーマットタイプの指定の特殊なマーク {@value} */ 045 public static final String HYBS_ITD_MARKER = "h_itd_marker"; 046 private static final Pattern ptnKey = Pattern.compile( "[ \t]+</td" ); // 4.3.2.0 (2008/09/10) 047 048 private FormatterType formatType = null; 049 private int[] location = null; 050 private String[] format = null; 051 private String formatTag = null; 052 private String rowspan = " rowspan=\"2\""; 053 private String trTag = null; 054 private boolean noClass = false; 055 // 3.5.6.0 (2004/06/18) '!' 値のみ 追加 既存の '$' は、レンデラー 056 private char[] type = null; // '#':ラベルのみ '$':レンデラー '!':値のみ その他:通常 057 private String usableKey = null; // キー情報のカラム文字列 058 private int usableKeyNo = -1; // キー情報のカラム番号 059 private String usableList = "1" ; 060 061 private String keyBreakClm = null; // 5.7.6.3 (2014/05/23) キーブレイクをチェックするカラムID 062 private int breakClmNo = -1; // 5.7.6.3 (2014/05/23) キーブレイクカラム番号 063 private String breakVal = null; // 5.7.6.3 (2014/05/23) キーブレイクをチェックする値 064 065 private String itdBody = ""; // 3.5.6.0 (2004/06/18) 追加 066 private Formatter formatter = null; 067 068 /** 069 * フォーマットをセットします。 070 * フォーマットに、<table>を含む場合、TextField扱いなので、フォーマット分割 071 * しません。table を含まず、tr を含む場合は、1行分のデータとして扱う為、 072 * trTag を求めます。 073 * trTag と format との間に、行ヘッダーが入ります。 074 * Tomcat6では、JSPのパース時に、tabやspaceはそのままパースされるため、</td>前 075 * のスペース削除処理も行います。 076 * 077 * @og.rev 4.3.2.0 (2008/09/10) </td>前のスペースを取り消します。 078 * @og.rev 5.5.0.3 (2012/03/13) <tr>を取らないフラグ追加 079 * 080 * @param fmt [カラム名] 形式のフォーマットデータ 081 * @param flg falseにすると先頭のtrタグを取る処理を行いません(5.5.0.3) 082 */ 083 public void setFormat( final String fmt , final boolean flg ) { 084 int tbl = fmt.indexOf( "<table" ); 085 int str = fmt.indexOf( "<tr" ); 086 087 // tr を含み、かつ、tableを含まないか、含んでも tr の後ろにtableがある場合。 088 if( str >= 0 && ( tbl < 0 || str < tbl ) && flg ) { // 5.5.0.3(2012/03/13) 089 int end = fmt.indexOf( '>',str ); 090 formatTag = fmt.substring(end+1); 091 trTag = fmt.substring(0,end+1) ; 092 } 093 else { 094 formatTag = fmt; 095 trTag = null; 096 } 097 // 4.3.2.0 (2008/09/10) </td>前のスペースを取り消す。 098 Matcher matcher = ptnKey.matcher( formatTag ); 099 formatTag = matcher.replaceAll( "</td" ); 100 101 } 102 103 /** 104 * フォーマットをセットします。 105 * フォーマットに、<table>を含む場合、TextField扱いなので、フォーマット分割 106 * しません。table を含まず、tr を含む場合は、1行分のデータとして扱う為、 107 * trTag を求めます。 108 * trTag と format との間に、行ヘッダーが入ります。 109 * Tomcat6では、JSPのパース時に、tabやspaceはそのままパースされるため、</td>前 110 * のスペース削除処理も行います。 111 * 112 * @og.rev 5.5.0.3 (2012/03/13) 引数追加につき。 113 * 114 * @param fmt [カラム名] 形式のフォーマットデータ 115 */ 116 public void setFormat( final String fmt ) { 117 setFormat( fmt , true ); 118 } 119 120 /** 121 * フォーマットを取得します。 122 * 123 * @og.rev 3.5.5.8 (2004/05/20) 新規追加 124 * @og.rev 5.1.7.0 (2010/06/01) サニタイズ戻し処理("\\]\\"から"["に戻し)を追加 125 * 126 * @return フォーマットデータ 127 */ 128 public String getFormat() { 129 if( trTag != null ) { 130 return decodeSanitizedStr( trTag + formatTag ); 131 } 132 else { 133 return decodeSanitizedStr( formatTag ); 134 } 135 } 136 137 /** 138 * DBTableModelを利用して、フォーマットデータを初期化します。 139 * 140 * @og.rev 3.5.5.0 (2004/03/12) [KEY.カラム名] 機能追加 141 * @og.rev 3.5.5.2 (2004/04/02) [I] で、行番号を作成します。 142 * @og.rev 3.5.6.0 (2004/06/18) '!' 値のみ 追加 既存の '$' は、レンデラー 143 * @og.rev 3.6.0.0 (2004/09/17) [ROW.ID] で、行毎のチェックボックスのIDを返します。 144 * @og.rev 5.1.7.0 (2010/06/01) サニタイズ戻し処理("\\]\\"から"["に戻し)を追加 145 * @og.rev 5.7.6.3 (2014/05/23) キーブレイクをチェックする keyBreakClm 属性追加 146 * 147 * @param table DBTableModelオブジェクト 148 */ 149 public void makeFormat( final DBTableModel table ) { 150 formatter = new Formatter( table ); 151 formatter.setFormat( formatTag ); 152 location = formatter.getClmNos(); 153 format = formatter.getFormat(); 154 155 // 5.1.7.0 (2010/06/01) サニタイズ戻し処理("\\]\\"から"["に戻し)を追加 156 if( format != null ) { 157 for( int i=0; i<format.length; i++ ) { 158 format[i] = decodeSanitizedStr( format[i] ); 159 } 160 } 161 162 type = formatter.getType(); 163 164 // このフォーマットを使用するかどうかを指定する判定条件の初期設定です。 165 if( usableKey != null ) { 166 usableKeyNo = table.getColumnNo( usableKey ); 167 } 168 169 // 5.7.6.3 (2014/05/23) キーブレイクをチェックする keyBreakClm 属性追加 170 if( keyBreakClm != null ) { 171 breakClmNo = table.getColumnNo( keyBreakClm ); 172 breakVal = null; // 初期化します。 173 } 174 } 175 176 /** 177 * テーブルフォーマットのタイプを指定します。 178 * enum FormatterType で、指定します。 179 * 180 * @og.rev 4.0.0.0 (2007/05/02) enum 定義に変更 181 * 182 * @param ftype フォーマットのタイプ 183 */ 184 public void setFormatType( final FormatterType ftype ) { 185 formatType = ftype; 186 } 187 188 /** 189 * このフォーマットのタイプを返します。 190 * 191 * このフォーマットのタイプを返します。 192 * 193 * @og.rev 4.0.0.0 (2007/05/02) enum 定義に変更 194 * 195 * @return このフォーマットのタイプを返します。 196 */ 197 public FormatterType getFormatType() { 198 return formatType; 199 } 200 201 /** 202 * テーブルの rowspan 属性をセットします。 203 * rowspan は、ヘッダー部のフォーマットの行数です。初期値は 2行 です。 204 * 設定は、"2" などの、数字部のみをセットします。 205 * 206 * @param rowspan 属性 207 */ 208 public void setRowspan( final String rowspan ) { 209 if( rowspan == null || rowspan.length() == 0 || rowspan.equals( "1" ) ) { 210 this.rowspan = ""; 211 } 212 else { 213 this.rowspan = " rowspan=\"" + rowspan + "\""; 214 } 215 } 216 217 /** 218 * 設定された rowspan を返します。 219 * これは、フォーマットの段組の数を取り出します。 220 * 文字列としては、rowspan="2" という形で取り出します。 221 * 222 * @return フォーマット文字列 223 */ 224 public String getRowspan() { 225 return rowspan; 226 } 227 228 /** 229 * ロケーション番号のサイズを返します。 230 * フォーム位置番号は、0 から getLocationSize()-1 までの数字を指定します。 231 * ロケーションサイズは、aaa[ABC]bbb[DEF]ccc[GHI]ddd となっている場合、 232 * aaa , bbb , ccc , ddd は、フォーマットで、サイズは4。 233 * ABC , DEF , GHI に対応するカラム番号がロケーションで、サイズは3。 234 * このメソッドで返すのは、ロケーション番号(3)の方です。 235 * 236 * @return ロケーション番号のサイズ 237 */ 238 public int getLocationSize() { 239 return location.length; 240 } 241 242 /** 243 * カラムのロケーション番号を返します。 244 * 引数は、0 から、getLocationSize()-1 までの数で指定します。 245 * 指定の位置の、フォーマットのカラム名に対応するロケーション番号 246 * を返します。 247 * 248 * @param no フォーム位置番号 249 * 250 * @return ロケーション番号 251 */ 252 public int getLocation( final int no ) { 253 return location[no]; 254 } 255 256 /** 257 * フォーマット文字列を返します。 258 * 引数は、0 から、getLocationSize() までの数で指定します。 259 * 指定のフォーマットが、aaa[ABC]bbb[DEF]ccc[GHI]ddd となっている場合、 260 * aaa , bbb , ccc , ddd を引数 0 , 1 , 2 , 3 で返します。 261 * 262 * @param no フォーム位置番号 263 * 264 * @return フォーマット文字列 265 */ 266 public String getFormat( final int no ) { 267 return format[no]; 268 } 269 270 /** 271 * システムフォーマット文字列を返します。 272 * システムフォーマット文字列は、[KEY.カラム名] などの特殊記号で指定された 273 * カラム名の事で、location には、マイナスの値が設定されます。 274 * マイナスの値に応じて、処理を変えることが出来ます。 275 * 276 * [KEY.カラム名] : 行番号付きカラム名 277 * [I] : 行番号 278 * [ROW.ID] : 行毎のチェックボックスのID 279 * [ROW.JSON] : 行毎の全データのJavaScriptオブジェクト形式 280 * 281 * @og.rev 3.5.5.0 (2004/03/12) [KEY.カラム名] 機能追加 282 * @og.rev 3.5.5.2 (2004/04/02) [I] で、行番号を作成します。 283 * @og.rev 3.6.0.0 (2004/09/17) [ROW.ID] で、行毎のチェックボックスのIDを返します。 284 * @og.rev 4.0.0.0 (2007/05/02) Formatter を使用するように変更 285 * 286 * @param row 行番号 287 * @param loc 位置番号 288 * 289 * @return フォーマット文字列 290 */ 291 public String getSystemFormat( final int row,final int loc ) { 292 if( loc == Formatter.SYS_ROWNUM ) { 293 return String.valueOf( row ); 294 } 295 else if( loc == Formatter.SYS_JSON ) { 296 return formatter.getJson( row ); 297 } 298 299 String errMsg = "システムフォーマットは、下記の形式しか使用できません。[" + loc + "]" + HybsSystem.CR 300 + " : [KEY.カラム名] : 行番号付きカラム名" + HybsSystem.CR 301 + " : [I] : 行番号" + HybsSystem.CR 302 + " : [ROW.ID] : 行毎のチェックボックスのID" + HybsSystem.CR 303 + " : [ROW.JSON] : 行毎の全データのJavaScriptオブジェクト形式" ; 304 throw new HybsSystemException( errMsg ); 305 } 306 307 /** 308 * タイプ文字列を返します。 309 * タイプとは、[XXX] の記述で、[#XXX] は、XXXカラムのラベルを、[$XXX]は、XXXカラムの 310 * レンデラーを、[!XXX} は、値のみ取り出す指定を行います。 311 * 主に、TextField系のフォーマットとTable系では、意味合いが異なりますので、 312 * ご注意ください。 313 * 314 * @param no フォーム位置番号 315 * 316 * @return タイプ文字列 '#':ラベルのみ '$':レンデラー '!':値のみ その他:通常 317 */ 318 public char getType( final int no ) { 319 return type[no]; 320 } 321 322 /** 323 * 設定された フォーマットの trタグを返します。 324 * これは、trタグにclass属性他の設定がされていた場合に、変換後の 325 * 文字列にも反映させる為に必要です。 326 * 327 * @og.rev 5.1.7.0 (2010/06/01) サニタイズ戻し処理("\\]\\"から"["に戻し)を追加 328 * 329 * @return フォーマットの trタグ 330 */ 331 public String getTrTag() { 332 if( trTag == null ) { return ""; } 333 334 return decodeSanitizedStr( trTag ) ; 335 } 336 337 /** 338 * カラムのクラス名(X,S9 など)のセットを行うかどうか指定します。 339 * 340 * "true" で、クラス属性を設定しません。これは、CSSファイルに書かれている属性を 341 * 使用しないことを意味します。 342 * 初期値は、"false" です。 343 * 344 * @param flag クラス名使用の有無(true:使用しない/false:使用する。) 345 */ 346 public void setNoClass( final String flag ) { 347 noClass = StringUtil.nval( flag,noClass ); 348 } 349 350 /** 351 * カラムのクラス名(X,S9 など)のセットを行うかどうか取得します。 352 * 353 * "true" で、クラス属性を設定しません。これは、CSSファイルに書かれている属性を 354 * 使用しないことを意味します。 355 * 初期値は、"false" です。 356 * 357 * @return クラス名使用の有無(true:使用しない/false:使用する。) 358 */ 359 public boolean isNoClass() { 360 return noClass; 361 } 362 363 /** 364 * フォーマットの使用可否を判断するキーとなるカラム名を指定します。 365 * 366 * キーが、usableList に含まれる場合は、このフォームを使用できます。 367 * キー(カラム名)が指定されない場合は、常に使用されます。 368 * ※ 現時点では、BODYタイプのみ使用しています。 369 * 370 * @param key フォーマットの使用可否を判断するカラム名 371 */ 372 public void setUsableKey( final String key ) { 373 usableKey = key; 374 } 375 376 /** 377 * フォーマットの使用可否を判断する文字列リストを指定します。 378 * 379 * キーが、この文字列リスト中に存在する場合は、このフォームを使用できます。 380 * この文字列リストは、固定な文字列です。{@XXXX}は使用できますが、[XXXX]は 381 * 使用できません。 382 * 初期値は、"1" です。 383 * ※ 現時点では、BODYタイプのみ使用しています。 384 * 385 * @param list フォーマットの使用可否を判断する文字列リスト 386 * @see TableFormatter#isUse( int,DBTableModel ) 387 */ 388 public void setUsableList( final String list ) { 389 if( list != null ) { 390 usableList = list; 391 } 392 } 393 394 /** 395 * ここで指定したカラムの値が、キーブレイクした場合、このタグを使用します。 396 * 397 * キーブレイクで 使用可否を指定する為の機能です。 398 * この設定値は、usableKey,usableList とは、独立しているため、それぞれで 399 * 有効になれば、使用されると判断されます。 400 * キーブレイク判定では、最初の1件目は、必ず使用されると判断されます。 401 * 402 * @og.rev 5.7.6.3 (2014/05/23) 新規追加 403 * 404 * @param kclm キーブレイクをチェックするカラムID 405 */ 406 public void setKeyBreakClm( final String kclm ) { 407 keyBreakClm = kclm; 408 } 409 410 /** 411 * このフォーマットを使用するかどうかの問い合わせを返します。 412 * 413 * "true" で、使用します。setUsableKey( String ) で、指定された 414 * カラム名の値が、setUsableList( String ) で指定された文字列に含まれていれば、 415 * 使用します。カラム名がセットされない場合は、デフォルト値("true")が使用されます。 416 * ※ 現時点では、BODYタイプのみ使用しています。 417 * カラムのデータに、不正なスペースが入る場合を想定して、trim() しています。 418 * よって、usableList の値にスペースは使用できません。 419 * 420 * 5.7.6.3 (2014/05/23) 以降は、keyBreakClm によるキーブレイクチェックも追加されました。 421 * 従来の usableKey,usableList とは、独立しているため、それぞれで有効になれば、 422 * 使用されると判断されます。 423 * 424 * @og.rev 3.5.6.2 (2004/07/05) 判定評価用カラムの値を trim() します。 425 * @og.rev 5.7.6.3 (2014/05/23) キーブレイクをチェックする keyBreakClm 属性追加 426 * 427 * @param row 行番号 428 * @param table DBTableModelオブジェクト 429 * 430 * @return このフォームを使用するかどうか(true:使用する/false:使用しない) 431 * @see TableFormatter#setUsableKey( String ) 432 * @see TableFormatter#setUsableList( String ) 433 */ 434 public boolean isUse( final int row, final DBTableModel table ) { 435// 5.7.6.3 (2014/05/23) keyBreakClm 属性の追加で、処理ロジックの見直し 436// if( usableKeyNo < 0 ) { return true; } 437// String val = table.getValue( row,usableKeyNo ).trim(); 438// return val.length() == 0 ? false : usableList.indexOf( val ) >= 0 ; 439 440 // どちらも設定されていなければ、使用される(=true) 441 if( usableKeyNo < 0 && breakClmNo < 0 ) { return true; } 442 443 // 以下、どちらかは設定されているため、true の時点で、使用される(=true)を返す。 444 if( usableKeyNo >= 0 ) { 445 String val = table.getValue( row,usableKeyNo ).trim(); 446 if( usableList.indexOf( val ) >= 0 ) { return true; } 447 } 448 449 if( breakClmNo >= 0 ) { 450 String val = table.getValue( row,breakClmNo ).trim(); 451 if( !val.equals( breakVal ) ) { // 同じでない場合は、true 452 breakVal = val; 453 return true; 454 } 455 } 456 457 return false ; // 最後まで残ると、使用されないと判断、false を返す。 458 } 459 460 /** 461 * itdフォーマット文字列を設定します。 462 * 463 * itd ボディ部の文字列を指定します。 464 * itd ボディは、繰り返し処理を行います。これを、上位のボディ文字列の中の 465 * HYBS_ITD_MARKER 文字列 と置き換えます。 466 * 467 * @og.rev 3.5.6.0 (2004/06/18) itdフォーマット文字列の取り込み 468 * 469 * @param itd itdフォーマットの文字列 470 */ 471 public void setItdBody( final String itd ) { 472 if( itd != null ) { 473 itdBody = itd; 474 } 475 } 476 477 /** 478 * itdフォーマット文字列を取得します。 479 * 480 * itd ボディ部の文字列を取得します。 481 * itd ボディは、繰り返し処理を行います。これを、上位のボディ文字列の中の 482 * HYBS_ITD_MARKER 文字列 と置き換えます。 483 * 484 * @og.rev 3.5.6.0 (2004/06/18) itdフォーマット文字列の取り込み 485 * 486 * @return itdフォーマットの文字列 487 */ 488 public String getItdBody() { 489 return itdBody; 490 } 491 492 /** 493 * サニタイズの戻し("\\]\\"から"["に戻し)を行います。 494 * 495 * @og.rev 5.1.7.0 (2010/06/01) 新規作成 496 * 497 * @param str サニタイズされた文字列 498 * 499 * @return サニタイズ戻し処理後の文字列 500 */ 501 private String decodeSanitizedStr( final String str ) { 502 if( str != null && str.indexOf( "\\]\\" ) >= 0 ) { 503 return str.replace( "\\]\\", "[" ); 504 } 505 else { 506 return str; 507 } 508 } 509}