    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() を先に判定すると必ず１件読み飛ばしてしまう。
    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() を先に判定すると必ず１件読み飛ばしてしまう。
    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) １文字 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}