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;
019import java.io.File;                                                                            // 6.2.0.0 (2015/02/27)
020
021import org.opengion.fukurou.model.NativeType;
022import org.opengion.fukurou.util.StringUtil;
023import org.opengion.hayabusa.common.HybsSystemException;
024import org.opengion.hayabusa.db.DBTableModel;
025import org.opengion.hayabusa.db.DBColumn;
026
027import org.opengion.fukurou.model.ExcelModel;
028
029/**
030 * ネイティブEXCELファイルの書き出しクラスです。
031 *
032 * DefaultTableWriter を継承していますので、ラベル、名前、データの出力部のみ
033 * オーバーライドして、MIcrosoft Excelファイルの出力機能を実現しています。
034 *
035 * 出力形式は、openXML形式にも対応しています。
036 * 出力ファイルの拡張子が、.xlsならExcel2003のバイナリ形式、.xlsxならExcel2007の
037 * openXML形式で出力されます。
038 *
039 * useCellStyle      = [false/true];  データを書き込んだ範囲に罫線を入れる(true)かどうか(初期値:false)
040 * useAutoCellSize   = [false/true];  セルの幅をデータの幅に自動的に合わせる(true)かどうか(初期値:false)
041 * useActiveWorkbook = [false/true];  セルの有効範囲を設定する(true)かどうか(初期値:false)
042 * pageBreakColumn   = PBCLM;         シートブレイクするキーとなるカラム名を指定します(このカラムの値がシート名になります)
043 * fileBreakColumn   = FBCLM;         ファイルブレイクするキーとなるカラム名を指定します(このカラムの値がファイル名になります)
044 *
045 * appendモードの場合は、オリジナルが雛形ファイルになります。雛形ファイルを指定した場合は、
046 * 同じファイル名で無ければエラーになります。
047 *
048 * @og.group ファイル出力
049 *
050 * @og.rev 4.3.4.3 (2008/12/22) 一部protected化
051 * @og.rev 4.3.6.7 (2009/05/22) ooxml形式対応
052 * @og.rev 6.0.1.2 (2014/08/08) ロジックの完全書き換え(保証もできない位・・・)
053 *
054 * @version     4.0
055 * @author      Kazuhiko Hasegawa
056 * @since       JDK5.0,
057 */
058public class TableWriter_Excel extends TableWriter_Default {
059        /** このプログラムのVERSION文字列を設定します。   {@value} */
060        private static final String VERSION = "8.5.2.0 (2023/07/14)" ;
061
062        private int             nRowIndex               ;                                               // 6.0.1.2 (2014/08/08) private化
063        private String  filename                ;                                               // 3.5.4.3 (2004/01/05)
064        private String  directory               ;                                               // 6.0.2.0 (2014/09/19) ディレクトリとファイルを分けて管理
065        private String  fileKey                 ;                                               // 6.0.2.0 (2014/09/19) ディレクトリとファイルを分けて管理
066        private String  sheetName               = "Sheet";                              // 3.5.4.3 (2004/01/05) 書き込むSheet名
067        private String  fontName                ;                                               // 3.8.5.3 (2006/08/07)
068        private short   fontPoint               = -1;                                   // 3.8.5.3 (2006/08/07)
069        private String  refFilename             ;                                               // 3.5.4.3 (2004/01/05)
070        private String  refSheetName    ;                                               // 3.5.4.3 (2004/01/05)
071        // 5.1.4.0 (2010/03/01) 行番号情報を、出力する(true)/しない(false)を指定
072        private boolean useNumber               = true;
073        private int             skipRowCount    ;                                               // 6.0.1.2 (2014/08/08) データの書き込み開始位置設定
074
075        private ExcelModel excel                ;                                               // 6.0.2.0 (2014/09/19) 新規作成
076
077        // 6.0.2.0 (2014/09/19) EXCEL関係機能追加
078        private boolean useCellStyle            ;                                       // データを書き込んだ範囲に罫線を入れるかどうかを指定します
079        private boolean useAutoCellSize         ;                                       // セルの幅をデータの幅に自動的に合わせるかどうかを指定します
080        private boolean useActiveWorkbook       ;                                       // セルの有効範囲を設定するかどうかを指定します
081        private String  fileBreakColumn         ;                                       // ファイルブレイクするキーとなるカラム名を指定します(このカラムの値がファイル名になります)
082        private String  pageBreakColumn         ;                                       // シートブレイクするキーとなるカラム名を指定します(このカラムの値がシート名になります)
083        private boolean noPageBreak                     ;                                       // 6.1.0.0 (2014/12/26) pageBreak,fileBreak 修正
084        private String  hLinkKeyColumn          ;                                       // Hyperlinkを作成するキーとなるカラム名を指定
085        private String  hLinkValColumn          ;                                       // Hyperlinkを作成する値となるカラム名を指定
086
087        private String  addTitleSheet           ;                                       // Sheet一覧を先頭Sheetに作成する場合のSheet名を指定します
088
089        private int             pageBreakClmNo          = -1;                           // シートブレイクするキーとなるカラムNo
090        private int             fileBreakClmNo          = -1;                           // ファイルブレイクするキーとなるカラムNo
091        private int             hLinkKeyClmNo           = -1;                           // Hyperlinkを作成するキーとなるカラムNo
092        private int             hLinkValClmNo           = -1;                           // Hyperlinkを作成する値となるカラムNo
093        private int             tblRow                          ;                                       // シートブレイクしても、データは続きから出力します。
094
095//      private boolean[] nvar                          ;                                       // 6.0.2.0 (2014/09/19) writeData( DBTableModel ,PrintWriter ) で使うカラム情報 8.5.2.0 (2023/07/14) Delete
096        private boolean[] isNums                        ;                                       // 6.0.2.0 (2014/09/19) writeData( DBTableModel ,PrintWriter ) で使うカラム情報
097
098        // 5.9.12.1 (2016/09/09) シート上書き設定
099        private boolean         sheetOverwrite          ;                               // 5.9.12.1 (2016/09/09)
100        private String[]        recalcSheetNames        ;                               // 5.9.12.1 (2016/09/09)
101
102        /**
103         * デフォルトコンストラクター
104         *
105         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
106         */
107        public TableWriter_Excel() { super(); }         // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
108
109        /**
110         * DBTableModel から 各形式のデータを作成して、PrintWriter に書き出します。
111         * このメソッドは、EXCEL 書き出し時に使用します。
112         *
113         * 雛形シートを使う場合は、雛形シートの後ろに追加していきます。
114         * 最後には、雛形シートとして存在しな部分は、すべて削除します。
115         * 雛形シートを使わない場合は、新規シートに追加していくことになります。
116         * appendモードの場合は、オリジナルが雛形ファイルになります。
117         * 雛形ファイルの指定は、無効になります。
118         *
119         * @og.rev 4.0.0.0 (2006/09/31) 新規追加
120         * @og.rev 5.1.4.0 (2010/03/01) columns 対応 、useNumber属性対応
121         * @og.rev 6.0.1.2 (2014/08/08) ロジックの完全書き換え(保証もできない位・・・)
122         * @og.rev 6.0.2.0 (2014/09/19) EXCEL新機能追加
123         * @og.rev 6.1.0.0 (2014/12/26) Excel関係改善
124         * @og.rev 6.2.0.0 (2015/02/27) ファイル引数を、String → File に変更
125         * @og.rev 6.2.2.3 (2015/04/10) 雛形シートにそのままデータを書き込んでいく。シートは削除不要
126         * @og.rev 5.9.12.1 (2016/09/09) sheetOverwrite,recalcSheetNames
127         * @og.rev 6.5.0.0 (2016/09/30) セルの計算式の再計算をさせる recalcSheetNames 属性の追加。(5.9.12.1 (2016/09/09))
128         *
129         * @see #isExcel()
130         */
131        @Override
132        public void writeDBTable() {
133                if( ! createDBColumn() ) { return ; }           // 親クラスを改造。2回実行されない。
134
135                useNumber = isUseNumber();
136
137                // 3.5.6.0 (2004/06/18) 移動
138                if( filename == null ) {
139                        final String errMsg = "ファイルが指定されていません。";
140                        throw new HybsSystemException( errMsg );
141                }
142
143                // appendモードの場合は、オリジナルが雛形ファイルになります。
144                // 雛形ファイルの指定は、無効になります。
145                if( isAppend() ) {
146                        // 互換性のため、雛形ファイルが出力ファイルと同じでない場合はエラーとします。
147                        if( refFilename != null && !filename.equalsIgnoreCase( refFilename ) ) {
148                                final String errMsg = "追加(appendモード)の時、雛形ファイルの指定は無効です。" + CR
149                                                                + " filename=[" + filename + "] , refFilename=[" + refFilename + "]" + CR ;
150                                throw new HybsSystemException( errMsg );
151                        }
152
153                        refFilename = filename ;
154                }
155
156                // 雛形があれば、雛形ファイルを読み込みます。なければ、オリジナルのファイルを読み込みます。
157                // 6.3.9.1 (2015/11/27) Found 'DD'-anomaly for variable(PMD)
158                final boolean isRefFile = refFilename != null && refFilename.length() > 0;
159                final String nameUse = isRefFile ? refFilename : filename ;             // 6.3.9.1 (2015/11/27)
160
161                initWriteData();                                                // 6.0.2.0 (2014/09/19) カラム関連の初期化
162
163                final boolean isDebug = isDebug();              // 6.1.0.0 (2014/12/26) デバッグ情報
164
165                // 6.1.0.0 (2014/12/26) useRenderer 時に使用。できるだけループ内処理を避ける。
166                final DBColumn fileBreakClm = fileBreakClmNo >= 0 && isUseRenderer() ? dbColumn[fileBreakClmNo] : null ;
167                final DBColumn pageBreakClm = pageBreakClmNo >= 0 && isUseRenderer() ? dbColumn[pageBreakClmNo] : null ;
168
169                // ファイルブレイクの初期値を求めます。(fileKey は、setFilename(String,String) で、初期値セット済み)
170                if( fileBreakClmNo >= 0 ) { fileKey = table.getValue( tblRow,fileBreakClmNo ); }
171                // 処理のループを抜ける条件は、すべてのデータを書出し終わった場合。fileKey = null をセットします。
172                while( fileKey != null ) {
173                        // fileKey は、super.writeDBTable( null ) で、writeData( DBTableModel ,PrintWriter )で、再セットされる。
174                        final String fileKey_ren = fileBreakClm == null ? fileKey : fileBreakClm.getWriteValue( fileKey );
175
176                        // ExcelModelで作成。新規の場合は、nameUseの拡張子(.xlsx/.xls)に応じて、タイプが変わります。
177                        excel = new ExcelModel( new File( nameUse ) , isRefFile );              // 6.2.0.0 (2015/02/27)
178
179                        // 雛形シートを使わない場合のみ、フォント設定を行う。
180                        if( !isRefFile ) { excel.setFont( fontName,fontPoint ); }
181                        // 6.0.2.0 (2014/09/19) 新機能追加
182                        if( useCellStyle ) { excel.setCellStyle(); }
183                        excel.useAutoCellSize( useAutoCellSize );
184                        excel.setRecalcSheetName( recalcSheetNames );                                   // 6.5.0.0 (2016/09/30) セルの計算式の再計算をさせる recalcSheetNames 属性の追加。
185                        excel.setAddTitleSheet( addTitleSheet );
186
187                        if( isRefFile ) { excel.setRefSheetName( refSheetName ); }
188
189                        // シートブレイクする場合は、sheetName名をあらかじめ取得する。
190                        if( pageBreakClmNo >= 0 ) { sheetName = table.getValue( tblRow,pageBreakClmNo ); }
191                        noPageBreak = true ;    // ファイルブレイク、シートブレイクの場合は、false をセット
192                        while( noPageBreak ) {
193                                // 6.1.0.0 (2014/12/26) デバッグ情報
194                                if( isDebug ) { System.out.println( " file=" + fileKey + " , sheet=" + sheetName + " , row=" + tblRow ) ; }
195
196                                // シート名のセット。重複チェックと新しいシート名の作成処理を行う。
197                                final String sheetName_ren = pageBreakClm == null ? sheetName : pageBreakClm.getWriteValue( sheetName );
198                //              excel.createSheet( sheetName_ren );
199                                excel.createSheet( sheetName_ren , sheetOverwrite );
200
201                                nRowIndex = skipRowCount;               // 6.0.1.2 (2014/08/08) 開始行の指定
202
203                                // この super.writeDBTable(null) 内から、各種実態のメソッドが呼ばれる。
204                                // シートブレイク,ファイルブレイク は、writeData( DBTableModel ,PrintWriter ) で処理される。
205                                // シートブレイクすると、新しい sheetName がセットされ、noPageBreak=false がセットされる。
206                                // ファイルブレイクすると、新しい fileKey がセットされ、noPageBreak=false がセットされる。
207                                super.writeDBTable( null );
208
209                                // 指定以降の余計な行を削除
210                                excel.removeRow( nRowIndex );
211                        }
212
213                        // 6.0.2.0 (2014/09/19) activeWorkbook は、全シートに対して、最後に適用する。
214                        if( useActiveWorkbook ) { excel.activeWorkbook( false ); }              // false は Cellの末尾削除は行わない。
215
216                        // メモリ中のデータをファイルに書き込む
217                        excel.saveFile( new File( directory,fileKey_ren ) );                    // 6.2.0.0 (2015/02/27)
218                }
219        }
220
221        /**
222         * PrintWriter に DBTableModelのヘッダー情報を書き込みます。
223         * ここでは、ラベル情報を同じデータを出力します。
224         *
225         * @og.rev 7.2.6.1 (2020/07/17) H:Header(ヘッダー)属性追加。
226         *
227         * @param       table   DBTableModelオブジェクト
228         * @param       writer  PrintWriterオブジェクト
229         */
230        @Override
231        protected void writeLabel2( final DBTableModel table,final PrintWriter writer ) {
232                writeLabel( table,writer );
233        }
234
235        /**
236         * PrintWriter に DBTableModelのラベル情報を書き込みます。
237         * 第一カラム目は、ラベル情報を示す "#Label" を書き込みます。
238         * この行は、出力形式に無関係に、TableWriter.TAB_SEPARATOR で区切られます。
239         *
240         * @og.rev 5.1.4.0 (2010/03/01) useNumber属性対応
241         * @og.rev 6.0.1.2 (2014/08/08) カラム飛ばしできる機能を追加
242         * @og.rev 6.2.3.0 (2015/05/01) writeKeyLabel 属性を追加
243         * @og.rev 6.2.4.2 (2015/05/29) StringUtil#tagCut(String) をラベルに適用します。
244         *
245         * @param       table   DBTableModelオブジェクト
246         * @param       writer  PrintWriterオブジェクト
247         */
248        @Override
249        protected void writeLabel( final DBTableModel table,final PrintWriter writer ) {
250                short nColIndex = 0;
251                excel.createRow( nRowIndex++ );
252                if( useNumber ) { headerCellValue( "Label",nColIndex++ ); }
253
254                for( int i=0; i<numberOfColumns; i++ ) {
255                        final int clm = clmNo[i];
256                        if( clm < 0 ) {                 // 6.0.1.2 (2014/08/08) カラム飛ばし
257                                nColIndex++;
258                                continue;
259                        }
260
261                        final String val = StringUtil.tagCut( dbColumn[clm].getLabel() );       // 6.2.4.2 (2015/05/29)
262                        headerCellValue( val,nColIndex++ );
263
264                        // 6.2.3.0 (2015/05/01) keyLabelは、後ろのカラムのラベルを付けません。
265                        if( isKeyLbl[i] ) {
266                                headerCellValue( "",nColIndex++ );
267                        }
268                }
269
270                // 余計なセルを削除
271                excel.removeCell( nColIndex );
272        }
273
274        /**
275         * PrintWriter に DBTableModelの項目名情報を書き込みます。
276         * 第一カラム目は、項目名情報を示す "#Name" を書き込みます。
277         * この行は、出力形式に無関係に、TableWriter.TAB_SEPARATOR で区切られます。
278         *
279         * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。
280         * @og.rev 5.1.4.0 (2010/03/01) useNumber属性対応
281         * @og.rev 6.0.1.2 (2014/08/08) カラム飛ばしできる機能を追加
282         * @og.rev 6.2.3.0 (2015/05/01) writeKeyLabel 属性を追加
283         *
284         * @param       table   DBTableModelオブジェクト
285         * @param       writer  PrintWriterオブジェクト
286         */
287        @Override
288        protected void writeName( final DBTableModel table,final PrintWriter writer ) {
289                short nColIndex = 0;
290                excel.createRow( nRowIndex++ );
291                if( useNumber ) { headerCellValue( "Name",nColIndex++ ); }
292
293                for( int i=0; i<numberOfColumns; i++ ) {
294                        final int clm = clmNo[i];
295                        if( clm < 0 ) {                 // 6.0.1.2 (2014/08/08) カラム飛ばし
296                                nColIndex++;
297                                continue;
298                        }
299
300                        final String name = table.getColumnName( clm );
301                        headerCellValue( name,nColIndex++ );
302
303                        // 6.2.3.0 (2015/05/01) keyLabelは、後ろのカラムの項目名を付けません。
304                        if( isKeyLbl[i] ) {
305                                headerCellValue( "",nColIndex++ );
306                        }
307                }
308
309                // 余計なセルを削除
310                excel.removeCell( nColIndex );
311        }
312
313        /**
314         * PrintWriter に DBTableModelのサイズ情報を書き込みます。
315         * 第一カラム目は、サイズ情報を示す "#Size" を書き込みます。
316         * この行は、出力形式に無関係に、TableWriter.TAB_SEPARATOR で区切られます。
317         *
318         * @og.rev 3.5.5.5 (2004/04/23) DBColumn の size と maxlength の 意味を変更
319         * @og.rev 5.1.4.0 (2010/03/01) useNumber属性対応
320         * @og.rev 6.0.1.2 (2014/08/08) カラム飛ばしできる機能を追加
321         * @og.rev 6.2.3.0 (2015/05/01) writeKeyLabel 属性を追加
322         *
323         * @param       table   DBTableModelオブジェクト
324         * @param       writer  PrintWriterオブジェクト
325         */
326        @Override
327        protected void writeSize( final DBTableModel table,final PrintWriter writer ) {
328                short nColIndex = 0;
329                excel.createRow( nRowIndex++ );
330                if( useNumber ) { headerCellValue( "Size",nColIndex++ ); }
331
332                for( int i=0; i<numberOfColumns; i++ ) {
333                        final int clm = clmNo[i];
334                        if( clm < 0 ) {                 // 6.0.1.2 (2014/08/08) カラム飛ばし
335                                nColIndex++;
336                                continue;
337                        }
338
339                        // 4.0.0 (2005/01/31) メソッド名変更
340                        final String val = String.valueOf( dbColumn[clm].getTotalSize() );
341                        headerCellValue( val,nColIndex++ );
342
343                        // 6.2.3.0 (2015/05/01) keyLabelは、後ろのカラムのサイズを付けません。
344                        if( isKeyLbl[i] ) {
345                                headerCellValue( "",nColIndex++ );
346                        }
347                }
348
349                // 余計なセルを削除
350                excel.removeCell( nColIndex );
351        }
352
353        /**
354         * PrintWriter に DBTableModelのクラス名情報を書き込みます。
355         * 第一カラム目は、サイズ情報を示す "#Class" を書き込みます。
356         * この行は、出力形式に無関係に、TableWriter.TAB_SEPARATOR で区切られます。
357         *
358         * @og.rev 5.1.4.0 (2010/03/01) useNumber属性対応
359         * @og.rev 6.0.1.2 (2014/08/08) カラム飛ばしできる機能を追加
360         * @og.rev 6.2.3.0 (2015/05/01) writeKeyLabel 属性を追加
361         *
362         * @param       table   DBTableModelオブジェクト
363         * @param       writer  PrintWriterオブジェクト
364         */
365        @Override
366        protected void writeClass( final DBTableModel table,final PrintWriter writer ) {
367                short nColIndex = 0;
368                excel.createRow( nRowIndex++ );
369                if( useNumber ) { headerCellValue( "Class",nColIndex++ ); }
370
371                for( int i=0; i<numberOfColumns; i++ ) {
372                        final int clm = clmNo[i];
373                        if( clm < 0 ) {                 // 6.0.1.2 (2014/08/08) カラム飛ばし
374                                nColIndex++;
375                                continue;
376                        }
377
378                        final String val = dbColumn[clm].getClassName();
379                        headerCellValue( val,nColIndex++ );
380
381                        // 6.2.3.0 (2015/05/01) keyLabelは、後ろのカラムのクラス名を付けません。
382                        if( isKeyLbl[i] ) {
383                                headerCellValue( "",nColIndex++ );
384                        }
385                }
386
387                // 余計なセルを削除
388                excel.removeCell( nColIndex );
389        }
390
391        /**
392         * PrintWriter に セパレーターを書き込みます。
393         * 第一カラム目は、サイズ情報を示す "#----" を書き込みます。
394         * この行は、出力形式に無関係に、TableWriter.TAB_SEPARATOR で区切られます。
395         *
396         * @og.rev 5.1.4.0 (2010/03/01) useNumber属性対応
397         * @og.rev 6.2.3.0 (2015/05/01) writeKeyLabel 属性を追加
398         *
399         * @param       table   DBTableModelオブジェクト
400         * @param       writer  PrintWriterオブジェクト
401         */
402        @Override
403        protected void writeSeparator( final DBTableModel table,final PrintWriter writer ) {
404                final String SEP = "----" ;
405
406                short nColIndex = 0;
407                excel.createRow( nRowIndex++ );
408                if( useNumber ) { headerCellValue( SEP,nColIndex++ ); }
409
410                for( int i=0; i<numberOfColumns; i++ ) {
411                        final int clm = clmNo[i];
412                        if( clm < 0 ) {                 // 6.0.1.2 (2014/08/08) カラム飛ばし
413                                nColIndex++;
414                                continue;
415                        }
416                        headerCellValue( SEP,nColIndex++ );
417
418                        // 6.2.3.0 (2015/05/01) keyLabelは、後ろのカラムのセパレーターを書き込みます。
419                        if( isKeyLbl[i] ) {
420                                headerCellValue( SEP,nColIndex++ );
421                        }
422                }
423
424                // 余計なセルを削除
425                excel.removeCell( nColIndex );
426        }
427
428        /**
429         * ExcelModel#setCellValue(String.int) の第一カラムの場合に、コメントの # を追加する簡易メソッドです。
430         *
431         * colNo == 0 の場合だけ、引数の val に、"#" を追加します。
432         * これは、openGion特有のコメント行を意味するため、ヘッダーレコードにのみ適用します。
433         *
434         * @og.rev 6.0.1.2 (2014/08/08) カラム飛ばしできる機能を追加
435         *
436         * @param       val             設定文字列
437         * @param       colNo   行番号
438         */
439        private void headerCellValue( final String val,final int colNo ) {
440                if( colNo == 0 ) {
441                        excel.setCellValue( "#" + val,colNo );
442                }
443                else {
444                        excel.setCellValue( val,colNo );
445                }
446        }
447
448        /**
449         * writeData( DBTableModel ,PrintWriter ) の呼び出し前に、一度だけ実行すればよい処理をまとめました。
450         *
451         * 通常のTableWriterは、1回の DBTableModel の読み込みで、1ファイルだけ出力します。
452         * そのため、writeData( DBTableModel ,PrintWriter ) の呼び出し処理の初めに、初期化している処理があります。
453         * EXCELでは、Sheet 処理と、File 処理のループがあり、本来1回だけ初期化すればよいのですが、
454         * writeData( DBTableModel ,PrintWriter ) が複数回呼ばれるため、無駄な処理になってしまいます。
455         * ただし、今までは、ローカル変数でしたが、インスタンス変数に変更しています。
456         *
457         * @og.rev 6.0.2.0 (2014/09/19) 新規追加
458         * @og.rev 8.5.2.0 (2023/07/14) 一部の機能廃止による修正(問合・トラブル 0200010980)
459         */
460        private void initWriteData() {
461                final DBTableModel table = getDBTableModel();
462                pageBreakClmNo  = table.getColumnNo( pageBreakColumn,false );                   // シートブレイクするキーとなるカラムNo
463                fileBreakClmNo  = table.getColumnNo( fileBreakColumn,false );                   // ファイルブレイクするキーとなるカラムNo
464
465                hLinkKeyClmNo   = table.getColumnNo( hLinkKeyColumn,false );                    // Hyperlinkを作成するキーとなるカラムNo
466                hLinkValClmNo   = table.getColumnNo( hLinkValColumn,false );                    // Hyperlinkを作成する値となるカラムNo
467
468//              nvar    = new boolean[numberOfColumns];                                                                 // 8.5.2.0 (2023/07/14) Delete
469                isNums  = new boolean[numberOfColumns];                                                                 // 6.0.2.0 (2014/09/19) NUMBER型かどうか
470                final boolean useRenderer = isUseRenderer();                                                    // 5.2.1.0 (2010/10/01)
471
472                for( int i=0; i<numberOfColumns; i++ ) {
473                        final int clm = clmNo[i];
474                        if( clm < 0 ) { continue; }                     // 6.0.1.2 (2014/08/08) カラム飛ばし
475
476                        // 5.7.6.3 (2014/05/23) ここでレンデラ時の文字タイプ判定を行う
477                        if( useRenderer && dbColumn[clm].isStringOutput() ){
478                                isNums[i] = false;
479                        }
480                        else {
481                                final NativeType nativeType = dbColumn[clm].getNativeType();
482                                switch( nativeType ) {
483                                        case INT    :
484                                        case LONG   :
485                                        case DOUBLE :
486                                                isNums[i] = true;
487                                                        break;
488                                        case STRING :
489                                        case CALENDAR :
490                                        default :
491                                                        isNums[i] = false;
492                                                        break;
493                                }
494                        }
495//                      nvar[i] = "NVAR".equals( dbColumn[clm].getDbType()) ;                           // 8.5.2.0 (2023/07/14) Delete
496                }
497        }
498
499        /**
500         * PrintWriter に DBTableModelのテーブル情報を書き込みます。
501         * このクラスでは、データを ダブルコーテーション(")で囲みます。
502         * PrintWriter に DBTableModelのテーブル情報を書き込みます。
503         *
504         * @og.rev 3.8.0.1 (2005/06/17) DBTypeが NVAR の場合は、元のUnicodeに戻します。
505         * @og.rev 3.8.5.3 (2006/08/07) DBType の nativeType に対応した、CELL_TYPE をセットします。
506         * @og.rev 4.1.1.2 (2008/02/28) NativeタイプをEnum型(fukurou.model.NativeType)に変更
507         * @og.rev 5.1.4.0 (2010/03/01) columns 対応
508         * @og.rev 5.1.4.0 (2010/03/01) useNumber属性対応
509         * @og.rev 5.2.1.0 (2010/10/01) useRenderer 対応
510         * @og.rev 5.7.6.3 (2014/05/23) stringOutput対応
511         * @og.rev 6.0.1.2 (2014/08/08) カラム飛ばしできる機能を追加
512         * @og.rev 6.0.4.0 (2014/11/28) データ出力用のレンデラー
513         * @og.rev 6.2.3.0 (2015/05/01) writeKeyLabel 属性を追加
514         * @og.rev 8.5.2.0 (2023/07/14) 一部の機能廃止による修正(問合・トラブル 0200010980)
515         *
516         * @param       table   DBTableModelオブジェクト
517         * @param       writer  PrintWriterオブジェクト(未使用)
518         */
519        @Override
520        protected void writeData( final DBTableModel table,final PrintWriter writer ) {
521                final int numberOfRows    = table.getRowCount();
522                final boolean useRenderer = isUseRenderer();            // 5.2.1.0 (2010/10/01)
523
524                if( useAutoCellSize ) {
525                        excel.setDataStartRow( nRowIndex );                             // データ行の書き込み開始位置の行番号を設定
526                }
527
528                int rowNo = 1;
529                for( ; tblRow<numberOfRows; tblRow++ ) {                        // tblRow は、シートブレイクしても連続してカウントアップ
530                        // まずはファイルブレイク判定
531                        if( fileBreakClmNo >= 0 ) {
532                                // ファイルブレイクすると、noPageBreak=false と、noFileBreak=false がセットされる。
533                                final String nowFBC = table.getValue( tblRow,fileBreakClmNo );
534                                if( !fileKey.equals( nowFBC ) ) {
535                                        fileKey = nowFBC;
536                                        noPageBreak = false;
537                                        return;
538                                }
539                        }
540                        if( pageBreakClmNo >= 0 ) {
541                                // シートブレイクすると、新しい sheetName がセットされ、noPageBreak=false がセットされる。
542                                final String nowPBC = table.getValue( tblRow,pageBreakClmNo );
543                                if( !sheetName.equals( nowPBC ) ) {
544                                        sheetName = nowPBC;
545                                        return;
546                                }
547                        }
548
549                        short nColIndex = 0;
550                        excel.createRow( nRowIndex++ );
551                        if( useNumber ) { excel.setCellValue( String.valueOf( rowNo++ ),nColIndex++,true ); }
552
553                        for( int i=0; i<numberOfColumns; i++ ) {
554                                final int clm = clmNo[i];
555                                if( clm < 0 ) {                 // 6.0.1.2 (2014/08/08) カラム飛ばし
556                                        nColIndex++;
557                                        continue;
558                                }
559
560                                String val = table.getValue( tblRow,clm );
561
562                                // 6.2.3.0 (2015/05/01) keyLabelは、後ろのカラムのラベルを付けません。
563                                if( isKeyLbl[i] ) {
564                                        excel.setCellValue( val,nColIndex++,isNums[i] );
565                                }
566
567//                              if( nvar[i] ) {                                                                                                 // 8.5.2.0 (2023/07/14) Delete
568//                                      val = StringUtil.getReplaceEscape( val );                                       // 8.5.2.0 (2023/07/14) Delete
569//                              }                                                                                                                               // 8.5.2.0 (2023/07/14) Delete
570                                // 5.2.1.0 (2010/10/01) useRenderer 対応
571//                              else if( useRenderer ) {                                                                                // 8.5.2.0 (2023/07/14) Modify
572                                if( useRenderer ) {
573                                        // 6.0.4.0 (2014/11/28) データ出力用のレンデラー
574                                        val = dbColumn[clm].getWriteValue( val );
575                                }
576
577                                excel.setCellValue( val,nColIndex,isNums[i] );
578
579                                // ハイパーリンク設定は、文字の設定の後で行います。
580                                if( clm == hLinkKeyClmNo && hLinkValClmNo >= 0 ) {
581                                        final String shtNm = table.getValue( tblRow,hLinkValClmNo );
582                                        excel.setCellLink( shtNm,nColIndex );
583                                }
584
585                                nColIndex++;
586                        }
587
588                        // 余計なセルを削除
589                        excel.removeCell( nColIndex );
590                }
591                noPageBreak = false;    // 最後まで終了した
592                fileKey         = null;         // 最後まで終了した
593        }
594
595        /**
596         * 出力先ディレクトリとファイル名をセットします。
597         * これは、EXCEL追加機能として実装されています。
598         *
599         * 雛形ファイルとの関係から、内部的に filename は合成しておきます。
600         *
601         * @og.rev 3.5.4.3 (2004/01/05) 新規作成
602         * @og.rev 6.0.2.0 (2014/09/19) ディレクトリとファイルを分けて管理します。
603         *
604         * @param       dir             出力先ディレクトリ
605         * @param       fname   出力ファイル名
606         */
607        @Override
608        public void setFilename( final String dir , final String fname ) {
609                filename        = StringUtil.urlAppend( dir,fname ) ;
610
611                directory       = dir;
612                fileKey         = fname;
613        }
614
615        /**
616         * DBTableModelのデータとして読み込むときのシート名を設定します。
617         * 初期値は、"Sheet1" です。
618         * これは、EXCEL追加機能として実装されています。
619         *
620         * @og.rev 3.5.4.2 (2003/12/15) 新規追加
621         *
622         * @param       shtName シート名
623         */
624        @Override
625        public void setSheetName( final String shtName ) {
626                if( shtName != null ) { this.sheetName = shtName; }
627        }
628
629        /**
630         * このクラスが、EXCEL対応機能を持っているかどうかを返します。
631         *
632         * EXCEL対応機能とは、シート名のセット、雛型参照ファイル名のセット、
633         * 書き込み元ファイルのFileオブジェクト取得などの、特殊機能です。
634         * 本来は、インターフェースを分けるべきと考えますが、taglib クラス等の
635         * 関係があり、問い合わせによる条件分岐で対応します。
636         *
637         * @og.rev 3.5.4.3 (2004/01/05) 新規追加
638         *
639         * @return      EXCEL対応機能を持っているかどうか(常に true)
640         */
641        @Override
642        public boolean isExcel() {
643                return true;
644        }
645
646        /**
647         * EXCEL雛型参考ファイル名をセットします。(DIR + Filename)
648         * これは、EXCEL追加機能として実装されています。
649         *
650         * @og.rev 3.5.4.3 (2004/01/05) 新規作成
651         *
652         * @param       rfname  EXCEL雛型参考ファイル名
653         */
654        @Override
655        public void setRefFilename( final String rfname ) {
656                refFilename = rfname;
657        }
658
659        /**
660         * 雛形のシート名を、そのまま使用する(true)か、新規、または、外部指定のシート名を使用する(false)を指定します。(初期値:false[外部指定のシート名を使用])。
661         *
662         * ※ Ver5では、追記モード時に、指定シートが存在した場合は上書きします(初期値:false[上書きしない])。5.9.12.1 (2016/09/09)
663         *    Ver6では、追記モード時に、雛形を指定できないため、雛形のシート名を、そのまま使用する(true)か、
664         *    新規、または、外部指定のシート名を使用する(false)を指定する属性になります。
665         *
666         * @og.rev 6.5.0.0 (2016/09/30) sheetOverwrite で、雛形シートの使用時に、元のシート名を使用します。
667         *
668         * @param       flag    元のシート名を使用するかどうか[true:使用する/false:新規、または、外部指定のシート名を使用]
669         */
670        @Override
671        public void setSheetOverwrite( final boolean flag ) {
672                sheetOverwrite = flag;
673        }
674
675        /**
676         * EXCELで、出力処理の最後にセルの計算式の再計算をさせるシート名をCSV形式で指定します。
677         *
678         * @og.rev 6.5.0.0 (2016/09/30) recalcSheetName で、セル内の計算式を再計算させるシート名を指定。5.9.12.1 (2016/09/09)
679         *
680         * @param       sheet   対象シート名をCSV形式で指定
681         */
682        @Override
683        public void setRecalcSheetName( final String sheet ){
684                recalcSheetNames = StringUtil.csv2Array( sheet);
685        }
686
687        /**
688         * EXCEL雛型参考ファイルのシート名を設定します。
689         * これは、EXCEL追加機能として実装されています。
690         *
691         * EXCELファイルを書き出す時に、雛型として参照するシート名を指定します。
692         * これにより、複数の形式の異なるデータを順次書き出したり(appendモードを併用)する
693         * ことや、シートを指定して新規にEXCELを作成する場合にフォームを設定する事が可能になります。
694         * 初期値は、null(第一シート) です。
695         *
696         * @og.rev 3.5.4.3 (2004/01/05) 新規追加
697         *
698         * @param       rshtName        シート名
699         */
700        @Override
701        public void setRefSheetName( final String rshtName ) {
702                if( rshtName != null ) { refSheetName = rshtName; }
703        }
704
705        /**
706         * データの書き込み開始位置を設定します(初期値:0)。
707         *
708         * TAB区切りテキストやEXCEL等のデータの書き込みの開始位置を指定します。
709         * 属性名は、行を飛ばす処理ということで、readTable タグと同じ名称です。
710         * ファイルの先頭行が、0行としてカウントしますので、設定値は、読み飛ばす
711         * 件数になります。(1と指定すると、1件読み飛ばし、2行目から読み込みます。)
712         * 行の読み飛ばしと、カラムの読み飛ばし(columns)、refFileURL、refFilename、
713         * refSheetName とともに使用すれば、ある程度のレイアウト設定が可能です。
714         * なお、この機能は、TableWriter_Excel のみに実装します。
715         *
716         * @og.rev 6.0.1.2 (2014/08/08) 新規作成
717         *
718         * @param       skipCount       書き込み開始位置
719         */
720        @Override
721        public void setSkipRowCount( final int skipCount ) {
722                skipRowCount = skipCount ;
723        }
724
725        /**
726         * EXCEL出力時のデフォルトフォント名を設定します。
727         * これは、EXCEL追加機能として実装されています。
728         *
729         * EXCELファイルを書き出す時に、デフォルトフォント名を指定します。
730         * フォント名は、EXCELのフォント名をそのまま使用してください。
731         * 内部的に、POI の org.apache.poi.hssf.usermodel.HSSFFont#setFontName( String )
732         * に設定されます。
733         * 雛形ファイルを使用しない場合のみ、有効です。
734         *
735         * @og.rev 3.8.5.3 (2006/08/07) 新規追加
736         *
737         * @param       font    デフォルトフォント名
738         */
739        @Override
740        public void setFontName( final String font ) {
741                fontName = font ;
742        }
743
744        /**
745         * EXCEL出力時のデフォルトフォントポイント数を設定します。
746         * これは、EXCEL追加機能として実装されています。
747         *
748         * EXCELファイルを書き出す時に、デフォルトポイント数を指定します。
749         * 内部的に、POI の org.apache.poi.hssf.usermodel.HSSFFont#setFontHeightInPoints( short )
750         * に設定されます。
751         * 雛形ファイルを使用しない場合のみ、有効です。
752         *
753         * @og.rev 3.8.5.3 (2006/08/07) 新規追加
754         *
755         * @param       point   デフォルトフォントポイント数
756         */
757        @Override
758        public void setFontPoint( final short point ) {
759                fontPoint = point;
760        }
761
762        /**
763         * EXCEL出力時に、データを書き込んだ範囲に罫線を入れるかどうかを指定します。
764         *
765         * データを書き込んでEXCELを作成しても、ノーマルのセルに値がセットされている
766         * だけなので、ある程度加工が必要です。
767         * そこで、データのセットされたセルに罫線を入れることで、それなりのデータが
768         * 出力された感じになります。
769         * この設定と、useAutoCellSize="true" で、セルの幅を自動調整すれば、見栄えが良くなります。
770         * なお、この機能は、TableWriter_Excel のみに実装します。
771         *
772         * @og.rev 6.0.2.0 (2014/09/19) 新規作成
773         *
774         * @param       useCellStyle    罫線を入れるかどうか(true:入れる/false:入れない)
775         * @see         #setUseAutoCellSize( boolean )
776         */
777        @Override
778        public void setUseCellStyle( final boolean useCellStyle ) {
779                this.useCellStyle = useCellStyle;
780        }
781
782        /**
783         * EXCEL出力時に、セルの幅をデータの幅に自動的に合わせるかどうかを指定します。
784         *
785         * データを書き込んでEXCELを作成しても、ノーマルのセルに値がセットされている
786         * だけなので、ある程度加工が必要です。
787         * そこで、データのセットされたセルの幅を自動調整することで、それなりのデータが
788         * 出力された感じになります。
789         * この設定と、useCellStyle="true" で、セルの罫線を自動設定すれば、見栄えが良くなります。
790         * なお、この機能は、TableWriter_Excel のみに実装します。
791         *
792         * @og.rev 6.0.2.0 (2014/09/19) 新規作成
793         *
794         * @param       useAutoCellSize データの幅に自動的に合わせるかどうか(true:自動調整/false:何もしない)
795         * @see         #setUseCellStyle( boolean )
796         */
797        @Override
798        public void setUseAutoCellSize( final boolean useAutoCellSize ) {
799                this.useAutoCellSize = useAutoCellSize;
800        }
801
802        /**
803         * EXCEL出力時に、セルの有効範囲を設定するかどうかを指定します。
804         *
805         * セルの有効範囲というのは、EXCELでの 空行、空列の存在しない範囲を指します。
806         * 通常、空行でも、データとして残っている場合は、EXCELのセルオブジェクトは存在します。
807         * ここで、useActiveWorkbook="true" とすると、空行、空列を削除します。
808         *
809         * 雛形を使用した場合は、データより多めに設定した計算などは、この処理で
810         * 削除されますので、データサイズにフィットさせることができます。
811         * なお、この機能は、TableWriter_Excel のみに実装します。
812         *
813         * @og.rev 6.0.2.0 (2014/09/19) 新規作成
814         *
815         * @param       useActiveWorkbook       セルの有効範囲を設定するかどうか(true:設定する/false:そのまま)
816         */
817        @Override
818        public void setUseActiveWorkbook( final boolean useActiveWorkbook ) {
819                this.useActiveWorkbook = useActiveWorkbook;
820        }
821
822        /**
823         * EXCEL出力時に、シートブレイクするキーとなるカラム名を指定します(このカラムの値がシート名になります)。
824         *
825         * EXCEL帳票では、帳票雛形に、PAGE_BRAKE キーを設定しましたが、TableWriterでは、
826         * メモリ上のカラムの値が変更したときに、シートブレイクさせることができます。
827         * このカラムの値がキーブレイクすると、新しいシートに書き出し始めます。
828         * シート名は、このカラムの値(キーブレイクする値)です。
829         *
830         * 雛形ファイルを使用する場合、雛形シートもキーブレイクに伴って、+1されます。
831         * つまり、雛形シートとデータシートは同時に変更されます。
832         * ただし、雛形シートは、最後の雛形シートで止まります。
833         * これは、雛形シートにヘッダー雛形とボディ雛形を用意しておき、最初のキーブレイクで
834         * ヘッダーからボディの書き込みにチェンジするイメージで使用できます。
835         * なお、この機能は、TableWriter_Excel のみに実装します。
836         *
837         * @og.rev 6.0.2.0 (2014/09/19) 新規作成
838         *
839         * @param       pageBreakColumn シートブレイクするキーとなるカラム名を指定
840         * @see         #setFileBreakColumn( String )
841         */
842        @Override
843        public void setPageBreakColumn( final String pageBreakColumn ) {
844                this.pageBreakColumn = pageBreakColumn;
845        }
846
847        /**
848         * EXCEL出力時に、ファイルブレイクするキーとなるカラム名を指定します(このカラムの値がファイル名になります)。
849         *
850         * EXCEL帳票では、メモリ上のカラムの値が変更したときに、ファイルブレイクすることができます。
851         * このカラムの値がキーブレイクすると、新しいファイルに書き出し始めます。
852         * ファイル名は、このカラムの値(キーブレイクする値)+ 元の出力ファイル名の拡張子(.xlsなど)です。
853         * この設定を使用する場合は、出力ファイル名は無視されますが、拡張子だけは使用されます。
854         *
855         * 雛形ファイルを使用する場合、雛形ファイルもキーブレイクに伴って、再利用されます。
856         * 例えば、pageBreakColumn と併用する場合、キーブレイクで雛形シートも最初から適用になります。
857         * なお、この機能は、TableWriter_Excel のみに実装します。
858         *
859         * @og.rev 6.0.2.0 (2014/09/19) 新規作成
860         *
861         * @param       fileBreakColumn ファイルブレイクするキーとなるカラム名を指定
862         * @see         #setPageBreakColumn( String )
863         */
864        @Override
865        public void setFileBreakColumn( final String fileBreakColumn ) {
866                this.fileBreakColumn = fileBreakColumn;
867        }
868
869        /**
870         * EXCEL出力時に、Hyperlinkを作成するキーとなるカラム名と値となるカラム名を指定します。
871         *
872         * ここで、作成するハイパーリンクは、EXCELのシートに対するハイパーリンクです。
873         * それ以外のリンク(本当のURLやファイル等)のリンクは(今は)作成できません。
874         * ハイパーリンクを作成するには、①作成するカラム と ②作成する値 が必要です。
875         * このメソッドで設定するのは、「①:②」という形式でカラム名を指定します。
876         * ②がなければ、①と同じとします。
877         * ②の値のシートの存在有無は、無視します。ハイパーリンクを作成するシートを作成する前に
878         * ハイパーリンクを作成するケースが存在します。
879         * (例えば、各シートへのリンクを持った一覧を作成してから、明細の各シートを作成する様なケース)
880         * なお、この機能は、TableWriter_Excel のみに実装します。
881         *
882         * @og.rev 6.0.2.0 (2014/09/19) 新規作成
883         *
884         * @param       hyperLinkColumn Hyperlinkを作成するキーとなるカラム名と値となるカラム名を指定
885         */
886        @Override
887        public void setHyperLinkColumn( final String hyperLinkColumn ) {
888                if( hyperLinkColumn != null && hyperLinkColumn.length() > 0 ) {
889                        final int sep = hyperLinkColumn.indexOf( ':' );                                         // ①:② の形式かどうかの確認
890                        if( sep >= 0 ) {
891                                hLinkKeyColumn = hyperLinkColumn.substring( 0,sep );                    // ①キーカラム
892                                hLinkValColumn = hyperLinkColumn.substring( sep+1 );                    // ②値カラム
893                        }
894                        else {
895                                hLinkKeyColumn = hyperLinkColumn;                                                               // ①キーカラム = ②値カラム
896                                hLinkValColumn = hyperLinkColumn;
897                        }
898                }
899        }
900
901        /**
902         * EXCEL出力時に、Sheet一覧を先頭Sheetに作成する場合のSheet名を指定します。
903         *
904         * これは、Workbook に含まれる Sheet 一覧を作成する場合に、利用可能です。
905         * なお、この機能は、TableWriter_Excel のみに実装します。
906         *
907         * @og.rev 6.0.2.0 (2014/09/19) 新規作成
908         *
909         * @param       sheetName       EXCELファイルのシート名
910         */
911        @Override
912        public void setAddTitleSheet( final String sheetName ) {
913                addTitleSheet = sheetName ;
914        }
915}