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                DBColumn[] dbColumn = new DBColumn[numberOfColumns];
109                boolean[] sumFilter                     = new boolean[numberOfColumns];
110                boolean[] groupFilter           = new boolean[numberOfColumns];
111                boolean[] subTotalFilter        = new boolean[numberOfColumns];
112                boolean[] totalFilter           = new boolean[numberOfColumns];
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         *
187         * @param rsv ResultSetValueオブジェクト
188         * @param skipRowCount 読み飛ばし件数
189         * @param maxRowCount 最大検索件数
190         * @param sumFilter 集計項目フィルター
191         * @param groupFilter グループキーフィルター
192         * @throws SQLException データベースアクセスエラー
193         */
194        private void addGroupRows( final ResultSetValue rsv, final int skipRowCount, final int maxRowCount
195                                                                , final boolean[] sumFilter, final boolean[] groupFilter ) throws SQLException {
196                int numberOfRows = 0;
197                while( numberOfRows < skipRowCount && rsv.next() ) {
198                        // 注意 resultSet.next() を先に判定すると必ず1件読み飛ばしてしまう。
199                        numberOfRows ++ ;
200                }
201                numberOfRows = 0;
202
203                final Map<String,String[]> groupLinkedMap       = new LinkedHashMap<>();
204                final Map<String,Integer> groupCountMap = new HashMap<>();
205                final Map<String,BigDecimal[]> sumMap           = new HashMap<>();      // 5.6.1.0 (2013/02/01)
206                final StringBuilder groupKey = new StringBuilder( BUFFER_MIDDLE );              // 6.1.0.0 (2014/12/26) refactoring
207                while( numberOfRows < maxRowCount && rsv.next() ) {
208                        groupKey.setLength(0);                                                                                                                  // 6.1.0.0 (2014/12/26) refactoring
209                        BigDecimal[] sumVals = new BigDecimal[config.getSumClmCount()]; // 5.6.1.0 (2013/02/01) 
210                        String[]   groupVals = new String[config.getGroupClmCount()];
211                        int sc = 0;
212                        int gc = 0;
213                        for( int column=0; column<numberOfColumns; column++ ) {
214                                if( column != rowCountColumn ) {
215                                        final String val = rsv.getValue( column );
216                                        if( sumFilter[column] ) {
217                                                // 5.3.9.0 (2011/09/01) 値がNULLの場合の対応漏れ
218                                                // sumVals[sc++] = ( val != null && val.length() > 0 ? Double.valueOf( val ) : 0 );
219                                                sumVals[sc++] = ( val != null && val.length() > 0 ? new BigDecimal( val ) : BigDecimal.ZERO ); // 5.6.1.0 (2013/02/01)
220                                        }
221                                        if( groupFilter[column] ) {
222                                                groupVals[gc++] = val;
223                                                groupKey.append( val ).append( JS );
224                                        }
225                                }
226                        }
227
228                        final String key = groupKey.toString();
229                        int groupCount = 0;
230                        if( groupLinkedMap.containsKey( key ) ) {
231                                final BigDecimal[] eSumVals = sumMap.get( key ); // 5.6.1.0 (2013/02/01)
232                                for( int i=0; i<config.getSumClmCount(); i++ ) {
233                                        sumVals[i] = sumVals[i] == null ? BigDecimal.ZERO : sumVals[i].add( eSumVals[i] ); // 5.6.1.0 (2013/02/01)
234                                }
235                                sumMap.put( key, sumVals );
236                                groupCount = groupCountMap.get( key ).intValue() + 1;
237                        }
238                        else {
239                                groupLinkedMap.put( key, groupVals );
240                                groupCount = 1;
241                                numberOfRows++;
242                        }
243                        sumMap.put( key, sumVals );
244                        groupCountMap.put( key, Integer.valueOf( groupCount ) );
245                }
246
247                // 6.4.3.4 (2016/03/11) forループを、forEach メソッドに置き換えます。
248                groupLinkedMap.forEach( (k,v) -> addRow( groupFilter, v, groupCountMap.get( k ), sumFilter, sumMap.get( k ) ) );
249
250                // 最大件数が、超えた場合でかつ次のデータがある場合は、オーバーフロー
251                if( numberOfRows >= maxRowCount && rsv.next() ) {
252                        setOverflow( true );
253                }
254        }
255
256        /**
257         * 検索結果オブジェクトを順に読み取り、そのままDBTableModelの行を追加します。
258         *
259         * @og.rev 5.5.2.4 (2012/05/16) int[] types は使われていないので、削除します。
260         * @og.rev 6.0.2.5 (2014/10/31) int[] types 復活。isOther フラグも使います。
261         * @og.rev 6.0.4.0 (2014/11/28) ResultSetValue を使用するように変更。
262         *
263         * @param rsv ResultSetValueオブジェクト
264         * @param skipRowCount 読み飛ばし件数
265         * @param maxRowCount 最大検索件数
266         * @throws      SQLException データベースアクセスエラー
267         */
268        private void addPlainRows( final ResultSetValue rsv, final int skipRowCount, final int maxRowCount ) throws SQLException {
269                int numberOfRows = 0;
270                while( numberOfRows < skipRowCount && rsv.next() ) {
271                        // 注意 resultSet.next() を先に判定すると必ず1件読み飛ばしてしまう。
272                        numberOfRows ++ ;
273                }
274                numberOfRows = 0;
275
276                // 6.0.2.5 (2014/10/31) 行列のループなので、 CLOB 使用可否でループを分ける。
277                        // 6.0.2.5 (2014/10/31) typesを考慮した処理
278                        while( numberOfRows < maxRowCount && rsv.next() ) {
279                                numberOfRows++ ;
280                                String[] columnValues = new String[numberOfColumns];
281                                for( int column=0; column<numberOfColumns; column++ ) {
282                                        // 6.1.0.0 (2014/12/26) refactoring : Avoid if(x != y) ..; else ..;
283                                        if( column == rowCountColumn ) {
284                                                columnValues[column] = "";
285                                        }
286                                        else {
287                                                columnValues[column] = rsv.getValue( column );
288                                        }
289                                }
290                                addColumnValues( columnValues );
291                        }
292
293                // 最大件数が、超えた場合でかつ次のデータがある場合は、オーバーフロー
294                if( numberOfRows >= maxRowCount && rsv.next() ) {
295                        setOverflow( true );
296                }
297        }
298
299        /**
300         * DBTableModelのソート処理を行います。
301         *
302         */
303        private void sort() {
304                // orderByClmsによる並び替え
305                final DBTableModelSorter temp = new DBTableModelSorter();
306                temp.setModel( this );
307                final String[] oClms = StringUtil.csv2Array( config.getOrderByClms() );
308                for( int i=oClms.length-1; i>=0; i-- ) {
309                        String oc = oClms[i];
310                        boolean ascending = true;
311                        if( StringUtil.startsChar( oc , '!' ) ) {                               // 6.2.0.0 (2015/02/27) 1文字 String.startsWith
312                                oc = oc.substring( 1 );
313                                ascending = false;
314                        }
315                        final int clmNo = getColumnNo( oc );
316                        temp.sortByColumn( clmNo, ascending );
317                }
318                this.data = temp.data;
319                this.rowHeader = temp.rowHeader;
320        }
321
322        /**
323         * DBTableModelからデータを読み取り、編集設定情報を元に合計行の追加処理を行います。
324         * 合計行の追加は、キーブレイクにより行われますので、同じキーが複数回出現した場合は、
325         * それぞれの行に対して、合計行が付加されます。
326         *
327         * @og.rev 5.3.7.0 (2011/07/01) 小計、合計行追加処理でオーバーフローフラグがセットされないバグを修正
328         * @og.rev 5.6.1.0 (2013/02/01) 誤差回避のため、doubleではなくdecimalで計算する
329         * @og.rev 5.6.8.1 (2013/09/13) 1行目が合計されていなかったので修正
330         * @og.rev 6.0.2.1 (2014/09/26) queryタグが複数あり、mainTrans=false で制御されていない場合、エラーが発生する対応
331         *
332         * @param       maxRowCount 最大検索件数
333         * @param       resource リソースマネージャー
334         * @param       sumFilter 集計項目フィルター
335         * @param       groupFilter グループキーフィルター
336         * @param       subTotalFilter 小計キーフィルター
337         * @param       totalFilter 合計キーフィルター
338         *
339         * @return      オーバーフローしたかどうか(最大件数が超えた場合でかつ次のデータがある場合は、true)
340         */
341        private boolean addTotalRows( final int maxRowCount, final ResourceManager resource
342                                                                        , final boolean[] sumFilter
343                                                                        , final boolean[] groupFilter
344                                                                        , final boolean[] subTotalFilter
345                                                                        , final boolean[] totalFilter ) {
346
347                final String subTotalLabel      = ( config.useSubTotal()   ? resource.makeDBColumn( "EDIT_SUBTOTAL_VALUE"   ).getLongLabel() : null );
348                final String totalLabel         = ( config.useTotal()      ? resource.makeDBColumn( "EDIT_TOTAL_VALUE"      ).getLongLabel() : null );
349                final String grandTotalLabel= ( config.useGrandTotal() ? resource.makeDBColumn( "EDIT_GRANDTOTAL_VALUE" ).getLongLabel() : null );
350
351                int numberOfRows = getRowCount();
352                final int sumClmCount  = config.getSumClmCount();
353                BigDecimal subTotalSum[]   = new BigDecimal[sumClmCount]; // 5.6.1.0 (2013/02/01)
354                BigDecimal totalSum[]      = new BigDecimal[sumClmCount];
355                BigDecimal grandTotalSum[] = new BigDecimal[sumClmCount];
356
357                String lastSubTotalKey = null;
358                String lastTotalKey    = null;
359
360                int subTotalCount   = 0;
361                int totalCount      = 0;
362                int grandTotalCount = 0;
363                int rowCount =0;
364
365                int tblIdx = 0;
366                final StringBuilder groupKey    = new StringBuilder( BUFFER_MIDDLE );   // 6.1.0.0 (2014/12/26) refactoring
367                final StringBuilder subTotalKey = new StringBuilder( BUFFER_MIDDLE );   // 6.1.0.0 (2014/12/26) refactoring
368                final StringBuilder totalKey    = new StringBuilder( BUFFER_MIDDLE );   // 6.1.0.0 (2014/12/26) refactoring
369                while( numberOfRows < maxRowCount && tblIdx < getRowCount() ) {
370                        BigDecimal[] sumVals      = new BigDecimal[sumClmCount];        // 5.6.1.0 (2013/02/01)
371                        groupKey.setLength(0);                                                                                                                  // 6.1.0.0 (2014/12/26) refactoring
372                        subTotalKey.setLength(0);                                                                                                               // 6.1.0.0 (2014/12/26) refactoring
373                        totalKey.setLength(0);                                                                                                                  // 6.1.0.0 (2014/12/26) refactoring
374
375                        int sc = 0;
376                        for( int column=0; column<numberOfColumns; column++ ) {
377                                final String val = getValue( tblIdx, column );
378                                if( groupFilter[column] )               { groupKey.append( val ).append( JS ); }
379                                if( sumFilter[column] )                 { sumVals[sc++] = ( val != null && val.length() > 0 ? new BigDecimal( val ) : BigDecimal.ZERO ); } // 5.6.1.0 (2013/02/01)
380                                if( subTotalFilter[column] )    { subTotalKey.append( val ).append( JS ); }
381                                if( totalFilter[column] )               { totalKey.append( val ).append( JS ); }
382                                if( column == rowCountColumn )  { rowCount = ( val != null && val.length() > 0 ? Integer.parseInt( val ) : 0 ); }       // 6.0.2.4 (2014/10/17) メソッド間違い
383                        }
384
385                        // 小計キーブレイク処理
386                        if( numberOfRows < maxRowCount && config.useSubTotal() && lastSubTotalKey != null && lastSubTotalKey.length() > 0
387                                && !lastSubTotalKey.equals( subTotalKey.toString() ) ) {
388                                addRow( subTotalFilter, subTotalLabel, subTotalCount, sumFilter, subTotalSum, tblIdx );
389                                subTotalSum = new BigDecimal[sumClmCount]; // 5.6.1.0 (2013/02/01)
390                                subTotalCount = 0;
391                                numberOfRows++;
392                                tblIdx++;
393                        }
394
395                        // 合計キーブレイク処理
396                        if( numberOfRows < maxRowCount && config.useTotal() && lastTotalKey != null && lastTotalKey.length() > 0
397                                && !lastTotalKey.equals( totalKey.toString() ) ) {
398                                addRow( totalFilter, totalLabel, totalCount, sumFilter, totalSum, tblIdx );
399                                totalSum = new BigDecimal[sumClmCount]; // 5.6.1.0 (2013/02/01)
400                                totalCount = 0;
401                                numberOfRows++;
402                                tblIdx++;
403                        }
404
405                        // 小計、合計、総合計単位に集計項目の合計値を加算します。
406                        // 6.0.2.0 (2014/09/19) BigDecimal.ZERO.add で、null エラーが発生するのは、query が複数あり、mainTrans=false で制御されていない場合
407                        for( int cnt=0; cnt<sc; cnt++ ) {
408                                subTotalSum[cnt]   = subTotalSum[cnt]   == null ? BigDecimal.ZERO.add(sumVals[cnt]) : subTotalSum[cnt].add(  sumVals[cnt]); // 5.6.8.1 (2013/09/13)
409                                totalSum[cnt]      = totalSum[cnt]      == null ? BigDecimal.ZERO.add(sumVals[cnt]) : totalSum[cnt].add(     sumVals[cnt]);
410                                grandTotalSum[cnt] = grandTotalSum[cnt] == null ? BigDecimal.ZERO.add(sumVals[cnt]) : grandTotalSum[cnt].add(sumVals[cnt]);
411                        }
412
413                        lastSubTotalKey = subTotalKey.toString();
414                        lastTotalKey = totalKey.toString();
415
416                        // グループ集計時はグルーピングした行数を加算する。
417                        int gcnt = 1;
418                        if( config.useGroup() && rowCountColumn >= 0 && rowCount > 0 ) {
419                                gcnt = rowCount;
420                        }
421                        subTotalCount += gcnt;
422                        totalCount    += gcnt;
423                        grandTotalCount += gcnt;
424
425                        tblIdx++;
426                }
427
428                // 最大件数が、超えた場合でかつ次のデータがある場合は、オーバーフロー
429                boolean isOverFlow = tblIdx < getRowCount() ;
430
431                // 小計キー最終行処理
432                if( config.useSubTotal() && lastSubTotalKey != null ) {
433                        if( numberOfRows < maxRowCount ) {
434                                addRow( subTotalFilter, subTotalLabel, subTotalCount, sumFilter, subTotalSum, tblIdx );
435                                numberOfRows++;
436                                tblIdx++;
437                        }
438                        else {
439                                isOverFlow = true;
440                        }
441                }
442
443                // 合計キー最終行処理
444                if( config.useTotal() && lastTotalKey != null ) {
445                        if( numberOfRows < maxRowCount ) {
446                                addRow( totalFilter, totalLabel, totalCount, sumFilter, totalSum, tblIdx );
447                                numberOfRows++;
448                                tblIdx++;
449                        }
450                        else {
451                                isOverFlow = true;
452                        }
453                }
454
455                // 総合計処理
456                if( config.useGrandTotal() && numberOfRows > 0 ) {
457                        if( numberOfRows < maxRowCount ) {
458                                final boolean[] grandTotalFilter = new boolean[numberOfColumns];
459                                // 総合計のラベル表示廃止
460                                // grandTotalFilter[0] = true;
461
462                                if( config.useFirstTotal() ) {          // 6.1.1.0 (2015/01/17)
463                                        addRow( grandTotalFilter, grandTotalLabel, grandTotalCount, sumFilter, grandTotalSum, 0 );
464                                }
465                                else {
466                                        addRow( grandTotalFilter, grandTotalLabel, grandTotalCount, sumFilter, grandTotalSum, tblIdx );
467                                        tblIdx++;
468                                }
469                                numberOfRows++;
470                        }
471                        else {
472                                isOverFlow = true;
473                        }
474                }
475
476                if( isOverFlow ) {
477                        setOverflow( true );
478                }
479
480                return isOverFlow;
481        }
482
483        /**
484         * キーの値配列、集計値の配列を引数として、追加行を生成し、DBTableModelに追加します。
485         * キー、及び集計値がDBTableModel上のどのカラムに位置するかは、キーフィルタ、集計フィルタで指定します。
486         * 
487         * @og.rev 5.6.1.0 (2013/02/01) doubleをdecimalに
488         *
489         * @param keyFilter キーフィルタ
490         * @param keyVals キーの値配列
491         * @param keyCount 集計した行のカウント
492         * @param sumFilter 集計フィルタ
493         * @param sumVals 集計値配列
494         * @param aRow 挿入する行番号
495         */
496        private void addRow( final boolean[] keyFilter, final String[] keyVals, final int keyCount
497                        , final boolean[] sumFilter, final BigDecimal[] sumVals, final int aRow ) {
498                String[] columnValues = new String[numberOfColumns];
499                int sc = 0;
500                int kc = 0;
501                for( int column=0; column<numberOfColumns; column++ ) {
502                        String val = "";
503                        if( keyFilter[column] ) {
504                                val = keyVals[kc++];
505                        }
506                        if( sumFilter[column] ) {
507                                val = FORMAT.format( sumVals[sc++] );
508                        }
509                        if( column == rowCountColumn ) {
510                                val = String.valueOf( keyCount );
511                        }
512                        columnValues[column] = val;
513                }
514
515                if( aRow < 0 ) {
516                        addColumnValues( columnValues );
517                }
518                else {
519                        addValues( columnValues, aRow, false );
520                }
521        }
522
523        /**
524         * キーの値配列、集計値の配列を引数として、追加行を生成し、DBTableModelに追加します。
525         * キー、及び集計値がDBTableModel上のどのカラムに位置するかは、キーフィルタ、集計フィルタで指定します。
526         * 
527         * @og.rev 5.6.1.0 (2013/02/01) doubleをbigDecimal
528         *
529         * @param keyFilter キーフィルタ
530         * @param keyVals キーの値配列
531         * @param keyCount 集計した行のカウント
532         * @param sumFilter 集計フィルタ
533         * @param sumVals 集計値配列
534         */
535        private void addRow( final boolean[] keyFilter, final String[] keyVals, final int keyCount
536                        , final boolean[] sumFilter, final BigDecimal[] sumVals ) {
537                addRow( keyFilter, keyVals, keyCount, sumFilter, sumVals, -1 );
538        }
539
540        /**
541         * キーの値、集計値の配列を引数として、追加行を生成し、DBTableModelに追加します。
542         * キー、及び集計値がDBTableModel上のどのカラムに位置するかは、キーフィルタ、集計フィルタで指定します。
543         * 
544         * @og.rev 5.6.1.0 (2013/02/01) doubleをbigDecimalに
545         *
546         * @param keyFilter キーフィルタ
547         * @param keyVal キーの値
548         * @param keyCount 集計した行のカウント
549         * @param sumFilter 集計フィルタ
550         * @param sumVals 集計値配列
551         * @param aRow 挿入する行番号
552         */
553        private void addRow( final boolean[] keyFilter, final String keyVal, final int keyCount
554                        , final boolean[] sumFilter, final BigDecimal[] sumVals, final int aRow ) {
555                final List<String> tmp = new ArrayList<>();
556                for( int column=0; column<numberOfColumns; column++ ) {
557                        if( keyFilter[column] ) {
558                                tmp.add( keyVal );
559                        }
560                }
561                addRow( keyFilter, tmp.toArray( new String[tmp.size()] ), keyCount, sumFilter, sumVals, aRow );
562        }
563}