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.File;
019import java.io.FileInputStream;
020import java.io.FileOutputStream;
021import java.io.IOException;
022import java.io.OutputStream;
023import java.io.PrintWriter;
024import java.util.Locale;
025
026import org.apache.poi.ss.usermodel.Cell;
027import org.apache.poi.ss.usermodel.CreationHelper;
028import org.apache.poi.ss.usermodel.Font;
029import org.apache.poi.ss.usermodel.RichTextString;
030import org.apache.poi.ss.usermodel.Row;
031import org.apache.poi.ss.usermodel.Sheet;
032import org.apache.poi.ss.usermodel.Workbook;
033import org.apache.poi.ss.usermodel.WorkbookFactory;
034import org.opengion.fukurou.model.NativeType;
035import org.opengion.fukurou.util.Closer;
036import org.opengion.fukurou.util.StringUtil;
037import org.opengion.hayabusa.common.HybsSystemException;
038import org.opengion.hayabusa.db.DBTableModel;
039
040/**
041 * ネイティブEXCELファイルの書き出しクラスです。
042 *
043 * DefaultTableWriter を継承していますので,ラベル,名前,データの出力部のみ
044 * オーバーライドして,MIcrosoft Excelファイルの出力機能を実現しています。
045 *
046 * 出力形式は、openXML形式にも対応しています。
047 * 出力ファイルの拡張子が、.xlsならExcel2003のバイナリ形式、.xlsxならExcel2007の
048 * openXML形式で出力されます。
049 *
050 * @og.group ファイル出力
051 *
052 * @og.rev 4.3.4.3 (2008/12/22) 一部protected化
053 * @og.rev 4.3.6.7 (2009/05/22) ooxml形式対応
054 *
055 * @version  4.0
056 * @author       Kazuhiko Hasegawa
057 * @since    JDK5.0,
058 */
059public class TableWriter_Excel extends TableWriter_Default {
060        //* このプログラムのVERSION文字列を設定します。   {@value} */
061        private static final String VERSION = "5.7.6.3 (2014/05/23)" ;
062
063        private Workbook wb                     = null;
064        private Sheet   sheet           = null;
065//      protected OutputStream out              = null;                         // 5.5.2.6 (2012/05/25) findbugs対応
066        protected       int             nRowIndex       = 0;
067        private String  sheetName               = "Sheet1";                     // 3.5.4.3 (2004/01/05)
068        private String  refSheetName    = null;                         // 3.5.4.3 (2004/01/05)
069        private String  filename                = null;         // 3.5.4.3 (2004/01/05)
070        private String  refFilename             = null;         // 3.5.4.3 (2004/01/05)
071        private String  fontName                = null;         // 3.8.5.3 (2006/08/07)
072        private short   fontPoint               = -1;           // 3.8.5.3 (2006/08/07)
073        private CreationHelper createHelper     = null; // poi.xssf対応
074        // 5.1.4.0 (2010/03/01) 行番号情報を、出力する(true)/しない(false)を指定
075        private boolean         useNumber       = true;
076
077        /**
078         * DBTableModel から 各形式のデータを作成して,PrintWriter に書き出します。
079         * このメソッドは、EXCEL 書き出し時に使用します。
080         *
081         * @og.rev 4.0.0.0 (2006/09/31) 新規追加
082         * @og.rev 5.1.4.0 (2010/03/01) columns 対応 、useNumber属性対応
083         * @og.rev 5.9.0.0 (2015/09/04) XLSXの出力をSXSSFWorkbook利用に変更
084         *
085         * @see #isExcel()
086         */
087        @Override
088        public void writeDBTable() {
089                if( ! createDBColumn() ) { return ; }
090
091                useNumber = isUseNumber();
092
093//              numberOfColumns = getDBTableModel().getColumnCount();
094
095//              if( numberOfColumns <= 0 ) { return; }
096
097                // 3.5.6.0 (2004/06/18) 移動
098                if( filename == null ) {
099                        String errMsg = "ファイルが指定されていません。";
100                        throw new HybsSystemException(errMsg );
101                }
102
103                // メモリにEXCELデータを作る
104                boolean isRefFileExisted  = false;
105                boolean isRefFile = false;
106                boolean isWorkFileExisted = checkAvailabity(filename);
107                boolean hasFile   = isWorkFileExisted;
108                String  nameUse   = filename;
109
110                // 同じワークブーク中に雛型シートが存在してある場合
111                boolean hasRefSheet = ((null != refSheetName) && (0 <= refSheetName.length()));
112
113                if( hasRefSheet && (null != refFilename) && (0 < refFilename.length())) {
114                        if(isWorkFileExisted ) {
115                                if( 0 == refFilename.compareToIgnoreCase(filename) ) {
116                                        nameUse = filename;
117                                        hasFile = true;
118                                }
119                                else {
120                                        String errMsg = "追加の時、雛型ファイル名と出力ファイル名が同じしか対応していなかった[" + refFilename + "]"  ;
121                                        throw new HybsSystemException( errMsg );
122                                }
123                        }
124                        else {
125                                nameUse = refFilename;
126                                hasFile = true;
127                                isRefFile = true;
128                        }
129                }
130
131                if( hasFile ) {
132                        wb = createWorkbook(nameUse);
133                }
134                else {
135                        // 新規の場合、ファイル名に.xlsxで終了した場合⇒.xlsx形式ファイル作成、その他⇒.xls形式ファイル作成
136                        if(filename.toLowerCase(Locale.JAPAN).endsWith( ".xlsx" ) ) {
137        //                      wb = new org.apache.poi.xssf.usermodel.XSSFWorkbook();
138                                wb = new org.apache.poi.xssf.streaming.SXSSFWorkbook(); // 5.9.0.0 (2015/09/04) 制限あり 高速、低メモリ消費
139                        }
140                        else {
141                                wb = new org.apache.poi.hssf.usermodel.HSSFWorkbook();
142                        }
143
144                        // 3.8.6.0 (2006/08/07) フォント名やフォントサイズの指定
145                        Font font = wb.getFontAt((short)0);
146                        if( fontName != null ) {
147                                font.setFontName( fontName );   // "MS Pゴシック" など
148                        }
149                        if( fontPoint > 0 ) {
150                                font.setFontHeightInPoints( fontPoint );
151                        }
152                }
153
154                int nSheetIndex = wb.getSheetIndex(sheetName);
155                int nSheetPattern = -1;
156
157                if( isRefFileExisted ) {
158                        sheet = wb.createSheet();
159                }
160                else {
161                        if( hasRefSheet ) { nSheetPattern = wb.getSheetIndex(refSheetName); }
162
163                        if( isRefFile ) {
164                                if(-1 >= nSheetPattern ) {
165                                        String errMsg = "雛型の中に参照としてのシートが存在しません[" + refFilename + "]"  ;
166                                        throw new HybsSystemException( errMsg );
167                                }
168                                while(true) {
169                                        int nTotalSheets = wb.getNumberOfSheets();
170
171                                        if( 1 == nTotalSheets ) { break; }
172
173                                        for( int nIndex = ( nTotalSheets - 1 ); nIndex >= 0; nIndex--) {
174                                                if( nIndex != nSheetPattern ) { wb.removeSheetAt(nIndex); }
175                                        }
176
177                                        if( hasRefSheet ) { nSheetPattern = wb.getSheetIndex(refSheetName); }
178                                }
179                        }
180                        else {
181                                // 新規の場合シートが存在すると、そのシートを削除
182                                if( -1 < nSheetIndex && !isAppend() && ( nSheetIndex != nSheetPattern ) && hasFile ) {
183                                        wb.removeSheetAt(nSheetIndex);
184                                }
185                        }
186                        // シートを削除して、もう一回雛型シートの位置を求める
187
188                        if( hasRefSheet ) { nSheetPattern = wb.getSheetIndex(refSheetName); }
189                        
190                        sheet = (-1 >= nSheetPattern) ? wb.createSheet() : wb.cloneSheet(nSheetPattern);
191
192                        // 雛型ファイルを使っていた場合、その雛形シートを削除する
193                        if(isRefFile) { wb.removeSheetAt(nSheetPattern); }
194                }
195
196                wb.setSheetName(wb.getNumberOfSheets() -1, getNewSheetNameByName(wb, sheetName) );
197
198                // poi.xssf対応(2009/04/08)
199                createHelper = wb.getCreationHelper();
200
201                nRowIndex = 0;
202
203                super.writeDBTable( null );
204
205                // 余計な行を削除
206                removeSheetRow( sheet, nRowIndex );
207
208                // メモリ中のデータをファイルに書き込む
209                // 3.5.6.0 (2004/06/18) close を finally で処理するように変更。
210                try {
211                        FileOutputStream fileOut = null ;
212                        try {
213                                fileOut = new FileOutputStream(filename);
214                                wb.write(fileOut);
215                        }
216                        finally {
217                                Closer.ioClose( fileOut );              // 4.0.0 (2006/01/31) close 処理時の IOException を無視
218                                if( null != sheet ) { sheet = null; }
219                                if( null != wb    ) { wb    = null; }
220                        }
221                }
222                catch( IOException e) {
223                        String errMsg = "ファイルへ書込み中にエラーが発生しました。"
224                                                + "  File=" + filename;                         // 5.1.8.0 (2010/07/01) errMsg 修正
225                        throw new HybsSystemException( errMsg,e );              // 3.5.5.4 (2004/04/15) 引数の並び順変更
226                }
227
228                // メモリ中のデータをファイルに書き込む
229        }
230
231        /**
232         * DBTableModel から データを作成して,PrintWriter に書き出します。
233         *
234         * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。
235         * @og.rev 3.5.4.3 (2004/01/05) 引数に PrintWriter を受け取るように変更します。
236         * @og.rev 3.8.5.3 (2006/08/07) フォント名やフォントサイズの指定
237         * @og.rev 4.0.0.0 (2006/09/31) UnsupportedOperationException を発行します。
238         *
239         * @param       writer PrintWriterオブジェクト
240         */
241        @Override
242        public void writeDBTable( final PrintWriter writer )  {
243                String errMsg = "このクラスでは実装されていません。";
244                throw new UnsupportedOperationException( errMsg );
245        }
246
247        /**
248         * PrintWriter に DBTableModelのラベル情報を書き込みます。
249         * 第一カラム目は、ラベル情報を示す "#Label" を書き込みます。
250         * この行は、出力形式に無関係に、TableWriter.TAB_SEPARATOR で区切られます。
251         *
252         * @og.rev 5.1.4.0 (2010/03/01) useNumber属性対応
253         *
254         * @param       table  DBTableModelオブジェクト
255         * @param       writer PrintWriterオブジェクト
256         */
257        @Override
258        protected void writeLabel( final DBTableModel table,final PrintWriter writer ) {
259                short nColIndex;
260                Row  oRow;
261
262                nColIndex = 0;
263                oRow = setFirstCellValue( nRowIndex++, nColIndex++, "#Label" );
264                for( int i=0; i<numberOfColumns; i++ ) {
265                        int clm = clmNo[i];
266                        String val = dbColumn[clm].getLabel();
267                        // 5.1.4.0 (2010/03/01) useNumber=false の場合は、nColIndex を一つ戻して、値に # を付ける。
268                        if( i==0 && !useNumber ) {
269                                nColIndex-- ;
270                                val = "#" + val;
271                        }
272//                      setRowCellValue( oRow, nColIndex++, dbColumn[clm].getLabel(),Cell.CELL_TYPE_STRING );
273                        setRowCellValue( oRow, nColIndex++, val,Cell.CELL_TYPE_STRING );
274                }
275
276                // 余計なセルを削除
277                removeRowCell( oRow, nColIndex );
278        }
279
280        /**
281         * PrintWriter に DBTableModelの項目名情報を書き込みます。
282         * 第一カラム目は、項目名情報を示す "#Name" を書き込みます。
283         * この行は、出力形式に無関係に、TableWriter.TAB_SEPARATOR で区切られます。
284         *
285         * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。
286         * @og.rev 5.1.4.0 (2010/03/01) useNumber属性対応
287         *
288         * @param       table  DBTableModelオブジェクト
289         * @param       writer PrintWriterオブジェクト
290         */
291        @Override
292        protected void writeName( final DBTableModel table,final PrintWriter writer ) {
293                short nColIndex;
294                Row  oRow;
295
296                nColIndex = 0;
297                oRow = setFirstCellValue( nRowIndex++, nColIndex++, "#Name" );
298                for( int i=0; i<numberOfColumns; i++ ) {
299                        int clm = clmNo[i];
300                        String val = table.getColumnName(clm);
301                        // 5.1.4.0 (2010/03/01) useNumber=false の場合は、nColIndex を一つ戻して、値に # を付ける。
302                        if( i==0 && !useNumber ) {
303                                nColIndex-- ;
304                                val = "#" + val;
305                        }
306//                      setRowCellValue( oRow, nColIndex++, table.getColumnName(clm),HSSFCell.CELL_TYPE_STRING );
307                        setRowCellValue( oRow, nColIndex++, val,Cell.CELL_TYPE_STRING );
308                }
309
310                // 余計なセルを削除
311                removeRowCell( oRow, nColIndex );
312        }
313
314        /**
315         * PrintWriter に DBTableModelのサイズ情報を書き込みます。
316         * 第一カラム目は、サイズ情報を示す "#Size" を書き込みます。
317         * この行は、出力形式に無関係に、TableWriter.TAB_SEPARATOR で区切られます。
318         *
319         * @og.rev 3.5.5.5 (2004/04/23) DBColumn の size と maxlength の 意味を変更
320         * @og.rev 5.1.4.0 (2010/03/01) useNumber属性対応
321         *
322         * @param       table  DBTableModelオブジェクト
323         * @param       writer PrintWriterオブジェクト
324         */
325        @Override
326        protected void writeSize( final DBTableModel table,final PrintWriter writer ) {
327                short nColIndex;
328                Row  oRow;
329
330                nColIndex = 0;
331                oRow = setFirstCellValue( nRowIndex++, nColIndex++, "#Size" );
332                for( int i=0; i<numberOfColumns; i++ ) {
333                        int clm = clmNo[i];
334                        // 4.0.0 (2005/01/31) メソッド名変更
335                        String val = String.valueOf(dbColumn[clm].getTotalSize());
336                        // 5.1.4.0 (2010/03/01) useNumber=false の場合は、nColIndex を一つ戻して、値に # を付ける。
337                        if( i==0 && !useNumber ) {
338                                nColIndex-- ;
339                                val = "#" + val;
340                        }
341                        setRowCellValue( oRow, nColIndex++, val, Cell.CELL_TYPE_NUMERIC );
342                }
343
344                // 余計なセルを削除
345                removeRowCell( oRow, nColIndex );
346        }
347
348        /**
349         * PrintWriter に DBTableModelのクラス名情報を書き込みます。
350         * 第一カラム目は、サイズ情報を示す "#Class" を書き込みます。
351         * この行は、出力形式に無関係に、TableWriter.TAB_SEPARATOR で区切られます。
352         *
353         * @og.rev 5.1.4.0 (2010/03/01) useNumber属性対応
354         *
355         * @param       table  DBTableModelオブジェクト
356         * @param       writer PrintWriterオブジェクト
357         */
358        @Override
359        protected void writeClass( final DBTableModel table,final PrintWriter writer ) {
360                short nColIndex;
361                Row  oRow;
362
363                nColIndex = 0;
364                oRow = setFirstCellValue( nRowIndex++, nColIndex++, "#Class" );
365                for( int i=0; i<numberOfColumns; i++ ) {
366                        int clm = clmNo[i];
367                        String val = dbColumn[clm].getClassName();
368                        // 5.1.4.0 (2010/03/01) useNumber=false の場合は、nColIndex を一つ戻して、値に # を付ける。
369                        if( i==0 && !useNumber ) {
370                                nColIndex-- ;
371                                val = "#" + val;
372                        }
373//                      setRowCellValue( oRow, nColIndex++, dbColumn[clm].getClassName(),Cell.CELL_TYPE_STRING );
374                        setRowCellValue( oRow, nColIndex++, val,Cell.CELL_TYPE_STRING );
375                }
376
377                // 余計なセルを削除
378                removeRowCell( oRow, nColIndex );
379        }
380
381        /**
382         * PrintWriter に セパレーターを書き込みます。
383         * 第一カラム目は、サイズ情報を示す "#----" を書き込みます。
384         * この行は、出力形式に無関係に、TableWriter.TAB_SEPARATOR で区切られます。
385         *
386         * @og.rev 5.1.4.0 (2010/03/01) useNumber属性対応
387         *
388         * @param       table  DBTableModelオブジェクト
389         * @param       writer PrintWriterオブジェクト
390         */
391        @Override
392        protected void writeSeparator( final DBTableModel table,final PrintWriter writer ) {
393                String sep = "----" ;
394                short nColIndex;
395                Row  oRow;
396
397                nColIndex = 0;
398                oRow = setFirstCellValue( nRowIndex++, nColIndex++, "#----" );
399                for( int i=0; i<numberOfColumns; i++ ) {
400                        // 5.1.4.0 (2010/03/01) useNumber=false の場合は、単になにもしないだけ
401                        if( i==0 && !useNumber ) {
402                                continue;
403                        }
404                        setRowCellValue( oRow, nColIndex++, sep,Cell.CELL_TYPE_STRING );
405                }
406
407                // 余計なセルを削除
408                removeRowCell( oRow, nColIndex );
409        }
410
411        /**
412         * PrintWriter に DBTableModelのテーブル情報を書き込みます。
413         * このクラスでは,データを ダブルコーテーション(")で囲みます。
414         * PrintWriter に DBTableModelのテーブル情報を書き込みます。
415         *
416         * @og.rev 3.8.0.1 (2005/06/17) DBTypeが NVAR の場合は、元のUnicodeに戻します。
417         * @og.rev 3.8.5.3 (2006/08/07) DBType の nativeType に対応した、CELL_TYPE をセットします。
418         * @og.rev 4.1.1.2 (2008/02/28) NativeタイプをEnum型(fukurou.model.NativeType)に変更
419         * @og.rev 5.1.4.0 (2010/03/01) columns 対応
420         * @og.rev 5.1.4.0 (2010/03/01) useNumber属性対応
421         * @og.rev 5.2.1.0 (2010/10/01) useRenderer 対応
422         * @og.rev 5.7.6.3 (2014/05/23) stringOutput対応
423         *
424         * @param       table  DBTableModelオブジェクト
425         * @param       writer PrintWriterオブジェクト
426         */
427        @Override
428        protected void writeData( final DBTableModel table,final PrintWriter writer ) {
429                int numberOfRows =      table.getRowCount();
430
431                short nColIndex;
432                Row  oRow;
433
434                // 5.1.4.0 columns 対応。forループは、引数i で廻す。
435                boolean[] nvar = new boolean[numberOfColumns];
436                int[] cellType = new int[numberOfColumns];
437                for( int i=0; i<numberOfColumns; i++ ) {
438                        int clm = clmNo[i];
439                        NativeType nativeType = dbColumn[clm].getNativeType();
440                        switch( nativeType ) {
441                                case INT    :
442                                case LONG   :
443                                case DOUBLE :
444                                        cellType[i] = Cell.CELL_TYPE_NUMERIC ;
445                                                break;
446                                case STRING :
447                                case CALENDAR :
448                                default :
449                                                cellType[i] = Cell.CELL_TYPE_STRING ;
450                                                break;
451                        }
452                        nvar[i] = "NVAR".equals( dbColumn[clm].getDbType()) ;
453                        
454                        // 5.7.6.3 (2014/05/23) ここでレンデラ時の文字タイプ判定を行う
455                        if( isUseRenderer() && dbColumn[clm].isStringOutput() ){
456                                cellType[i] = Cell.CELL_TYPE_STRING ;
457                        }
458                        
459                }
460                boolean useRenderer = isUseRenderer();  // 5.2.1.0 (2010/10/01)
461
462                for( int row=0; row<numberOfRows; row++ ) {
463                        nColIndex = 0;
464                        oRow = setFirstCellValue( nRowIndex++, nColIndex++, String.valueOf( row+1 ) );
465
466                        // 5.1.4.0 (2010/03/01) useNumber=false の場合は、nColIndex を一つ戻す。
467                        if( !useNumber ) {
468                                nColIndex-- ;
469                        }
470
471                        for( int i=0; i<numberOfColumns; i++ ) {
472                                int clm = clmNo[i];
473                                String val = table.getValue(row,clm);
474                                if( nvar[i] ) {
475                                        val = StringUtil.getReplaceEscape( val );
476                                }
477                                // 5.2.1.0 (2010/10/01) useRenderer 対応
478                                else if( useRenderer ) {
479                                        val = StringUtil.spanCut( dbColumn[clm].getRendererValue( val ) );
480                                }
481
482                                setRowCellValue( oRow, nColIndex++, val,cellType[i] );
483                        }
484
485                        // 余計なセルを削除
486                        removeRowCell( oRow, nColIndex );
487                }
488        }
489
490        /**
491         * Excelの指定行の一番目セルにデータを設定する。
492         *
493         * @og.rev 4.3.4.0 (2008/12/01) POI3.2対応
494         * @og.rev 4.3.4.3 (2008/12/22) protected化
495         *
496         * @param        indexOfRow 行の番号
497         * @param        indexOfCell セルの番号
498         * @param        dataVal    String文字列
499         *
500         * @return       Rowのobject型
501         */
502        protected Row setFirstCellValue( final int indexOfRow, final int indexOfCell, final String dataVal ) {
503                Row  oRow = sheet.getRow( indexOfRow );
504                if( oRow == null ) { oRow = sheet.createRow( indexOfRow ); }
505                Cell oCell = oRow.getCell( indexOfCell );
506                if( null == oCell ) { oCell = oRow.createCell( indexOfCell ); }
507
508                RichTextString richText = createHelper.createRichTextString( dataVal );
509                oCell.setCellValue( richText );
510
511                return oRow;
512        }
513
514        /**
515         * Excelの指定セルにデータを設定する。
516         *
517         * @og.rev 4.3.4.0 (2008/12/01) POI3.2対応
518         * @og.rev 4.3.4.3 (2008/12/22) protected化
519         * @og.rev 5.7.4.1 (2014/03/15) useRenderer対応
520         * @og.rev 5.7.6.3 (2014/05/23) stringOutput対応
521         *
522         * @param        oThisRow   Row型のオブジェクト
523         * @param        indexOfCell セルの番号
524         * @param        dataVal    String文字列
525         * @param        cellType   [Cell.CELL_TYPE_STRING/Cell.CELL_TYPE_NUMERIC]
526         */
527        protected void setRowCellValue( final Row oThisRow, final int indexOfCell, final String dataVal,final int cellType ) {
528                Cell oCell = oThisRow.getCell( indexOfCell );
529                if( null == oCell ) { oCell = oThisRow.createCell( indexOfCell ); }
530
531                // 5.7.4.1 (2014/03/15) useRendererがtrueの場合はdouble変換をかけない
532                // 5.7.6.3 (2014/05/23) 判定方法変更(stringOutputを利用)
533//              if( cellType == Cell.CELL_TYPE_NUMERIC ) {
534//              if( !isUseRenderer() && cellType == Cell.CELL_TYPE_NUMERIC ) {
535                if( cellType == Cell.CELL_TYPE_NUMERIC ) {
536                        oCell.setCellValue( StringUtil.parseDouble( dataVal ) );
537                }
538                else {
539                        RichTextString richText = createHelper.createRichTextString( dataVal );
540                        oCell.setCellValue( richText );
541                }
542        }
543
544        /**
545         * Excelの指定セルをシートから削除する。
546         *
547         * @og.rev 4.3.4.0 (2008/12/01) POI3.2対応
548         * @og.rev 4.3.4.3 (2008/12/22) protected化
549         *
550         * @param        oThisRow   Row型のオブジェクト
551         * @param        nBegin     セルの開始番号
552         */
553        protected void removeRowCell( final Row oThisRow, final int nBegin ) {
554                int nEnd = oThisRow.getLastCellNum();
555                for( int nIndex = nBegin; nIndex <= nEnd; nIndex++) {
556                        Cell oCell = oThisRow.getCell( nIndex );
557                        if( null != oCell ) { oThisRow.removeCell(oCell); }
558                }
559        }
560
561        /**
562         * Excelの指定行をシートから削除する。
563         *
564         * @param        oThisSheet Sheet型のオブジェクト
565         * @param        nBegin     行の開始番号
566         */
567        private void removeSheetRow( final Sheet oThisSheet, final int nBegin ) {
568                int nEnd = oThisSheet.getLastRowNum();
569                for( int nIndex = nBegin; nIndex <= nEnd; nIndex++) {
570                        Row oRow = oThisSheet.getRow( nIndex );
571                        if( null != oRow ) { oThisSheet.removeRow(oRow); }
572                }
573        }
574
575        /**
576         * DBTableModelのデータとして書き込むときのシート名をセットします。
577         * 初期値は、"Sheet1" です。同じ名称のシートが存在する場合、そのシート
578         * 名の後に(2)、(3)のような文字列をくっ付けます。
579         *
580         * @param        workbook   Workbookオブジェクト
581         * @param        nameSet    String文字列,指定のシート名
582         *
583         * @return      シート名
584         */
585        protected String getNewSheetNameByName( final Workbook workbook, final String nameSet) {
586                String nameSheet = nameSet;
587                String strAppendix;
588                // POIのソースからみると、シートの名前は30桁文字(31個文字)だと思われる。
589                int nMaxLen = 30;
590                int nCount = 1;
591                int nIndex = 0;
592                while( nIndex > -1) {
593                        if( nCount >= 2 ) {
594                                strAppendix = "(" + Integer.toString(nCount) + ")";
595                                if(nameSet.length() < ( nMaxLen - strAppendix.length()) ) {
596                                        nameSheet = nameSet + strAppendix;
597                                }else {
598                                        nameSheet = nameSet.substring(0, nMaxLen - strAppendix.length()) + strAppendix;
599                                }
600                        }
601                        nIndex = workbook.getSheetIndex(nameSheet);
602                        nCount++;
603                }
604
605                return nameSheet;
606        }
607
608        /**
609         * DBTableModelのデータとして読み込むときのシート名を設定します。
610         * 初期値は、"Sheet1" です。
611         * これは、EXCEL追加機能として実装されています。
612         *
613         * @og.rev 3.5.4.2 (2003/12/15) 新規追加
614         *
615         * @param   sheetName シート名
616         */
617        @Override
618        public void setSheetName( final String sheetName ) {
619                if( sheetName != null ) { this.sheetName = sheetName; }
620        }
621
622        /**
623         * EXCEL雛型参考ファイルのシート名を設定します。
624         * これは、EXCEL追加機能として実装されています。
625         *
626         * EXCELファイルを書き出す時に、雛型として参照するシート名を指定します。
627         * これにより、複数の形式の異なるデータを順次書き出したり(appendモードを併用)する
628         * ことや、シートを指定して新規にEXCELを作成する場合にフォームを設定する事が可能になります。
629         * 初期値は、null(第一シート) です。
630         *
631         * @og.rev 3.5.4.3 (2004/01/05) 新規追加
632         *
633         * @param   sheetName シート名
634         */
635        @Override
636        public void setRefSheetName( final String sheetName )  {
637                if( sheetName != null ) { refSheetName = sheetName; }
638        }
639
640        /**
641         * このクラスが、EXCEL対応機能を持っているかどうかを返します。
642         *
643         * EXCEL対応機能とは、シート名のセット、雛型参照ファイル名のセット、
644         * 書き込み元ファイルのFileオブジェクト取得などの、特殊機能です。
645         * 本来は、インターフェースを分けるべきと考えますが、taglib クラス等の
646         * 関係があり、問い合わせによる条件分岐で対応します。
647         *
648         * @og.rev 3.5.4.3 (2004/01/05) 新規追加
649         *
650         * @return      EXCEL対応機能を持っているかどうか(常に true)
651         */
652        @Override
653        public boolean isExcel() {
654                return true;
655        }
656
657        /**
658         * 出力先ファイル名をセットします。(DIR + Filename)
659         * これは、EXCEL追加機能として実装されています。
660         *
661         * @og.rev 3.5.4.3 (2004/01/05) 新規作成
662         *
663         * @param   filename EXCEL雛型参考ファイル名
664         */
665        @Override
666        public void setFilename( final String filename ) {
667                this.filename = filename;
668        }
669
670        /**
671         * EXCEL雛型参考ファイル名をセットします。(DIR + Filename)
672         * これは、EXCEL追加機能として実装されています。
673         *
674         * @og.rev 3.5.4.3 (2004/01/05) 新規作成
675         *
676         * @param   filename EXCEL雛型参考ファイル名
677         */
678        @Override
679        public void setRefFilename( final String filename ) {
680                refFilename = filename;
681        }
682
683        /**
684         * EXCEL出力時のデフォルトフォント名を設定します。
685         * これは、EXCEL追加機能として実装されています。
686         *
687         * EXCELファイルを書き出す時に、デフォルトフォント名を指定します。
688         * フォント名は、EXCELのフォント名をそのまま使用してください。
689         * 内部的に、POI の org.apache.poi.hssf.usermodel.HSSFFont#setFontName( String )
690         * に設定されます。
691         * 初期値は、システムリソース の TABLE_WRITER_DEFAULT_FONT_NAME です。
692         *
693         * @og.rev 3.8.5.3 (2006/08/07) 新規追加
694         *
695         * @param   fontName デフォルトフォント名
696         */
697        @Override
698        public void setFontName( final String fontName ) {
699                this.fontName = fontName ;
700        }
701
702        /**
703         * EXCEL出力時のデフォルトフォントポイント数を設定します。
704         * これは、EXCEL追加機能として実装されています。
705         *
706         * EXCELファイルを書き出す時に、デフォルトポイント数を指定します。
707         * 内部的に、POI の org.apache.poi.hssf.usermodel.HSSFFont#setFontHeightInPoints( short )
708         * に設定されます。
709         * 初期値は、システムリソース の TABLE_WRITER_DEFAULT_FONT_POINTS です。
710         *
711         * @og.rev 3.8.5.3 (2006/08/07) 新規追加
712         *
713         * @param   point デフォルトフォントポイント数
714         */
715        @Override
716        public void setFontPoint( final short point ) {
717                fontPoint = point;
718        }
719
720        /**
721         * EXCELファイルのWookbookというStream(MicrosoftのOLE用語)を作ります
722         * 条件によって、新規かとファイルから読み込み書き込みかが分かれます。
723         *
724         * @param   fname EXCEL雛型参考ファイル名
725         *
726         * @return  EXCELファイルのWorkbook
727         */
728        protected Workbook createWorkbook( final String fname ) {
729                final Workbook myWookbook ;
730                FileInputStream fileIn  = null;
731                try {
732                        fileIn = new FileInputStream(fname);
733                        myWookbook = WorkbookFactory.create(fileIn);
734                }
735                catch ( Exception ex ) {
736                        String errMsg = "ファイル読込みエラー[" + fname + "]"  ;
737                        throw new HybsSystemException( errMsg,ex );             // 3.5.5.4 (2004/04/15) 引数の並び順変更
738                }
739                finally {
740                        Closer.ioClose( fileIn );               // 4.0.0 (2006/01/31) close 処理時の IOException を無視
741                }
742
743                return myWookbook;
744        }
745
746        /**
747         * 指定の名前のファイルを使うかどうか確認します。
748         *
749         * @param   fname EXCEL雛型参考ファイル名
750         *
751         * @return      指定の名前のファイルを使うかどうか
752         */
753        private boolean checkAvailabity( final String fname ) {
754                boolean bRet = false;
755                // 4.0.0.0 (2007/11/29) 入れ子if の統合
756                if( isAppend() && null != fname ) {
757                        File oFile = new File(fname);
758                        if(oFile.exists() &&  oFile.isFile() && (oFile.length() > 0)) { bRet = true; }
759                }
760                return bRet;
761        }
762}