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.html;
017
018import java.util.regex.Pattern;
019import java.util.regex.Matcher;
020import java.util.stream.IntStream;                                                              // 6.4.3.4 (2016/03/11)
021
022import org.opengion.fukurou.system.OgRuntimeException ;                 // 6.4.2.0 (2016/01/29)
023import static org.opengion.fukurou.system.HybsConst.CR ;                // 6.1.0.0 (2014/12/26)
024import org.opengion.fukurou.util.StringUtil;
025import org.opengion.fukurou.model.Formatter;
026import org.opengion.hayabusa.common.HybsSystemException;
027import org.opengion.hayabusa.db.DBTableModel;
028
029/**
030 * [PN],[OYA] などの [] で指定されたカラムで表されたフォーマットデータに対して、
031 * DBTableModelオブジェクトを適用して 各カラムに実データを割り当てるオブジェクトです。
032 *
033 * 特に、[XXXX]に対して、[#XXXX]、[$XXXX]、[!XXXX]などの特殊記号が使用できます。
034 * 特殊記号の解釈は、HTMLFormatTextField系とHTMLFormatTable系で異なりますので
035 * ご注意ください。
036 *
037 * '#':ラベルのみ  '$':レンデラー '!':値のみ
038 *
039 * @og.rev 3.5.4.0 (2003/11/25) 新規追加
040 * @og.group 画面表示
041 *
042 * @version  4.0
043 * @author   Kazuhiko Hasegawa
044 * @since    JDK5.0,
045 */
046public class TableFormatter {
047
048        /** フォーマットタイプの指定の特殊なマーク {@value} */
049        public static final String HYBS_ITD_MARKER = "h_itd_marker";
050        // 4.3.2.0 (2008/09/10) </td>前のスペースを取り消す。
051        private static final Pattern PTN_KEY = Pattern.compile( "[ \t]+</td" );                 // 6.4.1.1 (2016/01/16) ptnKey → PTN_KEY refactoring
052
053        // 8.5.4.2 (2024/01/12) PMD 7.0.0 AvoidDuplicateLiterals 対応
054        private static final String MAKE_FORMAT_ERR = "#makeFormat(DBTableModel)を先に実行しておいてください。" ;
055
056        private FormatterType   formatType      ;
057        private int[]                   location        ;
058        private String[]                format          ;
059        private String                  formatTag       ;
060        private String                  rowspan         = " rowspan=\"2\"";
061        private String                  trTag           ;
062        private boolean                 noClass         ;
063        // 3.5.6.0 (2004/06/18) '!' 値のみ 追加 既存の '$' は、レンデラー
064        private char[]                  type            ;                       // '#':ラベルのみ  '$':レンデラー '!':値のみ  その他:通常
065        private String                  usableKey       ;                       // キー情報のカラム文字列
066        private int                             usableKeyNo     = -1;           // キー情報のカラム番号
067        private String                  usableList      = "1";
068
069        private String                  keyBreakClm     ;                       // 5.7.6.3 (2014/05/23) キーブレイクをチェックするカラムID
070        private int                             breakClmNo      = -1;           // 5.7.6.3 (2014/05/23) キーブレイクカラム番号
071        private String                  breakVal        ;                       // 5.7.6.3 (2014/05/23) キーブレイクをチェックする値
072
073        private String                  itdBody         = "";           // 3.5.6.0 (2004/06/18) 追加
074        private Formatter               formatter       ;
075
076        /**
077         * デフォルトコンストラクター
078         *
079         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
080         */
081        public TableFormatter() { super(); }            // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
082
083        /**
084         * フォーマットをセットします。
085         * フォーマットに、&lt;table&gt;を含む場合、TextField扱いなので、フォーマット分割
086         * しません。table を含まず、tr を含む場合は、1行分のデータとして扱う為、
087         * trTag を求めます。
088         * trTag と format との間に、行ヘッダーが入ります。
089         * Tomcat6では、JSPのパース時に、tabやspaceはそのままパースされるため、&lt;/td&gt;前
090         * のスペース削除処理も行います。
091         *
092         * @og.rev 4.3.2.0 (2008/09/10) &lt;/td&gt;前のスペースを取り消します。
093         * @og.rev 5.5.0.3 (2012/03/13) &lt;tr&gt;を取らないフラグ追加
094         *
095         * @param       fmt  [カラム名] 形式のフォーマットデータ
096         * @param   flag  falseにすると先頭のtrタグを取る処理を行いません(5.5.0.3)
097         */
098        public void setFormat( final String fmt , final boolean flag ) {
099                final int tbl = fmt.indexOf( "<table" );
100                final int str = fmt.indexOf( "<tr" );
101
102                // tr を含み、かつ、tableを含まないか、含んでも tr の後ろにtableがある場合。
103                if( str >= 0 && ( tbl < 0 || str < tbl ) && flag ) { // 5.5.0.3(2012/03/13)
104                        final int end = fmt.indexOf( '>',str );
105                        formatTag = fmt.substring(end+1);
106                        trTag = fmt.substring(0,end+1) ;
107                }
108                else {
109                        formatTag = fmt;
110                        trTag     = null;
111                }
112                // 4.3.2.0 (2008/09/10) </td>前のスペースを取り消す。
113                final Matcher matcher = PTN_KEY.matcher( formatTag );
114                formatTag = matcher.replaceAll( "</td" );
115        }
116
117        /**
118         * フォーマットをセットします。
119         * フォーマットに、&lt;table&gt;を含む場合、TextField扱いなので、フォーマット分割
120         * しません。table を含まず、tr を含む場合は、1行分のデータとして扱う為、
121         * trTag を求めます。
122         * trTag と format との間に、行ヘッダーが入ります。
123         * Tomcat6では、JSPのパース時に、tabやspaceはそのままパースされるため、&lt;/td&gt;前
124         * のスペース削除処理も行います。
125         *
126         * @og.rev 5.5.0.3 (2012/03/13) 引数追加につき。
127         *
128         * @param       fmt  [カラム名] 形式のフォーマットデータ
129         */
130        public void setFormat( final String fmt ) {
131                setFormat( fmt , true );
132        }
133
134        /**
135         * フォーマットを取得します。
136         *
137         * @og.rev 3.5.5.8 (2004/05/20) 新規追加
138         * @og.rev 5.1.7.0 (2010/06/01) サニタイズ戻し処理("\\]\\"から"["に戻し)を追加
139         *
140         * @return      フォーマットデータ
141         */
142        public String getFormat() {
143                // 6.4.1.1 (2016/01/16) PMD refactoring. A method should have only one exit point, and that should be the last statement in the method
144                // 反転注意
145                return trTag == null ? decodeSanitizedStr( formatTag ) : decodeSanitizedStr( trTag + formatTag );
146        }
147
148        /**
149         * DBTableModelを利用して、フォーマットデータを初期化します。
150         *
151         * @og.rev 3.5.5.0 (2004/03/12) [KEY.カラム名] 機能追加
152         * @og.rev 3.5.5.2 (2004/04/02) [I] で、行番号を作成します。
153         * @og.rev 3.5.6.0 (2004/06/18) '!' 値のみ 追加 既存の '$' は、レンデラー
154         * @og.rev 3.6.0.0 (2004/09/17) [ROW.ID] で、行毎のチェックボックスのIDを返します。
155         * @og.rev 5.1.7.0 (2010/06/01) サニタイズ戻し処理("\\]\\"から"["に戻し)を追加
156         * @og.rev 5.7.6.3 (2014/05/23) キーブレイクをチェックする keyBreakClm 属性追加
157         * @og.rev 6.4.3.4 (2016/03/11) Formatterに新しいコンストラクターを追加する。
158         *
159         * @param       table   DBTableModelオブジェクト
160         */
161        public void makeFormat( final DBTableModel table ) {
162                formatter = new Formatter( table,formatTag );           // 6.4.3.4 (2016/03/11)
163                location = formatter.getClmNos();
164                format   = formatter.getFormat();
165
166                // 5.1.7.0 (2010/06/01) サニタイズ戻し処理("\\]\\"から"["に戻し)を追加
167                // 6.0.2.5 (2014/10/31)  null でないことがわかっている値の冗長な null チェックがあります。
168                        for( int i=0; i<format.length; i++ ) {
169                                format[i] = decodeSanitizedStr( format[i] );
170                        }
171
172                type = formatter.getType();
173
174                // このフォーマットを使用するかどうかを指定する判定条件の初期設定です。
175                if( usableKey != null ) {
176                        usableKeyNo = table.getColumnNo( usableKey );
177                }
178
179                // 5.7.6.3 (2014/05/23) キーブレイクをチェックする keyBreakClm 属性追加
180                if( keyBreakClm != null ) {
181                        breakClmNo = table.getColumnNo( keyBreakClm );
182                        breakVal   = null;              // 初期化します。
183                }
184        }
185
186        /**
187         * テーブルフォーマットのタイプを指定します。
188         * enum FormatterType で、指定します。
189         *
190         * @og.rev 4.0.0.0 (2007/05/02) enum 定義に変更
191         *
192         * @param  ftype フォーマットのタイプ
193         */
194        public void setFormatType( final FormatterType ftype ) {
195                formatType = ftype;
196        }
197
198        /**
199         * このフォーマットのタイプを返します。
200         *
201         * このフォーマットのタイプを返します。
202         *
203         * @og.rev 4.0.0.0 (2007/05/02) enum 定義に変更
204         *
205         * @return      このフォーマットのタイプを返します。
206         */
207        public FormatterType getFormatType() {
208                return formatType;
209        }
210
211        /**
212         * テーブルの rowspan 属性をセットします。
213         * rowspan は、ヘッダー部のフォーマットの行数です。初期値は 2行 です。
214         * 設定は、"2" などの、数字部のみをセットします。
215         *
216         * @param  rowspan 属性
217         */
218        public void setRowspan( final String rowspan ) {
219//              if( rowspan == null || rowspan.isEmpty() || rowspan.equals( "1" ) ) {
220                if( rowspan == null || rowspan.isEmpty() || "1".equals( rowspan ) ) {   // 8.5.4.2 (2024/01/12) PMD 7.0.0 LiteralsFirstInComparisons
221                        this.rowspan = "";
222                }
223                else {
224                        this.rowspan = " rowspan=\"" + rowspan + "\"";
225                }
226        }
227
228        /**
229         * 設定された rowspan を返します。
230         * これは、フォーマットの段組の数を取り出します。
231         * 文字列としては、rowspan="2" という形で取り出します。
232         *
233         * @return フォーマット文字列
234         */
235        public String getRowspan() {
236                return rowspan;
237        }
238
239        /**
240         * ロケーション番号のサイズを返します。
241         * フォーム位置番号は、0 から getLocationSize()-1 までの数字を指定します。
242         * ロケーションサイズは、aaa[ABC]bbb[DEF]ccc[GHI]ddd となっている場合、
243         * aaa , bbb , ccc , ddd は、フォーマットで、サイズは4。
244         * ABC , DEF , GHI に対応するカラム番号がロケーションで、サイズは3。
245         * このメソッドで返すのは、ロケーション番号(3)の方です。
246         *
247         * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
248         *
249         * @return  ロケーション番号のサイズ
250         */
251        public int getLocationSize() {
252                // 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
253                if( location == null ) {
254                        // 8.5.4.2 (2024/01/12) PMD 7.0.0 AvoidDuplicateLiterals 対応
255//                      final String errMsg = "#makeFormat(DBTableModel)を先に実行しておいてください。" ;
256//                      throw new OgRuntimeException( errMsg );
257                        throw new OgRuntimeException( MAKE_FORMAT_ERR );
258                }
259
260                return location.length;
261        }
262
263        /**
264         * カラムのロケーション番号を返します。
265         * 引数は、0 から、getLocationSize()-1 までの数で指定します。
266         * 指定の位置の、フォーマットのカラム名に対応するロケーション番号
267         * を返します。
268         *
269         * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
270         *
271         * @param no フォーム位置番号
272         *
273         * @return ロケーション番号
274         */
275        public int getLocation( final int no ) {
276                // 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
277                if( location == null ) {
278                        // 8.5.4.2 (2024/01/12) PMD 7.0.0 AvoidDuplicateLiterals 対応
279//                      final String errMsg = "#makeFormat(DBTableModel)を先に実行しておいてください。" ;
280//                      throw new OgRuntimeException( errMsg );
281                        throw new OgRuntimeException( MAKE_FORMAT_ERR );
282                }
283
284                return location[no];
285        }
286
287        /**
288         * カラムのロケーション番号をIntStreamで返します。
289         *
290         * 指定の位置の、フォーマットのカラム名に対応するロケーション番号のIntStreamです。
291         *
292         * @og.rev 6.4.3.4 (2016/03/11) 内部のLocation配列を、IntStreamで返します。
293         *
294         * @return 内部のLocation配列を、IntStreamで返します。
295         */
296        public IntStream getLocationStream() {
297                // 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
298                if( location == null ) {
299                        // 8.5.4.2 (2024/01/12) PMD 7.0.0 AvoidDuplicateLiterals 対応
300//                      final String errMsg = "#makeFormat(DBTableModel)を先に実行しておいてください。" ;
301//                      throw new OgRuntimeException( errMsg );
302                        throw new OgRuntimeException( MAKE_FORMAT_ERR );
303                }
304
305                return IntStream.of( location );
306        }
307
308        /**
309         * 指定のロケーション番号の値をクリアします。
310         * ただし、直前のフォーマットに、td タグが存在する場合は、
311         * style="display:none;" を設定することで、td タグそのものが
312         * 無くなります。
313         * その場合、段組みなどのレイアウトを行っていると、フォーマットが
314         * 崩れますので、十分ご確認ください。
315         * また、同一 td 内に複数のカラムを指定した場合は、tdタグ内のすべての
316         * カラムが消えます。
317         * td タグが存在しない場合は、非表示というより、データを空に
318         * するだけになります。
319         *
320         * @og.rev 6.2.0.0 (2015/02/27) フォーマット系の noDisplay 対応
321         * @og.rev 6.2.0.1 (2015/03/06) 非表示のマーカーに、Formatter#NO_DISPLAY を使用する。
322         * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
323         *
324         * @param no フォーム位置番号
325         */
326        protected void setNoDisplay( final int no ) {
327                // 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
328                if( location == null || format == null ) {
329                        // 8.5.4.2 (2024/01/12) PMD 7.0.0 AvoidDuplicateLiterals 対応
330//                      final String errMsg = "#makeFormat(DBTableModel)を先に実行しておいてください。" ;
331//                      throw new OgRuntimeException( errMsg );
332                        throw new OgRuntimeException( MAKE_FORMAT_ERR );
333                }
334
335                location[no] = Formatter.NO_DISPLAY ;
336
337                int tdIdx = format[no] == null ? -1 : format[no].indexOf( "<td" ) ;             // nullチェックも兼ねる
338
339                // 6.2.0.1 (2015/03/06) 非表示のマーカーの td に、style="display:none;" 追加
340                if( tdIdx >= 0 ) {
341                        int adrs = format[no].indexOf( "style=\"" );
342                        if( adrs >= 0 ) {                                       // style 属性が既に存在する場合。
343                                adrs += "style=\"".length();    // style=" の直後の位置を求める。
344                                format[no] = format[no].substring( 0,adrs )
345                                                                + "display:none;"
346                                                                + format[no].substring( adrs ) ;
347                        }
348                        else {                                                          // style 属性がないので、td の直後に入れる。
349                                tdIdx += "<td".length();                // td の直後の位置を求める。
350                                format[no] = format[no].substring( 0,tdIdx )
351                                                                + " style=\"display:none;\""
352                                                                + format[no].substring( tdIdx ) ;
353                        }
354                }
355        }
356
357        /**
358         * フォーマット文字列を返します。
359         * 引数は、0 から、getLocationSize() までの数で指定します。
360         * 指定のフォーマットが、aaa[ABC]bbb[DEF]ccc[GHI]ddd となっている場合、
361         * aaa , bbb , ccc , ddd を引数 0 , 1 , 2 , 3 で返します。
362         *
363         * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
364         *
365         * @param no フォーム位置番号
366         *
367         * @return フォーマット文字列
368         */
369        public String getFormat( final int no ) {
370                // 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
371                if( format == null ) {
372                        // 8.5.4.2 (2024/01/12) PMD 7.0.0 AvoidDuplicateLiterals 対応
373//                      final String errMsg = "#makeFormat(DBTableModel)を先に実行しておいてください。" ;
374//                      throw new OgRuntimeException( errMsg );
375                        throw new OgRuntimeException( MAKE_FORMAT_ERR );
376                }
377
378                return format[no];
379        }
380
381        /**
382         * システムフォーマット文字列を返します。
383         * システムフォーマット文字列は、[KEY.カラム名] などの特殊記号で指定された
384         * カラム名の事で、location には、マイナスの値が設定されます。
385         * マイナスの値に応じて、処理を変えることが出来ます。
386         *
387         * [KEY.カラム名] : 行番号付きカラム名
388         * [I]            : 行番号
389         * [J]            : 登録数         7.3.1.3 (2021/03/09) ※ ただし、ここでは登録件数が判らないため、行番号を返しておきます。
390         * [ROW.ID]       : 行毎のチェックボックスのID
391         * [ROW.JSON]     : 行毎の全データのJavaScriptオブジェクト形式
392         *
393         * @og.rev 3.5.5.0 (2004/03/12) [KEY.カラム名] 機能追加
394         * @og.rev 3.5.5.2 (2004/04/02) [I] で、行番号を作成します。
395         * @og.rev 3.6.0.0 (2004/09/17) [ROW.ID] で、行毎のチェックボックスのIDを返します。
396         * @og.rev 4.0.0.0 (2007/05/02) Formatter を使用するように変更
397         * @og.rev 6.2.0.1 (2015/03/06) 非表示のマーカーに、Formatter#NO_DISPLAY を使用する。
398         * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
399         * @og.rev 7.3.1.3 (2021/03/09) [J] で、登録件数(1~) を表現する。
400         *
401         * @param       row     行番号
402         * @param       loc     位置番号
403         *
404         * @return フォーマット文字列
405         * @og.rtnNotNull
406         */
407        public String getSystemFormat( final int row,final int loc ) {
408                // 8.5.5.1 (2024/02/29) PMD 7.0.0 OnlyOneReturn メソッドには終了ポイントが 1 つだけ必要
409                final String rtn;
410//              if( loc == Formatter.SYS_ROWNUM ) {
411                if( loc == Formatter.SYS_ROWNUM || loc == Formatter.SYS_CNT ) {
412//                      return String.valueOf( row );
413                        rtn = String.valueOf( row );
414                }
415                else if( loc == Formatter.SYS_JSON ) {
416                        // 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
417                        if( formatter == null ) {
418                                // 8.5.4.2 (2024/01/12) PMD 7.0.0 AvoidDuplicateLiterals 対応
419//                              final String errMsg = "#makeFormat(DBTableModel)を先に実行しておいてください。" ;
420//                              throw new OgRuntimeException( errMsg );
421                                throw new OgRuntimeException( MAKE_FORMAT_ERR );
422                        }
423
424//                      return formatter.getJson( row );
425                        rtn = formatter.getJson( row );
426                }
427                else if( loc == Formatter.NO_DISPLAY ) {                // 6.2.0.1 (2015/03/06) 非表示のマーカー
428//                      return "";
429                        rtn = "";
430                }
431                else {
432                        final String errMsg = "システムフォーマットは、下記の形式しか使用できません。[" + loc + "]" + CR
433                                        + "  : [KEY.カラム名] : 行番号付きカラム名" + CR
434                                        + "  : [I]            : 行番号" + CR
435                                        + "  : [ROW.ID]       : 行毎のチェックボックスのID" + CR
436                                        + "  : [ROW.JSON]     : 行毎の全データのJavaScriptオブジェクト形式" ;
437                        throw new HybsSystemException( errMsg );
438                }
439                return rtn;
440        }
441
442        /**
443         * タイプ文字列を返します。
444         * タイプとは、[XXX] の記述で、[#XXX] は、XXXカラムのラベルを、[$XXX]は、XXXカラムの
445         * レンデラーを、[!XXX} は、値のみ取り出す指定を行います。
446         * 主に、TextField系のフォーマットとTable系では、意味合いが異なりますので、
447         * ご注意ください。
448         *
449         * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
450         *
451         * @param no フォーム位置番号
452         *
453         * @return タイプ文字列 '#':ラベルのみ  '$':レンデラー '!':値のみ  その他:通常
454         */
455        public char getType( final int no ) {
456                // 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
457                if( type == null ) {
458                        // 8.5.4.2 (2024/01/12) PMD 7.0.0 AvoidDuplicateLiterals 対応
459//                      final String errMsg = "#makeFormat(DBTableModel)を先に実行しておいてください。" ;
460//                      throw new OgRuntimeException( errMsg );
461                        throw new OgRuntimeException( MAKE_FORMAT_ERR );
462                }
463
464                return type[no];
465        }
466
467        /**
468         * 設定された フォーマットの trタグを返します。
469         * これは、trタグにclass属性他の設定がされていた場合に、変換後の
470         * 文字列にも反映させる為に必要です。
471         *
472         * @og.rev 5.1.7.0 (2010/06/01) サニタイズ戻し処理("\\]\\"から"["に戻し)を追加
473         *
474         * @return フォーマットの trタグ
475         * @og.rtnNotNull
476         */
477        public String getTrTag() {
478                // 6.4.1.1 (2016/01/16) PMD refactoring. A method should have only one exit point, and that should be the last statement in the method
479                return trTag == null ? "" : decodeSanitizedStr( trTag ) ;
480        }
481
482        /**
483         * カラムのクラス名(X,S9 など)のセットを行うかどうか指定します。
484         *
485         * "true" で、クラス属性を設定しません。これは、CSSファイルに書かれている属性を
486         * 使用しないことを意味します。
487         * 初期値は、"false" です。
488         *
489         * @param       flag クラス名使用の有無(true:使用しない/false:使用する。)
490         */
491        public void setNoClass( final String flag ) {
492                noClass = StringUtil.nval( flag,noClass );
493        }
494
495        /**
496         * カラムのクラス名(X,S9 など)のセットを行うかどうか取得します。
497         *
498         * "true" で、クラス属性を設定しません。これは、CSSファイルに書かれている属性を
499         * 使用しないことを意味します。
500         * 初期値は、"false" です。
501         *
502         * @return      クラス名使用の有無(true:使用しない/false:使用する。)
503         */
504        public boolean isNoClass() {
505                return noClass;
506        }
507
508        /**
509         * フォーマットの使用可否を判断するキーとなるカラム名を指定します。
510         *
511         * キーが、usableList に含まれる場合は、このフォームを使用できます。
512         * キー(カラム名)が指定されない場合は、常に使用されます。
513         * ※ 現時点では、BODYタイプのみ使用しています。
514         *
515         * @param  key フォーマットの使用可否を判断するカラム名
516         */
517        public void setUsableKey( final String key ) {
518                usableKey = key;
519        }
520
521        /**
522         *  フォーマットの使用可否を判断する文字列リストを指定します。
523         *
524         * キーが、この文字列リスト中に存在する場合は、このフォームを使用できます。
525         * この文字列リストは、固定な文字列です。{&#064;XXXX}は使用できますが、[XXXX]は
526         * 使用できません。
527         * 初期値は、"1" です。
528         * ※ 現時点では、BODYタイプのみ使用しています。
529         *
530         * @param  list フォーマットの使用可否を判断する文字列リスト
531         * @see TableFormatter#isUse( int,DBTableModel )
532         */
533        public void setUsableList( final String list ) {
534                if( list != null ) {
535                        usableList = list;
536                }
537        }
538
539        /**
540         * ここで指定したカラムの値が、キーブレイクした場合、このタグを使用します。
541         *
542         * キーブレイクで 使用可否を指定する為の機能です。
543         * この設定値は、usableKey,usableList とは、独立しているため、それぞれで
544         * 有効になれば、使用されると判断されます。
545         * キーブレイク判定では、最初の1件目は、必ず使用されると判断されます。
546         *
547         * @og.rev 5.7.6.3 (2014/05/23) 新規追加
548         *
549         * @param  kclm  キーブレイクをチェックするカラムID
550         */
551        public void setKeyBreakClm( final String kclm ) {
552                keyBreakClm = kclm;
553        }
554
555        /**
556         * このフォーマットを使用するかどうかの問い合わせを返します。
557         *
558         * "true" で、使用します。setUsableKey( String ) で、指定された
559         * カラム名の値が、setUsableList( String ) で指定された文字列に含まれていれば、
560         * 使用します。カラム名がセットされない場合は、デフォルト値("true")が使用されます。
561         * ※ 現時点では、BODYタイプのみ使用しています。
562         * カラムのデータに、不正なスペースが入る場合を想定して、trim() しています。
563         * よって、usableList の値にスペースは使用できません。
564         *
565         * 5.7.6.3 (2014/05/23) 以降は、keyBreakClm によるキーブレイクチェックも追加されました。
566         * 従来の usableKey,usableList とは、独立しているため、それぞれで有効になれば、
567         * 使用されると判断されます。
568         *
569         * @og.rev 3.5.6.2 (2004/07/05) 判定評価用カラムの値を trim() します。
570         * @og.rev 5.7.6.3 (2014/05/23) キーブレイクをチェックする keyBreakClm 属性追加
571         *
572         * @param  row 行番号
573         * @param       table   DBTableModelオブジェクト
574         *
575         * @return      このフォームを使用するかどうか(true:使用する/false:使用しない)
576         * @see TableFormatter#setUsableKey( String )
577         * @see TableFormatter#setUsableList( String )
578         */
579        public boolean isUse( final int row, final DBTableModel table ) {
580                // 8.5.5.1 (2024/02/29) PMD 7.0.0 OnlyOneReturn メソッドには終了ポイントが 1 つだけ必要
581                boolean flag = false;   // 最後まで残ると、使用されないと判断、false を返す。
582
583                // どちらも設定されていなければ、使用される(=true)
584//              if( usableKeyNo < 0 && breakClmNo < 0 ) { return true; }
585                if( usableKeyNo < 0 && breakClmNo < 0 ) { flag = true; }
586
587                // 以下、どちらかは設定されているため、true の時点で、使用される(=true)を返す。
588                else if( usableKeyNo >= 0 ) {
589                        final String val = table.getValue( row,usableKeyNo ).trim();
590//                      if( usableList.indexOf( val ) >= 0 ) { return true; }
591                        if( usableList.indexOf( val ) >= 0 ) { flag = true; }
592                }
593
594                else if( breakClmNo >= 0 ) {
595                        final String val = table.getValue( row,breakClmNo ).trim();
596                        if( !val.equals( breakVal ) ) {                 // 同じでない場合は、true
597                                breakVal = val;
598//                              return true;
599                                flag = true;
600                        }
601                }
602
603//              return false ;                  // 最後まで残ると、使用されないと判断、false を返す。
604                return flag ;                   // 最後まで残ると、使用されないと判断、false を返す。
605        }
606
607        /**
608         *  itdフォーマット文字列を設定します。
609         *
610         * itd ボディ部の文字列を指定します。
611         * itd ボディは、繰り返し処理を行います。これを、上位のボディ文字列の中の
612         * HYBS_ITD_MARKER 文字列 と置き換えます。
613         *
614         * @og.rev 3.5.6.0 (2004/06/18) itdフォーマット文字列の取り込み
615         *
616         * @param  itd itdフォーマットの文字列
617         */
618        public void setItdBody( final String itd ) {
619                if( itd != null ) {
620                        itdBody = itd;
621                }
622        }
623
624        /**
625         *  itdフォーマット文字列を取得します。
626         *
627         * itd ボディ部の文字列を取得します。
628         * itd ボディは、繰り返し処理を行います。これを、上位のボディ文字列の中の
629         * HYBS_ITD_MARKER 文字列 と置き換えます。
630         *
631         * @og.rev 3.5.6.0 (2004/06/18) itdフォーマット文字列の取り込み
632         *
633         * @return      itdフォーマットの文字列
634         */
635        public String getItdBody() {
636                return itdBody;
637        }
638
639        /**
640         * サニタイズの戻し("\\]\\"から"["に戻し)を行います。
641         *
642         * @og.rev 5.1.7.0 (2010/06/01) 新規作成
643         *
644         * @param str サニタイズされた文字列
645         *
646         * @return サニタイズ戻し処理後の文字列
647         */
648        private String decodeSanitizedStr( final String str ) {
649                // 6.4.1.1 (2016/01/16) PMD refactoring. A method should have only one exit point, and that should be the last statement in the method
650                return str != null && str.indexOf( "\\]\\" ) >= 0 ? str.replace( "\\]\\", "[" ) : str;
651        }
652}