    001/*
    002 * Copyright (c) 2009 The openGion Project.
    003 *
    004 * Licensed under the Apache License, Version 2.0 (the "License");
    005 * you may not use this file except in compliance with the License.
    006 * You may obtain a copy of the License at
    007 *
    008 *     http://www.apache.org/licenses/LICENSE-2.0
    009 *
    010 * Unless required by applicable law or agreed to in writing, software
    011 * distributed under the License is distributed on an "AS IS" BASIS,
    012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
    013 * either express or implied. See the License for the specific language
    014 * governing permissions and limitations under the License.
    015 */
    016package org.opengion.plugin.view;
    017
    018import org.opengion.fukurou.system.OgBuilder ;                                  // 6.4.4.2 (2016/04/01)
    019import org.opengion.fukurou.util.StringUtil;
    020import org.opengion.hayabusa.common.HybsSystem;
    021import org.opengion.hayabusa.common.HybsSystemException;
    022import org.opengion.hayabusa.db.DBTableModel;
    023import org.opengion.hayabusa.html.TableFormatter;
    024import org.opengion.hayabusa.html.ViewGanttTableParam;
    025
    026import java.util.regex.Pattern;
    027import java.util.regex.Matcher;
    028
    029import java.util.Locale;
    030import java.util.TreeSet;
    031import java.util.List;
    032import java.util.Date;
    033import java.util.Calendar;
    034import java.text.SimpleDateFormat;
    035import java.text.ParseException;
    036
    037/**
    038 * ガントチャート(テーブル形式)を作成する、ガントチャート表示クラスです。
    039 *
    040 * AbstractViewForm により、setter/getterメソッドのデフォルト実装を提供しています。
    041 * 各HTMLのタグに必要な setter/getterメソッドのみ，追加定義しています。
    042 *
    043 * AbstractViewForm を継承している為,ロケールに応じたラベルを出力させる事が出来ます。
    044 *
    045 * @og.group 画面表示
    046 *
    047 * @version  4.0
    048 * @author       Kazuhiko Hasegawa
    049 * @since    JDK5.0,
    050 */
    051public class ViewForm_HTMLGanttTable extends ViewForm_HTMLTable {
    052        /** このプログラムのVERSION文字列を設定します。   {@value} */
    053        private static final String VERSION = "7.0.4.0 (2019/05/31)" ;
    054
    055        // 3.5.4.0 (2003/11/25) TableFormatter クラス追加
    056        private TableFormatter          headerFormat    ;
    057        private TableFormatter[]        bodyFormats             ;
    058        private TableFormatter          footerFormat    ;
    059        private int                                     bodyFormatsCount;
    060
    061        // 繰り返すTD用 3.5.6.0 (2004/06/18) 廃止
    062        private TableFormatter[]        itdFormats              ;               // 追加
    063
    064        private String ganttHeadLine            ;
    065        private int[]  groupCols                        ;
    066        private int    posDuration                      = -1;
    067        private int    posDystart                       = -1;
    068
    069        private String formatDystart            = ViewGanttTableParam.DYSTART_FORMAT_VALUE;
    070        private double  minDuration                     = StringUtil.parseDouble( ViewGanttTableParam.MIN_DURATION_VALUE ) ;    // 3.5.5.8 (2004/05/20)
    071        private double  headerDuration          = minDuration ; // 3.5.5.8 (2004/05/20)
    072
    073        // 3.5.4.6 (2004/01/30) 初期値変更
    074        private static final int BODYFORMAT_MAX_COUNT = 10;
    075
    076        // <(td|th)(.*)>(.*)</(td|th)>を確認する
    077        private static final Pattern TDTH_PTN =                                                                 // 6.4.1.1 (2016/01/16) cpTdTh  → TDTH_PTN  refactoring
    078                Pattern.compile("\\<(td|th)([^\\>]*)\\>(.*)\\</(td|th)\\>"
    079                                , Pattern.DOTALL + Pattern.CASE_INSENSITIVE);
    080        // 3.5.5.9 (2004/06/07)
    081        private int maxDayCnt                           ;
    082        private String headerLocale                     ;
    083        private String[] headDays                       ;
    084        private int headDaysCnt                         ;
    085
    086        // 3.5.6.3 (2004/07/12) 行チェックによる編集用の hidden
    087        private static final String CHECK_ROW =
    088                "<input type=\"hidden\" name=\"" + HybsSystem.ROW_SEL_KEY + "\" value=\"";
    089
    090        // 3.6.1.0 (2005/01/05) 開始日付けと終了日付けの指定
    091        private boolean useSeqDay               ;
    092        private String startDay                 ;
    093        private String endDay                   ;
    094
    095        private boolean useItd                  ;               // 5.0.0.3 (2009/09/22)
    096
    097        /**
    098         * デフォルトコンストラクター
    099         *
    100         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
    101         */
    102        public ViewForm_HTMLGanttTable() { super(); }           // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
    103
    104        /**
    105         * 内容をクリア(初期化)します。
    106         *
    107         * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。
    108         * @og.rev 3.5.0.0 (2003/09/17) Noカラムに、表示を全て消せるように、class 属性を追加。
    109         * @og.rev 3.5.4.0 (2003/11/25) TableFormatter クラスを使用するように変更。
    110         * @og.rev 3.5.5.8 (2004/05/20) minDuration ,  headerDuration 追加。 不要な変数削除
    111         * @og.rev 3.5.6.0 (2004/06/18) ithFormat ,  itdFormat 属性削除、itdFormats属性を追加
    112         * @og.rev 3.6.1.0 (2005/01/05) startDay,endDay,useSeqDay 属性追加
    113         * @og.rev 5.0.0.3 (2009/09/22) itdタグの有無でcolspan対策のtdの出力個数を調整
    114         */
    115        @Override
    116        public void clear() {
    117                super.clear();
    118
    119                headerFormat            = null;
    120                bodyFormats                     = null;
    121                footerFormat            = null;
    122                bodyFormatsCount        = 0;
    123
    124                ganttHeadLine           = null;
    125                itdFormats                      = null;         // 3.5.6.0 (2004/06/18)
    126                groupCols                       = null;
    127                posDuration                     = -1  ;
    128                posDystart                      = -1;
    129                formatDystart           = ViewGanttTableParam.DYSTART_FORMAT_VALUE;
    130                minDuration                     = StringUtil.parseDouble( ViewGanttTableParam.MIN_DURATION_VALUE ) ;    // 3.5.5.8 (2004/05/20)
    131                headerDuration          = minDuration ;         // 3.5.5.8 (2004/05/20)
    132
    133                maxDayCnt                       = 0;    // 3.5.5.9 (2004/06/07)
    134                headerLocale            = null; // 3.5.5.9 (2004/06/07)
    135                headDays                        = null; // 3.5.5.9 (2004/06/07)
    136                headDaysCnt                     = 0;    // 3.5.5.9 (2004/06/07)
    137
    138                useSeqDay                       = false;        // 3.6.1.0 (2005/01/05)
    139                startDay                        = null; // 3.6.1.0 (2005/01/05)
    140                endDay                          = null; // 3.6.1.0 (2005/01/05)
    141
    142                useItd                  = false; // 5.0.0.3 (2009/09/22)
    143        }
    144
    145        /**
    146         * DBTableModel から HTML文字列を作成して返します。
    147         * startNo(表示開始位置)から、pageSize(表示件数)までのView文字列を作成します。
    148         * 表示残りデータが pageSize 以下の場合は,残りのデータをすべて出力します。
    149         *
    150         * @og.rev 3.5.0.0 (2003/09/17) BODY要素の noClass 属性を追加。
    151         * @og.rev 3.5.0.0 (2003/09/17) &lt;tr&gt;属性は、元のフォーマットのまま使用します。
    152         * @og.rev 3.5.2.0 (2003/10/20) ヘッダー繰り返し属性( headerSkipCount )を採用
    153         * @og.rev 3.5.3.1 (2003/10/31) skip属性を採用。headerLine のキャッシュクリア
    154         * @og.rev 3.5.4.0 (2003/11/25) TableFormatter クラスを使用するように変更。
    155         * @og.rev 3.5.5.0 (2004/03/12) systemFormat(例：[KEY.カラム名]形式等)の対応
    156         * @og.rev 3.5.5.9 (2004/06/07) IEの colspan が上手く動かない対策。
    157         * @og.rev 3.5.5.9 (2004/06/07) [#カラム名] , [$カラム名] に対応
    158         * @og.rev 3.5.6.0 (2004/06/18) itdFormat を、BODY毎のFormatを使用するように修正
    159         * @og.rev 3.5.6.0 (2004/06/18) '!' 値のみ 追加 既存の '$' は、レンデラー
    160         * @og.rev 3.5.6.3 (2004/07/12) 行チェックによる編集が出来るように機能を追加
    161         * @og.rev 3.5.6.4 (2004/07/16) ヘッダーとボディー部をJavaScriptで分離
    162         * @og.rev 3.6.1.0 (2005/01/05) 行チェックによる編集が、検索即登録時も可能なようにします。
    163         * @og.rev 4.0.0.0 (2005/01/31) 新規作成(getColumnClassName ⇒ getColumnDbType)
    164         * @og.rev 3.7.0.1 (2005/01/31) E の colspan バグ対応で入れた最終行の 空タグを消す為の修正
    165         * @og.rev 4.3.1.0 (2008/09/08) フォーマットが設定されていない場合のエラー追加
    166         * @og.rev 4.3.7.4 (2009/07/01) tbodyタグの入れ子を解消(FireFox対応)
    167         * @og.rev 5.0.0.3 (2009/09/22) itdタグの有無でcolspan対策のtdの出力個数を調整
    168         * @og.rev 5.5.4.4 (2012/07/20) 二重チェック状態になってしまう対策
    169         * @og.rev 6.2.0.0 (2015/02/27) フォーマット系の noDisplay 対応
    170         * @og.rev 6.4.3.4 (2016/03/11) tdに、[カラム]が無いケースで、次の[カラム]のクラス属性が、前方すべてのtdにセットされてしまう対応。
    171         * @og.rev 6.4.4.2 (2016/04/01) TableFormatterのタイプ別値取得処理の共通部をまとめる。
    172         * @og.rev 6.4.5.0 (2016/04/08) メソッド変更( getColumnDbType(int) → getClassName(int) )
    173         * @og.rev 6.8.1.1 (2017/07/22) ckboxTD変数は、&lt;td&gt; から &lt;td に変更します(タグの最後が記述されていない状態でもらう)。
    174         * @og.rev 6.8.2.0 (2017/10/13) makeNthChildの廃止と、makeCheckboxで、個別にclass指定するように変更。
    175         * @og.rev 7.0.1.0 (2018/10/15) XHTML → HTML5 対応(空要素の、"／＞" 止めを、"＞" に変更します)。
    176         *
    177         * @param  stNo   表示開始位置
    178         * @param  pgSize   表示件数
    179         *
    180         * @return      DBTableModelから作成された HTML文字列
    181         * @og.rtnNotNull
    182         */
    183        @Override
    184        public String create( final int stNo, final int pgSize )  {
    185                // ガントは、キーブレイクがあるため、全件表示します。
    186                final int pageSize = getRowCount() ;
    187                if( pageSize == 0 ) { return ""; }      // 暫定処置
    188                // 6.3.9.1 (2015/11/27) Found 'DD'-anomaly for variable(PMD)
    189
    190                // 4.3.1.0 (2008/09/08)
    191                if( headerFormat == null ) {
    192                        final String errMsg = "ViewTagで canUseFormat() = true の場合、Formatter は必須です。";
    193                        throw new HybsSystemException( errMsg );
    194                }
    195
    196                headerLine       = null;                // 3.5.3.1 (2003/10/31) キャッシュクリア
    197
    198                // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid declaring a variable if it is unreferenced before a possible exit point.
    199                // ガントは、キーブレイクがあるため、全件表示します。
    200                final int startNo  = 0;
    201                final int lastNo = getLastNo( startNo, pageSize );
    202                final int blc = getBackLinkCount();
    203                final int hsc = getHeaderSkipCount();           // 3.5.2.0 (2003/10/20)
    204                int hscCnt = 1;                                         // 3.5.2.0 (2003/10/20)
    205
    206                // このビューの特有な属性を初期化
    207                paramInit();
    208
    209                final StringBuilder out = new StringBuilder( BUFFER_LARGE );
    210
    211                out.append( getCountForm( startNo,pageSize ) );
    212
    213                if( posDuration < 0 ) { ganttHeadLine = getGanttHeadNoDuration(startNo, lastNo); }
    214                else {                                  ganttHeadLine = getGanttHead(startNo, lastNo); }
    215
    216                out.append( getHeader() );
    217
    218                if( bodyFormatsCount == 0 ) {
    219                        bodyFormats[0] = headerFormat ;
    220                        bodyFormatsCount ++ ;
    221                }
    222                else {
    223                        for( int i=0; i<bodyFormatsCount; i++ ) {
    224                                bodyFormats[i].makeFormat( getDBTableModel() );
    225                                // 6.2.0.0 (2015/02/27) フォーマット系の noDisplay 対応
    226                                setFormatNoDisplay( bodyFormats[i] );
    227
    228                                if( itdFormats[i] != null ) {
    229                                        itdFormats[i].makeFormat( getDBTableModel() );
    230                                        // 6.2.0.0 (2015/02/27) フォーマット系の noDisplay 対応
    231                                        setFormatNoDisplay( itdFormats[i] );
    232                                }
    233                        }
    234                }
    235
    236                String[] astrOldGroupKeys = new String[groupCols.length];
    237                for( int nIndex =0; nIndex<astrOldGroupKeys.length; nIndex++ ) {
    238                        astrOldGroupKeys[nIndex] = "";
    239                }
    240
    241                final StringBuilder bodyBuf = new StringBuilder( BUFFER_LARGE );                // 6.1.0.0 (2014/12/26) refactoring
    242                final StringBuilder itdBuf  = new StringBuilder( BUFFER_LARGE );                // 6.1.0.0 (2014/12/26) refactoring
    243                boolean checked = false;                // 3.5.6.3 (2004/07/12)
    244                int bgClrCnt = 0;
    245                TableFormatter itdFormat = null;
    246                for( int row=startNo; row<lastNo; row++ ) {
    247                        // 6.3.9.1 (2015/11/27) Found 'DD'-anomaly for variable(PMD)
    248                        boolean outputCheck = true;                     // 5.5.4.4. (2012/07/20) チェックボックス出力判定
    249                        // ガントでは、データのスキップは行いません。
    250
    251                        if( !isSameGroup(row, astrOldGroupKeys) ) {
    252                                // 3.5.6.3 (2004/07/12) キーブレイク時にチェック行かどうかを記録
    253                                checked = getDBTableModel().isRowChecked( row );
    254
    255                                if( row != startNo ) {
    256                                        // ヘッダー日付けが残っているのに、データがなくなった場合
    257                                        while( headDays != null && headDaysCnt < headDays.length ) {
    258                                                itdBuf.append( "<td></td>" );
    259                                                headDaysCnt++;
    260                                        }
    261                                        out.append(StringUtil.replace(bodyBuf.toString(), TableFormatter.HYBS_ITD_MARKER, itdBuf.toString()));
    262                                        itdBuf.setLength(0);            // 6.1.0.0 (2014/12/26) refactoring
    263                                        headDaysCnt     = 0;
    264                                }
    265
    266                                bodyBuf.setLength(0);
    267
    268                                // カラムのグループがブレイクするまで、BodyFormatは同一である前提
    269                                for( int i=0; i<bodyFormatsCount; i++ ) {
    270                                        final TableFormatter bodyFormat = bodyFormats[i];
    271                                        if( ! bodyFormat.isUse( row,getDBTableModel() ) ) { continue; }         // 3.5.4.0 (2003/11/25)
    272                                        itdFormat = itdFormats[i];              //
    273
    274                                        bodyBuf.append("<tbody")
    275                                                .append( getBgColorCycleClass( bgClrCnt++ ) )
    276                                                .append('>')                                                                                                    // 6.0.2.5 (2014/10/31) char を append する。
    277                                                .append( bodyFormat.getTrTag() );
    278
    279                                        // 3.5.5.0 (2004/03/12) No 欄そのものの作成判断追加
    280                                        if( isNumberDisplay() ) {
    281                                                final String ckboxTD = "<td" + bodyFormat.getRowspan();                 // 6.8.1.1 (2017/07/22)
    282                                                bodyBuf.append( makeCheckbox( ckboxTD,row,blc,true ) );                 // 6.8.2.0 (2017/10/13)
    283                                                outputCheck = false; // 5.5.4.4. (2012/07/20)
    284                                        }
    285
    286                                        int cl = 0;
    287                                        for( ; cl<bodyFormat.getLocationSize(); cl++ ) {
    288                                                String fmt = bodyFormat.getFormat(cl);
    289                                                final int loc = bodyFormat.getLocation(cl);     // 3.5.5.0 (2004/03/12)
    290                                                // 6.1.0.0 (2014/12/26) refactoring
    291                                                if( ! bodyFormat.isNoClass() && loc >= 0 ) {
    292                                                        // 6.4.3.4 (2016/03/11) tdに、[カラム]が無いケースで、次の[カラム]のクラス属性が、前方すべてのtdにセットされてしまう対応。
    293                                                        final int idx = fmt.lastIndexOf( "<td" );
    294                                                        if( idx >= 0 ) {        // matchしてるので、あるはず
    295                                                                final String tdclass = " class=\"" + getClassName(loc) + "\" ";         // 6.4.5.0 (2016/04/08)
    296                                                                fmt = fmt.substring( 0,idx+3 ) + tdclass + fmt.substring( idx+3 ) ;
    297                                                        }
    298                                                }
    299                                                bodyBuf.append( fmt );                                  // 3.5.0.0 (2003/09/17)
    300                                                // 3.5.5.9 (2004/06/07) #,$ 対応
    301                                                if( loc >= 0 ) {
    302                                                        // 6.4.4.2 (2016/04/01) 処理の共通部をまとめる。
    303                                                        bodyBuf.append( getTypeCaseValue( bodyFormat.getType(cl),row,loc ) );
    304                                                }
    305                                                else {
    306                                                        bodyBuf.append( bodyFormat.getSystemFormat(row,loc) );
    307                                                }
    308                                        }
    309                                        bodyBuf.append( bodyFormat.getFormat(cl) )
    310                                                .append("</tbody>").append( CR );
    311                                }
    312
    313                                // 3.5.2.0 (2003/10/20) ヘッダー繰り返し属性( headerSkipCount )を採用
    314                                if( hsc > 0 && hscCnt % hsc == 0 ) {
    315                                        bodyBuf.append("<tbody class=\"row_h\" >")
    316                                                .append( getHeadLine() )
    317                                                .append("</tbody>");
    318                                        hscCnt = 1;
    319                                }
    320                                else {
    321                                        hscCnt ++ ;
    322                                }
    323                        }
    324
    325                        // 3.5.6.3 (2004/07/12) キーブレイク時のチェック行の状態を繰り返し行に反映
    326                        // 3.6.1.0 (2005/01/05) さらに、外部でチェックを入れている場合は、個別対応する。
    327                        if( (checked || isChecked( row )) && outputCheck ) {     // 5.5.4.4. (2012/07/20)
    328                                getDBTableModel().setRowWritable( row,true );
    329                                out.append( CHECK_ROW )
    330                                        .append( row )
    331//                                      .append( "\" />" );
    332                                        .append( "\" >" );                              // 7.0.1.0 (2018/10/15)
    333                        }
    334
    335                        formatItd(row, itdFormat, itdBuf);
    336                }
    337
    338                // 残ったデータを出力
    339                if( itdBuf.length() > 0 ) {
    340                        // ヘッダー日付けが残っているのに、データがなくなった場合
    341                        while( headDays != null && headDaysCnt < headDays.length ) {
    342                                itdBuf.append( "<td></td>" );
    343                                headDaysCnt++;
    344                        }
    345                        out.append(StringUtil.replace(bodyBuf.toString(), TableFormatter.HYBS_ITD_MARKER, itdBuf.toString()));
    346                }
    347
    348                // 3.5.5.9 (2004/06/07) IEの colspan が上手く動かない対策。
    349                // minDuration が、1.0 以下の場合のみ実行
    350                if( minDuration < 1.0d ) {
    351                        // int tdCount = (int)Math.round( maxDayCnt / minDuration );
    352                        // 5.0.0.3 (2009/09/22) itdタグの有無でtdCountを変える。
    353                        final int tdCount = useItd ? (int) Math.round( maxDayCnt / minDuration ) : headerFormat.getLocationSize();
    354
    355                        // 3.7.0.1 (2005/01/31) E の colspan バグ対応で入れた最終行の 空タグを消す為の修正
    356                        out.append("<tbody><tr class=\"dummy\">").append( CR );
    357                        for( int i=0; i<tdCount; i++ ) {
    358//                              out.append( "<td/>" );
    359                                out.append( "<td></td>" );                              // 7.0.1.0 (2018/10/15)
    360                        }
    361                        out.append("</tr></tbody>").append( CR );
    362                }
    363
    364                if( footerFormat != null ) {
    365                        // 6.3.9.0 (2015/11/06) 引数にTableFormatterを渡して、処理の共有化を図る。
    366                        out.append( getTableFoot( footerFormat ) );
    367                }
    368
    369                out.append("</table>").append( CR )
    370                        .append( getScrollBarEndDiv() );        // 3.8.0.3 (2005/07/15)
    371
    372                return out.toString();
    373        }
    374
    375        /**
    376         * このビーに対する特別な初期化を行う。
    377         *
    378         * @og.rev 3.5.4.0 (2003/11/25) TableFormatter クラスを使用するように変更。
    379         * @og.rev 3.5.5.9 (2004/06/07) ヘッダーの日付け表示に、Locale を加味できるように変更
    380         * @og.rev 3.6.1.0 (2005/01/05) startDay,endDay,useSeqDay 属性追加
    381         */
    382        private void paramInit() {
    383
    384                final String strGroupCols       = getParam( ViewGanttTableParam.GROUP_COLUMNS_KEY       ,ViewGanttTableParam.GROUP_COLUMNS_VALUE        );
    385                final String strColDuration     = getParam( ViewGanttTableParam.DURATION_COLUMN_KEY     ,null                                   );
    386                final String strColDystart      = getParam( ViewGanttTableParam.DYSTART_COLUMN_KEY      ,ViewGanttTableParam.DYSTART_COLUMN_VALUE       );
    387                final String strMinDuration     = getParam( ViewGanttTableParam.MIN_DURATION_KEY        ,ViewGanttTableParam.MIN_DURATION_VALUE         );
    388
    389                formatDystart   = getParam( ViewGanttTableParam.DYSTART_FORMAT_KEY      ,ViewGanttTableParam.DYSTART_FORMAT_VALUE       );
    390                headerLocale    = getParam( ViewGanttTableParam.HEADER_LOCALE_KEY       ,ViewGanttTableParam.HEADER_LOCALE_VALUE        );
    391                startDay                = getParam( ViewGanttTableParam.START_DAY_KEY           ,null                                   );      // 3.6.1.0 (2005/01/05)
    392                endDay                  = getParam( ViewGanttTableParam.END_DAY_KEY                     ,null                                   );      // 3.6.1.0 (2005/01/05)
    393
    394                final String seqDay     = getParam( ViewGanttTableParam.USE_SEQ_DAY_KEY  ,ViewGanttTableParam.USE_SEQ_DAY_VALUE  );     // 3.6.1.0 (2005/01/05)
    395                useSeqDay       = Boolean.parseBoolean( seqDay );               // 6.1.0.0 (2014/12/26) refactoring
    396
    397                final DBTableModel table = getDBTableModel();
    398
    399                // 3.5.5.9 (2004/06/07) durationColumn を指定しない場合の処理を追加
    400                if( strColDuration != null ) {
    401                        posDuration = table.getColumnNo( strColDuration );
    402                }
    403
    404                posDystart  = table.getColumnNo( strColDystart );
    405
    406                final String[] groupKeys = StringUtil.csv2Array(strGroupCols);
    407                groupCols = new int[groupKeys.length];
    408                for( int nIndex=0; nIndex<groupCols.length ; nIndex++ ) {
    409                        groupCols[nIndex] = table.getColumnNo( groupKeys[nIndex] );
    410                }
    411
    412                minDuration = StringUtil.parseDouble( strMinDuration );
    413                if( minDuration <= 0.0d ) {
    414                        final String errMsg = "最小期間単位(minDuration)が、０ かそれ以下です。";
    415                        throw new HybsSystemException( errMsg );
    416                }
    417
    418                // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid declaring a variable if it is unreferenced before a possible exit point.
    419                final String strHeadDuration= getParam( ViewGanttTableParam.HEADER_DURATION_KEY ,strMinDuration                 );
    420                headerDuration = StringUtil.parseDouble( strHeadDuration );
    421                if( headerDuration <= 0.0d ) {
    422                        final String errMsg = "ヘッダーの表示期間(headerDuration)が、０ かそれ以下です。";
    423                        throw new HybsSystemException( errMsg );
    424                }
    425
    426                // 3.5.5.9 (2004/06/07) エラーチェックの強化
    427                // 4.0.0 (2005/01/31) Equality checks with floating point numbers can lead to unexpected behavior.
    428                if( posDuration < 0 && (
    429                                Double.compare( minDuration,1.0d ) != 0 ||
    430                                Double.compare( headerDuration,1.0d ) != 0 ) ) {
    431
    432                        final String errMsg = "期間カラム(durationColumn)を指定しない場合は、"
    433                                        + "最小期間単位(minDuration)および、"
    434                                        + "ヘッダーの表示期間(headerDuration)を '1' 以外に設定できません。";
    435                        throw new HybsSystemException( errMsg );
    436                }
    437        }
    438
    439        /**
    440         * 上下行のデータが同じグルプかどうかをチェックする。
    441         *
    442         * @param   nRowIndex テーブルモデルの行番号
    443         * @param   astrOldValues 古いグループデータ配列
    444         *
    445         * @return  使用可能(true)/ 使用不可能 (false)
    446         */
    447        private boolean isSameGroup(final int nRowIndex, final String[] astrOldValues) {
    448                boolean bRet = groupCols.length > 0 ;
    449                if( bRet ) {
    450                        for( int nIndex=0; bRet && nIndex<groupCols.length ; nIndex++ ) {
    451                                bRet = astrOldValues[nIndex].equals( getValue( nRowIndex, groupCols[nIndex] ) );
    452                        }
    453
    454                        // 不一致時に astrOldValues に 新しい値を設定しておきます。
    455                        if( !bRet ) {
    456                                for( int nIndex=0; nIndex<groupCols.length; nIndex++ ) {
    457                                        astrOldValues[nIndex] = getValue(nRowIndex, groupCols[nIndex]);
    458                                }
    459                        }
    460                }
    461
    462                return bRet;
    463        }
    464
    465        /**
    466         * DBTableModel から テーブルのタグ文字列を作成して返します。
    467         *
    468         * @og.rev 3.5.0.0 (2003/09/17) &lt;tr&gt;属性は、元のフォーマットのまま使用します。
    469         * @og.rev 3.5.1.0 (2003/10/03) Noカラムに、numberType 属性を追加
    470         * @og.rev 3.5.2.0 (2003/10/20) ヘッダー繰り返し部をgetHeadLine()へ移動
    471         * @og.rev 3.5.3.1 (2003/10/31) VERCHAR2 を VARCHAR2 に修正。
    472         * @og.rev 3.5.4.0 (2003/11/25) TableFormatter クラスを使用するように変更。
    473         * @og.rev 3.5.6.5 (2004/08/09) thead に、id="header" を追加
    474         * @og.rev 4.0.0.0 (2005/01/31) DBColumn の 属性(CLS_NM)から、DBTYPEに変更
    475         * @og.rev 6.2.0.0 (2015/02/27) フォーマット系の noDisplay 対応
    476         * @og.rev 5.9.1.2 (2015/10/23) 自己終了警告対応
    477         * @og.rev 6.4.4.1 (2016/03/18) NUMBER_DISPLAYを、static final 定数化します。
    478         * @og.rev 6.4.4.2 (2016/04/01) StringBuilderの代わりに、OgBuilderを使用する。
    479         * @og.rev 6.4.9.0 (2016/07/23) colgroupのHTML5対応(No欄)
    480         * @og.rev 6.4.9.1 (2016/08/05) colgroupのHTML5対応(No欄)時の対応ミス修正
    481         * @og.rev 6.8.1.0 (2017/07/14) HTML5対応ヘッダー出力設定時に、ブラウザを互換設定したときの対応。
    482         * @og.rev 6.8.2.0 (2017/10/13) makeNthChildの廃止と、makeCheckboxで、個別にclass指定するように変更。
    483         * @og.rev 7.0.4.0 (2019/05/31) colgroup 廃止
    484         *
    485         * @return      テーブルのタグ文字列
    486         * @og.rtnNotNull
    487         */
    488        @Override
    489        protected String getTableHead() {
    490                headerFormat.makeFormat( getDBTableModel() );
    491                // 6.2.0.0 (2015/02/27) フォーマット系の noDisplay 対応
    492                setFormatNoDisplay( headerFormat );
    493
    494                // 6.4.9.0 (2016/07/23) colgroupのHTML5対応(No欄)
    495                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
    496
    497//              // 7.0.4.0 (2019/05/31) colgroup 廃止
    498//              if( isNumberDisplay() ) {
    499//                      // 6.4.9.0 (2016/07/23) colgroupのHTML5対応(No欄)
    500//                              buf.append( NUMBER_DISPLAY );           // 6.8.1.0 (2017/07/14) HTML5ネイティブ時でも、出力します。
    501//                      // 6.8.1.0 (2017/07/14) HTML5対応ヘッダー出力設定時に、ブラウザを互換設定したときの対応。
    502//                      // 6.8.2.0 (2017/10/13) makeNthChildの廃止と、makeCheckboxで、個別にclass指定するように変更。
    503//      //              if( !useIE7Header ) {
    504//      //                      buf.append( "<style type=\"text/css\">" ).append( CR );
    505//      //                      makeNthChild( buf,2,"BIT" );
    506//      //                      makeNthChild( buf,3,"S9"  );
    507//      //                      buf.append( "</style>" ).append( CR );          // 6.4.9.1 (2016/08/05)
    508//      //              }
    509//              }
    510
    511                // 6.4.9.0 (2016/07/23) colgroupのHTML5対応(No欄)の関係で、修正します。
    512                return new OgBuilder()
    513                                        .appendIf( isNumberDisplay() , buf.toString() )
    514                                        .appendCR( "<thead id=\"header\">" )                            // 3.5.6.5 (2004/08/09)
    515                                        .append(   getHeadLine() )
    516                                        .appendCR( "</thead>" )
    517                                        .toString();
    518        }
    519
    520        /**
    521         * ヘッダー繰り返し部を、getTableHead()メソッドから分離。
    522         *
    523         * @og.rev 6.1.2.0 (2015/01/24) キャッシュを返すのを、#getHeadLine() に移動。
    524         *
    525         * @return      テーブルのタグ文字列
    526         * @og.rtnNotNull
    527         */
    528        @Override
    529        protected String getHeadLine() {
    530                if( headerLine == null ) {                                      // キャッシュになければ、設定する。
    531                        headerLine = getHeadLine( "<th" + headerFormat.getRowspan() ) ;
    532                }
    533
    534                return headerLine ;
    535        }
    536
    537        /**
    538         * ヘッダー繰り返し部を、getTableHead()メソッドから分離。
    539         *
    540         * @og.rev 3.5.2.0 (2003/10/20) 新規作成
    541         * @og.rev 3.5.4.0 (2003/11/25) TableFormatter クラスを使用するように変更。
    542         * @og.rev 3.5.4.3 (2004/01/05) useCheckControl 属性の機能を追加
    543         * @og.rev 3.5.4.6 (2004/01/30) numberType="none" 時の処理を追加(Noラベルを出さない)
    544         * @og.rev 3.5.4.7 (2004/02/06) ヘッダーにソート機能用のリンクを追加します。
    545         * @og.rev 3.5.5.0 (2004/03/12) systemFormat(例：[KEY.カラム名]形式等)の対応
    546         * @og.rev 3.7.0.1 (2005/01/31) 全件チェックコントロール処理変更
    547         * @og.rev 5.0.0.3 (2009/09/22) itdの有無を取得します。
    548         * @og.rev 6.1.2.0 (2015/01/24) キャッシュを返すのを、#getHeadLine() に移動。
    549         *
    550         * @param       thTag タグの文字列
    551         *
    552         * @return      テーブルのタグ文字列
    553         * @og.rtnNotNull
    554         */
    555        @Override
    556        protected String getHeadLine( final String thTag ) {
    557
    558                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE )
    559                        .append( headerFormat.getTrTag() ).append( CR );
    560
    561                // 3.5.5.0 (2004/03/12) No 欄そのものの作成判断追加
    562                if( isNumberDisplay() ) {
    563                        // 6.1.2.0 (2015/01/24) thTag に、headerFormat.getRowspan() を含ませて受け取る。
    564                        // 3.5.4.3 (2004/01/05) 追加分
    565                        if( isUseCheckControl() && "checkbox".equals( getSelectedType() ) ) {
    566                                buf.append( thTag ).append( "></th>" )
    567                                        .append( thTag ).append( '>' ).append( getAllCheckControl() ).append( "</th>" )         // 6.0.2.5 (2014/10/31) char を append する。
    568                                        .append( thTag ).append( '>' ).append( getNumberHeader()    ).append( "</th>" );        // 6.0.2.5 (2014/10/31) char を append する。
    569                        }
    570                        else {
    571                                buf.append( thTag ).append(" colspan=\"3\">").append( getNumberHeader() ).append( "</th>" );    // 6.0.2.5 (2014/10/31) char を append する。
    572                        }
    573                }
    574
    575                int cl = 0;
    576                for( ; cl<headerFormat.getLocationSize(); cl++ ) {
    577                        buf.append( headerFormat.getFormat(cl) );
    578                        final int loc = headerFormat.getLocation(cl);
    579                        if( loc >= 0 ) { buf.append( getSortedColumnLabel(loc) ); }
    580                }
    581                buf.append( headerFormat.getFormat(cl) ).append( CR );
    582
    583                // 5.0.0.3 (2009/09/22) ITD_MARKERの条件判断追加
    584                if( buf.indexOf( TableFormatter.HYBS_ITD_MARKER ) >= 0 ){
    585                        useItd = true;
    586                }
    587
    588                return StringUtil.replace( buf.toString(), TableFormatter.HYBS_ITD_MARKER, ganttHeadLine );
    589        }
    590
    591        /**
    592         * ガントチャートヘッダー繰り返し部を、getTableHead()メソッドから分離。
    593         * このメソッドは、durationColumn を利用して、連続日付けデータを作成します。
    594         * データは、開始日と期間データを持ち、ヘッダーは連続日付けになります。
    595         * ヘッダーの期間(headerDuration)とデータの最小期間(minDuration)が異なる為、
    596         * 最初の行データより、最終日を求め、headerDuration で割り算した個数の連続日数を
    597         * 表示させています。
    598         *
    599         * @og.rev 3.5.5.9 (2004/06/07) ヘッダーの日付け表示に、Locale を加味できるように変更
    600         * @og.rev 3.5.6.0 (2004/06/18) ithFormat 変数削除
    601         *
    602         * @param       startNo 開始行番号
    603         * @param       lastNo  最終行番号
    604         *
    605         * @return      テーブルのタグ文字列
    606         * @og.rtnNotNull
    607         */
    608        private String getGanttHead(final int startNo, final int lastNo) {
    609                String[] astrOldGroupKeys = new String[groupCols.length];
    610                for( int nIndex =0; nIndex<astrOldGroupKeys.length; nIndex++ ) {
    611                        astrOldGroupKeys[nIndex] = "";
    612                }
    613
    614                // 3.5.5.9 (2004/06/07) ヘッダーの日付け表示に、Locale を加味できるように変更
    615                final Locale local = new Locale( headerLocale );
    616                final SimpleDateFormat fmtDate = new SimpleDateFormat( formatDystart,local );
    617
    618                double nSumDuration = 0.0d ;
    619                Date dFirst = null ;
    620
    621                for( int nRowUp=startNo; nRowUp<lastNo; nRowUp++ ) {
    622                        // ガントでは、データのスキップは行いません。
    623
    624                        // 最初の行 または、ブレイクするまで
    625                        if( isSameGroup(nRowUp, astrOldGroupKeys) || nRowUp == startNo ) {
    626                                nSumDuration += StringUtil.parseDouble( getValue(nRowUp, posDuration) );
    627                                try {
    628                                        if( dFirst == null ) {
    629                                                dFirst = fmtDate.parse(getValue(nRowUp, posDystart));
    630                                        }
    631                                }
    632                                catch( final ParseException ex) {
    633                                        final String errMsg = "DYSTARTに指定した日付形式と異なるデータが存在しています。"
    634                                                        + "[" + getValue(nRowUp  , posDystart) + "] => ["
    635                                                        + fmtDate.toPattern() + "]" ;
    636                                        throw new HybsSystemException( errMsg,ex );
    637                                }
    638                        }
    639                        else { break; }
    640                }
    641
    642                String thVal    = ""     ;              // <td ･･･> の <td 以下の ･･･部分の属性文字列。
    643                String ymdForm  = "MM/dd" ;             // td タグの BODY 部 の 日付けフォーマット
    644
    645                if( headerFormat != null ) {
    646                        final String format = headerFormat.getItdBody().trim() ;
    647                        final Matcher matcher = TDTH_PTN.matcher(format);
    648                        if( matcher.find() ) {
    649                                thVal   = matcher.group(2);
    650                                ymdForm = matcher.group(3);
    651                        }
    652                }
    653
    654                try {
    655                        fmtDate.applyPattern(ymdForm);
    656                }
    657                catch( final IllegalArgumentException ex ) {
    658                        final String errMsg = "theadの内のitdの内側に指定された日付の形式が不正です。(" + ymdForm + ")";
    659                        throw new HybsSystemException( errMsg,ex );
    660                }
    661
    662                final int colspan = (int)Math.round( headerDuration / minDuration );
    663                final String th ;
    664                if( colspan == 1 ) { th = "<th " + thVal + ">"; }
    665                else { th = "<th colspan=\"" + colspan + "\" " + thVal + ">" ; }
    666
    667                final Calendar cal = Calendar.getInstance() ;
    668                cal.setTime( dFirst );
    669
    670                maxDayCnt = (int)Math.round(nSumDuration / headerDuration) ;            // 3.5.5.9 (2004/06/07)
    671                int addDate ;
    672                int field   ;
    673                if( headerDuration >= 1.0d ) {
    674                        addDate = (int)Math.round( headerDuration );
    675                        field   = Calendar.DATE ;
    676                }
    677                else {
    678                        addDate = (int)Math.round( 24.0d * headerDuration );
    679                        field   = Calendar.HOUR_OF_DAY ;
    680                }
    681
    682                // 端数を指定すると、積算誤差がでます。
    683                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
    684
    685                for( int nIndex=0; nIndex<maxDayCnt; nIndex++ ) {
    686                        buf.append( th )
    687                                .append( fmtDate.format( cal.getTime() ) )
    688                                .append( "</th>" );
    689                        cal.add( field ,addDate );
    690                }
    691
    692                return buf.toString();
    693        }
    694
    695        /**
    696         * ガントチャートヘッダー繰り返し部を、getTableHead()メソッドから分離。
    697         * このメソッドは、durationColumn が指定されていない場合の処理を行います。
    698         * データは、すべての行に関して、同じ日付けのデータとして扱われます。
    699         * よって、行間で、日付け違いの並び順になっているとずれることがあります。
    700         * ヘッダーは、最初の行の日付けをそのまま表示させます。よって、データと
    701         * 日付けが同期されていれば、不連続な日付けのヘッダーを表示させることも可能です。
    702         * ヘッダーの期間(headerDuration)とデータの最小期間(minDuration)は、
    703         * ともに、'1' であることが前提です。
    704         * useSeqDay 属性に、"true" を設定すると、開始日(startDay)と終了日(endDay)
    705         * の日付けを連続した日付けとします。開始日(startDay)や終了日(endDay)が指定
    706         * されていない場合は、dystartColumn 属性で指定されたカラムの値の最大値、最小値を
    707         * 自動セットします。
    708         *
    709         * @og.rev 3.5.5.9 (2004/06/07) 新規作成
    710         * @og.rev 3.5.6.0 (2004/06/18) ithFormat 変数削除
    711         * @og.rev 3.6.1.0 (2005/01/05) startDay,endDay,useSeqDay 属性追加
    712         *
    713         * @param       startNo 開始行番号
    714         * @param       lastNo  最終行番号
    715         *
    716         * @return      テーブルのタグ文字列
    717         * @og.rtnNotNull
    718         */
    719        private String getGanttHeadNoDuration(final int startNo, final int lastNo) {
    720                String[] astrOldGroupKeys = new String[groupCols.length];
    721                for( int nIndex=0; nIndex<astrOldGroupKeys.length; nIndex++ ) {
    722                        astrOldGroupKeys[nIndex] = "";
    723                }
    724
    725                String thVal    = ""     ;              // <td ･･･> の <td 以下の ･･･部分の属性文字列。
    726                String ymdForm  = "MM/dd" ;             // td タグの BODY 部 の 日付けフォーマット
    727
    728                if( headerFormat != null ) {
    729                        final String format = headerFormat.getItdBody().trim() ;
    730                        final Matcher matcher = TDTH_PTN.matcher(format);
    731                        if( matcher.find() ) {
    732                                thVal   = matcher.group(2);
    733                                ymdForm = matcher.group(3);
    734                        }
    735                }
    736
    737                // 3.5.5.9 (2004/06/07) ヘッダーの日付け表示に、Locale を加味できるように変更
    738                final Locale local = new Locale( headerLocale );
    739                final SimpleDateFormat dataFmt = new SimpleDateFormat( formatDystart,local );
    740
    741                final TreeSet<String> daySet = new TreeSet<>();
    742                for( int nRowUp=startNo; nRowUp<lastNo; nRowUp++ ) {
    743                        // ガントでは、データのスキップは行いません。
    744
    745                        final String day = getValue(nRowUp, posDystart);
    746                        daySet.add( day );
    747                }
    748                // 3.6.1.0 (2005/01/05)
    749                if( useSeqDay ) {
    750                        if( startDay == null ) { startDay = daySet.first() ; }
    751                        if( endDay   == null ) { endDay   = daySet.last()  ; }
    752
    753                        try {
    754                                final Calendar startCal = Calendar.getInstance() ;
    755                                final Date dStart = dataFmt.parse( startDay );
    756                                startCal.setTime( dStart );
    757
    758                                final Calendar endCal = Calendar.getInstance() ;
    759                                final Date dEnd = dataFmt.parse( endDay );
    760                                endCal.setTime( dEnd );
    761                                endCal.set( Calendar.HOUR_OF_DAY,12 );  // 日付け比較する為、１２時間進めておく。
    762
    763                                while( startCal.before( endCal ) ) {
    764                                        daySet.add( dataFmt.format( startCal.getTime() ) );
    765                                        startCal.add( Calendar.DATE ,1 );
    766                                }
    767                        }
    768                        catch( final ParseException ex) {
    769                                final String errMsg = "startDay,endDayに指定した日付形式と異なるデータが存在しています。"
    770                                                + "[" + startDay + "],["
    771                                                + "[" + endDay + "] => ["
    772                                                + dataFmt.toPattern() + "]" ;
    773                                throw new HybsSystemException( errMsg,ex );
    774                        }
    775                }
    776
    777                headDays = daySet.toArray( new String[daySet.size()] ); // 4.0.0 (2005/01/31)
    778
    779                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
    780                final String th = "<th " + thVal + ">";                                 // 6.1.0.0 (2014/12/26) ソースの統一のため、一旦
    781                // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid declaring a variable if it is unreferenced before a possible exit point.
    782                final SimpleDateFormat headFmt = new SimpleDateFormat( ymdForm,Locale.JAPAN );
    783                final Calendar cal = Calendar.getInstance() ;
    784                // 7.2.9.4 (2020/11/20) PMD:This for loop can be replaced by a foreach loop
    785                for( final String hDay : headDays ) {
    786//              for( int i=0; i<headDays.length; i++ ) {
    787                        try {
    788//                              cal.setTime( dataFmt.parse(headDays[i]) );
    789                                cal.setTime( dataFmt.parse(hDay) );
    790                                buf.append( th )
    791                                        .append( headFmt.format( cal.getTime() ) )
    792                                        .append( "</th>" );
    793                        }
    794                        catch( final ParseException ex) {
    795                                final String errMsg = "DYSTARTに指定した日付形式と異なるデータが存在しています。"
    796//                                              + "[" + headDays[i] + "] => ["
    797                                                + "[" + hDay + "] => ["
    798                                                + dataFmt.toPattern() + "]" ;
    799                                throw new HybsSystemException( errMsg,ex );
    800                        }
    801                }
    802
    803                return buf.toString();
    804        }
    805
    806        /**
    807         * itaタグの中身を形式化する。
    808         *
    809         * @og.rev 3.5.5.0 (2004/03/12) systemFormat(例：[KEY.カラム名]形式等)の対応
    810         * @og.rev 3.5.5.9 (2004/06/07) durationColumn を指定しない場合の処理を追加
    811         * @og.rev 3.5.6.0 (2004/06/18) itdタグの[$xx] , [#xx]対応
    812         * @og.rev 3.5.6.0 (2004/06/18) '!' 値のみ 追加 既存の '$' は、レンデラー
    813         * @og.rev 6.3.9.1 (2015/11/27) 修飾子を、なし → private に変更。
    814         * @og.rev 6.4.4.2 (2016/04/01) TableFormatterのタイプ別値取得処理の共通部をまとめる。
    815         *
    816         * @param   nTblRow             テーブルモデルの行番号
    817         * @param   myIteFormat TableFormatteオブジェクト
    818         * @param   strBuf              出力データバーファ(not null , 同じオブジェクトを return する)
    819         *
    820         */
    821        private void formatItd( final int nTblRow, final TableFormatter myIteFormat, final StringBuilder strBuf ) {
    822                if( myIteFormat == null ) { strBuf.setLength(0); }
    823
    824                // 6.3.9.1 (2015/11/27) Found 'DD'-anomaly for variable(PMD)
    825                final int colspan ;
    826                if( posDuration >= 0 ) {
    827                        // 3.7.0.0 (2005/01/18) 小数点の桁落ち対策
    828                        colspan = (int)Math.round( StringUtil.parseDouble( getValue(nTblRow, posDuration) ) / minDuration );
    829                }
    830                else {  // 日付けヘッダー未満は、空タグを出力しておく
    831                        final String today = getValue(nTblRow, posDystart);
    832                        int comp = headDays[headDaysCnt].compareTo( today );
    833                        headDaysCnt++ ;
    834                        while( comp < 0 && headDaysCnt < headDays.length ) {
    835                                strBuf.append( "<td></td>" );
    836                                comp = headDays[headDaysCnt].compareTo( today );
    837                                headDaysCnt++ ;
    838                        }
    839                        if( comp != 0 ) {       // 見つからなかった(先に日付けが無くなった)
    840                                final String errMsg = "日付けヘッダーと日付けデータに矛盾が発生しています。"
    841                                                + CR
    842                                                + "groupColumns で日付けがユニークになっていない可能性があります。"
    843                                                + "row=[" + (nTblRow +1) + "] , today=[" + today + "]" ;
    844                                throw new HybsSystemException( errMsg );
    845                        }
    846                        colspan = 1;            // 6.3.9.1 (2015/11/27)
    847                }
    848
    849                int cl = 0;
    850                for( ; cl<myIteFormat.getLocationSize(); cl++ ) {
    851                        String fmt = myIteFormat.getFormat(cl) ;
    852                        final int loc = myIteFormat.getLocation(cl);    // 3.5.6.0
    853                        if( cl == 0 && colspan != 1 ) {
    854                                fmt = StringUtil.replace( fmt , "<td", "<td colspan=\"" + colspan + "\"" );
    855                        }
    856                        strBuf.append( fmt );                   // 3.5.6.0
    857                        if( loc >= 0 ) {
    858                                // 6.4.4.2 (2016/04/01) 処理の共通部をまとめる。
    859                                strBuf.append( getTypeCaseValue( myIteFormat.getType(cl),nTblRow,loc ) );
    860                        }
    861                        else {
    862                                strBuf.append( myIteFormat.getSystemFormat(nTblRow,loc) );
    863                        }
    864                }
    865                strBuf.append( myIteFormat.getFormat(cl) );
    866        }
    867
    868        /**
    869         * フォーマットを設定します。
    870         *
    871         * @og.rev 3.5.4.0 (2003/11/25) 新規作成
    872         * @og.rev 3.5.4.4 (2004/01/16) 配列の最大数を変更
    873         * @og.rev 3.5.6.0 (2004/06/18) ithFormat ,  itdFormat 変数削除
    874         *
    875         * @param       list    TableFormatterのリスト
    876         */
    877        @Override
    878        public void setFormatterList( final List<TableFormatter> list ) {               // 4.3.3.6 (2008/11/15) Generics警告対応
    879                bodyFormats = new TableFormatter[BODYFORMAT_MAX_COUNT];
    880
    881                bodyFormatsCount = 0;
    882                // 7.2.9.4 (2020/11/20) PMD:This for loop can be replaced by a foreach loop
    883                for( final TableFormatter format : list ) {
    884//              for( int i=0; i<list.size(); i++ ) {
    885//                      final TableFormatter format = list.get( i );            // 4.3.3.6 (2008/11/15) Generics警告対応
    886
    887                        switch( format.getFormatType() ) {
    888                                case TYPE_HEAD : headerFormat = format; break;
    889                                case TYPE_BODY : bodyFormats[bodyFormatsCount++] = format; break;
    890                                case TYPE_FOOT : footerFormat = format; break;
    891                                default : final String errMsg = "FormatterType の定義外の値が指定されました。";
    892                                // 4.3.4.4 (2009/01/01)
    893                                                  throw new HybsSystemException( errMsg );
    894                        }
    895                        // 3.5.6.0 (2004/06/18) 廃止
    896                }
    897
    898                // 3.5.6.0 (2004/06/18) itdFormats 処理追加
    899                // tbody 配列分だけ設定しておきます。
    900                itdFormats = new TableFormatter[bodyFormatsCount];
    901                for( int i=0; i<bodyFormatsCount; i++ ) {
    902                        final String format = bodyFormats[i].getItdBody().trim();
    903                        itdFormats[i] = new TableFormatter();
    904                        itdFormats[i].setFormat( format );
    905                }
    906        }
    907
    908        /**
    909         * フォーマットメソッドを使用できるかどうかを問い合わせます。
    910         *
    911         * @return  使用可能(true)/ 使用不可能 (false)
    912         */
    913        @Override
    914        public boolean canUseFormat() {
    915                return true;
    916        }
    917
    918        /**
    919         * 表示項目の編集(並び替え)が可能かどうかを返します。
    920         *
    921         * @og.rev 5.1.6.0 (2010/05/01) 新規追加
    922         *
    923         * @return      表示項目の編集(並び替え)が可能かどうか(false:不可能)
    924         */
    925        @Override
    926        public boolean isEditable() {
    927                return false;
    928        }
    929}