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.hayabusa.common.HybsSystemException;
021import org.opengion.hayabusa.html.TableFormatter;
022
023/**
024 * ヘッダ、フッタ、ボディを指定して作成する、自由レイアウトが可能な、カスタムテーブル表示クラスです。
025 * 従来は、内部バグのため、thead,tbody,tfoot タグを使わないと処理できませんでしたが、
026 * viewタグの BODY 部にフォーマットを記述するだけで処理するように改善しました。(5.6.3.3 (2013/04/19))
027 *
028 * このタグでは、BODY部、または、bodyFormats を繰り返す処理を行います。
029 * ヘッダ があれば、最初に、1度のみ実行し、フッタがあれば、最後に実行します。
030 * このクラスが他と異なるのは、ヘッダのみ記述した場合、ヘッダとして使われず、ボディとしてのみ繰返し
031 * 使われます。また、bodyFormats のみの記述も可能です。
032 *
033 * このクラスは、ViewForm_HTMLFormatTable クラスの代替えとしても使用できます。
034 * その場合は、thead のみ指定すれば、同じフォームが tbody にも適用されます。
035 * これは、まさに、ViewForm_HTMLFormatTable と同じです。
036 * (※ 上記仕様が、未実装でしたので、対応しました。 5.6.3.3 (2013/04/19) )
037 *
038 * AbstractViewForm により、setter/getterメソッドのデフォルト実装を提供しています。
039 * 各HTMLのタグに必要な setter/getterメソッドのみ、追加定義しています。
040 *
041 * AbstractViewForm を継承している為、ロケールに応じたラベルを出力させる事が出来ます。
042 *
043 * <table class="plain">
044 *   <caption>ヘッダ と ボディ の組み合わせ</caption>
045 *   <tr><th>番号</th><th>headerFormat</th><th>bodyFormats</th><th>現状動作    </th><th>変更後(5.6.3.3以降)      </th></tr>
046 *   <tr><td>①  </td><td>あり        </td><td>なし       </td><td>headerのみ  </td><td>body の繰り返し          </td></tr>
047 *   <tr><td>②  </td><td>なし        </td><td>あり       </td><td>エラー      </td><td>bodyFormats のみ繰り返す </td></tr>
048 *   <tr><td>③  </td><td>あり        </td><td>あり       </td><td>それぞれ動作</td><td>← 同じ                  </td></tr>
049 *   <tr><td>④  </td><td>なし        </td><td>なし       </td><td>エラー      </td><td>← 同じ                  </td></tr>
050 * </table>
051 *
052 * @og.rev 3.7.1.1 (2005/05/23) 新規作成
053 * @og.rev 5.6.3.3 (2013/04/19) 処理変更
054 * @og.group 画面表示
055 *
056 * @version  4.0
057 * @author       Kazuhiko Hasegawa
058 * @since    JDK5.0,
059 */
060public class ViewForm_CustomData extends ViewForm_HTMLTable     {
061        /** このプログラムのVERSION文字列を設定します。   {@value} */
062        private static final String VERSION = "8.5.5.1 (2024/02/29)" ;
063
064        private static final int BODYFORMAT_MAX_COUNT = 10;
065
066        private TableFormatter          headerFormat    ;
067        private TableFormatter[]        bodyFormats = new TableFormatter[BODYFORMAT_MAX_COUNT]; // 7.3.0.0 (2021/01/06)
068        private TableFormatter          footerFormat    ;
069        private int                                     bodyFormatsCount;
070
071        /**
072         * デフォルトコンストラクター
073         *
074         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
075         */
076        public ViewForm_CustomData() { super(); }               // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
077
078        /**
079         * DBTableModel から HTML文字列を作成して返します。
080         * startNo(表示開始位置)から、pageSize(表示件数)までのView文字列を作成します。
081         * 表示残りデータが pageSize 以下の場合は、残りのデータをすべて出力します。
082         *
083         * @og.rev 4.3.1.0 (2008/09/08) フォーマットが設定されていない場合のエラー追加・編集行のみを表示する属性(isSkipNoEdit)追加
084         * @og.rev 5.6.3.3 (2013/04/19) headerFormatのみ、bodyFormatsのみ対応
085         * @og.rev 6.2.0.0 (2015/02/27) フォーマット系の noDisplay 対応
086         * @og.rev 6.3.9.0 (2015/11/06) 引数にTableFormatterを渡して、処理の共有化を図る。
087         * @og.rev 6.4.4.2 (2016/04/01) TableFormatterのタイプ別値取得処理の共通部をまとめる。
088         *
089         * @param  startNo        表示開始位置
090         * @param  pageSize   表示件数
091         *
092         * @return      DBTableModelから作成された HTML文字列
093         * @og.rtnNotNull
094         */
095        @Override
096        public String create( final int startNo, final int pageSize )  {
097                if( getRowCount() == 0 ) { return ""; } // 暫定処置
098
099                // 5.6.3.3 (2013/04/19) headerFormatのみ、bodyFormatsのみ対応
100                headerLine       = null;                // 3.5.3.1 (2003/10/31) キャッシュクリア
101
102                final int lastNo = getLastNo( startNo, pageSize );
103
104                // 5.6.3.3 (2013/04/19) headerFormatのみ、bodyFormatsのみ対応
105                if( headerFormat != null ) {
106                        headerFormat.makeFormat( getDBTableModel() );   // 3.5.6.2 (2004/07/05) 移動
107                        // 6.2.0.0 (2015/02/27) フォーマット系の noDisplay 対応
108                        setFormatNoDisplay( headerFormat );
109                }
110
111                // 6.9.8.0 (2018/05/28) FindBugs:コンストラクタで初期化されていないフィールドを null チェックなしで null 値を利用している
112                // bodyFormatsCount が、0 でない場合は、bodyFormats は、設定済みなので、null チェック不要
113//              if( bodyFormatsCount != 0 ) {
114                if( bodyFormatsCount > 0 ) {
115                        for( int i=0; i<bodyFormatsCount; i++ ) {
116                                bodyFormats[i].makeFormat( getDBTableModel() );
117                                // 6.2.0.0 (2015/02/27) フォーマット系の noDisplay 対応
118                                setFormatNoDisplay( bodyFormats[i] );
119                        }
120                }
121
122                final StringBuilder out = new StringBuilder( BUFFER_LARGE );
123                out.append( getHeader() );
124                for( int row=startNo; row<lastNo; row++ ) {
125                        if( isSkip( row ) || isSkipNoEdit( row ) ) { continue; } // 4.3.1.0 (2008/09/08)
126                        for( int i=0; i<bodyFormatsCount; i++ ) {
127                                final TableFormatter bodyFormat = bodyFormats[i];
128                                if( ! bodyFormat.isUse( row,getDBTableModel() ) ) { continue; }         // 3.5.4.0 (2003/11/25)
129
130                                int cl = 0;
131                                for( ; cl<bodyFormat.getLocationSize(); cl++ ) {
132                                        final String fmt = bodyFormat.getFormat(cl);
133                                        out.append( fmt );                      // 3.5.0.0
134
135                                        final int loc = bodyFormat.getLocation(cl);     // 3.5.5.0
136                                        if( loc >= 0 ) {
137                                                // 6.4.4.2 (2016/04/01) 処理の共通部をまとめる。
138                                                out.append( getTypeCaseValue( bodyFormat.getType(cl),row,loc ) );
139                                        }
140                                        else {
141                                                out.append( bodyFormat.getSystemFormat(row,loc) );
142                                        }
143                                }
144                                out.append( bodyFormat.getFormat(cl) );
145                        }
146                }
147
148                if( footerFormat != null ) {
149                        // 6.3.9.0 (2015/11/06) 引数にTableFormatterを渡して、処理の共有化を図る。
150                        out.append( getTableFoot( footerFormat ) );
151                }
152
153                return out.toString();
154        }
155
156        /**
157         * 内容をクリア(初期化)します。
158         *
159         */
160        @Override
161        public void clear() {
162                super.clear();
163                headerFormat            = null;
164//              bodyFormats                     = null;
165                bodyFormats                     = new TableFormatter[BODYFORMAT_MAX_COUNT];     // 7.3.0.0 (2021/01/06) SpotBugs:null チェックなしで null 値を利用
166                footerFormat            = null;
167                bodyFormatsCount        = 0;
168        }
169
170        /**
171         * DBTableModel から テーブルのヘッダータグ文字列を作成して返します。
172         *
173         * @og.rev 6.4.4.2 (2016/04/01) TableFormatterのタイプ別値取得処理の共通部をまとめる。
174         *
175         * @return      テーブルのヘッダータグ文字列
176         * @og.rtnNotNull
177         */
178        @Override
179        protected String getHeader() {
180                // 6.3.9.1 (2015/11/27) A method should have only one exit point, and that should be the last statement in the method.(PMD)
181
182                if( headerLine == null ) {
183                        if( headerFormat == null ) { headerLine = ""; }
184                        else {
185                                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
186
187                                int cl = 0;
188                                for( ; cl<headerFormat.getLocationSize(); cl++ ) {
189                                        buf.append( headerFormat.getFormat(cl) );
190                                        final int loc = headerFormat.getLocation(cl);
191                                        // 6.4.4.2 (2016/04/01)
192                                        if( loc >= 0 ) {
193                                                buf.append( getTypeCaseValue( headerFormat.getType(cl),-1,loc ) );
194                                        }
195                                }
196                                buf.append( headerFormat.getFormat(cl) ).append( CR );
197
198                                headerLine = buf.toString();
199                        }
200                }
201                return headerLine ;
202        }
203
204        /**
205         * DBTableModel から テーブルのタグ文字列を作成して返します。
206         *
207         * @og.rev 6.2.0.0 (2015/02/27) フォーマット系の noDisplay 対応
208         * @og.rev 6.3.9.0 (2015/11/06) 引数にTableFormatterを渡して、処理の共有化を図る。
209         * @og.rev 6.4.4.2 (2016/04/01) TableFormatterのタイプ別値取得処理の共通部をまとめる。
210         *
211         * @param       footerFormat TableFormatterオブジェクト
212         * @return      テーブルのタグ文字列
213         * @og.rtnNotNull
214         */
215        @Override
216        protected String getTableFoot( final TableFormatter footerFormat ) {
217                footerFormat.makeFormat( getDBTableModel() );
218                // 6.2.0.0 (2015/02/27) フォーマット系の noDisplay 対応
219                setFormatNoDisplay( footerFormat );
220
221                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
222
223                int cl = 0;
224                for( ; cl<footerFormat.getLocationSize(); cl++ ) {
225                        final int loc = footerFormat.getLocation(cl);
226                        // 6.4.4.2 (2016/04/01)
227                        if( loc >= 0 ) {
228                                buf.append( getTypeCaseValue( footerFormat.getType(cl),-1,loc ) );
229                        }
230                }
231                buf.append( footerFormat.getFormat(cl) ).append( CR );
232
233                return buf.toString();
234        }
235
236        /**
237         * フォーマットを設定します。
238         *
239         * @og.rev 5.6.3.3 (2013/04/19) headerFormatのみの場合、bodyFormats として使う。
240         * @og.rev 7.3.0.0 (2021/01/06) SpotBugs:null チェックなしで null 値を利用対策
241         * @og.rev 8.5.5.1 (2024/02/29) switch文にアロー構文を使用
242         *
243         * @param       list    TableFormatterのリスト
244         */
245        @Override
246        public void setFormatterList( final List<TableFormatter> list ) {               // 4.3.3.6 (2008/11/15) Generics警告対応
247//              bodyFormats = new TableFormatter[BODYFORMAT_MAX_COUNT];                         // 7.3.0.0 (2021/01/06)
248
249                bodyFormatsCount = 0;
250                // 7.2.9.4 (2020/11/20) PMD:This for loop can be replaced by a foreach loop
251                for( final TableFormatter format : list ) {
252//              for( int i=0; i<list.size(); i++ ) {
253//                      final TableFormatter format = list.get( i );            // 4.3.3.6 (2008/11/15) Generics警告対応
254
255                        // 8.5.5.1 (2024/02/29) switch文にアロー構文を使用
256//                      switch( format.getFormatType() ) {
257//                              case TYPE_HEAD : headerFormat = format; break;
258//                              case TYPE_BODY : bodyFormats[bodyFormatsCount++] = format; break;
259//                              case TYPE_FOOT : footerFormat = format; break;
260//                              default : final String errMsg = "FormatterType の定義外の値が指定されました。";
261//                                              // 4.3.4.4 (2009/01/01)
262//                                                throw new HybsSystemException( errMsg );
263//                      }
264                        switch( format.getFormatType() ) {
265                                case TYPE_HEAD -> headerFormat = format;
266                                case TYPE_BODY -> bodyFormats[bodyFormatsCount++] = format;
267                                case TYPE_FOOT -> footerFormat = format;
268                                default -> {
269                                        final String errMsg = "FormatterType の定義外の値が指定されました。";
270                                        // 4.3.4.4 (2009/01/01)
271                                        throw new HybsSystemException( errMsg );
272                                }
273                        }
274                }
275
276                // 5.6.3.3 (2013/04/19) headerFormatのみの場合、bodyFormats として使う。
277                if( bodyFormatsCount == 0 ) {           // bodyFormats がない場合は、headerFormatをコピーする。
278                        if( headerFormat == null ) {
279                                final String errMsg = "thead タグか、または、tbody タグによるフォーマットの指定は必須です。";
280                                throw new HybsSystemException( errMsg );
281                        }
282                        else {
283                                bodyFormats[bodyFormatsCount++] = headerFormat;
284                                headerFormat = null;
285                        }
286                }
287        }
288
289        /**
290         * フォーマットメソッドを使用できるかどうかを問い合わせます。
291         *
292         * @return  使用可能(true)/ 使用不可能 (false)
293         */
294        @Override
295        public boolean canUseFormat() {
296                return true;
297        }
298
299        /**
300         * 表示項目の編集(並び替え)が可能かどうかを返します。
301         *
302         * @og.rev 5.1.6.0 (2010/05/01) 新規追加
303         *
304         * @return      表示項目の編集(並び替え)が可能かどうか(false:不可能)
305         */
306        @Override
307        public boolean isEditable() {
308                return false;
309        }
310}