001/* 002 * Copyright (c) 2009 The openGion Project. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 013 * either express or implied. See the License for the specific language 014 * governing permissions and limitations under the License. 015 */ 016package org.opengion.plugin.view; 017 018import org.opengion.hayabusa.common.HybsSystem; 019import org.opengion.hayabusa.common.HybsSystemException; 020import org.opengion.hayabusa.db.DBTableModel; 021import org.opengion.fukurou.util.StringUtil; 022import org.opengion.hayabusa.html.TableFormatter; 023import org.opengion.hayabusa.html.ViewStackTableParam; 024 025import java.util.Calendar; 026import java.util.Date; 027import 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 */ 066public 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); // 終了日は範囲に入るので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 * @og.rev 5.9.1.2 (2015/10/23) 自己終了警告対応 421 * @og.rev 5.9.3.3 (2015/12/26) colgroup対応 422 * 423 * @return テーブルのタグ文字列 424 */ 425 @Override 426 protected String getTableHead() { 427 428 StringBuilder buf = new StringBuilder( HybsSystem.BUFFER_MIDDLE ); 429 430 431 // 5.9.3.3 (2015/12/26) HTML5 で colgroup が効かない対応 432 if( !useIE7Header ) { 433 buf.append( "<style type=\"text/css\">" ) 434 .append( HybsSystem.CR ); 435 if( isNumberDisplay() ) { 436 makeNthChild( buf,2,"BIT" ); 437 makeNthChild( buf,3,"S9" ); 438 } 439 buf.append( "</style>" ) 440 .append( HybsSystem.CR ); 441 } 442 443 // 3.5.5.0 (2004/03/12) No 欄そのものの作成判断追加 444 if( isNumberDisplay() ) { 445// buf.append("<colgroup class=\"X\" />"); // 4.0.0 (2005/01/31) 446// buf.append("<colgroup class=\"BIT\" />"); 447// buf.append("<colgroup class=\"S9\" />"); // 4.0.0 (2005/01/31) 448 buf.append("<colgroup class=\"X\" ><!-- --></colgroup>"); // 5.9.1.2 (2015/10/23) 449 buf.append("<colgroup class=\"BIT\" ><!-- --></colgroup>"); 450 buf.append("<colgroup class=\"S9\" ><!-- --></colgroup>"); 451 buf.append(HybsSystem.CR); 452 } 453 454 // 3.5.2.0 (2003/10/20) ヘッダー繰り返し部をgetHeadLine()へ移動 455 buf.append("<thead id=\"header\">").append( HybsSystem.CR ); // 3.5.6.5 (2004/08/09) 456 buf.append( getHeadLine() ); 457 buf.append("</thead>").append( HybsSystem.CR ); 458 459 return buf.toString(); 460 } 461 462 /** 463 * ヘッダー繰り返し部を、getTableHead()メソッドから分離。 464 * 465 * 466 * @return テーブルのタグ文字列 467 */ 468 @Override 469 protected String getHeadLine() { 470 return getHeadLine( "<th" ) ; 471 } 472 473 /** 474 * ヘッダー繰り返し部を、getTableHead()メソッドから分離。 475 * 476 * 477 * @param thTag タグの文字列 478 * 479 * @return テーブルのタグ文字列 480 */ 481 @Override 482 protected String getHeadLine( final String thTag ) { 483 if( headerLine != null ) { return headerLine; } // キャッシュを返す。 484 485 StringBuilder buf = new StringBuilder( HybsSystem.BUFFER_MIDDLE ); 486 487 buf.append( headerFormat.getTrTag() ).append( HybsSystem.CR ); 488 489 // 3.5.5.0 (2004/03/12) No 欄そのものの作成判断追加 490 if( isNumberDisplay() ) { 491 // 3.5.4.3 (2004/01/05) 追加分 492 if( isUseCheckControl() && "checkbox".equals( getSelectedType() ) ) { 493 buf.append( thTag ).append( headerFormat.getRowspan() ).append("></th>"); 494 buf.append( thTag ).append( headerFormat.getRowspan() ); 495 buf.append(">").append( getAllCheckControl() ).append( "</th>"); 496 buf.append( thTag ).append( headerFormat.getRowspan() ); 497 buf.append(">").append( getNumberHeader() ).append("</th>"); // 3.5.4.6 (2004/01/30) 498 } 499 else { 500 buf.append( thTag ).append(" colspan=\"3\""); 501 buf.append( headerFormat.getRowspan() ); 502 buf.append(">").append( getNumberHeader() ).append("</th>"); // 3.5.4.6 (2004/01/30) 503 } 504 } 505 506 int cl = 0; 507 for( ; cl < headerFormat.getLocationSize(); cl++ ) { 508 buf.append( StringUtil.replace( headerFormat.getFormat(cl) ,"td","th" )); 509 int loc = headerFormat.getLocation(cl); 510 if( loc >= 0 ) { buf.append( getSortedColumnLabel(loc) ); } 511 } 512 buf.append( StringUtil.replace( headerFormat.getFormat(cl) ,"td","th" ) ).append( HybsSystem.CR ); 513 514 headerLine = buf.toString(); 515 return headerLine; 516 } 517 518 /** 519 * DBTableModel から テーブルのタグ文字列を作成して返します。 520 * 521 * 522 * @return テーブルのタグ文字列 523 */ 524 protected String getTableFoot() { 525 footerFormat.makeFormat( getDBTableModel() ); 526 527 StringBuilder buf = new StringBuilder( HybsSystem.BUFFER_MIDDLE ); 528 529 buf.append("<tfoot>").append( HybsSystem.CR ); 530 buf.append( footerFormat.getTrTag() ).append( HybsSystem.CR ); 531 532 // 3.5.5.0 (2004/03/12) No 欄そのものの作成判断追加 533 if( isNumberDisplay() ) { 534 buf.append(" <th"); 535 buf.append(" colspan=\"3\""); 536 buf.append( footerFormat.getRowspan() ); 537 buf.append("></th>"); 538 } 539 540 int cl = 0; 541 for( ; cl < footerFormat.getLocationSize(); cl++ ) { 542 int loc = footerFormat.getLocation(cl); 543 if( loc >= 0 ) { buf.append( getSortedColumnLabel(loc) ); } 544 } 545 buf.append( footerFormat.getFormat(cl) ).append( HybsSystem.CR ); 546 buf.append("</tfoot>").append( HybsSystem.CR ); 547 548 return buf.toString(); 549 } 550 551 /** 552 * フォーマットを設定します。 553 * 554 * 555 * @param list TableFormatterのリスト 556 */ 557 @Override 558 public void setFormatterList( final List<TableFormatter> list ) { // 4.3.3.6 (2008/11/15) Generics警告対応 559 bodyFormats = new TableFormatter[BODYFORMAT_MAX_COUNT]; 560 561 bodyFormatsCount = 0; 562 for( int i=0; i<list.size(); i++ ) { 563 TableFormatter format = list.get( i ); // 4.3.3.6 (2008/11/15) Generics警告対応 564 565 switch( format.getFormatType() ) { 566 case TYPE_HEAD : headerFormat = format; break; 567 case TYPE_BODY : bodyFormats[bodyFormatsCount++] = format; break; 568 case TYPE_FOOT : footerFormat = format; break; 569 default : String errMsg = "FormatterType の定義外の値が指定されました。"; 570 // 4.3.4.4 (2009/01/01) 571 throw new HybsSystemException( errMsg ); 572 } 573 } 574 575 // 3.5.5.5 (2004/04/23) headerFormat が定義されていない場合はエラー 576 if( headerFormat == null ) { 577 String errMsg = "h:thead タグの、フォーマットの指定は必須です。"; 578 throw new HybsSystemException( errMsg ); 579 } 580 } 581 582 /** 583 * フォーマットメソッドを使用できるかどうかを問い合わせます。 584 * 585 * @return 使用可能(true)/ 使用不可能 (false) 586 */ 587 @Override 588 public boolean canUseFormat() { 589 return true; 590 } 591 592 /** 593 * ビューで表示したカラムの一覧をカンマ区切りで返します。 594 * 595 * @og.rev 5.1.6.0 (2010/05/01) 新規追加 596 * 597 * @return ビューで表示したカラムの一覧 598 */ 599 @Override 600 public String getViewClms() { 601 DBTableModel table = getDBTableModel(); 602 StringBuilder buf = new StringBuilder( HybsSystem.BUFFER_MIDDLE ); 603 for( int i=0; i<headerFormat.getLocationSize(); i++ ) { 604 if( buf.length() > 0 ) { buf.append( ',' ); } 605 buf.append( table.getColumnName( headerFormat.getLocation( i ) ) ); 606 } 607 return buf.toString(); 608 } 609 610 /** 611 * 上下行のデータが同じグループかどうかをチェックする。 612 * 613 * @param nRowIndex テーブルモデルの行番号 614 * @param astrOldValues 古いグルプデータ 615 * 616 * @return 使用可能(true)/ 使用不可能 (false) 617 */ 618// private boolean isSameGroup(final int nRowIndex, final String[] astrOldValues) { 619// boolean bRet = (groupCols.length > 0); 620// if( bRet ) { 621// for( int nIndex = 0; bRet && ( nIndex < groupCols.length ); nIndex++) { 622// bRet = ( astrOldValues[nIndex].equals(getValue(nRowIndex, groupCols[nIndex]))); 623// } 624// 625// // 不一致時に astrOldValues に 新しい値を設定しておきます。 626// if(!bRet) { 627// for( int nIndex = 0; nIndex < groupCols.length; nIndex++) { 628// astrOldValues[nIndex] = getValue(nRowIndex, groupCols[nIndex]); 629// } 630// } 631// } 632// return bRet; 633// } 634 635 /** 636 * 上下行のデータが同じ積上かどうかをチェックする。 637 * 638 * @param nRowIndex テーブルモデルの行番号 639 * @param astrOldValues 古いグルプデータ 640 * 641 * @return 使用可能(true)/ 使用不可能 (false) 642 */ 643 private boolean isSameStack(final int nRowIndex, final String[] astrOldValues) { 644 boolean bRet = (stackCols.length > 0); 645 if( bRet ) { 646 for( int nIndex = 0; bRet && ( nIndex < stackCols.length ); nIndex++) { 647 bRet = ( astrOldValues[nIndex].equals(getValue(nRowIndex, stackCols[nIndex]))); 648 } 649 650 // 不一致時に astrOldValues に 新しい値を設定しておきます。 651 if(!bRet) { 652 for( int nIndex = 0; nIndex < stackCols.length; nIndex++) { 653 astrOldValues[nIndex] = getValue(nRowIndex, stackCols[nIndex]); 654 } 655 } 656 } 657 return bRet; 658 } 659 660 /** 661 * 対象カラムが積上げカラムかどうか 662 * 663 * @param loc 列番号 664 * 665 * @return 対象(true)/ 非対象 (false) 666 */ 667 private boolean isStackClm(final int loc) { 668 boolean rtn = false; 669 for( int nIndex = 0; nIndex < stackCols.length ; nIndex++) { 670 if( stackCols[nIndex] == loc ){ 671 rtn = true; 672 } 673 } 674 return rtn; 675 } 676 677 678 /** 679 * 2つの日付の差を求めます。 680 * java.util.Date 型の日付 date1 - date2 が何日かを返します。 681 * 682 * 683 * @og.rev 5.5.8.3 (2012/11/17) 新規 684 * 685 * @param date1 日付 686 * @param date2 日付 687 * @return 2つの日付の差(日数 2-1) 同日なら0 688 */ 689 public static int differenceDays(final Date date1,final Date date2) { 690 long datetime1 = date1.getTime(); 691 long datetime2 = date2.getTime(); 692 long one_date_time = 1000 * 60 * 60 * 24; 693 long diffDays = (datetime2 - datetime1) / one_date_time; 694 return (int)diffDays; 695 } 696 697 698 /** 699 * 日付から枠番号を返す 700 * 701 * @og.rev 5.5.8.3 (2012/11/17) 新規 702 * 703 * @param date 日付(YYYY/MM/DD) 704 * @param zoom Zoom設定値 705 * @param calFD ヘッダ初日 706 * 707 * @return 枠番号 708 */ 709 private int calNumber(final Date date, final String zoom, Date calFD ) { 710 int rtn = 0; 711 if( zoom.equals( ViewStackTableParam.STACK_ZOOM_MONTH ) ){ 712 // 月だけは別の計算が必要 713 Calendar cal1 = Calendar.getInstance(); 714 cal1.setTime( calFD ); 715 Calendar cal2 = Calendar.getInstance(); 716 cal2.setTime( date ); 717 rtn = ( cal2.get( Calendar.YEAR )-cal1.get( Calendar.YEAR ) ) * 12 718 + ( cal2.get( Calendar.MONTH ) - cal1.get( Calendar.MONTH ) ); 719 } 720 else{ 721 int diff = differenceDays( calFD, date ); 722 if( zoom.equals( ViewStackTableParam.STACK_ZOOM_WEEK )){ 723 rtn = diff/7; 724 } 725 else{ 726 rtn = diff; 727 } 728 } 729 return rtn; 730 } 731 732 /** 733 * テーブル本体の作成 734 * 735 * @og.rev 5.5.8.3 (2012/11/17) 繰り返し利用するため分離 736 * @og.reb 5.6.1.2 (2013/02/22) td終了が抜けていたので追加、キャパシティ対応 737 * 738 * @param row テーブルモデルのrow 739 * @param stackRow スタック行保存用 740 * @param bgClrCnt 背景色カウンタ 741 * @param blc チェックボックス用 742 * @param costAry コスト集計配列 743 * @param cap 能力 744 * 745 * @return テーブル本体のHTML 746 */ 747// private StringBuffer makeBodyTable(int row, int stackRow, int bgClrCnt, int blc, double[] costAry){ 748 private StringBuffer makeBodyTable(int row, int stackRow, int bgClrCnt, int blc, double[] costAry, String cap){ 749 StringBuffer out = new StringBuffer(); 750 for( int i=0; i<bodyFormatsCount; i++ ) { 751 TableFormatter bodyFormat = bodyFormats[i]; 752 if( ! bodyFormat.isUse( row,getDBTableModel() ) ) { continue; } 753 out.append("<tbody").append( getBgColorCycleClass( bgClrCnt++,row ) ); 754 if( isNoTransition() ) { 755 out.append( getHiddenRowValue( row ) ); 756 } 757 out.append( STACK_TBODY ); 758 out.append( STACK_ROW_PREFIX ).append( stackRow ).append("'"); 759 out.append( STACK_ID_PREFIX ).append(stackRow).append( "'" ); 760 out.append(">"); 761 out.append( bodyFormat.getTrTag() ); 762 763 // No 欄そのものの作成判断追加 764 if( isNumberDisplay() ) { 765 String ckboxTD = "<td" + bodyFormat.getRowspan() + ">"; 766 out.append( makeCheckbox( ckboxTD,row,blc ) ); 767 } 768 769 int cl = 0; 770 for( ; cl < bodyFormat.getLocationSize(); cl++ ) { 771 String fmt = bodyFormat.getFormat(cl); 772 int loc = bodyFormat.getLocation(cl); // 3.5.5.0 773 if( ! bodyFormat.isNoClass() && loc >= 0 ) { // 3.5.5.7 (2004/05/10) 774 StringBuilder newtg = new StringBuilder( HybsSystem.BUFFER_LARGE ); 775 newtg.append("<td class=\""); 776 newtg.append( getColumnDbType(loc) ); // 4.0.0 (2005/01/31) 777 newtg.append("\" "); 778 String tdclass = newtg.toString(); 779 fmt = StringUtil.replace( bodyFormat.getFormat(cl) ,"<td", tdclass ); 780 } 781 out.append( fmt ); 782 783 // locがstackに入っていれば出力 784 if ( isStackClm(loc) ){ 785 if( loc >= 0 ) { 786 switch( bodyFormat.getType(cl) ) { 787 case '#' : out.append( getColumnLabel(loc) ); break; 788 case '$' : out.append( getRendererValue(row,loc) ); break; 789 case '!' : out.append( getValue(row,loc) ); break; 790 default : out.append( getValueLabel(row,loc) ); break; 791 } 792 } 793 else { 794 out.append( bodyFormat.getSystemFormat(row,loc) ); 795 } 796 } 797 else{ 798 //それ以外は出力しない 799 } 800 } 801 // 5.5.8.3 (2012/11/17)内部積上げの結果は出力場所の特定が難しいため一番最後尾にtd付きで出力しておきます 802 if( innerStack ){ 803 out.append("</td><td><div class='stackDivParent' capacity='"+ cap + "' style='width:100%; position:relative;'>"); // 5.6.1.2 (2013/02/22) td終了追加 804 for( int cs = 0; cs < costAry.length; cs++ ){ 805 out.append("<div class='stackDiv' style='position:absolute; top:0px;' num='") 806 .append( cs) 807 .append("' stackedCost='") 808 .append( costAry[cs] ) 809 .append( "'></div>"); 810 } 811 out.append("</div>"); 812 } 813 814 out.append( bodyFormat.getFormat(cl) ); 815 out.append("</tbody>").append( HybsSystem.CR ); 816 } 817 return out; 818 } 819}