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