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 018// import org.opengion.fukurou.util.StringUtil; // 8.0.0.0 (2021/07/31) Delete 019import org.opengion.fukurou.util.Attributes; 020 021import org.opengion.hayabusa.db.DBColumn; 022import org.opengion.hayabusa.db.DBColumnConfig; 023import org.opengion.hayabusa.db.DBTableModel; 024import org.opengion.hayabusa.resource.ResourceFactory; 025import org.opengion.hayabusa.resource.ResourceManager; 026// import org.opengion.hayabusa.resource.LabelData; // 8.0.0.0 (2021/07/31) Delete 027import org.opengion.hayabusa.common.HybsSystemException; 028 029import java.time.LocalDateTime; // 7.4.2.1 (2021/05/21) 030import java.time.format.DateTimeFormatter; // 7.4.2.1 (2021/05/21) 031 032import java.util.function.Consumer ; // 8.0.0.0 (2021/08/20) 033 034/** 035 * 指定の行-列と、動的カラムのテーブルを作成するクラスです。 036 * 037 * AbstractViewForm により、setter/getterメソッドのデフォルト実装を提供しています。 038 * 各HTMLのタグに必要な setter/getterメソッドのみ,追加定義しています。 039 * 行単位の繰り返し色は使いません。 040 * 041 * RENDERER,EDITOR,DBTYPE を使用する代わりに、簡易的な DATA_TYPE で決定します。 042 * 043 * GG10 履歴テーブル (書き込むテーブル) 044 * トークン(TOKEN) 必須キー(トークン) 045 * 更新カウンタ(UPCNT) ← 未使用(同一トークンでの最大値が有効:逆順検索なので、最初に見つかった値を採用) 046 * 値データ(VAL) 必須キー(値の設定) 047 * 単位(TANI) フィールドの後ろに追記(連続の場合は、一番最後のみ) 048 * 判定結果(JUDG) 0:未決 1:不要 2:任意 3:合格 4:保留 5:警告 6:必須 7:不合格 049 * 判定理由(RIYU) 上限、下限で判定した結果が入っている。titleに入れてポップアップさせる 050 * 051 * GG01 トークンマスタ (GG02がnullの時) 052 * トークン名称(TKN_NM) ← 未使用(GG02 のトークン名称が未設定の場合…SQL文で処理済み) 053 * 表示桁数(VIEW_LEN) テキストフィールドの長さセット 054 * データ型(DATA_TYPE) EDITORを決定 055 * トークングループ(TKN_GRP) (未使用=GG03のSEL_KEY の条件に使用している) 056 * 057 * GG03 選択マスタ (GG01 トークングループの名称とマーカー) 058 * 選択名称(SEL_NM) トークングループ名で、fieldset のキーブレイクに使用 059 * マーカー(MARKER) fieldset のstyle属性として使用 060 * 061 * GG02 雛形設定マスタ 062 * トークン名称(TKN_NM) (名称優先) 063 * タブ名称(TAB_NM) ← 未使用 064 * タグループ配置(GRP_POS) ← 未使用(fieldset を配置する場合に使う予定) 065 * 初期値(DEF_VAL) 値の設定 する場合の初期値に使用 066 * 行番号(ROWNO) トークンの並び順を指定 067 * 列番号(COLNO) ← 未使用(トークンの並び順のサブ) 068 * 行数(ROWSPAN) tableのカラムを複数縦につなげる場合 069 * 列数(COLSPAN) tableのカラムを複数横につなげる場合 070 * 登録方法(CDREC) 0:未決 1:不要 2:任意 4:保留 6:必須 071 * 表示方法(CDDISP) 1:ラベルカラム 2:カラム単発 3:カラム連続 4:表示のみ 072 * 異常下限(E_MIN) 異常値の下限判定をフィールドの横に記述 073 * 警告下限(W_MIN) 警告値の下限判定をフィールドの横に記述 074 * 警告上限(W_MAX) 警告値の上限判定をフィールドの横に記述 075 * 異常上限(E_MAX) 異常値の上限判定をフィールドの横に記述 076 * オプション属性(OPT_ATTR) トークンのフォームの属性に追記する 077 * 078 * @og.group 画面表示 079 * 080 * @version 7.3 081 * @author Kazuhiko Hasegawa 082 * @since JDK11.0, 083 */ 084public class ViewForm_HTMLTokenTable extends ViewForm_HTMLTable { 085 /** このプログラムのVERSION文字列を設定します。 {@value} */ 086 private static final String VERSION = "8.0.0.0 (2021/08/20)" ; 087 088 private static final String INS_VAL = "$$$$"; // 表示方法(CDDISP)が3:カラム連続 の場合の挿入位置を示すマーカー 089 090 private static final DateTimeFormatter YMD = DateTimeFormatter.ofPattern( "yyyyMMdd" ); 091 private static final DateTimeFormatter HM = DateTimeFormatter.ofPattern( "HHmm" ); 092 private static final DateTimeFormatter YMDHMS = DateTimeFormatter.ofPattern( "yyyyMMddHHmmss" ); 093 094 // Rendereを使う データ型(DATA_TYPE) の指定 095 // TP_IFRAME,TP_IMAGE,TP_LINE,TP_SIGNALは、Rendereを使う。contains で判定しているので、部分一致に注意 096 private static final String RENDERE_TYPE = "TP_IFRAME,TP_IMAGE,TP_LINE,TP_SIGNAL" ; 097 098 private int noToken = -1; 099// private int noUpcnt = -1; 100 private int noVal = -1; 101 private int noTani = -1; 102 private int noJudg = -1; 103 private int noRiyu = -1; 104 105 private int noViewlen = -1; 106 private int noType = -1; 107 108 private int noSelnm = -1; 109 private int noMarker = -1; 110 111 private int noName = -1; 112 private int noDefval = -1; 113 private int noRowno = -1; 114// private int noColno = -1; 115 private int noRowspan = -1; 116 private int noColspan = -1; 117 118 private int noCdrec = -1; 119 private int noCddisp = -1; 120 private int noEmin = -1; 121 private int noWmin = -1; 122 private int noWmax = -1; 123 private int noEmax = -1; 124 private int noOptAttr = -1; 125 126 private DBTableModel table ; 127 128 /** 129 * デフォルトコンストラクター 130 * 131 * @og.rev 7.3.2.1 (2021/03/25) 動的カラムのテーブルを作成する 132 */ 133 public ViewForm_HTMLTokenTable() { super(); } // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。 134 135 /** 136 * 初期化します。 137 * ここでは、内部で使用されているキャッシュをクリアし、 138 * 新しいモデル(DBTableModel)と言語(lang) を元に内部データを再構築します。 139 * ただし、設定情報は、以前の状態がそのままキープされています。 140 * 141 * @og.rev 7.3.2.1 (2021/03/25) 動的カラムのテーブルを作成する 142 * 143 * @param table DBTableModelオブジェクト 144 */ 145 @Override 146 public void init( final DBTableModel table ) { 147 super.init( table ); 148 this.table = table; 149 150 noToken = table.getColumnNo( "TOKEN" ); // トークン 151 // noUpcnt = table.getColumnNo( "UPCNT" ); // 更新カウンタ 152 noVal = table.getColumnNo( "VAL" ); // 値 153 noTani = table.getColumnNo( "TANI" , false ); // 154 noJudg = table.getColumnNo( "JUDG" , false ); // 155 noRiyu = table.getColumnNo( "RIYU" , false ); // 156 noViewlen = table.getColumnNo( "VIEW_LEN" , false ); // 157 noType = table.getColumnNo( "DATA_TYPE", false ); // 158 noSelnm = table.getColumnNo( "SEL_NM" , false ); // 159 noMarker = table.getColumnNo( "MARKER" , false ); // 160 noName = table.getColumnNo( "TKN_NM" , false ); // 161 noDefval = table.getColumnNo( "DEF_VAL" , false ); // 162 noRowno = table.getColumnNo( "ROWNO" , false ); // 163 // noColno = table.getColumnNo( "COLNO" , false ); // 164 noRowspan = table.getColumnNo( "ROWSPAN" , false ); // 165 noColspan = table.getColumnNo( "COLSPAN" , false ); // 166 noCdrec = table.getColumnNo( "CDREC" , false ); // 167 noCddisp = table.getColumnNo( "CDDISP" , false ); // 168 noEmin = table.getColumnNo( "E_MIN" , false ); // 169 noWmin = table.getColumnNo( "W_MIN" , false ); // 170 noWmax = table.getColumnNo( "W_MAX" , false ); // 171 noEmax = table.getColumnNo( "E_MAX" , false ); // 172 noOptAttr = table.getColumnNo( "OPT_ATTR" , false ); // 173 } 174 175 /** 176 * DBTableModel から HTML文字列を作成して返します。 177 * startNo(表示開始位置)から、pageSize(表示件数)までのView文字列を作成します。 178 * 表示残りデータが pageSize 以下の場合は,残りのデータをすべて出力します。 179 * 180 * @og.rev 7.3.2.1 (2021/03/25) 動的カラムのテーブルを作成する 181 * @og.rev 7.4.2.1 (2021/05/21) TP_RADIO追加,4:表示のみは、値をRendererで出す。 182 * @og.rev 7.4.2.3 (2021/06/09) 数値フォーマット(カンマ無し、桁数指定)を設定、addNoValue制御を追加 183 * 184 * @param startNo 表示開始位置 185 * @param pageSize 表示件数 186 * 187 * @return DBTableModelから作成された HTML文字列 188 * @og.rtnNotNull 189 */ 190 @Override 191 public String create( final int startNo, final int pageSize ) { 192 if( getRowCount() == 0 ) { return ""; } // 暫定処置 193 194 final int lastNo = getLastNo( startNo, pageSize ); 195 196 final StringBuilder tagOut = new StringBuilder( BUFFER_LARGE ); // 最終的に出力するタグの文字列バッファ 197// .append( getCountForm( startNo,pageSize ) ) 198// .append( getHeader() ); 199 200 final ResourceManager resource = ResourceFactory.newInstance( "ja" ) ; 201 202 int lastRow = -1; 203// int bgClrCnt = 0; 204 205 String bkSelNm = ""; // 最後にセットされた SEL_NM (キーブレイク用) 206 String bkToken = ""; // 更新カウンタの最大値(逆順検索しているので、最初に見つかったトークン)のみ採用する。 207 208 // final int clmCnt = getColumnCount(); 209 for( int row=startNo; row<lastNo; row++ ) { 210 final int rowno = rowData( row,noRowno,row-startNo ); // DBに指定した列の番号 211 212 final String token = table.getValue( row,noToken ); 213 // final String upcnt = table.getValue( row,noUpcnt ); // 更新カウンタは、同一トークン内で、一番最初に現れたレコードのみ使用する。 214 if( bkToken.equals( token ) ) { continue; } // 同一トークンなら、過去データなので取り直し 215 bkToken = token; 216 217 final String selNm = rowData( row,noSelnm ,"" ); // 選択名称(SEL_NM) 218// if( lastRow != rowno || !bkSelNm.equals( selNm ) ) { 219 if( lastRow != rowno ) { // 行のブレイク 220 if( lastRow >= 0 ) { // 最初のループだけは、実行しない。 221 if( !bkSelNm.equals( selNm ) && !bkSelNm.isEmpty() ) { 222 tagOut.append( "</tr></tbody></table></fieldset>" ); 223 } 224 else { 225 tagOut.append(" </tr>").append( CR ); 226 } 227 } 228 229 // ※ 繰り返し色:getBgColorCycleClass( bgClrCnt++,row ) は使いません。 230 if( !bkSelNm.equals( selNm ) && !selNm.isEmpty() ) { 231 final String style = rowData( row,noMarker," style=\"", "\"" ); // マーカー(MARKER) は、style属性に追加する。 232 tagOut.append( "<fieldset" ).append( style ).append( "><legend>" ).append( selNm ).append( "</legend>" ) 233 .append("<table><tbody><tr>").append( CR ); // 繰り返し色背景色は使わない 234// .append("<table><tbody><tr").append( getBgColorCycleClass( bgClrCnt++,row ) ).append('>').append( CR ); 235 } 236 else if( lastRow < 0 ) { // 最初の行で、fieldset のラベルが 未指定の場合、<table> が必要。 237 tagOut.append("<table><tbody><tr>").append( CR ); // 繰り返し色背景色は使わない 238// tagOut.append("<table><tbody><tr").append( getBgColorCycleClass( bgClrCnt++,row ) ).append('>').append( CR ); 239 } 240 else { 241 tagOut.append("<tr>").append( CR ); // 繰り返し色背景色は使わない 242// tagOut.append("<tr").append( getBgColorCycleClass( bgClrCnt++,row ) ).append('>').append( CR ); 243 } 244 bkSelNm = selNm; 245 lastRow = rowno; 246 } 247 248 final String lbl = rowData( row,noName,token ); // 表示するラベル(無ければトークンそのもの) 249 final String dbType= rowData( row,noType,"TP_TEXT" ); // DBタイプ。未指定時は、TP_TEXT:テキスト 250 251 final DBColumn clm = resource.makeDBColumn( dbType,lbl ); 252 final DBColumnConfig config = clm.getConfig(); 253 config.setName( "VAL" ); // 登録するカラムの名前は、VAL になる。 254 255 final String defVal = timeVal( dbType,rowData( row,noDefval,"" ) ); // 初期値 7.4.2.1 (2021/05/21) 256 final String val = rowData( row,noVal,defVal ); 257 258 final String cdrec = rowData( row,noCdrec ,"0" ); // 0:未決 1:不要 2:任意 4:保留 6:必須 259 final String judg = rowData( row,noJudg ,"0" ); // 0:未決 1:不要 2:任意 3:合格 4:保留 5:警告 6:必須 7:不合格 260 261 final Attributes editAttri = config.getEditorAttributes(); // 内部オブジェクトを取得している。 262// final String optAttr = changeOptAttr( editAttri, rowData( row,noOptAttr,"" ) ); // オプション属性(OPT_ATTR) 263 final String optAttr = changeOptAttr( config, editAttri, rowData( row,noOptAttr,"" ) ); // 7.4.2.3 (2021/06/09) オプション属性(OPT_ATTR) 264 265 final boolean isEmp = val.isEmpty() // 本当にempty 266 || ( "TP_CHECK".equals( dbType ) && "0".equals(val) ); // TP_CHECK が '0' は、未設定と同じ 267 268 if( isEmp ) { // val が未設定の場合は、cdrec をそのままセットする。 269 editAttri.add( "class" , "judg" + cdrec ); // 注意:キーは、judg 270 } 271 else { // val が設定済みの場合は、judg をセットする。 272 editAttri.add( "class" , "judg" + judg ); 273 } 274 275 // 日付フォーマットが日本風じゃないので、取りやめ 276 // // dbType が、TP_YMD,TP_HMS,TP_YMDH の場合は、日付、時刻のみ可能とする。 277 // if( "TP_YMD".equals( dbType ) ) { 278 // editAttri.set( "type" , "date" ); // type="date" で日付 279 // } 280 // else if( "TP_HMS".equals( dbType ) ) { 281 // editAttri.set( "type" , "time" ); // type="time" だけだと、秒が入らない。 282 // editAttri.set( "step" , "1" ); // 秒 を有効にするには、step="1" にする。 283 // } 284 285 // dbType が、TP_INT の場合は、数値のみ可能とする。 286 if( "TP_INT".equals( dbType ) ) { 287 editAttri.set( "type" , "number" ); // type="number" だけだと、整数しか入らない。 288 // Editor_NUMBER は、フォーマット指定できない。TableFilter_JUDG で書き戻しして、カンマを削除している。 289 } 290 else if( "TP_REAL".equals( dbType ) ) { 291 editAttri.set( "type" , "number" ); // type="number" だけだと、整数しか入らない。 292 editAttri.set( "step" , "0.01" ); // とりあえず、無条件に、0.01 刻みにする。 293 config.setEditorParam( "#0.00" ); // 7.4.2.3 (2021/06/09) 数値フォーマット(カンマ無し、桁数指定)を設定 294 } 295 296 // if( noViewlen >= 0 ) { config.setFieldSize( table.getValue( row,noViewlen ) ); } // フィールドの表示桁数 297 final String viewLen = rowData( row,noViewlen,"" ); // フィールドの文字桁数 298 if( !viewLen.isEmpty() ) { 299 config.setMaxlength( viewLen ); 300 301 // dbType が、TP_REAL の場合は、表示桁数 に合わせて、step を再設定する。 302 if( "TP_REAL".equals( dbType ) ) { 303 if( viewLen.contains( ".1" ) ) { 304 editAttri.set( "step" , "0.1" ); 305 // config.setEditorParam( "#0.0" ); // 7.4.2.3 (2021/06/09) 数値フォーマット(カンマ無し、桁数指定)を設定 306 } 307 else if( viewLen.contains( ".2" ) ) { 308 editAttri.set( "step" , "0.01" ); 309 // config.setEditorParam( "#0.00" ); // 7.4.2.3 (2021/06/09) 数値フォーマット(カンマ無し、桁数指定)を設定 310 } 311 else if( viewLen.contains( ".3" ) ) { 312 editAttri.set( "step" , "0.001" ); 313 // config.setEditorParam( "#0.000" ); // 7.4.2.3 (2021/06/09) 数値フォーマット(カンマ無し、桁数指定)を設定 314 } 315 else { 316 editAttri.set( "step" , "any" ); 317 } 318 } 319 } 320 321 final String cddisp = rowData( row,noCddisp,"1" ); // 1:ラベルカラム 2:カラム単発 3:カラム連続 4:表示のみ 322 323 // 表示方法(CDDISP)=3:カラム連続 かつ ラベルの末尾が数字の場合は、①~の番号を placeholder にセットする。 324 if( "3".equals( cddisp ) && !optAttr.contains( "placeholder" ) ) { // オプション属性 に plaseholder が未設定の場合のみ 325 int idx = lbl.length()-1; 326 while( idx >= 0 ) { 327 final char ch = lbl.charAt( idx ); 328 if( '0' <= ch && ch <= '9' ) { idx--; } // 末尾から数字の間、処理を継続 329 else { break; } // 数字でなくなった時点で処理終了 330 } 331 if( idx >= 0 && idx < lbl.length()-1 ) { // 末尾に何らかの数値があった場合 332 final char plc = (char)('①' + ( Integer.parseInt(lbl.substring( idx+1 ))-1 ) ); 333 editAttri.set( "placeholder" , String.valueOf( plc ) ); 334 } 335 } 336 337// // 理由 があれば、title に入れて popup させる 338// final String riyu= rowData( row,noRiyu,"" ); 339// if( ! riyu.isEmpty() ) { 340// editAttri.set( "title" , riyu ); 341// } 342 343 // 登録方法(CDREC) が、1:不要 か、書き込み禁止(isWritable( row )がfalse) の場合は、disabled をセットする。 344 if( "1".equals( cdrec ) || !isWritable( row ) ) { 345 editAttri.set( "disabled" , "disabled" ); // 1:不要 は、disabled をセットする。 346 } 347 348 // config.setEditorAttributes( editAttri ); // 内部オブジェクトを追加しているので、再設定不要。追加する場合に使用する。 349 350 if( "TP_FILE".equals( dbType ) ) { // ファイル添付は、値をアップロードするフォルダとする。 351 config.setEditorParam( "UPLOAD_DIR=" + val ); // jsp 以下のフォルダになります。 352 } 353 354 // RENDERE_TYPE="TP_IFRAME,TP_IMAGE,TP_LINE,TP_SIGNAL" は、Rendereを使う。 355 // 表示方法(CDDISP) 4:表示のみ の場合も、Rendereを使う。 356 // final String valBuf ; 357 String valBuf ; 358// if( "TP_IFRAME".equals( dbType ) || "TP_IMAGE".equals( dbType ) || "TP_LINE".equals( dbType ) || "TP_SIGNAL".equals( dbType ) || "4".equals( cddisp ) ) { 359 if( RENDERE_TYPE.contains( dbType ) || "4".equals( cddisp ) ) { 360 if( !optAttr.isEmpty() ) { 361 // final Attributes rendAttri = config.getRendererAttributes(); // 内部オブジェクトを取得している。 362 // rendAttri.add( "optionAttributes" , optAttr ); 363 config.setRendererParam( optAttr ); 364 } 365 valBuf = new DBColumn( config ).getRendererValue( row,val ); // 表示欄(Renderer) 366 } 367 else { 368 if( !optAttr.isEmpty() ) { 369 editAttri.add( "optionAttributes" , optAttr ); 370 // config.setEditorParam( optAttr ); 371 } 372 373 // dbType が、TP_MENU かTP_RADIO の場合は、DBMENUの引数($2)に、トークンを渡す。(GG03を検索する) 374 String tempVal = val; 375 if( "TP_MENU".equals( dbType ) || "TP_RADIO".equals( dbType ) ) { 376 config.setAddNoValue( true ); // プルダウンメニューは、空欄を選択できるようにしておく 377 tempVal = val + ":" + token; // DBMENUの引数($2) 378 } 379 380 valBuf = new DBColumn( config ).getEditorValue( row,tempVal ); // 入力欄(Editor) 381 } 382 383 // 理由 があれば、valBuf の直後にそのまま入れる。 384 final String riyu= rowData( row,noRiyu,"" ); 385 if( ! riyu.isEmpty() ) { 386 valBuf = valBuf + riyu ; 387 } 388 389 final int colspan = rowData( row,noColspan,1 ); 390 final int rowspan = rowData( row,noRowspan,1 ); 391 392 // 表示方法(CDDISP) 1:ラベルカラム 2:カラム単発 3:カラム連続 4:表示のみ で、 393 // 3:カラム連続 の場合のみ、</td> の直前に INSERT する。 394 395 // ラベル項目の表示 396 if( "1".equals( cddisp ) ) { // CDDISP=1:ラベルカラム の場合、ラベル表示される(colspanなし) 397 if( 1 == rowspan ) { 398 tagOut.append( "<td class='label'>" ); 399 } 400 else { 401 tagOut.append( "<td class='label' rowspan=\"" ).append( rowspan ).append( "\">" ); 402 } 403 tagOut.append(lbl).append( "</td>" ); 404 } 405 406 if( "1".equals( cddisp ) || "2".equals( cddisp ) ) { // CDDISP=1:ラベルカラム or 2:カラム単発 の場合 td が必要。 407 tagOut.append( "<td" ); 408 // colspan を反映させるのは、フィールド部のみ 409 if( 1 != colspan ) { 410 tagOut.append( " colspan=\"" ).append( colspan ).append( '"' ); // ラベルと本体があるが自分で調整する。 411 } 412 413 // rowspan を反映させるのは、フィールド部のみ 414 if( 1 != rowspan ) { 415 tagOut.append( " rowspan=\"" ).append( rowspan ).append( '"' ); 416 } 417 tagOut.append( '>' ).append( valBuf ).append( INS_VAL ); // INS_VAL は、CDDISP=3:カラム連続 の場合の挿入位置 418 taniErrWarn( row,tagOut ); 419 } 420 421 // 4:表示のみ の場合は、td を出す。 422 if( "4".equals( cddisp ) ) { // CDDISP=4:表示のみ の場合 td が必要。 423 tagOut.append( "<td" ); 424 // colspan を反映させる 425 if( 1 != colspan ) { 426 tagOut.append( " colspan=\"" ).append( colspan ).append( '"' ); // colspan をそのまま出す。自分で調整する。 427 } 428 429 // rowspan を反映させるのは、フィールド部のみ 430 if( 1 != rowspan ) { 431 tagOut.append( " rowspan=\"" ).append( rowspan ).append( '"' ); 432 } 433 tagOut.append( '>' ).append( valBuf ).append( "</td>" ); // valBuf を使うが、先にRenderer の値を設定している。 434 } 435 436 if( "3".equals( cddisp ) ) { // CDDISP=3:カラム連続 の場合は、INS_VALの直前に挿入する。 437 final int lstIdx = tagOut.lastIndexOf( INS_VAL ) ; 438 if( lstIdx >= 0 ) { 439 tagOut.insert( lstIdx,valBuf ); 440 } 441 else { // ありえないはずだが、挿入位置が見つからない場合は、td で囲う。 442 tagOut.append( "<td>" ).append( valBuf ).append( INS_VAL ).append( "</td>" ); 443 } 444 } 445 } 446 447 tagOut.append(" </tr></tbody></table>").append( CR ); 448 if( !bkSelNm.isEmpty() ) { tagOut.append( "</fieldset>" ); } 449 tagOut.append( getScrollBarEndDiv() ); 450 451 return tagOut.toString().replace( INS_VAL , "" ); // 最後に文字列に変換後、INS_VAL は、すべて空文字列に置き換えます。 452 } 453 454 /** 455 * 値出力の終端処理をまとめて行います。 456 * 457 * 全体出力の tagOut に、値フィールドの valBuf と、 tani を連結し、 458 * DBTableModelから、異常下限,警告下限,警告上限,異常上限を、div で固めます。 459 * valBuf は、初期化されます。 460 * 461 * @og.rev 7.3.1.1 (2021/02/25) USE_CSV 属性追加 462 * 463 * @param row 行 464 * @param tagOut 全体出力のStringBuilder 465 * @param valBuf 値フィールドのStringBuilder(このメソッド内でクリアする) 466 * @param tani 単位 467 */ 468// private void valBufOut( final int row,final StringBuilder tagOut,final StringBuilder valBuf,final String tani ) { 469 private void taniErrWarn( final int row,final StringBuilder tagOut ) { 470 final String tani = rowData( row,noTani,"(",")" ); // 単位表示(カラムの最後に出す) 471 tagOut.append( tani ); 472 473 final String wmin = rowData( row,noWmin,"" ); // 警告下限(W_MIN) 474 final String wmax = rowData( row,noWmax,"" ); // 警告上限(W_MAX) 475 final String emin = rowData( row,noEmin,"" ); // 異常下限(E_MIN) 476 final String emax = rowData( row,noEmax,"" ); // 異常上限(E_MAX) 477 478 if( wmin.isEmpty() && wmax.isEmpty() && emin.isEmpty() && emax.isEmpty() ) { 479 tagOut.append( "</td>" ); 480 } 481 else { 482 tagOut.append( "<div class='small' title='上段:警告 下段:異常'>" ); 483 484 if( !wmin.isEmpty() || !wmax.isEmpty() ) { // 警告下限(W_MIN) 警告上限(W_MAX) 485 final String max = "%" + Math.max( wmin.length() , wmax.length() ) + "s"; // 最大桁数を求める。 486 tagOut.append( String.format( max + "~" + max ,wmin,wmax ) ); 487 } 488 tagOut.append( "</br>" ); 489 490 if( !emin.isEmpty() || !emax.isEmpty() ) { // 異常下限(E_MIN) 異常上限(E_MAX) 491 final String max = "%" + Math.max( emin.length() , emax.length() ) + "s"; // 最大桁数を求める。 492 tagOut.append( String.format( max + " ~ " + max ,emin,emax ) ); // 異常の範囲の方が広いので、間を少し開けている。 493 } 494 tagOut.append( "</div></td>" ); 495 } 496 } 497 498 /** 499 * DBTableModelから、指定行-列のデータを取得します。 500 * 501 * 列番号がマイナスの場合は、カラムが存在していないため、初期値を返します。 502 * 503 * @og.rev 7.3.1.1 (2021/02/25) USE_CSV 属性追加 504 * 505 * @param row 行 506 * @param col 列 507 * @param defVal 初期値(文字列) 508 * 509 * @return 指定行-列のデータ(文字列) 510 */ 511 private String rowData( final int row , final int col , final String defVal ) { 512 String rtn = defVal ; 513 if( col >= 0 ) { 514 final String str = table.getValue( row,col ); 515 if( str != null && !str.isEmpty()) { 516 rtn = str ; 517 } 518 } 519 return rtn ; 520 } 521 522 /** 523 * DBTableModelから、指定行-列のデータを取得し、前後に文字列を追加します。 524 * 525 * 列番号がマイナスの場合は、カラムが存在していないため、長さゼロの文字列を返します。 526 * 取得したデータが、長さゼロの文字列でない場合は、前後に指定の文字列を追加して返します。 527 * 528 * @og.rev 7.3.1.1 (2021/02/25) USE_CSV 属性追加 529 * 530 * @param row 行 531 * @param col 列 532 * @param prefix 前に付ける文字列 533 * @param suffix 後ろに付ける文字列 534 * 535 * @return 指定行-列のデータ(文字列) 536 */ 537 private String rowData( final int row , final int col , final String prefix , final String suffix ) { 538 String rtn = "" ; 539 if( col >= 0 ) { 540 final String str = table.getValue( row,col ); 541 if( str != null && !str.isEmpty()) { 542 rtn = prefix + str + suffix ; 543 } 544 } 545 return rtn ; 546 } 547 548 /** 549 * DBTableModelから、指定行-列のデータを取得します。 550 * 551 * 列番号がマイナスの場合は、カラムが存在していないため、初期値を返します。 552 * 553 * @og.rev 7.3.1.1 (2021/02/25) USE_CSV 属性追加 554 * 555 * @param row 行 556 * @param col 列 557 * @param defVal 初期値(数値) 558 * 559 * @return 指定行-列のデータ(数値) 560 */ 561 private int rowData( final int row , final int col , final int defVal ) { 562 final String val = col < 0 ? null : table.getValue( row,col ) ; 563 564 try { 565 return val == null || val.isEmpty() ? defVal : Integer.parseInt( val ); 566 } 567 catch( final NumberFormatException ex ) { 568 final String errMsg = "数値項目に数値以外の文字が含まれています。行=" + row + " , 列=" + col + " , 値=" + val ; 569 throw new HybsSystemException( errMsg,ex ); 570 } 571 } 572 573 /** 574 * DBタイプ TP_YMD、TP_HMS、TP_YMDH の初期値に現在時刻を求めます。 575 * 576 * DBタイプが、上記以外か、val が NOW 以外の場合は、val をそのまま返します。 577 * 578 * @og.rev 7.3.1.1 (2021/02/25) USE_CSV 属性追加 579 * 580 * @param dbType DBタイプ TP_YMD、TP_HMS、TP_YMDH 以外は、引数のval をそのまま返します。 581 * @param val 変換する文字列 NOW 以外の場合は、引数のval をそのまま返します。 582 * 583 * @return 日時タイプの初期値を求めます 584 */ 585 private String timeVal( final String dbType , final String val ) { 586 String rtn = val; 587 if( "NOW".equalsIgnoreCase( val ) ) { 588 final LocalDateTime now = LocalDateTime.now(); 589 590 if( "TP_YMD".equals(dbType) ) { 591 rtn = now.format( YMD ); 592 } 593 else if( "TP_HMS".equals(dbType) ) { 594 rtn = now.format( HM ); 595 } 596 else if( "TP_YMDH".equals(dbType) ) { 597 rtn = now.format( YMDHMS ); 598 } 599 } 600 601 return rtn ; 602 } 603 604 /** 605 * オプション属性の特殊記号を変換します。 606 * 607 * シングルクオートは必要です。『=』から後ろ全てをそのまま 適用します。 608 * 609 * 【これらの設定は、Attributesオブジェクトに設定します】 610 * P='AAA' → placeholder='AAA' 611 * T='ツールチップ' → title='ツールチップ' 612 * C='HALF' → class='HALF' 613 * S='XX:BB;YY:CC;' → style='XX:BB;YY:CC;' 614 * 615 * 【これらは変換して属性に設定します】 616 * W='120px' → width='120px' 617 * H='300px' → height='300px' 618 * D='GRP1' → dis='GRP1' DIS で指定したグループを disabled するときのキー 619 * 620 * 【DISはonchangeで書き込み不可制御を行います】 621 * DIS(・・・・) → onchange=disabl(this.・・・・) 622 * 以下、変換は同一です。 623 * DIS(value=='123','GRP1') → onchange=disabl(this.value=='123','GRP1') textfieldなど 624 * DIS(checked,'GRP1') → onchange=disabl(this.checked,'GRP1') チェックボックス 625 * DIS(selectedIndex==2,'GRP1') → onchange=disabl(selectedIndex==2,'GRP1') プウルダウンメニュー(インデックス判定) 626 * DIS(options[selectedIndex].value=='テスト2','GRP1') → onchange=disabl(options[selectedIndex].value=='テスト2','GRP1') プウルダウンメニュー(値判定) 627 * 628 * 【ANVは、addNoValue制御の略で、メニューに空オプションを追加できます】 629 * ANV='true' → DBColumnConfig#setAddNoValue(true) を設定します。 630 * 【AKLは、addKeyLabel制御の略で、trueでキー:ラベル形式、falseでラベルのみ、null(未指定)はリソースに準拠します】 631 * AKL='true' → DBColumnConfig#setAddKeyLabel("true") を設定します。 632 * 633 * 【それ以外は、変換なしで設定します】 634 * readonly → readonly (例) 635 * 636 * @og.rev 7.3.1.1 (2021/02/25) オプション属性の特殊記号を変換 637 * @og.rev 7.4.2.3 (2021/06/09) addNoValue制御、addKeyLabel制御を追加 638 * @og.rev 8.0.0.0 (2021/08/20) rows,cols 属性を処理できるようにします。 639 * 640 * @param attri Attributesオブジェクト 641 * @param val 変換するオプション属性 642 * 643 * @return 変換後のオプション属性 644 */ 645// private String changeOptAttr( final Attributes attri,final String val ) { 646 private String changeOptAttr( final DBColumnConfig config , final Attributes attri,final String val ) { 647 if( val.isEmpty() ) { return val; } // 確率的に、空文字はそのまま返します。 648 649 final StringBuilder buf = new StringBuilder( val ); // 最終的に出力するタグの文字列バッファ 650 651 // 【これらの設定は、Attributesオブジェクトに設定します】 652 // P='AAA' → placeholder='AAA' 653 // T='ツールチップ' → title='ツールチップ' 654 // C='HALF' → class='HALF' 655 // S='XX:BB;YY:CC;' → style='XX:BB;YY:CC;' 656 657 keyChange( buf,"P=", key -> attri.set( "placeholder",key ) ); 658 keyChange( buf,"T=", key -> attri.set( "title",key ) ); 659 keyChange( buf,"C=", key -> attri.add( "class",key ) ); 660 keyChange( buf,"S=", key -> attri.add( "style",key ) ); 661 662 // 8.0.0.0 (2021/08/20) rows,cols 属性を処理できるようにします。 663 keyChange( buf,"rows=", key -> attri.set( "rows",key ) ); 664 keyChange( buf,"cols=", key -> attri.set( "cols",key ) ); 665 666 // 【ANVは、addNoValue制御の略で、メニューに空オプションを追加できます】 667 // ANV='true' → DBColumnConfig#setAddNoValue(true) を設定します。 668 // 【AKLは、addKeyLabel制御の略で、trueでキー:ラベル形式、falseでラベルのみ、null(未指定)はリソースに準拠します】 669 // AKL='true' → DBColumnConfig#setAddKeyLabel("true") を設定します。 670 keyChange( buf,"ANV=", key -> config.setAddNoValue( Boolean.parseBoolean( key ) ) ); 671 keyChange( buf,"AKL=", key -> config.setAddKeyLabel( key ) ); 672 673// int st = 0; 674// int ed = 0; 675 676// st = buf.indexOf( "P=" ); 677// if( st >= 0 ) { 678// ed = Math.max( buf.indexOf( "'" , st+3 ),buf.indexOf( "\"" , st+3 ) ); // シングルか、ダブルか 679// attri.set( "placeholder" , buf.substring( st+3,ed ) ); // P= の後ろ+1から、最後のコーテーション(含まず)まで 680// buf.delete( st,ed+1 ); 681// } 682 683// st = buf.indexOf( "T=" ); 684// if( st >= 0 ) { 685// ed = Math.max( buf.indexOf( "'" , st+3 ),buf.indexOf( "\"" , st+3 ) ); 686// attri.set( "title" , buf.substring( st+3,ed ) ); // T= の後ろ+1から、最後のコーテーション(含まず)まで 687// buf.delete( st,ed+1 ); 688// } 689 690// st = buf.indexOf( "C=" ); 691// if( st >= 0 ) { 692// ed = Math.max( buf.indexOf( "'" , st+3 ),buf.indexOf( "\"" , st+3 ) ); 693// attri.add( "class" , buf.substring( st+3,ed ) ); // T= の後ろ+1から、最後のコーテーション(含まず)まで 694// buf.delete( st,ed+1 ); 695// } 696 697// st = buf.indexOf( "S=" ); 698// if( st >= 0 ) { 699// ed = Math.max( buf.indexOf( "'" , st+3 ),buf.indexOf( "\"" , st+3 ) ); 700// attri.add( "style" , buf.substring( st+3,ed ) ); // T= の後ろ+1から、最後のコーテーション(含まず)まで 701// buf.delete( st,ed+1 ); 702// } 703 704// // 7.4.2.3 (2021/06/09) addNoValue制御追加 705// st = buf.indexOf( "ANV=" ); 706// if( st >= 0 ) { 707// ed = Math.max( buf.indexOf( "'" , st+5 ),buf.indexOf( "\"" , st+5 ) ); 708// config.setAddNoValue( Boolean.parseBoolean( buf.substring( st+5,ed ) ) ); 709// buf.delete( st,ed+1 ); 710// } 711 712// // 7.4.2.3 (2021/06/09) addKeyLabel制御を追加 713// st = buf.indexOf( "AKL=" ); 714// if( st >= 0 ) { 715// ed = Math.max( buf.indexOf( "'" , st+5 ),buf.indexOf( "\"" , st+5 ) ); 716// config.setAddKeyLabel( buf.substring( st+5,ed ) ); // 空文字列は、処理不定 717// buf.delete( st,ed+1 ); 718// } 719 720 return buf.toString() 721 .replace( "W=" , "width=" ) 722 .replace( "H=" , "height=" ) 723 .replace( "D=" , "dis=" ) 724 .replace( "DIS(" , "onchange=disabl(this." ) ; 725 } 726 727 /** 728 * キーワードをStringBuilderから見つけ、置換するための関数型ファンクションを呼び出します。 729 * キーワードが見つからない場合は、処理しません。 730 * 731 * @og.rev 8.0.0.0 (2021/08/20) 共通の処理を関数型ファンクションと置き換えます。 732 * 733 * @param buf StringBuilderで、key が存在すれば置換処理を行い、bufから削除します。 734 * @param key 存在チェックと置換元 735 * @param cons 置換処理の関数型Consumerインターフェース 736 * 737 * @see #changeOptAttr(DBColumnConfig , Attributes , String) 738 */ 739 private static void keyChange( final StringBuilder buf , final String key , final Consumer<String> cons ) { 740 final int st = buf.indexOf( key ); 741 if( st >= 0 ) { 742 final int stLen = st + key.length() + 1; 743 final int ed = Math.max( buf.indexOf( "'" , stLen ),buf.indexOf( "\"" , stLen ) ); // シングルか、ダブルか 744 cons.accept( buf.substring( stLen,ed ) ); 745 buf.delete( st,ed+1 ); 746 } 747 } 748 749 /** 750 * DBTableModel から テーブルのヘッダータグ文字列を作成して返します。 751 * 752 * @og.rev 3.5.2.0 (2003/10/20) ヘッダーそのもののキャッシュはしない。 753 * 754 * @return テーブルのヘッダータグ文字列 755 * @og.rtnNotNull 756 */ 757// protected String getHeader() { 758// // ヘッダーは不要なので、オーバーライドしておく。 759// return "" ; 760// } 761}