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.io; 017 018import java.io.PrintWriter; 019 020import org.odftoolkit.odfdom.OdfFileDom; 021import org.odftoolkit.odfdom.doc.OdfSpreadsheetDocument; 022import org.odftoolkit.odfdom.doc.office.OdfOfficeAutomaticStyles; 023import org.odftoolkit.odfdom.doc.office.OdfOfficeSpreadsheet; 024import org.odftoolkit.odfdom.doc.table.OdfTable; 025import org.odftoolkit.odfdom.doc.table.OdfTableCell; 026import org.odftoolkit.odfdom.doc.table.OdfTableRow; 027import org.odftoolkit.odfdom.doc.text.OdfTextParagraph; 028import org.odftoolkit.odfdom.dom.attribute.office.OfficeValueTypeAttribute; 029import org.opengion.fukurou.model.NativeType; 030import org.opengion.fukurou.util.StringUtil; 031import org.opengion.hayabusa.common.HybsSystemException; 032import org.opengion.hayabusa.db.DBTableModel; 033import org.w3c.dom.Node; 034 035/** 036 * Calcファイルの書き出しクラスです。 037 * 038 * DefaultTableWriter を継承していますので,ラベル,名前,データの出力部のみ 039 * オーバーライドして,OpenOfficeのCalcファイルの出力機能を実現しています。 040 * 041 * @og.group ファイル出力 042 * 043 * @version 5.0 044 * @author Hiroki Nakamura 045 * @since JDK6.0, 046 */ 047public class TableWriter_Calc extends TableWriter_Default { 048 //* このプログラムのVERSION文字列を設定します。 {@value} */ 049 private static final String VERSION = "6.0.1.2 (2014/08/08)" ; 050 051 protected OdfSpreadsheetDocument wb = null; 052 protected OdfTable sheet = null; 053 protected OdfFileDom contentDom = null; 054 protected OdfOfficeSpreadsheet officeSpreadsheet = null; 055 protected OdfOfficeAutomaticStyles contentAutoStyles = null; 056 057 protected boolean useNumber = true; 058 059 private String sheetName = "Sheet1"; 060// private String refSheetName = null; 061 private String filename = null; 062// private String refFilename = null; 063 064 /** 065 * DBTableModel から 各形式のデータを作成して,PrintWriter に書き出します。 066 * このメソッドは、Calc 書き出し時に使用します。 067 * 068 * @see #isExcel() 069 */ 070 @Override 071 public void writeDBTable() { 072 if( !createDBColumn() ) { return; } 073 074 useNumber = isUseNumber(); 075 076 if( filename == null ) { 077 String errMsg = "ファイルが指定されていません。"; 078 throw new HybsSystemException( errMsg ); 079 } 080 081 /* 以下は未実装 ***********************************************/ 082 if( isAppend() ) { 083 String errMsg = "Calcの場合はAppend利用できません。"; 084 throw new HybsSystemException( errMsg ); 085 } 086 087 // 6.0.1.2 (2014/08/08) 元々、EXCEL以外には実装していない為、削除。 088// if( ( refFilename != null && refFilename.length() > 0 ) || ( refSheetName != null && refSheetName.length() >= 0 ) ) { 089// String errMsg = "Calcの場合は,refFilename,refSheetName利用できません。"; 090// throw new HybsSystemException( errMsg ); 091// } 092 093 // if( fontName != null && fontName.length() > 0 ) { 094 // String errMsg = "Calcの場合はfontNameは、利用できません。"; 095 // throw new HybsSystemException( errMsg ); 096 // System.err.println( errMsg ); 097 // } 098 099 // if( fontPoint >= 0 ) { 100 // String errMsg = "Calcの場合はfontPointは、利用できません。"; 101 // throw new HybsSystemException( errMsg ); 102 // System.err.println( errMsg ); 103 // } 104 /* *************************************************************/ 105 106 // 新規の場合 107 try { 108 wb = OdfSpreadsheetDocument.newSpreadsheetDocument(); 109 // コンテンツのルートとDOMを取得 110 contentDom = wb.getContentDom(); 111 officeSpreadsheet = wb.getContentRoot(); 112 contentAutoStyles = contentDom.getOrCreateAutomaticStyles(); 113 114 // デフォルトで用意されているノードを削除 115 Node childNode = officeSpreadsheet.getFirstChild(); 116 while( childNode != null ) { 117 officeSpreadsheet.removeChild( childNode ); 118 childNode = officeSpreadsheet.getFirstChild(); 119 } 120 } 121 catch( Exception ex ) { 122 String errMsg = "Calcの文書宣言ができません。"; 123 throw new HybsSystemException( errMsg, ex ); 124 } 125 126 //デフォルトで用意されているStyles調整 127 resetAutoStylesAndMasterStyles(); 128 129 sheet = new OdfTable( contentDom ); 130 sheet.setTableNameAttribute( sheetName ); 131 132 super.writeDBTable( null ); 133 134 officeSpreadsheet.appendChild( sheet ); 135 136 try { 137 wb.save( filename ); 138 wb.close(); 139 } 140 catch( Exception ex ) { 141 String errMsg = "Calcの文書saveができません。"; 142 throw new HybsSystemException( errMsg, ex ); 143 } 144 finally { 145 if( null != sheet ) { sheet = null; } 146 if( null != wb ) { wb = null; } 147 } 148 } 149 150 /** 151 * DBTableModel から データを作成して,PrintWriter に書き出します。 152 * 153 * @og.rev 6.0.1.2 (2014/08/08) 親クラスで同様の処理は定義済みのため、削除。 154 * 155 * @param writer PrintWriterオブジェクト 156 */ 157// @Override 158// public void writeDBTable( final PrintWriter writer ) { 159// String errMsg = "このクラスでは実装されていません。"; 160// throw new UnsupportedOperationException( errMsg ); 161// } 162 163 /** 164 * PrintWriter に DBTableModelのラベル情報を書き込みます。 165 * 第一カラム目は、ラベル情報を示す "#Label" を書き込みます。 166 * この行は、出力形式に無関係に、TableWriter.TAB_SEPARATOR で区切られます。 167 * 168 * @og.rev 6.0.1.2 (2014/08/08) カラム飛ばしできる機能を追加 169 * 170 * @param table DBTableModelオブジェクト 171 * @param writer PrintWriterオブジェクト 172 */ 173 @Override 174 protected void writeLabel( final DBTableModel table, final PrintWriter writer ) { 175 OdfTableRow row = new OdfTableRow( contentDom ); 176 177 if( useNumber ) { 178 row.appendCell( createTextCell( contentDom, "#Label", false, false ) ); 179 } 180 181 for( int i = 0; i < numberOfColumns; i++ ) { 182 int clm = clmNo[i]; 183 if( clm < 0 ) { // 6.0.1.2 (2014/08/08) カラム飛ばし 184 row.appendCell( createTextCell( contentDom, "", false, false ) ); 185 continue; 186 } 187 188 String val = dbColumn[clm].getLabel(); 189 if( i == 0 && !useNumber ) { 190 val = "#" + val; 191 } 192 row.appendCell( createTextCell( contentDom, val, false, false ) ); 193 } 194 row.setStyleName( "ro1" ); 195 sheet.appendRow( row ); 196 } 197 198 /** 199 * PrintWriter に DBTableModelの項目名情報を書き込みます。 200 * 第一カラム目は、項目名情報を示す "#Name" を書き込みます。 201 * この行は、出力形式に無関係に、TableWriter.TAB_SEPARATOR で区切られます。 202 * 203 * @og.rev 6.0.1.2 (2014/08/08) カラム飛ばしできる機能を追加 204 * 205 * @param table DBTableModelオブジェクト 206 * @param writer PrintWriterオブジェクト 207 */ 208 @Override 209 protected void writeName( final DBTableModel table, final PrintWriter writer ) { 210 OdfTableRow row = new OdfTableRow( contentDom ); 211 212 if( useNumber ) { 213 row.appendCell( createTextCell( contentDom, "#Name", false, false ) ); 214 } 215 216 for( int i = 0; i < numberOfColumns; i++ ) { 217 int clm = clmNo[i]; 218 if( clm < 0 ) { // 6.0.1.2 (2014/08/08) カラム飛ばし 219 row.appendCell( createTextCell( contentDom, "", false, false ) ); 220 continue; 221 } 222 223 String val = table.getColumnName( clm ); 224 if( i == 0 && !useNumber ) { 225 val = "#" + val; 226 } 227 row.appendCell( createTextCell( contentDom, val, false, false ) ); 228 } 229 row.setStyleName( "ro1" ); 230 sheet.appendRow( row ); 231 } 232 233 /** 234 * PrintWriter に DBTableModelのサイズ情報を書き込みます。 235 * 第一カラム目は、サイズ情報を示す "#Size" を書き込みます。 236 * この行は、出力形式に無関係に、TableWriter.TAB_SEPARATOR で区切られます。 237 * 238 * @og.rev 6.0.1.2 (2014/08/08) カラム飛ばしできる機能を追加 239 * 240 * @param table DBTableModelオブジェクト 241 * @param writer PrintWriterオブジェクト 242 */ 243 @Override 244 protected void writeSize( final DBTableModel table, final PrintWriter writer ) { 245 OdfTableRow row = new OdfTableRow( contentDom ); 246 247 if( useNumber ) { 248 row.appendCell( createTextCell( contentDom, "#Size", false, false ) ); 249 } 250 251 for( int i = 0; i < numberOfColumns; i++ ) { 252 int clm = clmNo[i]; 253 if( clm < 0 ) { // 6.0.1.2 (2014/08/08) カラム飛ばし 254 row.appendCell( createTextCell( contentDom, "", false, false ) ); 255 continue; 256 } 257 258 String val = String.valueOf( dbColumn[clm].getTotalSize() ); 259 if( i == 0 && !useNumber ) { 260 val = "#" + val; 261 } 262 row.appendCell( createTextCell( contentDom, val, true, false ) ); 263 } 264 row.setStyleName( "ro1" ); 265 sheet.appendRow( row ); 266 } 267 268 /** 269 * PrintWriter に DBTableModelのクラス名情報を書き込みます。 270 * 第一カラム目は、サイズ情報を示す "#Class" を書き込みます。 271 * この行は、出力形式に無関係に、TableWriter.TAB_SEPARATOR で区切られます。 272 * 273 * @og.rev 6.0.1.2 (2014/08/08) カラム飛ばしできる機能を追加 274 * 275 * @param table DBTableModelオブジェクト 276 * @param writer PrintWriterオブジェクト 277 */ 278 @Override 279 protected void writeClass( final DBTableModel table, final PrintWriter writer ) { 280 OdfTableRow row = new OdfTableRow( contentDom ); 281 282 if( useNumber ) { 283 row.appendCell( createTextCell( contentDom, "#Class", false, false ) ); 284 } 285 286 for( int i = 0; i < numberOfColumns; i++ ) { 287 int clm = clmNo[i]; 288 if( clm < 0 ) { // 6.0.1.2 (2014/08/08) カラム飛ばし 289 row.appendCell( createTextCell( contentDom, "", false, false ) ); 290 continue; 291 } 292 293 String val = dbColumn[clm].getClassName(); 294 if( i == 0 && !useNumber ) { 295 val = "#" + val; 296 } 297 row.appendCell( createTextCell( contentDom, val, false, false ) ); 298 } 299 row.setStyleName( "ro1" ); 300 sheet.appendRow( row ); 301 } 302 303 /** 304 * PrintWriter に セパレーターを書き込みます。 305 * 第一カラム目は、サイズ情報を示す "#----" を書き込みます。 306 * この行は、出力形式に無関係に、TableWriter.TAB_SEPARATOR で区切られます。 307 * 308 * @param table DBTableModelオブジェクト 309 * @param writer PrintWriterオブジェクト 310 */ 311 @Override 312 protected void writeSeparator( final DBTableModel table, final PrintWriter writer ) { 313 String sep = "----"; 314 315 OdfTableRow row = new OdfTableRow( contentDom ); 316 row.appendCell( createTextCell( contentDom, "#----", false, false ) ); 317 for( int i = 0; i < numberOfColumns; i++ ) { 318 if( i == 0 && !useNumber ) { 319 continue; 320 } 321 row.appendCell( createTextCell( contentDom, sep, false, false ) ); 322 } 323 sheet.appendRow( row ); 324 } 325 326 /** 327 * PrintWriter に DBTableModelのテーブル情報を書き込みます。 328 * このクラスでは,データを ダブルコーテーション(")で囲みます。 329 * PrintWriter に DBTableModelのテーブル情報を書き込みます。 330 * 331 * @og.rev 5.2.1.0 (2010/10/01) useRenderer 対応 332 * @og.rev 6.0.1.2 (2014/08/08) カラム飛ばしできる機能を追加 333 * 334 * @param table DBTableModelオブジェクト 335 * @param writer PrintWriterオブジェクト 336 */ 337 @Override 338 protected void writeData( final DBTableModel table,final PrintWriter writer ) { 339 int numberOfRows = table.getRowCount(); 340 341 boolean[] nvar = new boolean[numberOfColumns]; 342 boolean[] cellType = new boolean[numberOfColumns]; 343 for( int i=0; i<numberOfColumns; i++ ) { 344 int clm = clmNo[i]; 345 if( clm < 0 ) { continue; } // 6.0.1.2 (2014/08/08) カラム飛ばし 346 347 NativeType nativeType = dbColumn[clm].getNativeType(); 348 switch( nativeType ) { 349 case INT : 350 case LONG : 351 case DOUBLE : 352 cellType[i] = true ; 353 break; 354 case STRING : 355 case CALENDAR : 356 default : 357 cellType[i] = false ; 358 break; 359 } 360 nvar[i] = "NVAR".equals( dbColumn[clm].getDbType() ); 361 } 362 boolean useRenderer = isUseRenderer(); // 5.2.1.0 (2010/10/01) 363 364 for( int r = 0; r < numberOfRows; r++ ) { 365 OdfTableRow row = new OdfTableRow( contentDom ); 366 367 if( useNumber ) { 368 row.appendCell( createTextCell( contentDom, String.valueOf( r + 1 ), true, true ) ); 369 } 370 371 for( int i = 0; i < numberOfColumns; i++ ) { 372 int clm = clmNo[i]; 373 if( clm < 0 ) { // 6.0.1.2 (2014/08/08) カラム飛ばし 374 row.appendCell( createTextCell( contentDom, "", false, false ) ); 375 continue; 376 } 377 378 String val = table.getValue( r, clm ); 379 if( nvar[i] ) { 380 val = StringUtil.getReplaceEscape( val ); 381 } 382 // 5.2.1.0 (2010/10/01) useRenderer 対応 383 else if( useRenderer ) { 384 val = StringUtil.spanCut( dbColumn[clm].getRendererValue( val ) ); 385 } 386 row.appendCell( createTextCell( contentDom, val, cellType[i], false ) ); 387 } 388 row.setStyleName( "ro1" ); 389 sheet.appendRow( row ); 390 } 391 } 392 393 /** 394 * テキストコンテンツ用のセルを生成する 395 * 396 * @param contentDom OdfFileDomオブジェクト 397 * @param content コンテンツ 398 * @param isCellTypeNumber [true:数字型/false:文字型] 399 * @param isNumberList [true:数字リスト=999/false:通常] 400 * 401 * @return OpenOfficeのセルテーブルオブジェクト 402 */ 403 protected OdfTableCell createTextCell( final OdfFileDom contentDom, 404 final String content, 405 final Boolean isCellTypeNumber, 406 final Boolean isNumberList ) { 407 OdfTableCell cell = new OdfTableCell( contentDom ); 408 if( isCellTypeNumber ) { 409 cell.setOfficeValueAttribute( Double.parseDouble( content ) ); 410 cell.setOfficeValueTypeAttribute( OfficeValueTypeAttribute.Value.FLOAT.toString() ); 411 } 412 else { 413 cell.setOfficeValueTypeAttribute( OfficeValueTypeAttribute.Value.STRING.toString() ); 414 } 415 OdfTextParagraph paragraph = new OdfTextParagraph( contentDom, null, content ); 416 cell.appendChild( paragraph ); 417 return cell; 418 } 419 420 /** 421 * デフォルトで用意されているStylesを調整します。 422 * ※ここでは何もしません。 423 * 424 */ 425 protected void resetAutoStylesAndMasterStyles(){ 426 // Document empty method 対策 427 } 428 429 /** 430 * このクラスが、Calc対応機能(=Excel対応機能)を持っているかどうかを返します。 431 * 432 * Calc対応機能とは、シート名のセット、雛型参照ファイル名のセット、 433 * 書き込み元ファイルのFileオブジェクト取得などの、特殊機能です。 434 * 本来は、インターフェースを分けるべきと考えますが、taglib クラス等の 435 * 関係があり、問い合わせによる条件分岐で対応します。 436 * 437 * @return Calc対応機能(=Excel対応機能)を持っているかどうか(true 固定) 438 */ 439 @Override 440 public boolean isExcel() { 441 return true; 442 } 443 444 /** 445 * 出力先ファイル名をセットします。(DIR + Filename) 446 * これは、Calc追加機能として実装されています。 447 * 448 * @param filename Calc雛型参考ファイル名 449 */ 450 @Override 451 public void setFilename( final String filename ) { 452 this.filename = filename; 453 } 454 455 /** 456 * DBTableModelのデータとして読み込むときのシート名を設定します。 457 * 初期値は、"Sheet1" です。 458 * これは、Calc追加機能として実装されています。 459 * 460 * @param sheetName シート名 461 */ 462 @Override 463 public void setSheetName( final String sheetName ) { 464 if( sheetName != null ) { 465 this.sheetName = sheetName; 466 } 467 } 468 469 /** 470 * Calc雛型参考ファイル名をセットします。(DIR + Filename) 471 * これは、Calc追加機能として実装されています。 472 * 473 * @og.rev 6.0.1.2 (2014/08/08) 元々、EXCEL以外には実装していない為、削除。 474 * 475 * @param filename Calc雛型参考ファイル名 476 */ 477 @Override 478 public void setRefFilename( final String filename ) { 479// refFilename = filename; 480 String errMsg = "Calcの場合はrefFilenameは、利用できません。refFilename=[" + filename + "]"; 481 System.err.println( errMsg ); 482 } 483 484 /** 485 * Calc雛型参考ファイルのシート名を設定します。 486 * これは、Calc追加機能として実装されています。 487 * 488 * Calcファイルを書き出す時に、雛型として参照するシート名を指定します。 489 * これにより、複数の形式の異なるデータを順次書き出したり(appendモードを併用)する 490 * ことや、シートを指定して新規にCalcを作成する場合にフォームを設定する事が可能になります。 491 * 初期値は、null(第一シート) です。 492 * 493 * @og.rev 6.0.1.2 (2014/08/08) 元々、EXCEL以外には実装していない為、削除。 494 * 495 * @param sheetName シート名 496 */ 497 @Override 498 public void setRefSheetName( final String sheetName ) { 499// if( sheetName != null ) { 500// refSheetName = sheetName; 501// } 502 String errMsg = "Calcの場合はrefSheetNameは、利用できません。refSheetName=[" + sheetName + "]"; 503 System.err.println( errMsg ); 504 } 505 506 /** 507 * Calc出力時のデフォルトフォント名を設定します。 508 * Calcの場合はfontNameは、利用できません。 509 * 510 * Calcファイルを書き出す時に、デフォルトフォント名を指定します。 511 * フォント名は、Calcのフォント名をそのまま使用してください。 512 * に設定されます。 513 * 初期値は、システムリソース の TABLE_WRITER_DEFAULT_FONT_NAME です。 514 * 515 * @og.rev 5.5.2.6 (2012/05/25) findbugs対応 516 * 517 * @param fontName デフォルトフォント名 518 */ 519 @Override 520 public void setFontName( final String fontName ) { 521 String errMsg = "Calcの場合はfontNameは、利用できません。fontName=[" + fontName + "]"; 522 System.err.println( errMsg ); 523 } 524 525 /** 526 * Calc出力時のデフォルトフォントポイント数を設定します。 527 * Calcの場合はfontPointは、利用できません。 528 * 529 * Calcファイルを書き出す時に、デフォルトポイント数を指定します。 530 * に設定されます。 531 * 初期値は、システムリソース の TABLE_WRITER_DEFAULT_FONT_POINTS です。 532 * 533 * @og.rev 5.5.2.6 (2012/05/25) findbugs対応 534 * 535 * @param point デフォルトフォントポイント数 536 */ 537 @Override 538 public void setFontPoint( final short point ) { 539 String errMsg = "Calcの場合はfontPointは、利用できません。fontPoint=[" + point + "]"; 540 System.err.println( errMsg ); 541 } 542}