    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}