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.hayabusa.db.DBTableModel;
021    import org.opengion.fukurou.util.StringUtil;
022    import org.opengion.hayabusa.html.TableFormatter;
023    import org.opengion.hayabusa.html.ViewStackTableParam;
024    
025    import java.util.Calendar;
026    import java.util.Date;
027    import java.util.List;
028    
029    /**
030     * 積上ガント表示専用のViewFormです?
031     * stackParamTagを利用する事でスタ?ガント用の行を出力する事が可能です?
032     * stackParamTagによりstackColumnsが指定された場合?、そのカラ?にブレークして?
033     * stacklink属?により積上げ行?判別が可能なtbody行を出力します?
034     * そ?際?stackColumnsで?されたカラ?外?[xxx]は処?れません?空白として出力?
035     * [xxx]以外で書かれた?、例えば<iGantBar>タグの本体部??出力されます?
036     * 
037     * ヘッ??表示にはstackHeaderタグを利用します?
038     * 
039     * [エンジン?積上げを行わな???
040     * 積上?表示はJavaScriptによってiGantBarタグの?に作?されます?
041     * 積上げそ?も?もiGantBarによって出力されるガントを利用してJavaScriptで行って?ため?
042     * ?検索行数と表示行数に注意して下さ??
043     * 
044     * [エンジン?積上げを行う場?
045     * 工数積上げをエンジン?で行いdivタグとして出力します?
046     * そ?後?描画?位置調整?等)?JavaScriptで行います?
047     * ガント部??出力されません?
048     * スタ?部??body部???尾に新たにtd作?するため、注意してください?
049     * paramタグでの?で、costColumnが??です?
050     * 
051     * 
052     * AbstractViewForm により、setter/getterメソ?の?ォルト実?提供して?す?
053     * 各HTMLのタグに?な setter/getterメソ?のみ?追?義して?す?
054     *
055     * AbstractViewForm を継承して?為,ロケールに応じたラベルを?力させる事が出来ます?
056     * 
057     * @og.rev 5.5.7.0 (2012/10/01) 新規作?
058     * @og.rev 5.5.8.3 (2012/11/17) ?積上げ対?
059     * @og.rev 5.6.1.2 (2013/02/22) キャパシ?対?
060     * @og.group 画面表示
061     *
062     * @version  5.0
063     * @author       Takahashi Masakazu
064     * @since    JDK5.0,
065     */
066    public class ViewForm_HTMLStackedGanttTable extends ViewForm_HTMLTable  {
067            //* こ?プログラ??VERSION??を設定します?       {@value} */
068            private static final String VERSION = "5.6.2.1 (2013/06/13)" ;
069    
070            /** ヘッ??フォーマット変数 */
071            protected TableFormatter                headerFormat    = null;
072            /** ボディーフォーマット?列変数 */
073            protected TableFormatter[]              bodyFormats             = null;
074            /** フッターフォーマット変数 */
075            protected TableFormatter                footerFormat    = null;
076            /** ボディーフォーマット数 */
077            protected int                                   bodyFormatsCount = 0;
078    
079            /** ボディーフォーマット最大数 初期値:{@value} */
080            protected static final int BODYFORMAT_MAX_COUNT = 10;
081            // stack行?判定?力用
082            protected static final String STACK_TBODY = " stackline='true'";
083            protected static final String GANTT_TBODY = " stackline='false'";
084            protected static final String STACK_ID_PREFIX     = " id='stack_";
085            protected static final String STACK_ROW_PREFIX = " stackrow='";
086    
087            // stack,gantt用
088            private int[]  stackCols                        = null;
089    //      private int[]  groupCols                        = null;
090            
091            // 5.5.8.3 (2012/11/17)
092            private int[]   costCols                = null; // 工数カラ??開始日カラ??終?カラ?
093            private boolean innerStack = Boolean.parseBoolean( ViewStackTableParam.INNER_STACK_VALUE );
094            private boolean stackHoliday = Boolean.parseBoolean( ViewStackTableParam.STACK_HOLIDAY_KEY );
095            String[][] calArray     = null;                                 // headで作?されたカレン????タ
096            int capCol = -1;                // 5.6.1.2 (2013/02/22) 能力?カラ?
097    
098            /**
099             * DBTableModel から HTML??を作?して返します?
100             * startNo(表示開始位置)から、pageSize(表示件数)までのView??を作?します?
101             * 表示残り??タ?pageSize 以下?場合?,残りの??タをすべて出力します?
102             *
103             *
104             * @og.rev 5.5.8.3 (2012/11/17) ?積上げ対?
105             * @og.rev 5.6.1.2 (2013/02/22) キャパシ?対?
106             * @og.rev 5.6.2.1 (2013/06/13) 積上不?合修正
107             *
108             * @param  sttNo          表示開始位置
109             * @param  pgSize   表示件数
110             *
111             * @return      DBTableModelから作?され?HTML??
112             */
113            @Override
114            public String create( final int sttNo, final int pgSize )  {
115                    // ガント?、キーブレイクがあるため?全件表示します?
116                    int startNo  = 0;
117                    int pageSize = getRowCount() ;
118                    if( pageSize == 0 ) { return ""; }      // 暫定?置
119    
120                    // 4.3.1.0 (2008/09/08)
121                    if( headerFormat == null ) {
122                            String errMsg = "ViewTagで canUseFormat() = true の場合?Formatter は??です?";
123                            throw new HybsSystemException( errMsg );
124                    }
125    
126                    headerLine       = null;                // 3.5.3.1 (2003/10/31) キャ?ュクリア
127    
128                    int lastNo = getLastNo( startNo, pageSize );
129                    int blc = getBackLinkCount();
130                    int hsc = getHeaderSkipCount();         
131                    int hscCnt = 1;                                 
132                    
133                    // こ?ビューの特有な属?を?期化
134                    paramInit();
135    
136                    StringBuilder out = new StringBuilder( HybsSystem.BUFFER_LARGE );
137    
138                    headerFormat.makeFormat( getDBTableModel() );   // 3.5.6.2 (2004/07/05) 移?
139    
140                    out.append( getCountForm( startNo,pageSize ) );
141                    out.append( getHeader() );
142    
143                    if( bodyFormatsCount == 0 ) {
144                            bodyFormats[0] = headerFormat ;
145                            bodyFormatsCount ++ ;
146                    }
147                    else {
148                            for( int i=0; i<bodyFormatsCount; i++ ) {
149                                    bodyFormats[i].makeFormat( getDBTableModel() );
150                            }
151                    }
152    
153    //              String[] astrOldGroupKeys = new String[groupCols.length];
154                    String[] astrOldStackKeys = new String[stackCols.length];
155    //              for( int nIndex =0; nIndex < astrOldGroupKeys.length; nIndex++) {
156    //                      astrOldGroupKeys[nIndex] = "";
157    //              }
158                    for( int nIndex =0; nIndex < astrOldStackKeys.length; nIndex++) {
159                            astrOldStackKeys[nIndex] = "";
160                    }
161                    
162                    int bgClrCnt = 0;
163                    int stackRow = 0;
164                    
165                    // 5.5.8.3 (2012/11/17)
166                    double[] costAry = null;
167                    Calendar firstCalday = null;
168                    Calendar fstCalEnd = null;
169                    String calZoom = null;
170                    String capacity = null; // 5.6.1.2 (2013/02/22)
171                    if( innerStack ){
172                            costAry = new double[calArray.length];
173                            String[] firstCal = calArray[0];
174                                    firstCalday = HybsSystem.getCalendar(firstCal[0]);
175                                    fstCalEnd   = HybsSystem.getCalendar(firstCal[2]);
176    
177                            if( differenceDays(firstCalday.getTime(),fstCalEnd.getTime()) == 1 ){
178                                    calZoom = ViewStackTableParam.STACK_ZOOM_DAY;
179                            }
180                            else if( differenceDays(firstCalday.getTime(),fstCalEnd.getTime()) == 7 ){
181                                    calZoom = ViewStackTableParam.STACK_ZOOM_WEEK;
182                            }
183                            else{
184                                    calZoom = ViewStackTableParam.STACK_ZOOM_MONTH;
185                            }
186                    }
187                    
188                    for( int row=startNo; row<lastNo; row++ ) {
189                            // ??タのスキ??は行わな?
190                            
191                            // ガント?ブレイク
192                    //      if(! isSameGroup(row, astrOldGroupKeys)) {
193                                    if( (!isSameStack(row, astrOldStackKeys) && stackCols.length > 0) ) { // 積上?ブレイク
194                                            if( !(innerStack && row == startNo) ) { // 5.5.8.3 (2012/11/17) ?積上げは後から積上げる?で、?回?出力しな?
195                                                    stackRow = row;
196                                            
197    //                                              out.append(makeBodyTable(innerStack ? row -1 : row, stackRow, bgClrCnt, blc, costAry));
198                                                    out.append(makeBodyTable(innerStack ? row -1 : row, stackRow, bgClrCnt, blc, costAry, capacity)); // 5.6.1.2 (2013/02/22)
199                                                    
200                                                    if( innerStack ){
201                                                            costAry = new double[calArray.length];
202                                                    }
203                                            }
204                                    }
205                                    if( !innerStack ){// 5.5.8.3 (2012/11/17) ?積上げの場合?ガント部??出力せずに積上げ?する?
206                                            for( int i=0; i<bodyFormatsCount; i++ ) {
207                                                    TableFormatter bodyFormat = bodyFormats[i];
208                                                    if( ! bodyFormat.isUse( row,getDBTableModel() ) ) { continue; }         // 3.5.4.0 (2003/11/25)
209                                                    out.append("<tbody").append( getBgColorCycleClass( bgClrCnt++,row ) );
210                                                    if( isNoTransition() ) { // 4.3.3.0 (2008/10/01)
211                                                            out.append( getHiddenRowValue( row ) );
212                                                    }
213                                                    out.append( GANTT_TBODY );
214                                                    out.append( STACK_ROW_PREFIX ).append( stackRow ).append("'");
215                                                    out.append(">");     // 3.7.0.3 (2005/03/01)
216                                                    out.append( bodyFormat.getTrTag() );
217                    
218                                                    // 3.5.5.0 (2004/03/12) No ?のも?の作?判断追?
219                                                    if( isNumberDisplay() ) {
220                                                            String ckboxTD = "<td" + bodyFormat.getRowspan() + ">";
221                                                            out.append( makeCheckbox( ckboxTD,row,blc ) );
222                                                    }
223                    
224                                                    int cl = 0;
225                                                    for( ; cl < bodyFormat.getLocationSize(); cl++ ) {
226                                                            String fmt = bodyFormat.getFormat(cl);
227                                                            int loc = bodyFormat.getLocation(cl);   // 3.5.5.0
228                                                            if( ! bodyFormat.isNoClass() && loc >= 0 ) { // 3.5.5.7 (2004/05/10)
229                                                                    StringBuilder newtg = new StringBuilder( HybsSystem.BUFFER_LARGE );
230                                                                    newtg.append("<td class=\"");
231                                                                    newtg.append( getColumnDbType(loc) );   // 4.0.0 (2005/01/31)
232                                                                    newtg.append("\" ");
233                                                                    String tdclass = newtg.toString();
234                                                                    fmt = StringUtil.replace( bodyFormat.getFormat(cl) ,"<td", tdclass );
235                                                            }
236                                                            out.append( fmt );                      // 3.5.0.0
237                                                            // 3.5.5.7 (2004/05/10) #,$ 対?
238                                                            if( loc >= 0 ) {
239                                                                    switch( bodyFormat.getType(cl) ) {
240                                                                            case '#' : out.append( getColumnLabel(loc) );           break;
241                                                                            case '$' : out.append( getRendererValue(row,loc) );     break;
242                                                                            case '!' : out.append( getValue(row,loc) );                     break;
243                                                                            default  : out.append( getValueLabel(row,loc) );        break;
244                                                                    }
245                                                            }
246                                                            else {
247                                                                    out.append( bodyFormat.getSystemFormat(row,loc) );
248                                                            }
249                                                    }
250                                                    out.append( bodyFormat.getFormat(cl) );
251                                                    out.append("</tbody>").append( HybsSystem.CR );
252                                            }
253                                    }
254                                    else{ // ?積上げをする??5.5.8.3 (2012/11/17)
255                                            double costDbl = Double.parseDouble( getValue(row,costCols[0]) ); //工数
256                                            Calendar startDay = HybsSystem.getCalendar(getValue(row,costCols[1]));
257                                            Calendar endDay   = HybsSystem.getCalendar(getValue(row,costCols[2]));
258                                            
259                                            Date startDayDate = startDay.getTime();
260                                            Date endDayDate = endDay.getTime();
261                                            
262                                            // 5.6.1.2 (2013/02/22)
263                                            if( capCol > -1 ){
264                                                    capacity = getValue(row,capCol);
265                                            }
266                                            else{
267                                                    capacity = "1";
268                                            }
269                                            
270                                            // ??そ?ままで計?
271                                            int fromCell = calNumber(startDayDate,calZoom,firstCalday.getTime());
272                                            int toCell   = calNumber(endDayDate,calZoom,firstCalday.getTime());     
273                                            
274                                            endDay.add(Calendar.DATE, 1); // 終?は?に入る?で?つ進める
275                                            endDayDate = endDay.getTime();
276                                            
277                                            int stackMother = differenceDays(startDayDate,endDayDate);
278                                            if( !stackHoliday ){
279                                                    for(int cel = fromCell; cel <= toCell; cel++ ){
280                                                            if ("1".equals( calArray[cel][1] ) ){
281                                                                    stackMother--;
282                                                            }
283                                                    }
284                                            }
285                                            
286                                            Date calFrom;
287                                            Date calTo;
288                                            int cellDays = 1;
289     
290                                            for(int cel = fromCell; cel <= toCell; cel++ ){
291                                                    calFrom = (HybsSystem.getCalendar(calArray[cel][0])).getTime();
292                                                    calTo  = (HybsSystem.getCalendar(calArray[cel][2])).getTime();
293                                                    if( calFrom.compareTo( startDayDate ) < 0 ){
294                                                            calFrom = startDayDate;
295                                                    }
296                                                    if( endDayDate.compareTo( calTo ) < 0 ){
297                                                            calTo = endDayDate;
298                                                    }
299                                                    cellDays = differenceDays( calFrom, calTo );
300                                                    if( stackHoliday ){
301                                                            costAry[cel] += (costDbl / stackMother) * cellDays;
302                                                    }
303                                                    else{
304                                                            // 休日のみの場合?積上げられな??
305                                                            if (!"1".equals( calArray[cel][1] ) ){
306                                                                    costAry[cel] += (costDbl / stackMother) * cellDays;
307                                                            }
308                                                    }
309                                            }
310                                    }
311                            }
312                                    
313                    
314                    // 3.5.2.0 (2003/10/20) ヘッ??繰り返し属?( headerSkipCount )を採用
315                            if( hsc > 0 && hscCnt % hsc == 0 ) {
316                                    out.append("<tbody class=\"row_h\"").append(" >");
317                                    out.append( getHeadLine() );
318                                    out.append("</tbody>");
319                                    hscCnt = 1;
320                            }
321                            else {
322                                    hscCnt ++ ;
323                            }
324            //      } // 5.6.5.2 (2013/06/21) 括弧の位置間違??ため修正
325                    
326                    // ?積上げ時??行?出力を行う
327                    if( innerStack ){
328    //                      out.append(makeBodyTable(lastNo-1, stackRow, bgClrCnt, blc, costAry));
329                            out.append(makeBodyTable(lastNo-1, stackRow, bgClrCnt, blc, costAry, capacity)); // 5.6.1.2 (2013/02/22)
330                    }
331    
332                    if( footerFormat != null ) {
333                            out.append( getTableFoot() );
334                    }
335    
336    //              out.append("</tbody>").append( HybsSystem.CR ); // 4.3.7.4 (2009/07/01)
337                    out.append("</table>").append( HybsSystem.CR );
338    
339                    out.append( getScrollBarEndDiv() );     // 3.8.0.3 (2005/07/15)
340                    return out.toString();
341            }
342    
343            /**
344             * ?をクリア(初期?します?
345             *
346             * @og.rev 5.5.8.3 (2012/11/17) ?積上げのための修正
347             * @og.rev 5.6.1.2 (2013/02/22) キャパシ?対?
348             *
349             */
350            @Override
351            public void clear() {
352                    super.clear();
353                    headerFormat                    = null;
354                    bodyFormats                             = null;
355                    footerFormat                    = null;
356                    bodyFormatsCount                = 0;
357                    stackCols               = null; // 5.5.8.3 (2012/11/17)
358                    costCols                = null; // 5.5.8.3 (2012/11/17)
359                    innerStack              = Boolean.parseBoolean( ViewStackTableParam.INNER_STACK_VALUE ); // 5.5.8.3 (2012/11/17)
360                    calArray                = null; // 5.5.8.3 (2012/11/17)
361                    stackHoliday = Boolean.parseBoolean( ViewStackTableParam.STACK_HOLIDAY_KEY ); // 5.5.8.3 (2012/11/17)
362                    capCol                  = -1; // 5.6.1.2 (2013/02/22)
363            }
364            
365            /**
366             * こ?ビューに対する特別な初期化を行う?
367             *
368             * @og.rev 5.5.8.3 (2012/11/17)
369             * @og.rev 5.5.9.0 (2012/12/03) objectではなくArrayList?
370             * @og.rev 5.6.1.2 (2013/02/22) キャパシ?対?
371             * @og.rev 5.6.2.1 (2013/03/08) stackHolidayが抜けて?ので追?
372             */
373            private void paramInit() {
374    
375    //              String strGroupCols             = getParam( ViewStackTableParam.GROUP_COLUMNS_KEY       ,ViewStackTableParam.GROUP_COLUMNS_VALUE        );
376                    String strStackCols             = getParam( ViewStackTableParam.STACK_COLUMNS_KEY       ,ViewStackTableParam.STACK_COLUMNS_VALUE        );
377                    String costCol                  = getParam( ViewStackTableParam.COST_COLUMNS_KEY,       ViewStackTableParam.COST_COLUMNS_VALUE  ); // 5.5.8.3 (2012/11/17)
378                    innerStack                              = getBoolParam( ViewStackTableParam.INNER_STACK_KEY     ); // 5.5.8.3 (2012/11/17)
379                    String capColName               = getParam( ViewStackTableParam.CAP_COLUMN_KEY, ViewStackTableParam.CAP_COLUMN_VALUE    ); // 5.6.1.2 (2013/02/22)
380                    stackHoliday                            = getBoolParam( ViewStackTableParam.STACK_HOLIDAY_KEY   ); // 5.6.2.1 (2013/03/08)
381                    
382                    if( innerStack ){
383    //                      calArray = (String[][])getViewObject( ViewStackTableParam.STACK_CAL_KEY );
384                            calArray = getViewArrayList().toArray(new String[][]{}); // 5.5.9.0 (2012/12/03)
385                            if( calArray == null || costCol == null){
386                                    String errMsg = "ヘッ??カレン?ータ、costColumnsの設定???です?"+costCol;
387                                    throw new HybsSystemException( errMsg );
388                            }
389                    }
390                    
391                    DBTableModel table = getDBTableModel();
392    
393    //              String[] groupKeys = StringUtil.csv2Array(strGroupCols);
394    //              groupCols = new int[groupKeys.length];
395    //              for( int nIndex = 0; nIndex < groupCols.length ; nIndex++) {
396    //                      groupCols[nIndex] = table.getColumnNo( groupKeys[nIndex] );
397    //              }
398                    
399                    String[] stackKeys = StringUtil.csv2Array(strStackCols);
400                    stackCols = new int[stackKeys.length];
401                    for( int nIndex = 0; nIndex < stackCols.length ; nIndex++) {
402                            stackCols[nIndex] = table.getColumnNo( stackKeys[nIndex] );
403                    }
404                    
405                    String[] costKeys = StringUtil.csv2Array(costCol);
406                    costCols = new int[costKeys.length];
407                    for( int nIndex = 0; nIndex < costCols.length ; nIndex++) {
408                            costCols[nIndex] = table.getColumnNo( costKeys[nIndex] );
409                    }
410                    
411                    // 5.6.1.2 (2013/02/22) キャパシ?
412                    if( capColName != null && capColName.length() > 0 ){
413                            capCol = table.getColumnNo(capColName);
414                    }
415            }
416    
417            /**
418             * DBTableModel から ??ブルのタグ??を作?して返します?
419             *
420             *
421             * @return      ??ブルのタグ??
422             */
423            @Override
424            protected String getTableHead() {
425    
426                    StringBuilder buf = new StringBuilder( HybsSystem.BUFFER_MIDDLE );
427                    // 3.5.5.0 (2004/03/12) No ?のも?の作?判断追?
428                    if( isNumberDisplay() ) {
429                            buf.append("<colgroup class=\"X\" />");                   // 4.0.0 (2005/01/31)
430                            buf.append("<colgroup class=\"BIT\" />");
431                            buf.append("<colgroup class=\"S9\" />");                  // 4.0.0 (2005/01/31)
432                            buf.append(HybsSystem.CR);
433                    }
434    
435            // 3.5.2.0 (2003/10/20) ヘッ??繰り返し部をgetHeadLine()へ移?
436                    buf.append("<thead id=\"header\">").append( HybsSystem.CR );      // 3.5.6.5 (2004/08/09)
437                    buf.append( getHeadLine() );
438                    buf.append("</thead>").append( HybsSystem.CR );
439    
440                    return buf.toString();
441            }
442    
443            /**
444             * ヘッ??繰り返し部を?getTableHead()メソ?から??
445             *
446             *
447             * @return      ??ブルのタグ??
448             */
449            @Override
450            protected String getHeadLine() {
451                    return getHeadLine( "<th" ) ;
452            }
453    
454            /**
455             * ヘッ??繰り返し部を?getTableHead()メソ?から??
456             *
457             *
458             * @param       thTag タグの??
459             *
460             * @return      ??ブルのタグ??
461             */
462            @Override
463            protected String getHeadLine( final String thTag ) {
464                    if( headerLine != null ) { return headerLine; }         // キャ?ュを返す?
465    
466                    StringBuilder buf = new StringBuilder( HybsSystem.BUFFER_MIDDLE );
467    
468                    buf.append( headerFormat.getTrTag() ).append( HybsSystem.CR );
469    
470                    // 3.5.5.0 (2004/03/12) No ?のも?の作?判断追?
471                    if( isNumberDisplay() ) {
472                            // 3.5.4.3 (2004/01/05) 追??
473                            if( isUseCheckControl() && "checkbox".equals( getSelectedType() ) ) {
474                                    buf.append( thTag ).append( headerFormat.getRowspan() ).append("></th>");
475                                    buf.append( thTag ).append( headerFormat.getRowspan() );
476                                    buf.append(">").append( getAllCheckControl() ).append( "</th>");
477                                    buf.append( thTag ).append( headerFormat.getRowspan() );
478                                    buf.append(">").append( getNumberHeader() ).append("</th>");   // 3.5.4.6 (2004/01/30)
479                            }
480                            else {
481                                    buf.append( thTag ).append(" colspan=\"3\"");
482                                    buf.append( headerFormat.getRowspan() );
483                                    buf.append(">").append( getNumberHeader() ).append("</th>");   // 3.5.4.6 (2004/01/30)
484                            }
485                    }
486    
487                    int cl = 0;
488                    for( ; cl < headerFormat.getLocationSize(); cl++ ) {
489                            buf.append( StringUtil.replace( headerFormat.getFormat(cl) ,"td","th" ));
490                            int loc = headerFormat.getLocation(cl);
491                            if( loc >= 0 ) { buf.append( getSortedColumnLabel(loc) ); }
492                    }
493                    buf.append( StringUtil.replace( headerFormat.getFormat(cl) ,"td","th" ) ).append( HybsSystem.CR );
494    
495                    headerLine = buf.toString();
496                    return headerLine;
497            }
498    
499            /**
500             * DBTableModel から ??ブルのタグ??を作?して返します?
501             *
502             *
503             * @return      ??ブルのタグ??
504             */
505            protected String getTableFoot() {
506                    footerFormat.makeFormat( getDBTableModel() );
507    
508                    StringBuilder buf = new StringBuilder( HybsSystem.BUFFER_MIDDLE );
509    
510                    buf.append("<tfoot>").append( HybsSystem.CR );
511                    buf.append( footerFormat.getTrTag() ).append( HybsSystem.CR );
512    
513                    // 3.5.5.0 (2004/03/12) No ?のも?の作?判断追?
514                    if( isNumberDisplay() ) {
515                            buf.append(" <th");
516                            buf.append(" colspan=\"3\"");
517                            buf.append( footerFormat.getRowspan() );
518                            buf.append("></th>");
519                    }
520    
521                    int cl = 0;
522                    for( ; cl < footerFormat.getLocationSize(); cl++ ) {
523                            int loc = footerFormat.getLocation(cl);
524                            if( loc >= 0 ) { buf.append( getSortedColumnLabel(loc) ); }
525                    }
526                    buf.append( footerFormat.getFormat(cl) ).append( HybsSystem.CR );
527                    buf.append("</tfoot>").append( HybsSystem.CR );
528    
529                    return buf.toString();
530            }
531    
532            /**
533             * フォーマットを設定します?
534             *
535             *
536             * @param       list    TableFormatterのリス?
537             */
538            @Override
539            public void setFormatterList( final List<TableFormatter> list ) {         // 4.3.3.6 (2008/11/15) Generics警告対?
540                    bodyFormats = new TableFormatter[BODYFORMAT_MAX_COUNT];
541    
542                    bodyFormatsCount = 0;
543                    for( int i=0; i<list.size(); i++ ) {
544                            TableFormatter format = list.get( i );          // 4.3.3.6 (2008/11/15) Generics警告対?
545    
546                            switch( format.getFormatType() ) {
547                                    case TYPE_HEAD : headerFormat = format; break;
548                                    case TYPE_BODY : bodyFormats[bodyFormatsCount++] = format; break;
549                                    case TYPE_FOOT : footerFormat = format; break;
550                                    default : String errMsg = "FormatterType の定義外?値が指定されました?;
551                                    // 4.3.4.4 (2009/01/01)
552                                                      throw new HybsSystemException( errMsg );
553                            }
554                    }
555    
556                    // 3.5.5.5 (2004/04/23) headerFormat が定義されて???合?エラー
557                    if( headerFormat == null ) {
558                            String errMsg = "h:thead タグの、フォーマット?????です?";
559                            throw new HybsSystemException( errMsg );
560                    }
561            }
562    
563            /**
564             * フォーマットメソ?を使用できるかど?を問?わせます?
565             *
566             * @return  使用可能(true)/ 使用不可能 (false)
567             */
568            @Override
569            public boolean canUseFormat() {
570                    return true;
571            }
572            
573            /**
574             * ビューで表示したカラ???をカンマ区?で返します?
575             *
576             * @og.rev 5.1.6.0 (2010/05/01) 新規追?
577             *
578             * @return      ビューで表示したカラ???
579             */
580            @Override
581            public String getViewClms() {
582                    DBTableModel table = getDBTableModel();
583                    StringBuilder buf = new StringBuilder( HybsSystem.BUFFER_MIDDLE );
584                    for( int i=0; i<headerFormat.getLocationSize(); i++ ) {
585                            if( buf.length() > 0 ) { buf.append( ',' ); }
586                            buf.append( table.getColumnName( headerFormat.getLocation( i ) ) );
587                    }
588                    return buf.toString();
589            }
590            
591            /**
592             * 上下行???タが同じグループかど?をチェ?する?
593             *
594             * @param   nRowIndex ??ブルモ?の行番号
595             * @param   astrOldValues 古?ルプデータ
596             *
597             * @return  使用可能(true)/ 使用不可能 (false)
598             */
599    //      private boolean isSameGroup(final int nRowIndex, final String[] astrOldValues) {
600    //              boolean bRet = (groupCols.length > 0);
601    //              if( bRet ) {
602    //                      for( int nIndex = 0; bRet && ( nIndex < groupCols.length ); nIndex++) {
603    //                              bRet = ( astrOldValues[nIndex].equals(getValue(nRowIndex, groupCols[nIndex])));
604    //                      }
605    //
606    //                      // 不??時に astrOldValues に 新しい値を設定しておきます?
607    //                      if(!bRet) {
608    //                              for( int nIndex = 0; nIndex < groupCols.length; nIndex++) {
609    //                                      astrOldValues[nIndex] = getValue(nRowIndex, groupCols[nIndex]);
610    //                              }
611    //                      }
612    //              }               
613    //              return bRet;
614    //      }
615            
616            /**
617             * 上下行???タが同じ積上かど?をチェ?する?
618             *
619             * @param   nRowIndex ??ブルモ?の行番号
620             * @param   astrOldValues 古?ルプデータ
621             *
622             * @return  使用可能(true)/ 使用不可能 (false)
623             */
624            private boolean isSameStack(final int nRowIndex, final String[] astrOldValues) {
625                    boolean bRet = (stackCols.length > 0);
626                    if( bRet ) {
627                            for( int nIndex = 0; bRet && ( nIndex < stackCols.length ); nIndex++) {
628                                    bRet = ( astrOldValues[nIndex].equals(getValue(nRowIndex, stackCols[nIndex])));
629                            }
630    
631                            // 不??時に astrOldValues に 新しい値を設定しておきます?
632                            if(!bRet) {
633                                    for( int nIndex = 0; nIndex < stackCols.length; nIndex++) {
634                                            astrOldValues[nIndex] = getValue(nRowIndex, stackCols[nIndex]);
635                                    }
636                            }
637                    }
638                    return bRet;
639            }
640            
641            /**
642             * 対象カラ?積上げカラ?ど?
643             *
644             * @param   loc 列番号
645             *
646             * @return  対象(true)/ 非対象 (false)
647             */
648            private boolean isStackClm(final int loc) {
649                    boolean rtn = false;
650                    for( int nIndex = 0; nIndex < stackCols.length ; nIndex++) {
651                            if( stackCols[nIndex] == loc ){
652                                    rtn = true;
653                            }
654                    }
655                    return rtn;
656            }
657            
658            
659            /**
660             * 2つの日付?差を求めます?
661             * java.util.Date 型?日?date1 - date2 が何日かを返します?
662             * 
663             * 
664             * @og.rev 5.5.8.3 (2012/11/17) 新?
665             * 
666             * @param date1    日?
667             * @param date2    日?
668             * @return    2つの日付?差(日数 2-1) 同日なら?
669             */
670            public static int differenceDays(final Date date1,final Date date2) {
671                long datetime1 = date1.getTime();
672                long datetime2 = date2.getTime();
673                long one_date_time = 1000 * 60 * 60 * 24;
674                long diffDays = (datetime2 - datetime1) / one_date_time;
675                return (int)diffDays;
676            }
677    
678            
679            /**
680             * 日付から枠番号を返す
681             * 
682             * @og.rev 5.5.8.3 (2012/11/17) 新?
683             *
684             * @param   date 日?YYYY/MM/DD)
685             * @param       zoom Zoom設定?
686             * @param       calFD ヘッ??日
687             *
688             * @return  ?号
689             */
690            private int calNumber(final Date date, final String zoom, Date calFD ) {
691                    int rtn = 0;
692                    if( zoom.equals( ViewStackTableParam.STACK_ZOOM_MONTH ) ){
693                            // 月だけ?別の計算が??
694                            Calendar cal1 = Calendar.getInstance();
695                            cal1.setTime( calFD );
696                            Calendar cal2 = Calendar.getInstance();
697                            cal2.setTime( date );
698                            rtn = ( cal2.get( Calendar.YEAR )-cal1.get( Calendar.YEAR ) ) * 12
699                                            + ( cal2.get( Calendar.MONTH ) - cal1.get( Calendar.MONTH ) );
700                    }
701                    else{
702                            int diff = differenceDays( calFD, date );
703                            if( zoom.equals( ViewStackTableParam.STACK_ZOOM_WEEK )){
704                                    rtn = diff/7;
705                            }
706                            else{
707                                    rtn = diff;
708                            }
709                    }
710                    return rtn;
711            }
712            
713            /**
714             * ??ブル本体?作?
715             * 
716             * @og.rev 5.5.8.3 (2012/11/17) 繰り返し利用するため?
717             * @og.reb 5.6.1.2 (2013/02/22) td終?抜けて?ので追??キャパシ?対?
718             *
719             * @param   row ??ブルモ?のrow
720             * @param       stackRow スタ?行保存用
721             * @param       bgClrCnt 背景色カウンタ
722             * @param       blc     チェ?ボックス用
723             * @param       costAry コスト集計??
724             * @param       cap     能?
725             *
726             * @return  ??ブル本体?HTML
727             */
728    //      private StringBuffer makeBodyTable(int row, int stackRow, int bgClrCnt, int blc, double[] costAry){
729            private StringBuffer makeBodyTable(int row, int stackRow, int bgClrCnt, int blc, double[] costAry, String cap){
730                    StringBuffer out = new StringBuffer();
731                    for( int i=0; i<bodyFormatsCount; i++ ) {
732                            TableFormatter bodyFormat = bodyFormats[i];
733                            if( ! bodyFormat.isUse( row,getDBTableModel() ) ) { continue; } 
734                            out.append("<tbody").append( getBgColorCycleClass( bgClrCnt++,row ) );
735                            if( isNoTransition() ) { 
736                                    out.append( getHiddenRowValue( row ) );
737                            }
738                            out.append( STACK_TBODY );
739                            out.append( STACK_ROW_PREFIX ).append( stackRow ).append("'");
740                            out.append( STACK_ID_PREFIX ).append(stackRow).append( "'" );
741                            out.append(">");
742                            out.append( bodyFormat.getTrTag() );
743    
744                            //  No ?のも?の作?判断追?
745                            if( isNumberDisplay() ) {
746                                    String ckboxTD = "<td" + bodyFormat.getRowspan() + ">";
747                                    out.append( makeCheckbox( ckboxTD,row,blc ) );
748                            }
749    
750                            int cl = 0;
751                            for( ; cl < bodyFormat.getLocationSize(); cl++ ) {
752                                    String fmt = bodyFormat.getFormat(cl);
753                                    int loc = bodyFormat.getLocation(cl);   // 3.5.5.0
754                                    if( ! bodyFormat.isNoClass() && loc >= 0 ) { // 3.5.5.7 (2004/05/10)
755                                            StringBuilder newtg = new StringBuilder( HybsSystem.BUFFER_LARGE );
756                                            newtg.append("<td class=\"");
757                                            newtg.append( getColumnDbType(loc) );   // 4.0.0 (2005/01/31)
758                                            newtg.append("\" ");
759                                            String tdclass = newtg.toString();
760                                            fmt = StringUtil.replace( bodyFormat.getFormat(cl) ,"<td", tdclass );
761                                    }
762                                    out.append( fmt );
763                                    
764                                    // locがstackに入って?ば出?
765                                    if ( isStackClm(loc) ){
766                                            if( loc >= 0 ) {
767                                                    switch( bodyFormat.getType(cl) ) {
768                                                            case '#' : out.append( getColumnLabel(loc) );           break;
769                                                            case '$' : out.append( getRendererValue(row,loc) );     break;
770                                                            case '!' : out.append( getValue(row,loc) );                     break;
771                                                            default  : out.append( getValueLabel(row,loc) );        break;
772                                                    }
773                                            }
774                                            else {
775                                                    out.append( bodyFormat.getSystemFormat(row,loc) );
776                                            }
777                                    }
778                                    else{
779                                            //それ以外?出力しな?
780                                    }
781                            }
782                            // 5.5.8.3 (2012/11/17)?積上げの結果は出力???特定が難しいため??尾にtd付きで出力しておきま?
783                            if( innerStack ){
784                                    out.append("</td><td><div class='stackDivParent' capacity='"+ cap + "' style='width:100%; position:relative;'>"); // 5.6.1.2 (2013/02/22) td終??
785                                    for( int cs = 0; cs < costAry.length; cs++ ){
786                                            out.append("<div class='stackDiv' style='position:absolute; top:0px;' num='")
787                                             .append( cs)
788                                             .append("' stackedCost='")
789                                             .append( costAry[cs] )
790                                             .append( "'></div>");
791                                    }
792                                    out.append("</div>");
793                            }
794                            
795                            out.append( bodyFormat.getFormat(cl) );
796                            out.append("</tbody>").append( HybsSystem.CR );
797                    }
798                    return out;
799            }
800    }