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