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.db; 017 018import java.math.BigDecimal; 019import java.sql.ResultSet; 020import java.sql.SQLException; 021import java.text.DecimalFormat; 022import java.util.ArrayList; 023import java.util.HashMap; 024import java.util.LinkedHashMap; 025import java.util.List; 026import java.util.Map; 027 028import org.opengion.fukurou.db.ResultSetValue; // 6.0.4.0 (2014/11/28) 029import org.opengion.fukurou.util.StringUtil; 030import org.opengion.hayabusa.common.HybsSystem; 031import org.opengion.hayabusa.common.HybsSystemException; 032import org.opengion.hayabusa.resource.ResourceManager; 033import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE; // 6.1.0.0 (2014/12/26) refactoring 034 035/** 036 * DBTableModelを継承した TableModelの編集設定による変換を行うための実装クラスです。 037 * 038 * このクラスでは、オブジェクト初期化後は、通常のDBTableModelと同じ振る舞いをします。 039 * オブジェクト初期化時(createメソッド呼び出し時)に、検索結果オブジェクトから直接、編集設定に 040 * 応じて変換されたDBTableModelを生成します。 041 * 042 * このような実装を行う理由は、メモリ使用量を節約するためです。 043 * この編集設定では、集計機能を備えていますが、一旦DBTableModel作成後に集計処理を行うと、 044 * メモリを大量に使用する恐れがあるため、検索結果オブジェクトから直接集計処理を行い、DBTableModelを 045 * 生成しています。 046 * 047 * DBTableModel インターフェースは、データベースの検索結果(Resultset)をラップする 048 * インターフェースとして使用して下さい。 049 * 050 * @og.rev 5.3.6.0 (2011/06/01) 新規作成 051 * @og.group テーブル管理 052 * 053 * @version 5.0 054 * @author Hiroki Nakamura 055 * @since JDK6.0, 056 */ 057public class DBTableModelEditor extends DBTableModelImpl { 058 private static final String JS = HybsSystem.JOINT_STRING; 059 private static final DecimalFormat FORMAT = new DecimalFormat( "0.#########" ); 060 061 private int rowCountColumn = -1; 062 private DBEditConfig config; 063 064 /** 065 * デフォルトコンストラクター 066 * 067 * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor. 068 */ 069 public DBTableModelEditor() { super(); } // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。 070 071 /** 072 * DBTableModel を設定し、このオブジェクトを初期化します。 073 * 074 * @og.rev 5.7.1.2 (2013/12/20) msg ⇒ errMsg 変更 075 * @og.rev 6.0.2.1 (2014/09/26) queryタグが複数あり、mainTrans=false で制御されていない場合、エラーが発生する 076 * @og.rev 6.0.2.5 (2014/10/31) FireBardでの日付型取得対応 077 * @og.rev 6.0.4.0 (2014/11/28) ResultSetValue を使用するように変更。 078 * @og.rev 6.0.4.0 (2014/11/28) queryタグが複数ある場合の事前チェックの条件訂正 079 * 080 * @param result 検索結果オブジェクト 081 * @param skipRowCount 読み飛ばし件数 082 * @param maxRowCount 最大検索件数 083 * @param resource ResourceManagerオブジェクト 084 * @param config 編集設定オブジェクト 085 * @throws SQLException データベースアクセスエラー 086 */ 087 public void create( final ResultSet result, final int skipRowCount, final int maxRowCount, final ResourceManager resource, final DBEditConfig config ) throws SQLException { 088 if( result == null || config == null || resource == null ) { 089 final String errMsg = "DBTableModelまたは、DBEditConfigが設定されていません。"; 090 throw new HybsSystemException( errMsg ); // 5.7.1.2 (2013/12/20) msg ⇒ errMsg 変更 091 } 092 093 this.config = config; 094 095 /********************************************************************** 096 * 各パラメーターの初期化処理 097 **********************************************************************/ 098 // 6.0.4.0 (2014/11/28) ResultSetValue を使用するように変更。 099 final ResultSetValue rsv = new ResultSetValue( result ); // 6.0.4.0 (2014/11/28) 100 int colCnt = rsv.getColumnCount(); // 6.0.4.0 (2014/11/28) 101 102 if( config.useGroup() || config.useSubTotal() || config.useTotal() || config.useGrandTotal() ) { 103 rowCountColumn = colCnt; 104 colCnt++; 105 } 106 init( colCnt ); 107 108 final DBColumn[] dbColumn = new DBColumn[numberOfColumns]; // 8.5.4.2 (2024/01/12) PMD 7.0.0 LocalVariableCouldBeFinal 109 final boolean[] sumFilter = new boolean[numberOfColumns]; // 8.5.4.2 (2024/01/12) PMD 7.0.0 LocalVariableCouldBeFinal 110 final boolean[] groupFilter = new boolean[numberOfColumns]; // 8.5.4.2 (2024/01/12) PMD 7.0.0 LocalVariableCouldBeFinal 111 final boolean[] subTotalFilter = new boolean[numberOfColumns]; // 8.5.4.2 (2024/01/12) PMD 7.0.0 LocalVariableCouldBeFinal 112 final boolean[] totalFilter = new boolean[numberOfColumns]; // 8.5.4.2 (2024/01/12) PMD 7.0.0 LocalVariableCouldBeFinal 113 boolean sumFilterCheck = false; // 6.0.2.1 (2014/09/26) 114 if( config.useGrandTotal() ) { sumFilterCheck = true; } // 6.0.4.0 (2014/11/28) 115 for( int column=0; column<numberOfColumns; column++ ) { 116 String name = null; 117 // 6.1.0.0 (2014/12/26) refactoring : Avoid if(x != y) ..; else ..; 118 if( column == rowCountColumn ) { 119 name = "rowCount"; 120 dbColumn[column] = resource.makeDBColumn( name ); 121 } 122 else { 123 name = rsv.getColumnName(column); // 6.0.4.0 (2014/11/28) 124 dbColumn[column] = resource.getDBColumn( name ); 125 if( dbColumn[column] == null ) { 126 dbColumn[column] = DBTableModelUtil.makeDBColumn( name,column,rsv,resource ); // 6.0.4.0 (2014/11/28) 127 } 128 } 129 130 setDBColumn( column,dbColumn[column] ); 131 sumFilter[column] = config.isSumClm( name ); 132 groupFilter[column] = config.isGroupClm( name ); 133 subTotalFilter[column] = config.isSubTotalClm( name ); 134 totalFilter[column] = config.isTotalClm( name ); 135 // 6.0.4.0 (2014/11/28) queryタグが複数ある場合の事前チェックの条件訂正 136 if( sumFilter[column] || groupFilter[column] || subTotalFilter[column] || totalFilter[column] ) { 137 sumFilterCheck = true; 138 } 139 } 140 141 /********************************************************************** 142 * 集計、ソート、合計処理 143 **********************************************************************/ 144 // 集計キーに基づく集計処理を行いデータを追加します。 145 if( config.useGroup() ) { 146 // 6.0.4.0 (2014/11/28) ResultSetValue を使用するように変更。 147 addGroupRows( rsv, skipRowCount, maxRowCount, sumFilter, groupFilter ); 148 } 149 // 通常と同じように結果カーソルからデータを読込みデータを追加します。 150 else { 151 // 5.5.2.4 (2012/05/16) int[] types は使われていないので、削除します。 152 // 6.0.2.5 (2014/10/31) int[] types 復活。isOther フラグも使います。 153 // 6.0.4.0 (2014/11/28) ResultSetValue を使用するように変更。 154 addPlainRows( rsv, skipRowCount, maxRowCount ); 155 } 156 157 // ソート処理 158 if( getRowCount() > 0 && config.useOrderBy() ) { 159 sort(); 160 } 161 162 // 小計・合計行を追加します。 163 if( getRowCount() > 0 && !isOverflow() 164 && ( config.useSubTotal() || config.useTotal() || config.useGrandTotal() ) ) { 165 166 // 6.0.2.1 (2014/09/26) queryタグが複数あり、mainTrans=false で制御されていない場合、エラーが発生する 167 if( !sumFilterCheck ) { 168 final String errMsg = "小計、合計カラムが存在しません。" 169 + " これは、queryタグが複数あり、mainTrans=false で制御されていない可能性があります。" ; 170 throw new HybsSystemException( errMsg ); 171 } 172 173 addTotalRows( maxRowCount, resource, sumFilter, groupFilter, subTotalFilter, totalFilter ); 174 } 175 } 176 177 /** 178 * 集計キーの設定に基づき、DBTableModelの行を追加します。 179 * 内部的には、キーブレイクではなく、内部マップにより集計処理を行っているため、 180 * 集計キーが検索順により散在した場合でも1まとまりで集計されます。 181 * 182 * @og.rev 5.3.9.0 (2011/09/01) 値がNULLの場合にエラーになるバグを修正 183 * @og.rev 5.6.1.0 (2013/02/01) doubleをBigDecimalに変更 184 * @og.rev 6.0.4.0 (2014/11/28) ResultSetValue を使用するように変更。 185 * @og.rev 6.4.3.4 (2016/03/11) forループを、forEach メソッドに置き換えます。 186 * @og.rev 7.0.5.0 (2019/09/09) アンダーバー付きの文字列から、アンダーバーを削除する。 187 * 188 * @param rsv ResultSetValueオブジェクト 189 * @param skipRowCount 読み飛ばし件数 190 * @param maxRowCount 最大検索件数 191 * @param sumFilter 集計項目フィルター 192 * @param groupFilter グループキーフィルター 193 * @throws SQLException データベースアクセスエラー 194 */ 195 private void addGroupRows( final ResultSetValue rsv, final int skipRowCount, final int maxRowCount 196 , final boolean[] sumFilter, final boolean[] groupFilter ) throws SQLException { 197 int numberOfRows = 0; 198 while( numberOfRows < skipRowCount && rsv.next() ) { 199 // 注意 resultSet.next() を先に判定すると必ず1件読み飛ばしてしまう。 200 numberOfRows ++ ; 201 } 202 numberOfRows = 0; 203 204 final Map<String,String[]> groupLinkedMap = new LinkedHashMap<>(); 205 final Map<String,Integer> groupCountMap = new HashMap<>(); 206 final Map<String,BigDecimal[]> sumMap = new HashMap<>(); // 5.6.1.0 (2013/02/01) 207 final StringBuilder groupKey = new StringBuilder( BUFFER_MIDDLE ); // 6.1.0.0 (2014/12/26) refactoring 208 while( numberOfRows < maxRowCount && rsv.next() ) { 209 groupKey.setLength(0); // 6.1.0.0 (2014/12/26) refactoring 210 // 8.5.4.2 (2024/01/12) PMD 7.0.0 LocalVariableCouldBeFinal 211 final BigDecimal[] sumVals = new BigDecimal[config.getSumClmCount()]; // 5.6.1.0 (2013/02/01) 212 final String[] groupVals = new String[config.getGroupClmCount()]; // 8.5.4.2 (2024/01/12) PMD 7.0.0 LocalVariableCouldBeFinal 213 int sc = 0; 214 int gc = 0; 215 for( int column=0; column<numberOfColumns; column++ ) { 216 if( column != rowCountColumn ) { 217 final String val = rsv.getValue( column ); 218 if( sumFilter[column] ) { 219 // 5.3.9.0 (2011/09/01) 値がNULLの場合の対応漏れ 220 // sumVals[sc++] = ( val != null && val.length() > 0 ? Double.valueOf( val ) : 0 ); 221 // sumVals[sc++] = ( val != null && val.length() > 0 ? new BigDecimal( val ) : BigDecimal.ZERO ); // 5.6.1.0 (2013/02/01) 222 // 7.0.5.0 (2019/09/09) アンダーバー付きの文字列から、アンダーバーを削除する。 223 sumVals[sc++] = new BigDecimal( unscoDel( val,"0" ) ); 224 225 } 226 if( groupFilter[column] ) { 227 groupVals[gc++] = val; 228 groupKey.append( val ).append( JS ); 229 } 230 } 231 } 232 233 final String key = groupKey.toString(); 234 int groupCount = 0; 235 if( groupLinkedMap.containsKey( key ) ) { 236 final BigDecimal[] eSumVals = sumMap.get( key ); // 5.6.1.0 (2013/02/01) 237 for( int i=0; i<config.getSumClmCount(); i++ ) { 238 sumVals[i] = sumVals[i] == null ? BigDecimal.ZERO : sumVals[i].add( eSumVals[i] ); // 5.6.1.0 (2013/02/01) 239 } 240 sumMap.put( key, sumVals ); 241// groupCount = groupCountMap.get( key ).intValue() + 1; 242 groupCount = groupCountMap.get( key ) + 1; // 8.5.4.2 (2024/01/12) PMD 7.0.0 UnnecessaryBoxing 243 } 244 else { 245 groupLinkedMap.put( key, groupVals ); 246 groupCount = 1; 247 numberOfRows++; 248 } 249 sumMap.put( key, sumVals ); 250 // 2.0.0 (2024/01/12) PMD 7.0.0 UnnecessaryBoxing 251// groupCountMap.put( key, Integer.valueOf( groupCount ) ); 252 groupCountMap.put( key, groupCount ); 253 } 254 255 // 6.4.3.4 (2016/03/11) forループを、forEach メソッドに置き換えます。 256 groupLinkedMap.forEach( (k,v) -> addRow( groupFilter, v, groupCountMap.get( k ), sumFilter, sumMap.get( k ) ) ); 257 258 // 最大件数が、超えた場合でかつ次のデータがある場合は、オーバーフロー 259 if( numberOfRows >= maxRowCount && rsv.next() ) { 260 setOverflow( true ); 261 } 262 } 263 264 /** 265 * 検索結果オブジェクトを順に読み取り、そのままDBTableModelの行を追加します。 266 * 267 * @og.rev 5.5.2.4 (2012/05/16) int[] types は使われていないので、削除します。 268 * @og.rev 6.0.2.5 (2014/10/31) int[] types 復活。isOther フラグも使います。 269 * @og.rev 6.0.4.0 (2014/11/28) ResultSetValue を使用するように変更。 270 * 271 * @param rsv ResultSetValueオブジェクト 272 * @param skipRowCount 読み飛ばし件数 273 * @param maxRowCount 最大検索件数 274 * @throws SQLException データベースアクセスエラー 275 */ 276 private void addPlainRows( final ResultSetValue rsv, final int skipRowCount, final int maxRowCount ) throws SQLException { 277 int numberOfRows = 0; 278 while( numberOfRows < skipRowCount && rsv.next() ) { 279 // 注意 resultSet.next() を先に判定すると必ず1件読み飛ばしてしまう。 280 numberOfRows ++ ; 281 } 282 numberOfRows = 0; 283 284 // 6.0.2.5 (2014/10/31) 行列のループなので、 CLOB 使用可否でループを分ける。 285 // 6.0.2.5 (2014/10/31) typesを考慮した処理 286 while( numberOfRows < maxRowCount && rsv.next() ) { 287 numberOfRows++ ; 288 final String[] columnValues = new String[numberOfColumns]; // 8.5.4.2 (2024/01/12) PMD 7.0.0 LocalVariableCouldBeFinal 289 for( int column=0; column<numberOfColumns; column++ ) { 290 // 6.1.0.0 (2014/12/26) refactoring : Avoid if(x != y) ..; else ..; 291 if( column == rowCountColumn ) { 292 columnValues[column] = ""; 293 } 294 else { 295 columnValues[column] = rsv.getValue( column ); 296 } 297 } 298 addColumnValues( columnValues ); 299 } 300 301 // 最大件数が、超えた場合でかつ次のデータがある場合は、オーバーフロー 302 if( numberOfRows >= maxRowCount && rsv.next() ) { 303 setOverflow( true ); 304 } 305 } 306 307 /** 308 * DBTableModelのソート処理を行います。 309 * 310 */ 311 private void sort() { 312 // orderByClmsによる並び替え 313 final DBTableModelSorter temp = new DBTableModelSorter(); 314 temp.setModel( this ); 315 final String[] oClms = StringUtil.csv2Array( config.getOrderByClms() ); 316 for( int i=oClms.length-1; i>=0; i-- ) { 317 String oc = oClms[i]; 318 boolean ascending = true; 319 if( StringUtil.startsChar( oc , '!' ) ) { // 6.2.0.0 (2015/02/27) 1文字 String.startsWith 320 oc = oc.substring( 1 ); 321 ascending = false; 322 } 323 final int clmNo = getColumnNo( oc ); 324 temp.sortByColumn( clmNo, ascending ); 325 } 326 this.data = temp.data; 327 this.rowHeader = temp.rowHeader; 328 } 329 330 /** 331 * DBTableModelからデータを読み取り、編集設定情報を元に合計行の追加処理を行います。 332 * 合計行の追加は、キーブレイクにより行われますので、同じキーが複数回出現した場合は、 333 * それぞれの行に対して、合計行が付加されます。 334 * 335 * @og.rev 5.3.7.0 (2011/07/01) 小計、合計行追加処理でオーバーフローフラグがセットされないバグを修正 336 * @og.rev 5.6.1.0 (2013/02/01) 誤差回避のため、doubleではなくdecimalで計算する 337 * @og.rev 5.6.8.1 (2013/09/13) 1行目が合計されていなかったので修正 338 * @og.rev 6.0.2.1 (2014/09/26) queryタグが複数あり、mainTrans=false で制御されていない場合、エラーが発生する対応 339 * 340 * @param maxRowCount 最大検索件数 341 * @param resource リソースマネージャー 342 * @param sumFilter 集計項目フィルター 343 * @param groupFilter グループキーフィルター 344 * @param subTotalFilter 小計キーフィルター 345 * @param totalFilter 合計キーフィルター 346 * 347 * @return オーバーフローしたかどうか(最大件数が超えた場合でかつ次のデータがある場合は、true) 348 */ 349 private boolean addTotalRows( final int maxRowCount, final ResourceManager resource 350 , final boolean[] sumFilter 351 , final boolean[] groupFilter 352 , final boolean[] subTotalFilter 353 , final boolean[] totalFilter ) { 354 355 final String subTotalLabel = config.useSubTotal() ? resource.makeDBColumn( "EDIT_SUBTOTAL_VALUE" ).getLongLabel() : null; 356 final String totalLabel = config.useTotal() ? resource.makeDBColumn( "EDIT_TOTAL_VALUE" ).getLongLabel() : null; 357 final String grandTotalLabel= config.useGrandTotal() ? resource.makeDBColumn( "EDIT_GRANDTOTAL_VALUE" ).getLongLabel() : null; 358 359 int numberOfRows = getRowCount(); 360 final int sumClmCount = config.getSumClmCount(); 361 BigDecimal subTotalSum[] = new BigDecimal[sumClmCount]; // 5.6.1.0 (2013/02/01) 362 BigDecimal totalSum[] = new BigDecimal[sumClmCount]; 363 final BigDecimal grandTotalSum[] = new BigDecimal[sumClmCount]; // 8.5.4.2 (2024/01/12) PMD 7.0.0 LocalVariableCouldBeFinal 364 365 String lastSubTotalKey = null; 366 String lastTotalKey = null; 367 368 int subTotalCount = 0; 369 int totalCount = 0; 370 int grandTotalCount = 0; 371 int rowCount =0; 372 373 int tblIdx = 0; 374 final StringBuilder groupKey = new StringBuilder( BUFFER_MIDDLE ); // 6.1.0.0 (2014/12/26) refactoring 375 final StringBuilder subTotalKey = new StringBuilder( BUFFER_MIDDLE ); // 6.1.0.0 (2014/12/26) refactoring 376 final StringBuilder totalKey = new StringBuilder( BUFFER_MIDDLE ); // 6.1.0.0 (2014/12/26) refactoring 377 while( numberOfRows < maxRowCount && tblIdx < getRowCount() ) { 378 // 8.5.4.2 (2024/01/12) PMD 7.0.0 LocalVariableCouldBeFinal 379 final BigDecimal[] sumVals = new BigDecimal[sumClmCount]; // 5.6.1.0 (2013/02/01) 380 groupKey.setLength(0); // 6.1.0.0 (2014/12/26) refactoring 381 subTotalKey.setLength(0); // 6.1.0.0 (2014/12/26) refactoring 382 totalKey.setLength(0); // 6.1.0.0 (2014/12/26) refactoring 383 384 int sc = 0; 385 for( int column=0; column<numberOfColumns; column++ ) { 386 final String val = getValue( tblIdx, column ); 387 if( groupFilter[column] ) { groupKey.append( val ).append( JS ); } 388 // 7.0.5.0 (2019/09/09) アンダーバー付きの文字列から、アンダーバーを削除する。 389 // if( sumFilter[column] ) { sumVals[sc++] = ( val != null && val.length() > 0 ? new BigDecimal( val ) : BigDecimal.ZERO ); } // 5.6.1.0 (2013/02/01) 390 if( sumFilter[column] ) { sumVals[sc++] = new BigDecimal( unscoDel( val,"0" ) ) ; } // 7.0.5.0 (2019/09/09) 391 if( subTotalFilter[column] ) { subTotalKey.append( val ).append( JS ); } 392 if( totalFilter[column] ) { totalKey.append( val ).append( JS ); } 393 // 7.0.5.0 (2019/09/09) アンダーバー付きの文字列から、アンダーバーを削除する。 394 // if( column == rowCountColumn ) { rowCount = ( val != null && val.length() > 0 ? Integer.parseInt( val ) : 0 ); } // 6.0.2.4 (2014/10/17) メソッド間違い 395 if( column == rowCountColumn ) { rowCount = Integer.parseInt( unscoDel( val,"0" ) ); } // 7.0.5.0 (2019/09/09) 396 } 397 398 // 小計キーブレイク処理 399 if( numberOfRows < maxRowCount && config.useSubTotal() && lastSubTotalKey != null && lastSubTotalKey.length() > 0 400 && !lastSubTotalKey.equals( subTotalKey.toString() ) ) { 401 addRow( subTotalFilter, subTotalLabel, subTotalCount, sumFilter, subTotalSum, tblIdx ); 402 subTotalSum = new BigDecimal[sumClmCount]; // 5.6.1.0 (2013/02/01) 403 subTotalCount = 0; 404 numberOfRows++; 405 tblIdx++; 406 } 407 408 // 合計キーブレイク処理 409 if( numberOfRows < maxRowCount && config.useTotal() && lastTotalKey != null && lastTotalKey.length() > 0 410 && !lastTotalKey.equals( totalKey.toString() ) ) { 411 addRow( totalFilter, totalLabel, totalCount, sumFilter, totalSum, tblIdx ); 412 totalSum = new BigDecimal[sumClmCount]; // 5.6.1.0 (2013/02/01) 413 totalCount = 0; 414 numberOfRows++; 415 tblIdx++; 416 } 417 418 // 小計、合計、総合計単位に集計項目の合計値を加算します。 419 // 6.0.2.0 (2014/09/19) BigDecimal.ZERO.add で、null エラーが発生するのは、query が複数あり、mainTrans=false で制御されていない場合 420 for( int cnt=0; cnt<sc; cnt++ ) { 421 subTotalSum[cnt] = subTotalSum[cnt] == null ? BigDecimal.ZERO.add(sumVals[cnt]) : subTotalSum[cnt].add( sumVals[cnt]); // 5.6.8.1 (2013/09/13) 422 totalSum[cnt] = totalSum[cnt] == null ? BigDecimal.ZERO.add(sumVals[cnt]) : totalSum[cnt].add( sumVals[cnt]); 423 grandTotalSum[cnt] = grandTotalSum[cnt]== null ? BigDecimal.ZERO.add(sumVals[cnt]) : grandTotalSum[cnt].add(sumVals[cnt]); 424 } 425 426 lastSubTotalKey = subTotalKey.toString(); 427 lastTotalKey = totalKey.toString(); 428 429 // グループ集計時はグルーピングした行数を加算する。 430 int gcnt = 1; 431 if( config.useGroup() && rowCountColumn >= 0 && rowCount > 0 ) { 432 gcnt = rowCount; 433 } 434 subTotalCount += gcnt; 435 totalCount += gcnt; 436 grandTotalCount += gcnt; 437 438 tblIdx++; 439 } 440 441 // 最大件数が、超えた場合でかつ次のデータがある場合は、オーバーフロー 442 boolean isOverFlow = tblIdx < getRowCount() ; 443 444 // 小計キー最終行処理 445 if( config.useSubTotal() && lastSubTotalKey != null ) { 446 if( numberOfRows < maxRowCount ) { 447 addRow( subTotalFilter, subTotalLabel, subTotalCount, sumFilter, subTotalSum, tblIdx ); 448 numberOfRows++; 449 tblIdx++; 450 } 451 else { 452 isOverFlow = true; 453 } 454 } 455 456 // 合計キー最終行処理 457 if( config.useTotal() && lastTotalKey != null ) { 458 if( numberOfRows < maxRowCount ) { 459 addRow( totalFilter, totalLabel, totalCount, sumFilter, totalSum, tblIdx ); 460 numberOfRows++; 461 tblIdx++; 462 } 463 else { 464 isOverFlow = true; 465 } 466 } 467 468 // 総合計処理 469 if( config.useGrandTotal() && numberOfRows > 0 ) { 470 if( numberOfRows < maxRowCount ) { 471 final boolean[] grandTotalFilter = new boolean[numberOfColumns]; 472 // 総合計のラベル表示廃止 473 // grandTotalFilter[0] = true; 474 475 if( config.useFirstTotal() ) { // 6.1.1.0 (2015/01/17) 476 addRow( grandTotalFilter, grandTotalLabel, grandTotalCount, sumFilter, grandTotalSum, 0 ); 477 } 478 else { 479 addRow( grandTotalFilter, grandTotalLabel, grandTotalCount, sumFilter, grandTotalSum, tblIdx ); 480 tblIdx++; 481 } 482 numberOfRows++; 483 } 484 else { 485 isOverFlow = true; 486 } 487 } 488 489 if( isOverFlow ) { 490 setOverflow( true ); 491 } 492 493 return isOverFlow; 494 } 495 496 /** 497 * キーの値配列、集計値の配列を引数として、追加行を生成し、DBTableModelに追加します。 498 * キー、及び集計値がDBTableModel上のどのカラムに位置するかは、キーフィルタ、集計フィルタで指定します。 499 * 500 * @og.rev 5.6.1.0 (2013/02/01) doubleをdecimalに 501 * 502 * @param keyFilter キーフィルタ 503 * @param keyVals キーの値配列 504 * @param keyCount 集計した行のカウント 505 * @param sumFilter 集計フィルタ 506 * @param sumVals 集計値配列 507 * @param aRow 挿入する行番号 508 */ 509 private void addRow( final boolean[] keyFilter, final String[] keyVals, final int keyCount 510 , final boolean[] sumFilter, final BigDecimal[] sumVals, final int aRow ) { 511 final String[] columnValues = new String[numberOfColumns]; // 8.5.4.2 (2024/01/12) PMD 7.0.0 LocalVariableCouldBeFinal 512 int sc = 0; 513 int kc = 0; 514 for( int column=0; column<numberOfColumns; column++ ) { 515 String val = ""; 516 if( keyFilter[column] ) { 517 val = keyVals[kc++]; 518 } 519 if( sumFilter[column] ) { 520 synchronized( FORMAT ) { // 7.2.9.5 (2020/11/28) 521 val = FORMAT.format( sumVals[sc++] ); 522 } 523 } 524 if( column == rowCountColumn ) { 525 val = String.valueOf( keyCount ); 526 } 527 columnValues[column] = val; 528 } 529 530 if( aRow < 0 ) { 531 addColumnValues( columnValues ); 532 } 533 else { 534 addValues( columnValues, aRow, false ); 535 } 536 } 537 538 /** 539 * キーの値配列、集計値の配列を引数として、追加行を生成し、DBTableModelに追加します。 540 * キー、及び集計値がDBTableModel上のどのカラムに位置するかは、キーフィルタ、集計フィルタで指定します。 541 * 542 * @og.rev 5.6.1.0 (2013/02/01) doubleをbigDecimal 543 * 544 * @param keyFilter キーフィルタ 545 * @param keyVals キーの値配列 546 * @param keyCount 集計した行のカウント 547 * @param sumFilter 集計フィルタ 548 * @param sumVals 集計値配列 549 */ 550 private void addRow( final boolean[] keyFilter, final String[] keyVals, final int keyCount 551 , final boolean[] sumFilter, final BigDecimal[] sumVals ) { 552 addRow( keyFilter, keyVals, keyCount, sumFilter, sumVals, -1 ); 553 } 554 555 /** 556 * キーの値、集計値の配列を引数として、追加行を生成し、DBTableModelに追加します。 557 * キー、及び集計値がDBTableModel上のどのカラムに位置するかは、キーフィルタ、集計フィルタで指定します。 558 * 559 * @og.rev 5.6.1.0 (2013/02/01) doubleをbigDecimalに 560 * 561 * @param keyFilter キーフィルタ 562 * @param keyVal キーの値 563 * @param keyCount 集計した行のカウント 564 * @param sumFilter 集計フィルタ 565 * @param sumVals 集計値配列 566 * @param aRow 挿入する行番号 567 */ 568 private void addRow( final boolean[] keyFilter, final String keyVal, final int keyCount 569 , final boolean[] sumFilter, final BigDecimal[] sumVals, final int aRow ) { 570 final List<String> tmp = new ArrayList<>(); 571 for( int column=0; column<numberOfColumns; column++ ) { 572 if( keyFilter[column] ) { 573 tmp.add( keyVal ); 574 } 575 } 576// addRow( keyFilter, tmp.toArray( new String[tmp.size()] ), keyCount, sumFilter, sumVals, aRow ); 577 addRow( keyFilter, tmp.toArray( new String[0] ), keyCount, sumFilter, sumVals, aRow ); // 8.5.4.2 (2024/01/12) PMD 7.0.0 OptimizableToArrayCall 対応 578 } 579 580 /** 581 * アンダーバー付きの文字列から、アンダーバーを削除します。 582 * null,ゼロ文字列の場合は、第二引数の値を返します。 583 * 584 * @og.rev 7.0.5.0 (2019/09/09) アンダーバー付きの文字列から、アンダーバーを削除する。 585 * 586 * @param inStr 基準となる文字列 587 * @param def デフォルト文字列 588 * 589 * @return null、ゼロ文字列、"_"の場合は、デフォルト文字列を、そうでなければ、入力文字からアンダーバーを削除した文字列を返す。 590 */ 591 public static String unscoDel( final String inStr,final String def ) { 592 final String rtn = StringUtil.nval2( inStr,def ); 593 594 return rtn.charAt(0) == '_' ? rtn.substring(1) : rtn ; 595 } 596}