    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}