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