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