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.view;
017
018import java.util.List;
019
020import org.opengion.fukurou.util.StringUtil;
021import org.opengion.hayabusa.common.HybsSystemException;
022import org.opengion.hayabusa.html.TableFormatter;
023
024/**
025 * JavaScript のツリー階層を持ったテーブル表示を行う、ツリーテーブル表示クラスです。
026 *
027 * AbstractViewForm により、setter/getterメソッドのデフォルト実装を提供しています。
028 * 各HTMLのタグに必要な setter/getterメソッドのみ,追加定義しています。
029 *
030 * AbstractViewForm を継承している為,ロケールに応じたラベルを出力させる事が出来ます。
031 *
032 * @og.group 画面表示
033 *
034 * @version  4.0
035 * @author   Hiroki Nakamura
036 * @since    JDK5.0,
037 */
038public class ViewForm_HTMLCustomTreeBOM extends ViewForm_HTMLTable  {
039        /** このプログラムのVERSION文字列を設定します。   {@value} */
040        private static final String VERSION = "7.3.0.0 (2021/01/06)" ;
041
042        private TableFormatter          headerFormat    ;
043        private TableFormatter[]        bodyFormats             ;
044        private int                                     bodyFormatsCount;
045
046        private static final int BODYFORMAT_MAX_COUNT = 10;
047
048        // 6.4.4.1 (2016/03/18) static final 定数化にします。
049        private static final String FUTTER = "initializeDocument()" + CR + "//-->" + CR + "</script>" + CR + "</table>" + CR ;
050
051        // 6.4.4.1 (2016/03/18) static final 定数化にします。
052        // 8.1.0.0 (2021/12/28) HTML5 準拠に見直し(<script> type属性削除)
053        private static final String HEADER = "<table id=\"viewTable\" border=\"0\" cellspacing=\"2\" cellpadding=\"0\"  summary=\"bomTable\">"
054//                                                                              + CR + "<script type=\"text/javascript\">" + CR + "<!--" + CR + "aux0 = gFld('" ;
055                                                                                + CR + "<script>" + CR + "<!--" + CR + "aux0 = gFld('" ;
056
057        /**
058         * デフォルトコンストラクター
059         *
060         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
061         */
062        public ViewForm_HTMLCustomTreeBOM() { super(); }                // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
063
064        /**
065         * DBTableModel から HTML文字列を作成して返します。
066         * startNo(表示開始位置)から、pageSize(表示件数)までのView文字列を作成します。
067         * 表示残りデータが pageSize 以下の場合は,残りのデータをすべて出力します。
068         *
069         * @og.rev 4.3.1.0 (2008/09/08) フォーマットが設定されていない場合のエラー追加
070         * @og.rev 6.2.0.0 (2015/02/27) フォーマット系の noDisplay 対応
071         * @og.rev 6.4.3.4 (2016/03/11) tdに、[カラム]が無いケースで、次の[カラム]のクラス属性が、前方すべてのtdにセットされてしまう対応。
072         * @og.rev 6.4.4.1 (2016/03/18) FUTTER を、static final 定数化にします。
073         * @og.rev 6.4.4.2 (2016/04/01) TableFormatterのタイプ別値取得処理の共通部をまとめる。
074         * @og.rev 6.4.5.0 (2016/04/08) メソッド変更( getColumnDbType(int) → getClassName(int) )
075         *
076         * @param  stNo     表示開始位置
077         * @param  pgSize   表示件数
078         *
079         * @return  DBTableModelから作成された HTML文字列
080         * @og.rtnNotNull
081         */
082        @Override
083        public String create( final int stNo, final int pgSize )  {
084                // このクラスでは、テーブル全データを使用します。
085                if( getRowCount() == 0 ) { return ""; } // 暫定処置
086
087                // 4.3.1.0 (2008/09/08)
088                if( headerFormat == null ) {
089                        final String errMsg = "ViewTagで canUseFormat() = true の場合、Formatter は必須です。";
090                        throw new HybsSystemException( errMsg );
091                }
092
093                final int startNo = 0;
094                final int pageSize = getRowCount();
095
096                final int lastNo = getLastNo( startNo, pageSize );
097
098                headerFormat.makeFormat( getDBTableModel() );
099                // 6.2.0.0 (2015/02/27) フォーマット系の noDisplay 対応
100                setFormatNoDisplay( headerFormat );
101
102                if( bodyFormatsCount == 0 ) {
103                        bodyFormats[0] = headerFormat ;
104                        bodyFormatsCount ++ ;
105                }
106                else {
107                        for( int i=0; i<bodyFormatsCount; i++ ) {
108                                bodyFormats[i].makeFormat( getDBTableModel() );
109                                // 6.2.0.0 (2015/02/27) フォーマット系の noDisplay 対応
110                                setFormatNoDisplay( bodyFormats[i] );
111                        }
112                }
113
114                final StringBuilder out = new StringBuilder( BUFFER_LARGE );
115                out.append( getHeader() );
116
117                int level;
118                // 6.3.9.1 (2015/11/27) Found 'DD'-anomaly for variable(PMD)
119                for( int row=startNo; row<lastNo; row++ ) {
120                        // カラム==0は、レベルを指定する。
121                        level = Integer.parseInt( getValueLabel(row,0) );
122                        final boolean isFld = row+1<lastNo && level < Integer.parseInt( getValueLabel(row+1,0) );
123                        out.append( getLevelScript( level,isFld ) );
124
125                        // 開始
126                        for( int i=0; i<bodyFormatsCount; i++ ) {
127                                final TableFormatter bodyFormat = bodyFormats[i];
128
129                                int cl = 0;
130                                for( ; cl<bodyFormat.getLocationSize(); cl++ ) {
131                                        // 6.3.9.1 (2015/11/27) Found 'DD'-anomaly for variable(PMD)
132                                        String fmt = bodyFormat.getFormat(cl);
133                                        final int loc = bodyFormat.getLocation(cl);
134                                        if( ! bodyFormat.isNoClass() && loc >= 0 ) {
135                                                // 6.4.3.4 (2016/03/11) tdに、[カラム]が無いケースで、次の[カラム]のクラス属性が、前方すべてのtdにセットされてしまう対応。
136                                                final int idx = fmt.lastIndexOf( "<td" );
137                                                if( idx >= 0 ) {        // matchしてるので、あるはず
138                                                        final String tdclass = " class=\"" + getClassName(loc) + "\" ";                 // 6.4.5.0 (2016/04/08)
139                                                        fmt = fmt.substring( 0,idx+3 ) + tdclass + fmt.substring( idx+3 ) ;
140                                                }
141                                        }
142                                        out.append( fmt );
143                                        if( loc >= 0 ) {
144                                                // 6.4.4.2 (2016/04/01) 処理の共通部をまとめる。
145                                                out.append( getTypeCaseValue( bodyFormat.getType(cl),row,loc ) );
146                                        }
147                                }
148                                out.append( StringUtil.replace( bodyFormat.getFormat(cl), "</tr>", "" ) );
149                        }
150                        // 終了
151
152                        out.append( "', '', 'gold')" );
153                        if( level != 0 ) {
154                                out.append( ')' );              // 6.0.2.5 (2014/10/31) char を append する。
155                        }
156                        out.append( CR );
157                }
158                out.append( FUTTER );                   // 6.4.4.1 (2016/03/18)
159
160                return out.toString();
161        }
162
163        /**
164         * DBTableModel から テーブルのヘッダータグ文字列を作成して返します。
165         * JavaScript の TreeBody では、JavaScriptに関連する定義もこのヘッダーに
166         * 含めます。
167         *
168         * @og.rev 6.4.4.1 (2016/03/18) HEADER を、static final 定数化にします。
169         * @og.rev 7.3.0.0 (2021/01/06) SpotBugs:null チェックなしで null 値を利用対策
170         *
171         * @return  テーブルのヘッダータグ文字列
172         * @og.rtnNotNull
173         */
174        @Override
175        protected String getHeader() {
176                // 7.3.0.0 (2021/01/06) SpotBugs:null チェックなしで null 値を利用対策
177                if( headerFormat == null ) {
178                        final String errMsg = "ViewTagで canUseFormat() = true の場合、Formatter は必須です。";
179                        throw new HybsSystemException( errMsg );
180                }
181
182                // 6.4.4.1 (2016/03/18) HEADER を、static final 定数化にします。
183                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE ).append( HEADER );
184
185                int cl = 0;
186                // 6.9.8.0 (2018/05/28) FindBugs:コンストラクタで初期化されていないフィールドを null チェックなしで null 値を利用している
187                // フレームワークとして、create メソッドからしか、呼ばれないため、nullチェック済みです。
188                for( ; cl<headerFormat.getLocationSize(); cl++ ) {
189                        buf.append( StringUtil.replace( headerFormat.getFormat(cl) ,"td","th" ));
190                        final int loc = headerFormat.getLocation(cl);
191                        if( loc >= 0 ) { buf.append( getColumnLabel(loc) ); }
192                        // ヘッダーフォーマット部では、何もしません。
193                }
194                buf.append( StringUtil.replace( StringUtil.replace( headerFormat.getFormat(cl) ,"td","th" ), "</tr>", "" ) )
195                        .append("', '', 'gold')")
196                        .append( CR );
197
198                return buf.toString();
199        }
200
201        /**
202         * 行のレベルに応じた JavaScript関数のヘッダー部分を返します。
203         *
204         * @og.rev 3.5.2.1 (2003/10/27) JavaScript 内のダブルコーテーションをシングルコーテーションに変更する。
205         *
206         * @param       lvl             ツリーのレベル
207         * @param       isFld   フォルダかどうか[true:フォルダ/false:最下層]
208         *
209         * @return  JavaScript関数のヘッダー部分
210         */
211        private String getLevelScript( final int lvl,final boolean isFld ) {
212
213                final String auxX = "\taux" + ( lvl );
214                final String auxY = "aux" + ( lvl-1 );
215
216                final String rtn ;
217                if( isFld ) {
218                        rtn = auxX + " = insFld(" + auxY + ", gFld('";
219                }
220                else {
221                        rtn = "\tinsFld(" + auxY + ", gLnk('CONTENTS','";
222                }
223
224                return rtn;
225        }
226
227        /**
228         * フォーマットを設定します。
229         *
230         * @param       list    TableFormatterのリスト
231         */
232        @Override
233        public void setFormatterList( final List<TableFormatter> list ) {               // 4.3.3.6 (2008/11/15) Generics警告対応
234                bodyFormats = new TableFormatter[BODYFORMAT_MAX_COUNT];
235
236                bodyFormatsCount = 0;
237                // 7.2.9.4 (2020/11/20) PMD:This for loop can be replaced by a foreach loop
238                for( final TableFormatter format : list ) {
239//              for( int i=0; i<list.size(); i++ ) {
240//                      final TableFormatter format = list.get( i );            // 4.3.3.6 (2008/11/15) Generics警告対応
241                        switch( format.getFormatType() ) {
242                        case TYPE_HEAD : headerFormat = format; break;
243                        case TYPE_BODY : bodyFormats[bodyFormatsCount++] = format; break;
244                        default : final String errMsg = "FormatterType の定義外の値が指定されました。";
245                        // 4.3.4.4 (2009/01/01)
246                                          throw new HybsSystemException( errMsg );
247                        }
248                }
249
250                if( headerFormat == null ) {
251                        final String errMsg = "og:thead タグの、フォーマットの指定は必須です。";
252                        throw new HybsSystemException( errMsg );
253                }
254        }
255
256        /**
257         * フォーマットメソッドを使用できるかどうかを問い合わせます。
258         *
259         * @return  使用可能(true)/ 使用不可能 (false)
260         */
261        @Override
262        public boolean canUseFormat() {
263                return true;
264        }
265
266        /**
267         * ビューで表示したカラムの一覧をCSV形式で返します。
268         *
269         * @og.rev 5.1.6.0 (2010/05/01) 新規追加
270         * @og.rev 6.2.0.1 (2015/03/06) TableFormatter#getLocation(int)の有効判定
271         * @og.rev 6.4.3.4 (2016/03/11) getViewClms(TableFormatter) を使用して表示されたカラム一覧を求めます。
272         *
273         * @return      ビューで表示したカラムの一覧
274         * @og.rtnNotNull
275         */
276        @Override
277        public String getViewClms() {
278                return getViewClms( headerFormat );
279        }
280}