    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.hayabusa.report2;
    017
    018import java.util.ArrayList;
    019import java.util.List;
    020
    021import org.opengion.hayabusa.common.HybsSystemException;
    022
    023/**
    024 * シート単位のcontent.xmlを管理するためのクラスです。
    025 * シートのヘッダー、行の配列、フッター及びシート名を管理します。
    026 *
    027 * @og.group 帳票システム
    028 *
    029 * @version  4.0
    030 * @author   Hiroki.Nakamura
    031 * @since    JDK1.6
    032 */
    033class OdsSheet {
    034
    035        //======== content.xmlのパースで使用 ========================================
    036
    037        /* 行の開始終了タグ */
    038        private static final String ROW_START_TAG = "<table:table-row ";
    039        private static final String ROW_END_TAG = "</table:table-row>";
    040
    041        /* シート名を取得するための開始終了文字 */
    042        private static final String SHEET_NAME_START = "table:name=\"";
    043        private static final String SHEET_NAME_END = "\"";
    044
    045        /* 変数定義の開始終了文字及び区切り文字 */
    046        private static final String VAR_START = "{@";
    047        private static final String VAR_END = "}";
    048        private static final String VAR_CON = "_";
    049
    050        /* ラインコピー文字列 5.0.0.2 (2009/09/15) */
    051        private static final String LINE_COPY = "LINECOPY";
    052
    053        private final List<String>        sheetRows       = new ArrayList<String>();
    054        private String                  sheetHeader;
    055        private String                  sheetFooter;
    056        private String                  sheetName;
    057        private String                  origSheetName;
    058        private String                  confSheetName;
    059
    060        /**
    061         * シートを行単位に分解します。
    062         *
    063         * @og.rev 5.0.0.2 (2009/09/15) ボディ部のカウントを引数に追加し、LINECOPY機能実装。
    064         * @og.rev 5.2.1.0 (2010/10/01) シート名定義対応
    065         *
    066         * @param sheet シート名
    067         * @param bodyRowCount 行番号
    068         */
    069        public void analyze( final String sheet, final int bodyRowCount ) {
    070                String[] tags = TagParser.tag2Array( sheet, ROW_START_TAG, ROW_END_TAG );
    071                sheetHeader = tags[0];
    072                sheetFooter = tags[1];
    073                for( int i = 2; i < tags.length; i++ ) {
    074                        sheetRows.add( tags[i] );
    075                        lineCopy( tags[i], bodyRowCount ); // 5.0.0.2 (2009/09/15)
    076                }
    077
    078                sheetName = TagParser.getValueFromTag( sheetHeader, SHEET_NAME_START, SHEET_NAME_END );
    079                origSheetName = sheetName;
    080
    081                confSheetName = null;
    082                if( sheetName != null ) {
    083                        int cnfIdx = sheetName.indexOf( "__" );
    084                        if( cnfIdx > 0 && !sheetName.endsWith( "__" ) ) {
    085                                confSheetName = sheetName.substring( cnfIdx + 2 );
    086                                sheetName = sheetName.substring( 0, cnfIdx );
    087                        }
    088                }
    089        }
    090
    091        /**
    092         * ラインコピーに関する処理を行います。
    093         *
    094         * {&#064;LINE_COPY}が存在した場合に、テーブルモデル分だけ
    095         * 行をコピーします。
    096         * その際、{&#064;xxx_y}のyをカウントアップしてコピーします。
    097         *
    098         * 整合性等のエラーハンドリングはこのメソッドでは行わず、
    099         * 実際のパース処理中で行います。
    100         *
    101         * @og.rev 5.0.0.2 (2009/09/15) 追加
    102         * @og.rev 5.1.8.0 (2010/07/01) パース処理の内部実装を変更
    103         *
    104         * @param row
    105         * @param rowCount
    106         */
    107        private void lineCopy( final String row, final int rowCount ) {
    108//              int preOffset = -1;
    109//              int curOffset = -1;
    110//
    111//              preOffset = row.indexOf( VAR_START + LINE_COPY );
    112//              // この段階で存在しなければ即終了
    113//              if( preOffset < 0 ) { return; }
    114//
    115//              curOffset = row.indexOf( VAR_END, preOffset );
    116//              String lcKey = row.substring( preOffset + VAR_START.length(), curOffset );
    117//              StringBuilder tmpBuf = new StringBuilder( row );
    118//              if( LINE_COPY.equals( OdsParseUtil.checkKey( lcKey, tmpBuf ) ) ) {
    119//                      // 存在すればテーブルモデル行数-1回ループ(自身を除くため)
    120//                      for( int i = 1; i < rowCount; i++ ) {
    121//                              tmpBuf = new StringBuilder();
    122//                              preOffset = -1;
    123//                              curOffset = 0;
    124//                              while( ( preOffset = row.indexOf( VAR_START, preOffset + 1 ) ) >= 0 ) {
    125//                                      tmpBuf.append( row.substring( curOffset, preOffset ) );
    126//                                      curOffset = row.indexOf( VAR_END, preOffset + 1 ) + VAR_END.length();
    127//
    128//                                      // {@XXXX_XX}のXXXX_XXの部分
    129//                                      String key = row.substring( preOffset + VAR_START.length(), curOffset - VAR_END.length() );
    130//                                      key = OdsParseUtil.checkKey( key, tmpBuf );
    131//                                      // 不整合はreturnで何もしないで返しておく
    132//                                      int keyCheck = key.indexOf( '<' );
    133//                                      if( keyCheck >= 0 ) { return; }
    134//                                      tmpBuf.append( VAR_START ).append( incrementKey( key, i ) ).append( VAR_END );
    135//                              }
    136//                              tmpBuf.append( row.substring( curOffset, row.length() ) );
    137//
    138//                              sheetRows.add( tmpBuf.toString() ); // シートに追加
    139//                      }
    140//              }
    141
    142                // この段階で存在しなければ即終了
    143                int lcStrOffset = row.indexOf( VAR_START + LINE_COPY );
    144                if( lcStrOffset < 0 ) { return; }
    145                int lcEndOffset = row.indexOf( VAR_END, lcStrOffset );
    146                if( lcEndOffset < 0 ) { return; }
    147
    148                StringBuilder lcStrBuf = new StringBuilder( row );
    149                String lcKey = TagParser.checkKey( row.substring( lcStrOffset + VAR_START.length(), lcEndOffset ), lcStrBuf );
    150                if( lcKey == null || !LINE_COPY.equals( lcKey ) ) { return; }
    151
    152                // 存在すればテーブルモデル行数-1回ループ(自身を除くため)
    153                for( int i = 1; i < rowCount; i++ ) {
    154                        final int cRow = i;
    155                        String rowStr = new TagParser() {
    156                                @Override
    157                                protected void exec( final String str, final StringBuilder buf, final int offset ) {
    158                                        String key = TagParser.checkKey( str, buf );
    159                                        if( key.indexOf( '<' ) >= 0 ){
    160                                                String errMsg = "[ERROR]PARSE:{@と}の整合性が不正です。変数内の特定の文字列に書式設定がされている可能性があります。キー=" + key;
    161                                                throw new HybsSystemException( errMsg );
    162                                        }
    163                                        buf.append( VAR_START ).append( incrementKey( key, cRow ) ).append( VAR_END );
    164                                }
    165                        }.doParse( lcStrBuf.toString(), VAR_START, VAR_END, false );
    166                        sheetRows.add( rowStr );
    167                }
    168        }
    169
    170        /**
    171         * xxx_yのy部分を引数分追加して返します。
    172         * yが数字でない場合や、_が無い場合はそのまま返します。
    173         *
    174         * @og.rev 5.0.0.2 LINE_COPYで利用するために追加
    175         *
    176         * @param key
    177         * @param inc
    178         *
    179         * @return 変更後キー
    180         */
    181        private String incrementKey( final String key, final int inc ) {
    182                int conOffset = key.lastIndexOf( VAR_CON );
    183                if( conOffset < 0 ) { return key; }
    184
    185                String name = key.substring( 0, conOffset );
    186                int rownum = -1;
    187                try {
    188                        rownum = Integer.valueOf( key.substring( conOffset + VAR_CON.length(), key.length() ) );
    189                }
    190                // エラーが起きてもなにもしない。
    191                catch( NumberFormatException ex ) {}
    192
    193                // アンダースコア後が数字に変換できない場合はヘッダフッタとして認識
    194                if( rownum < 0 ){ return key; }
    195                else                    { return name + VAR_CON + ( rownum + inc ); }
    196        }
    197
    198        /**
    199         * シートのヘッダー部分を返します。
    200         *
    201         * @return ヘッダー
    202         */
    203        public String getHeader() {
    204                return sheetHeader;
    205        }
    206
    207        /**
    208         * シートのフッター部分を返します。
    209         *
    210         * @return フッター
    211         */
    212        public String getFooter() {
    213                return sheetFooter;
    214        }
    215
    216        /**
    217         * シート名称を返します。
    218         *
    219         * @return シート名称
    220         */
    221        public String getSheetName() {
    222                return sheetName;
    223        }
    224
    225        /**
    226         * 定義済シート名称を返します。
    227         *
    228         * @og.rev 5.2.1.0 (2010/10/01) シート名定義対応
    229         *
    230         * @return 定義済シート名称
    231         */
    232        public String getConfSheetName() {
    233                return confSheetName;
    234        }
    235
    236        /**
    237         * 定義名変換前のシート名称を返します。
    238         *
    239         * @og.rev 5.2.1.0 (2010/10/01) シート名定義対応
    240         *
    241         * @return 定義済シート名称
    242         */
    243        public String getOrigSheetName() {
    244                return origSheetName;
    245        }
    246
    247        /**
    248         * シートの各行を配列で返します。
    249         *
    250         * @og.rev 4.3.1.1 (2008/08/23) あらかじめ、必要な配列の長さを確保しておきます。
    251         *
    252         * @return シートの各行の配列
    253         */
    254        public String[] getRows() {
    255                return sheetRows.toArray( new String[sheetRows.size()] );
    256        }
    257}
    258