    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.table;
    017
    018import java.util.Map;
    019import java.util.HashMap;
    020
    021import java.util.List;                                                                                  // 8.0.0.1 (2021/10/08)
    022import java.util.ArrayList;                                                                             // 8.0.0.1 (2021/10/08)
    023
    024import org.opengion.fukurou.util.StringUtil;
    025import org.opengion.fukurou.util.HybsDateUtil;                                  // 8.0.1.2 (2021/11/19)
    026// import org.opengion.hayabusa.common.HybsSystem;                              // 8.0.0.0 (2021/09/30)
    027import org.opengion.hayabusa.db.AbstractTableFilter;
    028import org.opengion.hayabusa.db.DBColumn;
    029import org.opengion.hayabusa.db.DBColumnConfig;
    030import org.opengion.hayabusa.db.DBTableModel;
    031import org.opengion.hayabusa.db.DBTableModelUtil;
    032import org.opengion.hayabusa.resource.ResourceManager;
    033import org.opengion.hayabusa.html.ViewMarker;                                   // 8.0.0.0 (2021/09/30)
    034
    035/**
    036 * TableFilter_ROTATE は､TableFilter ｲﾝﾀｰﾌｪｰｽを継承した､DBTableModel 処理用の
    037 * 実装ｸﾗｽです｡
    038 *
    039 * ここではﾃｰﾌﾞﾙの回転<del>及びその逆回転</del>を行います｡
    040 *   8.0.0.0 (2021/07/31) 逆回転 廃止
    041 *
    042 * ﾊﾟﾗﾒｰﾀは､tableFilterﾀｸﾞの keys, vals にそれぞれ記述するか､BODY 部にCSS形式で記述します｡
    043 * 【ﾊﾟﾗﾒｰﾀ】
    044 *  {
    045 *       KEY_CLM        : ｷｰｶﾗﾑ(複数指定可)                 (必須)
    046 *       ROTATE_CLM     : 回転するｶﾗﾑ                       (必須)
    047 *       ROTATE_LBL     : 回転ｶﾗﾑのﾍｯﾀﾞｰﾗﾍﾞﾙ                (任意指定)                         8.0.0.1 (2021/10/08)
    048 *       ADD_CLMS       : 回転するｶﾗﾑ値を外部から与えます   (任意指定)                            8.0.1.2 (2021/11/19)
    049 *       LBL_FORMAT     : ﾍｯﾀﾞｰﾗﾍﾞﾙの日付ﾌｫｰﾏｯﾄ指定(日付)   (任意指定)                             8.0.1.2 (2021/11/19)
    050 *       VALUE_CLM      : 回転ｶﾗﾑの値                       (必須)
    051 *       USE_LABEL      : 値ﾗﾍﾞﾙのｶﾗﾑを生成するか           (任意指定 初期値:false) 8.0.0.0 (2021/07/31)
    052 *       USE_RENDERER   : 値の表示に､renndererを使用するか (任意指定 初期値:false)        8.0.0.0 (2021/07/31)
    053 *       USE_MARKER     : 値の表示に､viewMarkerを使用するか (任意指定 初期値:false)       8.0.0.0 (2021/09/30)
    054 *  <del>REVERSE        : 回転(false)･逆回転(true)   (任意指定 初期値:false)</del>  8.0.0.0 (2021/07/31) 廃止
    055 *       MUST_CLM       : 必須属性を定義するｶﾗﾑ      (任意指定 初期値:false)
    056 *       DEF_CLM        : 初期値を定義するｶﾗﾑ        (任意指定)
    057 *  }
    058 *
    059 *  ※ それぞれに指定されたｶﾗﾑ名が存在しない場合は､処理されませんのでご注意下さい｡
    060 *
    061 * ①回転
    062 *  ｷｰｶﾗﾑ(KEY_CLM)に指定された値が同じN行を1行として回転します｡
    063 *  (ｷｰｶﾗﾑの値がﾌﾞﾚｲｸしたﾀｲﾐﾝｸﾞで､行を変更します)
    064 *  このN行に含まれる回転ｶﾗﾑの値がｶﾗﾑ名に､回転ｶﾗﾑ値が各ｶﾗﾑの値になります｡
    065 *  ｷｰｶﾗﾑは､CSV形式で複数指定可能です｡
    066 *
    067 *  生成されたﾃｰﾌﾞﾙﾓﾃﾞﾙのｶﾗﾑは､始めのMｶﾗﾑがｷｰｶﾗﾑに､その後ろのNｶﾗﾑが
    068 *  回転されたｶﾗﾑになります｡
    069 *
    070 *  生成されたﾃｰﾌﾞﾙのｶﾗﾑｵﾌﾞｼﾞｪｸﾄは､ROTATE_CLM で指定されたｷｰで生成されます｡
    071 *  ﾘｿｰｽに存在しない場合は､ROTATE_LBL で､ﾗﾍﾞﾙを指定することができます｡
    072 *
    073 *  また､元ﾃｰﾌﾞﾙにMUST_CLMにより､各ｶﾗﾑの必須属性を定義することが
    074 *  できます｡(MUST属性は､'1'又は'true'の場合に必須になります｡)
    075 *
    076 * 8.0.0.0 (2021/07/31)
    077 *  USE_LABEL="true" を指定した場合､VALUE_CLM のﾗﾍﾞﾙを､ｷｰｶﾗﾑと回転ｶﾗﾑの間に
    078 *  追加します｡これは､VALUE_CLM を 複数指定できる機能追加に伴う処置です｡
    079 *
    080 * 8.0.0.0 (2021/07/31) 逆回転 廃止
    081 * <del>②逆回転
    082 *  回転時の逆の挙動になります｡
    083 *  "ｷｰｶﾗﾑに指定されたｶﾗﾑ以外"を回転ｶﾗﾑで指定されたｶﾗﾑの値として分解します｡
    084 *  各回転ｶﾗﾑの値は､回転ｶﾗﾑ値に指定されたｶﾗﾑに格納されます｡
    085 *
    086 *  分解後のｶﾗﾑ数は､ｷｰｶﾗﾑ数 + 2 (回転ｶﾗﾑ､回転ｶﾗﾑ値)になります｡
    087 *  また､行数は､(分解前の行数) x (回転ｶﾗﾑ数)になります｡
    088 *</del>
    089 *
    090 * @og.formSample
    091 * ●形式：
    092 *      ① &lt;og:tableFilter classId="ROTATE" selectedAll="true"
    093 *                   keys="KEY_CLM,ROTATE_CLM,VALUE_CLM" vals='"GOKI,MAX_SID,MAX_TM_RPS",TOKEN,X_VAL' /&gt;
    094 *
    095 *      ② &lt;og:tableFilter classId="ROTATE"  selectedAll="true" &gt;
    096 *               {
    097 *                   KEY_CLM    : GOKI,MAX_SID,MAX_TM_RPS ;
    098 *                   ROTATE_CLM : TOKEN ;
    099 *                   VALUE_CLM  : X_VAL ;
    100 *               }
    101 *         &lt;/og:tableFilter&gt;
    102 *
    103 * @og.rev 5.6.6.0 (2013/07/05) keys の整合性ﾁｪｯｸを追加
    104 * @og.rev 8.0.0.0 (2021/07/31) VALUE_CLMの複数指定対応と､USE_LABEL属性の追加
    105 *
    106 * @version  0.9.0  2000/10/17
    107 * @author   Hiroki Nakamura
    108 * @since    JDK1.1,
    109 */
    110public class TableFilter_ROTATE extends AbstractTableFilter {
    111        /** このﾌﾟﾛｸﾞﾗﾑのVERSION文字列を設定します｡ {@value} */
    112        private static final String VERSION = "8.0.1.2 (2021/11/19)" ;
    113
    114        private DBTableModel    table    ;                      // 5.5.2.6 (2012/05/25) 共通に使うため､変数定義
    115        private ResourceManager resource ;                      // 5.5.2.6 (2012/05/25) 共通に使うため､変数定義
    116
    117        /**
    118         * ﾃﾞﾌｫﾙﾄｺﾝｽﾄﾗｸﾀｰ
    119         *
    120         * @og.rev 6.4.1.1 (2016/01/16) keysMap を､ｻﾌﾞｸﾗｽから設定させるように変更｡
    121         */
    122        public TableFilter_ROTATE() {
    123                super();
    124                initSet( "KEY_CLM"      , "ｷｰｶﾗﾑ(複数指定可)(必須)"                                    );
    125                initSet( "ROTATE_CLM"   , "回転するｶﾗﾑ(必須)"                                         );
    126                initSet( "ROTATE_LBL"   , "回転ｶﾗﾑのﾍｯﾀﾞｰﾗﾍﾞﾙ"                                             );              // 8.0.0.1 (2021/10/08)
    127                initSet( "ADD_CLMS"             , "回転するｶﾗﾑ値を外部から与えます"                   );              // 8.0.1.2 (2021/11/19)
    128                initSet( "LBL_FORMAT"   , "ﾍｯﾀﾞｰﾗﾍﾞﾙのﾌｫｰﾏｯﾄ指定(日付)"                              );              // 8.0.1.2 (2021/11/19)
    129                initSet( "VALUE_CLM"    , "回転ｶﾗﾑの値(複数指定可)(必須)"                  );
    130                initSet( "USE_LABEL"    , "値ﾗﾍﾞﾙのｶﾗﾑを生成するか(初期値:false)"  );              // 8.0.0.0 (2021/07/31)
    131                initSet( "USE_RENDERER" , "値の表示にrenndererを使用するか(初期値:false)" );  // 8.0.0.0 (2021/07/31)
    132                initSet( "USE_MARKER"   , "値の表示にviewMarkerを使用するか(初期値:false)" ); // 8.0.0.0 (2021/09/30)
    133//              initSet( "REVERSE"              , "回転(false)/逆回転(true) (初期値:false)"     );              // 8.0.0.0 (2021/07/31) 廃止
    134                initSet( "MUST_CLM"             , "必須属性を定義するｶﾗﾑ (初期値:false)"    );
    135                initSet( "DEF_CLM"              , "初期値を定義するｶﾗﾑ"                                         );
    136        }
    137
    138        /**
    139         * DBTableModel処理を実行します｡
    140         *
    141         * @og.rev 4.3.7.4 (2009/07/01) 新規追加
    142         * @og.rev 5.5.2.6 (2012/05/25) protected変数を､private化したため､getterﾒｿｯﾄﾞで取得するように変更
    143         *
    144         * @return 処理結果のDBTableModel
    145         */
    146        public DBTableModel execute() {
    147                table    = getDBTableModel();           // 5.5.2.6 (2012/05/25) ｲﾝﾀｰﾌｪｰｽにgetterﾒｿｯﾄﾞ追加
    148                resource = getResource();                       // 5.5.2.6 (2012/05/25) ｲﾝﾀｰﾌｪｰｽにgetterﾒｿｯﾄﾞ追加
    149
    150                return getRotateTable();
    151        }
    152
    153        /**
    154         * 回転後のDBTableModelを返します｡
    155         *
    156         * @og.rev 5.1.8.0 (2010/07/01) ﾒｿｯﾄﾞ名変更(setDefValue ⇒ setDefault)
    157         * @og.rev 6.4.3.4 (2016/03/11) forﾙｰﾌﾟを､forEach ﾒｿｯﾄﾞに置き換えます｡
    158         * @og.rev 8.0.0.0 (2021/07/31) VALUE_CLMの複数指定対応と､USE_LABEL属性の追加
    159         * @og.rev 8.0.0.1 (2021/10/08) ROTATE_LBL(回転ｶﾗﾑのﾍｯﾀﾞｰﾗﾍﾞﾙ)の追加
    160         * @og.rev 8.0.1.2 (2021/11/19) ADD_CLMS、LBL_FORMAT 追加
    161         *
    162         * @return 回転後のDBTableModel
    163         */
    164        private DBTableModel getRotateTable() {
    165                // 8.0.0.0 (2021/07/31) VALUE_CLMの複数指定対応と､USE_LABEL属性の追加
    166                // ｴﾗｰ時の原因表示を入れておきます｡
    167
    168                final String tmpKeyClm  = getValue( "KEY_CLM" );
    169                final String[] keyClm   = StringUtil.csv2Array( tmpKeyClm );
    170                if( keyClm.length == 0 ) { System.out.println( "KEY_CLM is none[" + tmpKeyClm + "]" ); }
    171
    172                final String tmpRotClm  = getValue( "ROTATE_CLM" );
    173                final int rotateNo              = table.getColumnNo( tmpRotClm );               // 8.0.0.0 (2021/09/30) ｴﾗｰにします｡
    174
    175                // 8.0.0.1 (2021/10/08) ROTATE_LBL(回転ｶﾗﾑのﾍｯﾀﾞｰﾗﾍﾞﾙ)の追加
    176                final String tmpRotLbl  = getValue( "ROTATE_LBL" );
    177                final int lblNo                 = table.getColumnNo( tmpRotLbl, false );        // 任意なので;
    178
    179                final String tmpValClm  = getValue( "VALUE_CLM" );
    180                final String[] valClm   = StringUtil.csv2Array( tmpValClm );
    181                if( valClm.length == 0 ) { System.out.println( "VALUE_CLM is none[" + tmpValClm + "]" ); }
    182
    183                int clmCount = 0; // 回転後のｶﾗﾑ数
    184                // ｷｰｶﾗﾑのｶﾗﾑ番号を求め､ｶﾗﾑ数としてｶｳﾝﾄします｡
    185                final Map<String, Integer> clmMap = new HashMap<>();
    186                final int[] keyNos = new int[keyClm.length];
    187                for( int i=0; i<keyNos.length; i++ ) {
    188                        keyNos[i] = table.getColumnNo( keyClm[i] );             // 8.0.0.0 (2021/09/30) ｴﾗｰにします｡
    189                        clmMap.put( keyClm[i], clmCount++ );                    // 固定ｶﾗﾑ
    190                }
    191
    192                // 8.0.0.0 (2021/07/31) USE_LABEL属性の追加
    193                final boolean useValLbl = StringUtil.nval( getValue( "USE_LABEL" ), false );
    194                if( useValLbl ) {
    195                        clmMap.put( "LABEL", clmCount++ );                              // ﾗﾍﾞﾙｶﾗﾑ
    196                }
    197
    198                // ============ 以下は回転ｶﾗﾑの処理 ============
    199
    200                final int valStartNo = clmCount ;                                       // 値ｶﾗﾑ(回転ｶﾗﾑ)の開始ｱﾄﾞﾚｽ
    201                final List<String> lblList = new ArrayList<>();         // 8.0.0.1 (2021/10/08) ROTATE_LBL(未使用時は､nullをｾｯﾄする)
    202                for( int i=0; i<valStartNo; i++ ) { lblList.add( null ); }      // 後の処理を共通にするため｡
    203
    204                // 8.0.1.2 (2021/11/19) LBL_FORMAT 回転ｶﾗﾑのﾗﾍﾞﾙﾌｫｰﾏｯﾄ(日付)を設定します。
    205                final String lblFormat  = getValue( "LBL_FORMAT" );             // "MM/dd\n(EEE)" などの日付ﾌｫｰﾏｯﾄを指定します。
    206
    207                // 8.0.1.2 (2021/11/19) ADD_CLMS 回転ｶﾗﾑを追加します。
    208                final String tmpAddClms = getValue( "ADD_CLMS" );
    209                final String[] addClms  = StringUtil.csv2Array( tmpAddClms );
    210                for( final String clm : addClms ) {
    211                        clmMap.put( clm, clmCount++ );                          // ﾗﾍﾞﾙｶﾗﾑ
    212                        if( lblFormat != null ) {
    213                                lblList.add( HybsDateUtil.getDateFormat( lblFormat,clm ) );     // 後の処理を共通にするため｡
    214                        }
    215                }
    216
    217                // 8.0.0.0 (2021/07/31) USE_RENDERER属性の追加
    218                final boolean useValRend = StringUtil.nval( getValue( "USE_RENDERER" ), false );
    219                // 8.0.0.0 (2021/09/30) USE_MARKER属性の追加
    220                final boolean useMarker = StringUtil.nval( getValue( "USE_MARKER" ), false );
    221                final ViewMarker viewMarker = useMarker ? getViewMarker() : null;
    222
    223                // 値ｶﾗﾑのｶﾗﾑ番号を求める｡(ｶﾗﾑ数としてｶｳﾝﾄしない=行が増える)
    224                final int[] valNos = new int[valClm.length];
    225                final DBColumn[] valClmns = new DBColumn[valClm.length];
    226                for( int i=0; i<valNos.length; i++ ) {
    227                        valNos[i] = table.getColumnNo( valClm[i] );                                     // 8.0.0.0 (2021/09/30) ｴﾗｰにします｡
    228                        if( useValRend ) {
    229                                valClmns[i] = table.getDBColumn( valNos[i] );
    230                        }
    231                }
    232
    233                int rowCount = 0; // 回転後の行数(KEY_CLMで指定したﾕﾆｰｸになる行数で､実際の行数は､VALUE_CLM 倍になる)
    234                // 回転ｶﾗﾑの値から回転後のｶﾗﾑ数を求めます｡
    235                // また同時に､ｷｰｶﾗﾑの値のﾌﾞﾚｲｸ数により行数を求めます｡
    236                final Map<String, Integer> rowMap               = new HashMap<>();
    237                final Map<String, Boolean> mustMap              = new HashMap<>();
    238                final Map<String, String>  defaultMap   = new HashMap<>();
    239                final int mustNo = table.getColumnNo( getValue( "MUST_CLM"), false );   // 任意なので
    240                final int defNo  = table.getColumnNo( getValue( "DEF_CLM" ), false );   // 任意なので
    241                for( int i=0; i<table.getRowCount(); i++ ) {
    242                        final String clmKey = table.getValue( i, rotateNo );
    243                        if( clmMap.get( clmKey ) == null ) {
    244                                clmMap.put( clmKey, clmCount++ );                       // 回転ｶﾗﾑ
    245
    246                                if( lblFormat == null ) {
    247                                        // 8.0.0.1 (2021/10/08) ROTATE_LBL(未使用時は､nullをｾｯﾄする)
    248                                        lblList.add( lblNo >= 0 ? table.getValue( i, lblNo ) : null );  // 後の処理を共通にするため｡
    249                                }
    250                                else {
    251                                        // 8.0.1.2 (2021/11/19) LBL_FORMAT 回転ｶﾗﾑのﾗﾍﾞﾙﾌｫｰﾏｯﾄ(日付)を設定します。
    252                                        final String fmt = lblNo >= 0 ? table.getValue( i, lblNo ) : clmKey ;
    253                                        lblList.add( HybsDateUtil.getDateFormat( lblFormat,fmt ) );     // 後の処理を共通にするため｡
    254                                }
    255                        }
    256                        // 必須ｶﾗﾑ抜き出し
    257                        if( mustNo > -1 && StringUtil.nval( table.getValue( i, mustNo ), false ) ) {
    258                                mustMap.put( clmKey, true );
    259                        }
    260                        // ﾃﾞﾌｫﾙﾄ値を書き換えるｶﾗﾑの抜き出し
    261                        if( defNo > -1 && table.getValue( i, defNo ) != null && table.getValue( i, defNo ).length() > 0 ) {
    262                                defaultMap.put( clmKey, table.getValue( i, defNo ) );
    263                        }
    264
    265                        final String rowKey = getSeparatedValue( i, keyNos );
    266                        // 6.0.0.1 (2014/04/25) These nested if statements could be combined
    267                        if( rowKey != null && rowKey.length() > 0 && rowMap.get( rowKey ) == null ) {
    268                                rowMap.put( rowKey, rowCount++ );
    269                        }
    270                }
    271
    272                // 回転後のｶﾗﾑ一覧よりDBTableModelを初期化します｡
    273                // 6.3.9.1 (2015/11/27) Found 'DD'-anomaly for variable(PMD)
    274                final String names[] = new String[clmMap.size()];
    275                // 6.4.3.4 (2016/03/11) forﾙｰﾌﾟを､forEach ﾒｿｯﾄﾞに置き換えます｡
    276                clmMap.forEach( (k,v) -> names[v] = k );
    277
    278                final DBTableModel nTable = DBTableModelUtil.newDBTable();
    279                nTable.init( names.length );
    280                for( int i=0; i<names.length; i++ ) {
    281                        if( mustMap.get( names[i] ) != null ) {
    282                                table.addMustType( i, "must" );
    283                        }
    284//                      DBColumn column = resource.makeDBColumn( names[i] );
    285                        DBColumn column = resource.makeDBColumn( names[i],lblList.get(i) );                     // 8.0.0.1 (2021/10/08) ﾍｯﾀﾞｰのﾗﾍﾞﾙ｡未使用時は null
    286                        // 8.0.0.0 (2021/07/31) ｵﾘｼﾞﾅﾙが数字ﾀｲﾌﾟだと､ｴﾗｰになる可能性があるため
    287                        final DBColumnConfig dbConfig = column.getConfig();                     // 固定ｶﾗﾑより値ｶﾗﾑの方が多いので､処理速度は気にしないことにする｡
    288                        if( valStartNo <= i ) {                 // 値ｶﾗﾑ(回転ｶﾗﾑ)
    289                                dbConfig.setRenderer( "LABEL" );                                                //
    290                        }
    291
    292//                      if( defaultMap.get( names[i] ) != null ) {
    293//                              dbConfig.setDefault( defaultMap.get( names[i] ) );              // 5.1.8.0 (2010/07/01)
    294//                      }
    295                        final String defVal = defaultMap.get( names[i] ) ;
    296                        if( defVal != null ) {
    297                                dbConfig.setDefault( defVal );                                                  // 5.1.8.0 (2010/07/01)
    298                        }
    299                        column = new DBColumn( dbConfig );                                                      // 8.0.0.0 (2021/07/31)
    300                        nTable.setDBColumn( i, column );                                                        // 5.1.8.0 (2010/07/01)
    301                }
    302
    303                // 値の一覧を作成し､DBTableModelに値をｾｯﾄします｡
    304                if( rowCount > 0 ) {
    305                        // 6.3.9.1 (2015/11/27) Found 'DD'-anomaly for variable(PMD)
    306                        final String[][] vals = new String[rowCount*valClm.length][names.length];       // 行数は､valClm.length 倍になる
    307                        for( int i=0; i<table.getRowCount(); i++ ) {
    308                                final int row = rowMap.get( getSeparatedValue( i, keyNos ) );
    309                                final int clm = clmMap.get( table.getValue( i, rotateNo ) );
    310
    311                                final int nrow = row * valClm.length ;
    312                                // 8.0.0.0 (2021/07/31) VALUE_CLM が複数存在した場合の処理
    313                                for( int k=0; k<valNos.length; k++ ) {
    314                                        for( int j=0; j<keyNos.length; j++ ) {
    315                                                String val2 = table.getValue( i, keyNos[j] );
    316
    317                                                if( viewMarker != null ) {
    318                                                        val2 = viewMarker.getMarkerString( i,keyNos[j],val2 );                  // ViewMarkerを使用
    319                                                }
    320                                                vals[nrow+k][j] = val2;
    321
    322                //                              vals[nrow+k][j] = table.getValue( i, keyNos[j] );
    323                                        }
    324                                        if( useValLbl ) {
    325                                                // 実際は､上のﾙｰﾌﾟの最後の j ( = keyNos.length )
    326                                                vals[nrow+k][keyNos.length] = table.getColumnLabel( valNos[k] );
    327                                        }
    328
    329                                        String val = table.getValue( i, valNos[k] );
    330                                        if( useValRend ) { val = valClmns[k].getRendererValue( val ); }         // Rndererを使用
    331                                        if( viewMarker != null ) {
    332                                                val = viewMarker.getMarkerString( i,valNos[k],val );                    // ViewMarkerを使用
    333                                        }
    334                                        vals[nrow+k][clm] = val;
    335                                }
    336                        }
    337                        for( int i=0; i<vals.length; i++ ) {
    338                                nTable.addColumnValues( vals[i] );
    339                        }
    340                }
    341
    342                return nTable;
    343        }
    344
    345        /**
    346         * 各行のｷｰとなるｷｰｶﾗﾑの値を連結した値を返します｡
    347         *
    348         * @param       row             行番号
    349         * @param       clmNo   ｶﾗﾑ番号配列(可変長引数)
    350         *
    351         * @return      各行のｷｰとなるｷｰｶﾗﾑの値を連結した値
    352         * @og.rtnNotNull
    353         */
    354        private String getSeparatedValue( final int row, final int... clmNo ) {
    355                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
    356                for( int i=0; i<clmNo.length; i++ ) {
    357                        final String val = table.getValue( row, clmNo[i] );
    358                        if( val != null && val.length() > 0 ) {
    359                                if( i > 0 ) {
    360                                        buf.append( "__" );
    361                                }
    362                                buf.append( val );
    363                        }
    364                }
    365                return buf.toString();
    366        }
    367}