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.plugin.view; 017 018import java.util.List; 019// import java.util.regex.Pattern; // 6.4.3.3 (2016/03/04) 020 021import org.opengion.fukurou.system.OgBuilder ; // 6.4.4.2 (2016/04/01) 022// import org.opengion.fukurou.util.StringUtil; 023import org.opengion.hayabusa.common.HybsSystemException; 024import org.opengion.hayabusa.html.TableFormatter; 025 026/** 027 * ヘッダー部分のフォーマットに応じたテーブルを自動作成する、フォーマットテーブル作成クラスです。 028 * 029 * AbstractViewForm により、setter/getterメソッドのデフォルト実装を提供しています。 030 * 各HTMLのタグに必要な setter/getterメソッドのみ、追加定義しています。 031 * [XXXX]は、カラムを指定します。ラベル+入力フィールドをそれぞれtdで囲います。 032 * [#XXXX]は、対応するカラムのラベルを出力します。 033 * [$XXXX]は、対応するカラムのレンデラーを出力します。 034 * [!XXXX]は、対応するカラムの値を出力します。 035 * 特殊記号の解釈は、HTMLFormatTextField系とHTMLFormatTable系で異なりますので 036 * ご注意ください。 037 * 038 * AbstractViewForm を継承している為、ロケールに応じたラベルを出力させる事が出来ます。 039 * 040 * @og.group 画面表示 041 * 042 * @version 4.0 043 * @author Kazuhiko Hasegawa 044 * @since JDK5.0, 045 */ 046public class ViewForm_HTMLFormatTable extends ViewForm_HTMLTable { 047 /** このプログラムのVERSION文字列を設定します。 {@value} */ 048 private static final String VERSION = "8.5.6.1 (2024/03/29)" ; 049 050 // 6.4.3.3 (2016/03/04) class属性(ColumnのDBType)置換で、td属性に[カラム]があると、誤ってそちらがセットされてしまう対応。 051 // ※ 正規表現の「.」は、改行を除く任意の文字なので、改行を含みあい場合は、「[\\s\\S]」とします。 052 // 8.5.6.1 (2024/03/29) AbstractViewForm に移動します。 053// private static final Pattern TD_BODY = Pattern.compile( "[\\s\\S]*<td[^>]*>[\\s]*" ); // 6.4.4.2 (2016/04/01) tdタグが完了して、BODY部分の解析に入る。 054// private static final Pattern TD_END = Pattern.compile( "[^<]*>[^<>]*" ); // 何らかのタグが完了して、BODY部分の解析に入る。 055 056 /** 3.5.4.0 (2003/11/25) TableFormatter クラス追加 */ 057 private TableFormatter format ; 058 059 /** 060 * デフォルトコンストラクター 061 * 062 * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor. 063 */ 064 public ViewForm_HTMLFormatTable() { super(); } // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。 065 066 /** 067 * DBTableModel から HTML文字列を作成して返します。 068 * startNo(表示開始位置)から、pageSize(表示件数)までのView文字列を作成します。 069 * 表示残りデータが pageSize 以下の場合は、残りのデータをすべて出力します。 070 * 071 * @og.rev 3.5.0.0 (2003/09/17) BODY要素の noClass 属性を追加。 072 * @og.rev 3.5.0.0 (2003/09/17) <tr>属性は、元のフォーマットのまま使用します。 073 * @og.rev 3.5.2.0 (2003/10/20) ヘッダー繰り返し属性( headerSkipCount )を採用 074 * @og.rev 3.5.3.1 (2003/10/31) skip属性を採用。headerLine のキャッシュクリア 075 * @og.rev 3.5.4.0 (2003/11/25) TableFormatter クラスを使用するように変更。 076 * @og.rev 3.5.5.0 (2004/03/12) systemFormat(例:[KEY.カラム名]形式等)の対応 077 * @og.rev 3.5.5.0 (2004/03/12) No 欄そのものの作成判断ロジックを追加 078 * @og.rev 3.5.5.7 (2004/05/10) [#カラム名] , [$カラム名] に対応 079 * @og.rev 3.5.6.0 (2004/06/18) '!' 値のみ 追加 既存の '$' は、レンデラー 080 * @og.rev 3.5.6.4 (2004/07/16) ヘッダーとボディー部をJavaScriptで分離 081 * @og.rev 3.7.0.3 (2005/03/01) getBgColorCycleClass に、選択行マーカーを採用 082 * @og.rev 4.0.0.0 (2005/01/31) 新規作成(getColumnClassName ⇒ getColumnDbType) 083 * @og.rev 4.3.1.0 (2008/09/08) フォーマットが設定されていない場合のエラー追加・編集行のみを表示する属性(isSkipNoEdit)追加 084 * @og.rev 4.3.3.0 (2008/10/01) noTransition属性対応 085 * @og.rev 4.3.7.4 (2009/07/01) tbodyタグの入れ子を解消(FireFox対応) 086 * @og.rev 6.2.0.0 (2015/02/27) フォーマット系の noDisplay 対応 087 * @og.rev 6.4.3.3 (2016/03/04) class属性(ColumnのDBType)置換で、td属性に[カラム]があると、誤ってそちらがセットされてしまう対応。 088 * @og.rev 6.4.3.4 (2016/03/11) tdに、[カラム]が無いケースで、次の[カラム]のクラス属性が、前方すべてのtdにセットされてしまう対応。 089 * @og.rev 6.4.4.2 (2016/04/01) TableFormatterのタイプ別値取得処理の共通部をまとめる。 090 * @og.rev 6.4.5.0 (2016/04/08) メソッド変更( getColumnDbType(int) → getClassName(int) ) 091 * @og.rev 6.8.1.1 (2017/07/22) ckboxTD変数は、<td> から <td に変更します(タグの最後が記述されていない状態でもらう)。 092 * @og.rev 6.8.1.1 (2017/07/22) 行番号のtdに、個別に class="S9" を追加するための useS9 変数を追加。 093 * @og.rev 8.5.4.2 (2024/01/12) class 属性がフォーマット中に存在する場合、追記になる。 094 * @og.rev 8.5.6.1 (2024/03/29) PMD 7.0.0 Finding duplicated code with CPD 095 * 096 * @param startNo 表示開始位置 097 * @param pageSize 表示件数 098 * 099 * @return DBTableModelから作成された HTML文字列 100 * @og.rtnNotNull 101 */ 102 @Override 103 public String create( final int startNo, final int pageSize ) { 104 if( getRowCount() == 0 ) { return ""; } // 暫定処置 105 106 // 4.3.1.0 (2008/09/08) 107 if( format == null ) { 108 final String errMsg = "ViewTagで canUseFormat() = true の場合、Formatter は必須です。"; 109 throw new HybsSystemException( errMsg ); 110 } 111 // 6.2.0.0 (2015/02/27) フォーマット系の noDisplay 対応 112 // ※ makeFormat の直後に setFormatNoDisplay を実行する順番を他のクラスと合わせます。 113 // 元の場所では、setColumnDisplay のタイミングが後なので、うまく動きません 114 format.makeFormat( getDBTableModel() ); // 6.2.0.0 (2015/02/27) #setFormatterList( List<TableFormatter> ) から移動 115 setFormatNoDisplay( format ); 116 117 headerLine = null; // 3.5.3.1 (2003/10/31) キャッシュクリア 118 final int lastNo = getLastNo( startNo, pageSize ); 119 final int blc = getBackLinkCount(); 120 final int hsc = getHeaderSkipCount(); // 3.5.2.0 (2003/10/20) 121 int hscCnt = 1; // 3.5.2.0 (2003/10/20) 122 123 final StringBuilder out = new StringBuilder( BUFFER_LARGE ) 124 .append( getCountForm( startNo,pageSize ) ) 125 .append( getHeader() ); 126 127 final String ckboxTD = "<td " + format.getRowspan(); // 6.8.1.1 (2017/07/22) 128 int bgClrCnt = 0; 129 for( int row=startNo; row<lastNo; row++ ) { 130 if( isSkip( row ) || isSkipNoEdit( row ) ) { continue; } // 4.3.1.0 (2008/09/08) 131 if( ! format.isUse( row,getDBTableModel() ) ) { continue; } // 3.5.4.0 (2003/11/25) 132 out.append("<tbody").append( getBgColorCycleClass( bgClrCnt++,row ) ); 133 if( isNoTransition() ) { // 4.3.3.0 (2008/10/01) 134 out.append( getHiddenRowValue( row ) ); 135 } 136 out.append('>') // 6.0.2.5 (2014/10/31) char を append する。 137 .append( format.getTrTag() ); 138 139 // 3.5.5.0 (2004/03/12) No 欄そのものの作成判断追加 140 if( isNumberDisplay() ) { 141 out.append( makeCheckbox( ckboxTD,row,blc,true ) ); // 6.8.1.1 (2017/07/22) 行番号のtdに、個別に class="S9" を追加 142 } 143 144 // 8.5.6.1 (2024/03/29) PMD 7.0.0 Finding duplicated code with CPD 145 addFormatBody( out, format, row ); 146// int cl = 0; 147// boolean isTdBody = false; // 6.4.3.3 (2016/03/04) tdBody処理を行ってよいかどうかのフラグ 148// for( ; cl<format.getLocationSize(); cl++ ) { 149// String fmt = format.getFormat(cl); // 3.5.0.0 (2003/09/17) 150// final int loc = format.getLocation(cl); // 3.5.5.0 (2004/03/12) 151// if( ! format.isNoClass() && loc >= 0 ) { // 3.5.5.7 (2004/05/10) 152// if( isTdBody && TD_END.matcher( fmt ).matches() ) { // 6.4.3.3 (2016/03/04) tdBody許可があり、TDが閉じた場合。 153// isTdBody = false; 154// final int idx = out.lastIndexOf( "<td" ); 155// if( idx >= 0 ) { 156// // 8.5.4.2 (2024/01/12) class 属性がフォーマット中に存在する場合、追記になる。 157// insertClassName( out,loc,idx ); // 8.5.4.2 (2024/01/12) 158// 159// // final String tdclass = " class=\"" + getClassName(loc) + "\" "; // 6.4.5.0 (2016/04/08) 160// // out.insert( idx+3, tdclass ); // +3 は、"<td" の後ろという意味。fmtでなくそれ以前に戻る必要がある。 161// } 162// } 163// if( TD_BODY.matcher( fmt ).matches() ) { // 6.4.3.3 (2016/03/04) TDが閉じた場合。 164// // 6.4.3.4 (2016/03/11) tdに、[カラム]が無いケースで、次の[カラム]のクラス属性が、前方すべてのtdにセットされてしまう対応。 165// final int idx = fmt.lastIndexOf( "<td" ); 166// if( idx >= 0 ) { // matchしてるので、あるはず 167// // 8.5.4.2 (2024/01/12) class 属性がフォーマット中に存在する場合、追記になる。 168// fmt = insertClassName( fmt,loc,idx ); // 8.5.4.2 (2024/01/12) 169// 170// // final String tdclass = " class=\"" + getClassName(loc) + "\" "; // 6.4.5.0 (2016/04/08) 171// // fmt = fmt.substring( 0,idx+3 ) + tdclass + fmt.substring( idx+3 ) ; 172// } 173// isTdBody = false; // 6.4.3.3 (2016/03/04) これは、要らない・・・はず。 174// } 175// else { 176// isTdBody = true; // TDが閉じていない。 177// } 178// } 179// out.append( fmt ); // 3.5.0.0 180// 181// // 3.5.5.7 (2004/05/10) #,$ 対応 182// if( loc >= 0 ) { 183// // 6.4.4.2 (2016/04/01) 処理の共通部をまとめる。 184// out.append( getTypeCaseValue( format.getType(cl),row,loc ) ); 185// } 186// else { 187// out.append( format.getSystemFormat(row,loc) ); 188// } 189// } 190// out.append( format.getFormat(cl) ) 191// .append("</tbody>").append( CR ); 192 193 // 3.5.2.0 (2003/10/20) ヘッダー繰り返し属性( headerSkipCount )を採用 194 if( hsc > 0 && hscCnt % hsc == 0 ) { 195 out.append("<tbody class=\"row_h\" >") 196 .append( getHeadLine() ) 197 .append("</tbody>"); 198 hscCnt = 1; 199 } 200 else { 201 hscCnt ++ ; 202 } 203 } 204 out.append("</table>").append( CR ) 205 .append( getScrollBarEndDiv() ); // 3.8.0.3 (2005/07/15) 206 207 return out.toString(); 208 } 209 210 /** 211 * 内容をクリア(初期化)します。 212 * 213 * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。 214 * @og.rev 3.5.0.0 (2003/09/17) Noカラムに、表示を全て消せるように、class 属性を追加。 215 * @og.rev 3.5.4.0 (2003/11/25) TableFormatter クラスを使用するように変更。 216 * 217 */ 218 @Override 219 public void clear() { 220 super.clear(); 221 format = null; 222 } 223 224 /** 225 * DBTableModel から テーブルのタグ文字列を作成して返します。 226 * 227 * @og.rev 3.2.4.0 (2003/06/12) makeFormat() する位置を移動。 228 * @og.rev 3.5.0.0 (2003/09/17) <tr>属性は、元のフォーマットのまま使用します。 229 * @og.rev 3.5.1.0 (2003/10/03) Noカラムに、numberType 属性を追加 230 * @og.rev 3.5.2.0 (2003/10/20) ヘッダー繰り返し部をgetHeadLine()へ移動 231 * @og.rev 3.5.3.1 (2003/10/31) VERCHAR2 を VARCHAR2 に修正。 232 * @og.rev 3.5.5.0 (2004/03/12) No 欄そのものの作成判断ロジックを追加 233 * @og.rev 3.5.6.5 (2004/08/09) thead に、id="header" を追加 234 * @og.rev 4.0.0.0 (2005/01/31) DBColumn の 属性(CLS_NM)から、DBTYPEに変更 235 * @og.rev 5.9.1.2 (2015/10/23) 自己終了警告対応 236 * @og.rev 6.4.4.1 (2016/03/18) NUMBER_DISPLAYを、static final 定数化します。 237 * @og.rev 6.4.4.2 (2016/04/01) StringBuilderの代わりに、OgBuilderを使用する。 238 * @og.rev 6.4.9.0 (2016/07/23) colgroupのHTML5対応(No欄) 239 * @og.rev 6.4.9.1 (2016/08/05) colgroupのHTML5対応(No欄)時の対応ミス修正 240 * @og.rev 6.8.1.0 (2017/07/14) HTML5対応ヘッダー出力設定時に、ブラウザを互換設定したときの対応。 241 * @og.rev 6.8.2.0 (2017/10/13) makeNthChildの廃止と、makeCheckboxで、個別にclass指定するように変更。 242 * @og.rev 7.0.4.0 (2019/05/31) colgroup 廃止 243 * @og.rev 8.5.6.1 (2024/03/29) thead に、class="row_h" 属性を追加します。 244 * @og.rev 8.5.6.1 (2024/03/29) thead に、固定の id と class 属性を共通に定義します。 245 * 246 * @return テーブルのタグ文字列 247 * @og.rtnNotNull 248 */ 249 @Override 250 protected String getTableHead() { 251 // 6.4.9.0 (2016/07/23) colgroupのHTML5対応(No欄) 252 final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE ); 253 254// // 7.0.4.0 (2019/05/31) colgroup 廃止 255// if( isNumberDisplay() ) { 256// // 6.4.9.0 (2016/07/23) colgroupのHTML5対応(No欄) 257// buf.append( NUMBER_DISPLAY ); // 6.8.1.0 (2017/07/14) HTML5ネイティブ時でも、出力します。 258// // 6.8.1.0 (2017/07/14) HTML5対応ヘッダー出力設定時に、ブラウザを互換設定したときの対応。 259// // 6.8.2.0 (2017/10/13) makeNthChildの廃止と、makeCheckboxで、個別にclass指定するように変更。 260// // if( !useIE7Header ) { 261// // buf.append( "<style type=\"text/css\">" ).append( CR ); 262// // makeNthChild( buf,2,"BIT" ); 263// // makeNthChild( buf,3,"S9" ); 264// // buf.append( "</style>" ).append( CR ); // 6.4.9.1 (2016/08/05) 265// // } 266// } 267 268 // 6.4.9.0 (2016/07/23) colgroupのHTML5対応(No欄)の関係で、修正します。 269 return new OgBuilder() 270 .appendIf( isNumberDisplay() , buf.toString() ) 271// .appendCR( "<thead id=\"header\">" ) // 3.5.6.5 (2004/08/09) 272 .append( THEAD_TAG ) // 8.5.6.1 (2024/03/29) 273 .append( getHeadLine() ) 274 .appendCR( "</thead>" ) 275 .toString(); 276 } 277 278 /** 279 * ヘッダー繰り返し部を、getTableHead()メソッドから分離。 280 * 281 * @og.rev 6.1.2.0 (2015/01/24) キャッシュを返すのを、#getHeadLine() に移動。 282 * @og.rev 7.3.0.0 (2021/01/06) SpotBugs:null チェックなしで null 値を利用対策 283 * @og.rev 8.5.6.1 (2024/03/29) getHeadLine(String) → getFormatHeadLine(TableFormatter,String) 284 * 285 * @return テーブルのタグ文字列 286 * @og.rtnNotNull 287 */ 288 protected String getHeadLine() { 289 // 7.3.0.0 (2021/01/06) SpotBugs:null チェックなしで null 値を利用対策 290 if( format == null ) { 291 final String errMsg = "ViewTagで canUseFormat() = true の場合、Formatter は必須です。"; 292 throw new HybsSystemException( errMsg ); 293 } 294 295 // 6.9.8.0 (2018/05/28) FindBugs:コンストラクタで初期化されていないフィールドを null チェックなしで null 値を利用している 296 // フレームワークとして、create メソッドからしか、呼ばれないため、nullチェック済みです。 297 if( headerLine == null ) { // キャッシュになければ、設定する。 298// headerLine = getHeadLine( "<th" + format.getRowspan() ) ; 299 headerLine = getFormatHeadLine( format, "<th" + format.getRowspan() ) ; // 8.5.6.1 (2024/03/29) 300 } 301 302 return headerLine ; 303 } 304 305// /** 306// * ヘッダー繰り返し部を、getTableHead()メソッドから分離。 307// * 308// * @og.rev 3.5.2.0 (2003/10/20) 新規作成 309// * @og.rev 3.5.4.0 (2003/11/25) TableFormatter クラスを使用するように変更。 310// * @og.rev 3.5.4.3 (2004/01/05) useCheckControl 属性の機能を追加 311// * @og.rev 3.5.4.6 (2004/01/30) numberType="none" 時の処理を追加(Noラベルを出さない) 312// * @og.rev 3.5.4.7 (2004/02/06) ヘッダーにソート機能用のリンクを追加します。 313// * @og.rev 3.5.5.0 (2004/03/12) systemFormat(例:[KEY.カラム名]形式等)の対応 314// * @og.rev 3.5.5.0 (2004/03/12) No 欄そのものの作成判断ロジックを追加 315// * @og.rev 3.7.0.1 (2005/01/31) 全件チェックコントロール処理変更 316// * @og.rev 6.1.2.0 (2015/01/24) キャッシュを返すのを、#getHeadLine() に移動。 317// * @og.rev 6.4.3.4 (2016/03/11) ヘッダーでもTableFormatterのType(#,$,!)に対応した値を出すようにする。 318// * @og.rev 6.4.4.2 (2016/04/01) TableFormatterのタイプ別値取得処理の共通部をまとめる。 319// * @og.rev 7.3.0.0 (2021/01/06) SpotBugs:null チェックなしで null 値を利用対策 320// * @og.rev 8.5.6.1 (2024/03/29) getHeadLine(String) → getFormatHeadLine(TableFormatter,String) 321// * 322// * @param thTag タグの文字列 323// * 324// * @return テーブルのタグ文字列 325// * @og.rtnNotNull 326// */ 327// protected String getHeadLine( final String thTag ) { 328// // 7.3.0.0 (2021/01/06) SpotBugs:null チェックなしで null 値を利用対策 329// if( format == null ) { 330// final String errMsg = "ViewTagで canUseFormat() = true の場合、Formatter は必須です。"; 331// throw new HybsSystemException( errMsg ); 332// } 333// 334// final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE ) 335// .append( format.getTrTag() ).append( CR ); 336// 337// // 3.5.5.0 (2004/03/12) No 欄そのものの作成判断追加 338// if( isNumberDisplay() ) { 339// // 6.1.2.0 (2015/01/24) thTag に、headerFormat.getRowspan() を含ませて受け取る。 340// // 3.5.4.3 (2004/01/05) 追加分 341// if( isUseCheckControl() && "checkbox".equals( getSelectedType() ) ) { 342// buf.append( thTag ).append( "></th>" ) 343// .append( thTag ).append( '>' ).append( getAllCheckControl() ).append( "</th>" ) 344// .append( thTag ).append( '>' ).append( getNumberHeader() ).append( "</th>" ); 345// } 346// else { 347// buf.append( thTag ).append( " colspan=\"3\">" ).append( getNumberHeader() ).append( "</th>" ); // 6.0.2.5 (2014/10/31) char を append する。 348// } 349// } 350// 351// int cl = 0; 352// // 6.9.8.0 (2018/05/28) FindBugs:コンストラクタで初期化されていないフィールドを null チェックなしで null 値を利用している 353// // フレームワークとして、create メソッドからしか、呼ばれないため、nullチェック済みです。 354// for( ; cl<format.getLocationSize(); cl++ ) { 355// buf.append( StringUtil.replace( format.getFormat(cl) ,"td","th" )); 356// final int loc = format.getLocation(cl); 357// // 6.4.3.4 (2016/03/11) ヘッダーでもTableFormatterのType(#,$,!)に対応した値を出すようにする。 358// if( loc >= 0 ) { 359// // 6.4.4.2 (2016/04/01) 処理の共通部をまとめる。 360// buf.append( getTypeCaseValue( format.getType(cl),-1,loc ) ); 361// } 362// } 363// buf.append( StringUtil.replace( format.getFormat(cl) ,"td","th" ) ).append( CR ); 364// 365// return buf.toString(); // 6.1.2.0 (2015/01/24) 366// } 367 368 /** 369 * フォーマットを設定します。 370 * 371 * @og.rev 3.5.4.0 (2003/11/25) 新規作成 372 * @og.rev 6.2.0.0 (2015/02/27) フォーマット系の noDisplay 対応。ロジックを共通にするため、処理を移動 373 * 374 * @param list TableFormatterのリスト 375 */ 376 @Override 377 public void setFormatterList( final List<TableFormatter> list ) { // 4.3.3.6 (2008/11/15) Generics警告対応 378 format = list.get(0); // 4.3.3.6 (2008/11/15) Generics警告対応 379 // 6.2.0.0 (2015/02/27) フォーマット系の noDisplay 対応。ロジックを共通にするため、処理を移動 380 } 381 382 /** 383 * フォーマットメソッドを使用できるかどうかを問い合わせます。 384 * 385 * @return 使用可能(true)/ 使用不可能 (false) 386 */ 387 @Override 388 public boolean canUseFormat() { 389 return true; 390 } 391 392 /** 393 * ビューで表示したカラムの一覧をCSV形式で返します。 394 * 395 * @og.rev 5.1.6.0 (2010/05/01) 新規追加 396 * @og.rev 6.2.0.1 (2015/03/06) TableFormatter#getLocation(int)の有効判定 397 * @og.rev 6.4.3.4 (2016/03/11) getViewClms(TableFormatter) を使用して表示されたカラム一覧を求めます。 398 * 399 * @return ビューで表示したカラムの一覧 400 * @og.rtnNotNull 401 */ 402 @Override 403 public String getViewClms() { 404 return getViewClms( format ); 405 } 406}