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.taglib;
017
018import org.opengion.fukurou.system.OgBuilder ;                          // 6.4.4.1 (2016/03/18)
019
020import org.opengion.fukurou.util.TagBuffer;
021import org.opengion.fukurou.util.XHTMLTag;
022import org.opengion.fukurou.util.ToString;                                              // 6.1.1.0 (2015/01/17)
023import org.opengion.hayabusa.common.HybsSystemException;
024import org.opengion.hayabusa.db.DBTableModel;
025import org.opengion.hayabusa.db.DBTableModelUtil;
026
027import static org.opengion.fukurou.util.StringUtil.nval;
028
029import java.io.IOException;
030import java.io.ObjectInputStream;
031import java.util.ArrayList;
032import java.util.List;
033import java.util.Locale;
034import java.util.Arrays;                                                                                // 6.4.3.4 (2016/03/11)
035import java.util.stream.Collectors;                                                             // 6.4.3.4 (2016/03/11)
036
037/** タブ形式のリンクを表示するタグです。
038 *
039 * このタグ形式の実態は、リンクのリストであるため、実の画面の表示はターゲットを指定して
040 * 別フレームで行う必要があります。
041 *
042 * タブの指定方法については、listType属性の指定により、クエリ発行(DB)により動的に生成する
043 * パターンと、タグ指定(TAG)により、静的に生成するパターンがあります。
044 * listType属性に何も指定されていない場合は、Body部分に記述された内容により、自動判定されます。
045 * ("SELECT"で始まっている場合はDB、それ以外はTAGとして処理)
046 *
047 * ①listType属性が"DB"の場合
048 *  検索された各カラムは、その順番により次の意味を持ちます。
049 *  [第1カラム] タブの名前        : リンク時のキー情報、後述のopenTabName属性のキーとしても使用 ※必須
050 *  [第2カラム] タブの表示名称    : タブの表示名称 指定がない場合は、第1カラムが表示名称となります。
051 *  [第3カラム] タブのリンク先URL : タブのリンク先URL 指定がない場合は、href属性の値が適用されます。
052 *  [第4カラム] タブのクラス属性  : 個別のタブに付加されるクラス属性 指定がない場合は、unselClass属性の値が適用されます。
053 *  [第5カラム] タブのロールズ    : タブのロールズを指定します。ユーザーロールズと一致しない指定した場合は、タブが表示されなくなります。
054 *  [第6カラム] タブの選択可否    : タブの選択可否を'true'or'false'で指定します。falseを指定した場合は、タブが表示されなくなります。
055 *                                  (ロールズで選択不可になっている場合は、この値は無視されます)
056 *  各カラムの値は[カラム名]=[値]の形で、リンク先のJSPに引数として渡されます。
057 *  また、リンク先のJSPについては、href属性で指定します。
058 *
059 * ②listType属性が"TAG"の場合
060 *  tabListタグを記述し、個別にタブを定義します。
061 *  制御可能な項目は、①DBの場合と同等です。
062 *  タブの名前を定義するname属性は、tabListタグで必ず定義する必要があります。
063 *  lbl属性が指定されていない場合は、name属性のラベル名称を取得します。
064 *  タブのリンク先JSP及び、クラス属性については、tabListタグで指定がない場合、tabListタグの値が適用されます。
065 *
066 * [共通設定]
067 * 初期設定では、第1番目の"有効な"タブが自動的に開かれます。(="true")
068 * 各タブの表示方法で、選択不可能なタブが存在している場合は、それらを読み飛ばした上で、"有効な"タブを
069 * 検索します。
070 * また、自動で開くタブは、openTabName属性で指定可能であり、これに変数を定義することで、
071 * 画面リロード時も、開いていたタブを再度選択された状態で表示することが可能です。
072 *
073 * 選択したタブ及び非選択のタブの枠線や、背景色等を変更する場合は、custom.cssでクラスを定義し、
074 * 変更して下さい。
075 *
076 * タブの表示方向(水平方向 or 垂直方向)については、orientation属性で変更することが可能です。
077 * (初期値は、水平方向)
078 * 水平方向にした場合は、listCount属性により強制的に一定数のタブを表示する毎に、改行を挿入することができます。
079 *
080 * このタグを使用する場合は、headタグで必ずuseTabLink="true"を指定してJavaScriptをロードして下さい。
081 *
082 * 各属性は、{@XXXX} 変数が使用できます。
083 * これは、ServletRequest から、XXXX をキーに値を取り出し,この変数に割り当てます。
084 * つまり、このXXXXをキーにリクエストすれば、この変数に値をセットすることができます。
085 *
086 * @og.formSample
087 * ●形式:<og:tabLink href="…" … />
088 * ●body:あり(EVAL_BODY_BUFFERED:BODYを評価し、{@XXXX} を解析します)
089 *
090 * ●Tag定義:
091 *   <og:tabLink
092 *       listType           【TAG】タブの一覧をどこから取得するかを指定します(初期値:AUTO)
093 *       href               【TAG】リンク先のJSPを指定します(初期値:result.jsp)
094 *       target             【TAG】リンクのターゲットを指定します(初期値:RESULT)
095 *       openTab            【TAG】リンク表示にタブリンクを自動で開くかどうか[true/false]を指定します(初期値:true[=開く])
096 *       openTabName        【TAG】最初に開くタブリンクの名前を指定します
097 *       constKeys          【TAG】次画面に渡す定数パラメーターのキーを指定します
098 *       constVals          【TAG】次画面に渡す定数パラメーターの値を指定します
099 *       listCount          【TAG】1行辺りに表示するタブの数を指定します(初期値:10)
100 *       selClass           【TAG】選択タブのクラスを指定します(初期値:selTab)
101 *       unselClass         【TAG】非選択タブのクラスを指定します(初期値:unselTab)
102 *       orientation        【TAG】タブの方向、横型(Horizontal)か縦型(Vertical)を指定します(初期値:横型)
103 *       width              【TAG】タブリンクの幅を % 、px 、または "auto" で指定します
104 *       height             【TAG】タブの高さを、% 、px 、または "auto" で指定します
105 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
106 *   >   ... Body ...
107 *   </og:tabLink>
108 *
109 * ●使用例
110 *   ①DBからタブリストを取得する場合
111 *
112 *    Body部分に記述されたクエリよりタブ一覧を生成します。
113 *
114 *      <og:tabLink
115 *          listType        = "DB"                      タブの一覧をどこから取得するか
116 *          href            = "result.jsp"              リンク先のJSP
117 *          target          = "RESULT"                  リンクターゲット
118 *          openTab         = "[true/false]"            タブ表示後にタブを自動で開く
119 *          openTabName     = "{@PN}               自動で開くタブの名前
120 *          constKeys       = "KEY1"                    次画面に固定で渡すキー一覧
121 *          constVals       = "{@VAL1}"            次画面に固定で渡す値一覧
122 *          listCount       = "10"                      1行辺りに表示するタブの数
123 *          selClass        = "selTab"                  選択タブのクラス
124 *          unselClass      = "unselTab"                非選択タブのクラス
125 *          width           = "100px"                   タブリンクの幅
126 *          height          = "50px"                    タブリンクの高さ
127 *       >
128 *               select PN,HINM,'tabClass','query.jsp','ADMIN','false' from XX01 where PN = '{@PN}' order by PN
129 *      </og:tabLink>
130 *
131 *   ②tabListタグからタブリストを生成する場合
132 *
133 *    tabListタグよりタブ一覧を生成します。
134 *
135 *      <og:tabLink
136 *          listType        = "DB"                      タブの一覧をどこから取得するか
137 *          href            = "result.jsp"              リンク先のJSP
138 *          target          = "RESULT"                  リンクターゲット
139 *          openTab         = "[true/false]"            タブ表示後にタブを自動で開く
140 *          openTabName     = "{@PN}               自動で開くタブの名前
141 *          constKeys       = "KEY1"                    次画面に固定で渡すキー一覧
142 *          constVals       = "{@VAL1}"            次画面に固定で渡す値一覧
143 *          listCount       = "10"                      1行辺りに表示するタブの数
144 *          selClass        = "selTab"                  選択タブのクラス
145 *          unselClass      = "unselTab"                非選択タブのクラス
146 *          width           = "100px"                   タブリンクの幅
147 *          height          = "50px"                    タブリンクの高さ
148 *       >
149 *          <og:tabList name="TAB1" href="result1.jsp" keys="PN,CDK" vals="ABC,V" />
150 *          <og:tabList name="TAB2" href="result2.jsp" keys="PN,CDK" vals="BCD,W" />
151 *          <og:tabList name="TAB3" href="result3.jsp" keys="PN,CDK" vals="CDE,X" />
152 *      </og:tabLink>
153 *
154 * @og.group 画面表示
155 *
156 * @version  0.9.0      2008/09/26
157 * @author       Nakamura
158 * @since        JDK1.4,
159 */
160public class TabLinkTag extends CommonTagSupport {
161        private static final String VERSION = "6.4.4.1 (2016/03/18)" ;
162        private static final long serialVersionUID = 644120160318L ;
163
164        /** リストのulタグのclass属性 */
165        private static final String             UL_TAG_START            = "<ul class=\"tabList\">";
166        private static final String             UL_TAG_END                      = "</ul>";
167
168        /** タブ表示を入れ替えるためのJavaScript関数 */
169        private static final String             CHANGE_TAB_SCRIPT       = "changeTab";
170        private static final String             INITIAL_TAB_SCRIPT      = "initialTabSelect";
171
172        /** 自動で開くタブに付加されるID */
173        private static final String             FIRST_TAB_ID            = "firstTab";
174
175        /** リスト取得タイプのEnum */
176        private enum LIST_TYPE { AUTO, DB, TAG };
177//      private static enum LIST_TYPE { AUTO, DB, TAG };
178
179        /** 内部変数 */
180        private String          query                   ;
181        private transient List<TabData>         tabData         = new ArrayList<>();
182
183        /** タグで設定する属性 */
184        private LIST_TYPE       type                    = LIST_TYPE.AUTO;
185        private String          href                    = "result.jsp";
186        private String          target                  = "RESULT";
187        private boolean         openTab                 = true;
188        private String          openTabName             ;
189        private String[]        constKeys               ;
190        private String[]        constVals               ;
191        private int                     listCount               = 10;
192        private String          selClass                = "selTab";
193        private String          unselClass              = "unselTab";
194        private boolean         isHorizontal    = true;
195        private String          width                   = "auto";
196        private String          height                  = "auto";
197
198        /**
199         * デフォルトコンストラクター
200         *
201         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
202         */
203        public TabLinkTag() { super(); }                // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
204
205        /**
206         * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。
207         *
208         * @return      後続処理の指示( EVAL_BODY_BUFFERED )
209         */
210        @Override
211        public int doStartTag() {
212                return EVAL_BODY_BUFFERED ;     // Body を評価する
213        }
214
215        /**
216         * Taglibのタグ本体を処理する doAfterBody() を オーバーライドします。
217         *
218         * @og.rev 6.3.1.1 (2015/07/10) BodyString,BodyRawStringは、CommonTagSupport で、trim() します。
219         *
220         * @return      後続処理の指示(SKIP_BODY)
221         */
222        @Override
223        public int doAfterBody() {
224                query = getBodyString();
225                return SKIP_BODY ;
226        }
227
228        /**
229         * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
230         *
231         * @og.rev 4.3.5.0 (2008/02/01) 処理及び内部構造を大幅に見直し
232         *
233         * @return      後続処理の指示
234         */
235        @Override
236        public int doEndTag() {
237                debugPrint();
238                final int rtnCode = EVAL_PAGE;
239
240                // 種別の自動判定処理
241                if( type == LIST_TYPE.AUTO ) {
242                        if( query == null || query.isEmpty() ) {
243                                type = LIST_TYPE.TAG;
244                        }
245                        else {
246                                if( query.toUpperCase( Locale.JAPAN ).indexOf( "SELECT" ) >= 0 ) {
247                                        type = LIST_TYPE.DB;
248                                }
249                                else {
250                                        type = LIST_TYPE.TAG;
251                                }
252                        }
253                }
254
255                if( type == LIST_TYPE.DB ) {
256                        makeTabsFromQuery();
257                }
258                else if( type == LIST_TYPE.TAG ) {
259                        makeTabsFromTag();
260                }
261
262                // リンク一覧が何も設定されていない場合は、処理しない
263                if( ! tabData.isEmpty() ) {
264                        makeTag();
265                }
266
267                return rtnCode ;
268        }
269
270        /**
271         * タグリブオブジェクトをリリースします。
272         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
273         */
274        @Override
275        protected void release2() {
276                super.release2();
277                query                   = null;
278                tabData                 = new ArrayList<>();
279                type                    = LIST_TYPE.AUTO;
280                href                    = "result.jsp";
281                target                  = "RESULT";
282                openTab                 = true;
283                openTabName             = null;
284                constKeys               = null;
285                constVals               = null;
286                listCount               = 10;
287                selClass                = "selTab";
288                unselClass              = "unselTab";
289                isHorizontal    = true;
290                width                   = "auto";
291                height                  = "auto";
292        }
293
294        /**
295         * DBからタブリンクの一覧を作成します。
296         * DBTableModelが作成されない(行数が0の場合)は、リンク一覧は生成されません。
297         *
298         * @og.rev 6.3.9.1 (2015/11/27) 3項演算子を || or &amp;&amp; で簡素化できる(PMD)。
299         */
300        private void makeTabsFromQuery() {
301                final DBTableModel table = DBTableModelUtil.makeDBTable( query, new String[0], getResource(), getApplicationInfo() );
302                if( table == null || table.getRowCount() == 0 ) {
303                        return;
304                }
305
306                // 6.3.9.1 (2015/11/27) 初期値設定の簡素化
307                final boolean isSetLabel        = table.getColumnCount() > 1;
308                final boolean isSetHref         = table.getColumnCount() > 2;
309                final boolean isSetClazz        = table.getColumnCount() > 3;
310                final boolean isSetRoles        = table.getColumnCount() > 4;
311                final boolean isSetVisible      = table.getColumnCount() > 5;
312
313                final int rowCount = table.getRowCount();
314                final String key   = table.getColumnName( 0 );
315                // 6.3.9.1 (2015/11/27) visible=true以外は処理しないので、先に求める。
316                for( int row=0; row<rowCount; row++ ) {
317                        final boolean visible = ( !isSetRoles   || getUser().isAccess( table.getValue( row, 4 ) ) ) &&
318                                                                        ( !isSetVisible || Boolean.valueOf(    table.getValue( row, 5 ) ) );
319
320                        if( visible ) {
321                                final String value      = table.getValue( row, 0 );
322                                final String label      = ( isSetLabel ? nval( table.getValue( row, 1 ), value ) : value );
323                                String newHref  = ( isSetHref  ? nval( table.getValue( row, 2 ), href ) : href );
324                                // 第1カラムのカラム名とその値はリンクの引数に含める
325                                newHref = XHTMLTag.addUrlEncode( newHref, XHTMLTag.urlEncode( key, value ) );
326
327                                final String clazz      = ( isSetClazz ? nval( table.getValue( row, 3 ), unselClass ) : unselClass );
328
329                                tabData.add( new TabData( newHref, value, label, clazz, visible ) );
330                        }
331                }
332        }
333
334        /**
335         * タブリストからタブリンクの一覧を作成します。
336         * (予めaddTagメソッドにより、リンク一覧が登録されているため、ここでは何も処理しません)
337         *
338         * @see #addTag( String, String, String, String, boolean, String[], String[] )
339         */
340        private void makeTabsFromTag() {
341                // 何もありません。(PMD エラー回避)
342        }
343
344        /**
345         * 子タグであるタブリストタグからタブ情報をセットします。
346         *
347         * @param hr 画面URL
348         * @param name タブの名前
349         * @param label タブの表示名称
350         * @param clz 非選択状態のタブに付加するclass名
351         * @param visible タブが選択可能 [true:可能/false:不可能]
352         * @param keys リンク先のJSPに渡すキー一覧
353         * @param vals リンク先のJSPに渡す値一覧
354         */
355        protected void addTag( final String hr, final String name, final String label, final String clz
356                                                        ,final boolean visible, final String[] keys, final String[] vals ) {
357                String newHref = nval( hr, href );
358                if( keys != null && keys.length > 0 ) {
359                        newHref = XHTMLTag.addUrlEncode( newHref, XHTMLTag.urlEncode( keys, vals ) );
360                }
361
362                if( visible ) { // visible=falseの場合は表示しない
363                        tabData.add( new TabData( newHref, name, nval( label, getLabel( name ) ), nval( clz, unselClass ), visible ) );
364                }
365        }
366
367        /**
368         * リンク一覧からHTMLタグを作成します。
369         *
370         * @og.rev 5.0.2.0 (2009/11/01) openTab属性がfalseの場合でも、openTabNameに指定されたタブに色付けする。
371         * @og.rev 5.1.4.0 (2010/03/01) FF対応&FirstTabのID付加に関するバグを修正
372         * @og.rev 6.4.4.1 (2016/03/18) StringBuilderの代わりに、OgBuilderを使用する。
373         */
374        private void makeTag() {
375                final OgBuilder buf = new OgBuilder().appendCR();
376
377                boolean isExistFirst = false;
378                for( int idx=0; idx<tabData.size(); idx++ ) {
379                        final TabData tab = tabData.get( idx );
380
381                        if( idx % listCount == 0 ) {
382                                buf.appendIfCR( idx > 0 , UL_TAG_END )                          // if
383                                        .appendCR( UL_TAG_START );
384                        }
385
386                        // openTabNameが定義されていない場合は、1番目の有効なタブを開く
387                        // 5.1.4.0 (2010/03/01) バグ修正
388                        if( !isExistFirst && tab.visible
389                                && ( openTabName == null || openTabName.isEmpty() || openTabName.equals( tab.name ) ) ) {
390                                buf.append( tab.makeLiTag( idx, true ) );
391                                isExistFirst = true;
392                        }
393                        else {
394                                buf.append( tab.makeLiTag( idx, false ) );
395                        }
396                }
397                buf.appendCR( UL_TAG_END )
398                        .appendIf( openTab || openTabName != null && openTabName.length() > 0                                           // 6.9.7.0 (2018/05/14) PMD Useless parentheses.
399                                        , "<script type=\"text/javascript\">addEvent(window,\"load\", function() { "
400                                        , INITIAL_TAB_SCRIPT
401                                        , "(" , String.valueOf( openTab ) , "); } );</script>" );
402
403                jspPrint( buf.toString() );
404        }
405
406        /**
407         * Tabデータ を管理している 内部クラス
408         *
409         * タブの情報を管理するための簡易的な、内部クラスです。
410         */
411        private final class TabData {
412                // 引数として初期設定される変数
413                private final String href;
414                private final String name;
415                private final String label;
416                private final String clazz;
417                // 現状の実装では、visible=falseは渡ってきませんが、将来的にdisableの状態で
418                // 表示したい場合等に対応するため残しておきます。
419                private final boolean visible;
420
421                /**
422                 * コンストラクタ
423                 *
424                 * @param hr 画面URL
425                 * @param nm タブの名前
426                 * @param lbl タブの表示名称
427                 * @param clz 非選択状態のタブに付加するclass名
428                 * @param vsb タブが選択可能 [true:可能/false:不可能]
429                 */
430                public TabData( final String hr, final String nm, final String lbl, final String clz, final boolean vsb ) {
431                        href    = hr;
432                        name    = nm;
433                        label   = lbl;
434                        clazz   = clz;
435                        visible = vsb;
436                }
437
438                /**
439                 * liタグの部分の文字列を生成します。
440                 *
441                 * @og.rev 6.4.4.1 (2016/03/18) StringBuilderの代わりに、OgBuilderを使用する。
442                 *
443                 * @param idx           生成したタブのインデックス番号
444                 * @param isFirst       始めの有効なタブかどうか[true:始め/false:それ以外]
445                 * @return liタグ文字列
446                 * @og.rtnNotNull
447                 */
448                private String makeLiTag( final int idx, final boolean isFirst ) {
449                        return new OgBuilder()
450                                .append( "<li class=\"" , clazz , "\""
451                                                , " style=\""
452                                                , " width: "    , width  , ";"
453                                                , " height: "   , height , ";" )
454                                .appendIf( isHorizontal , " float: left;" )
455                                .appendIf( isHorizontal && ( idx % listCount == 0 )     // if-if なので、少し無駄かも
456                                                , " clear: left; margin-left: "
457                                                , String.valueOf( (idx/listCount) * 10 )
458                                                , "px;" )
459                                .appendCR( " \">" , makeLinkTag( isFirst ) , "</li>" )
460                                .toString();
461                }
462
463                /**
464                 * aタグの部分の文字列を生成します。
465                 * タブが選択不可能な状態の場合は、タブの表示文字列をそのまま返します。
466                 *
467                 * @og.rev 4.3.6.4 戻るボタンがでない問題への対応
468                 *
469                 * @param       isFirst 始めの有効なタブかどうか[true:始め/false:それ以外]
470                 * @return      liタグ文字列
471                 * @og.rtnNotNull
472                 */
473                private String makeLinkTag( final boolean isFirst ) {
474                        String newHref = XHTMLTag.addUrlEncode( href, XHTMLTag.urlEncode( constKeys, constVals ) );
475                        // 4.3.6.4 (2009/05/01)
476                        // タブ画面から遷移した時に、タブの読込により、画面IDが消えてしまい
477                        // 戻るボタンがでない不具合への対応
478                        newHref = XHTMLTag.addUrlEncode( newHref, "GAMENID=" + getGUIInfoAttri( "KEY" ) );
479
480                        // 6.1.1.0 (2015/01/17) TagBufferの連結記述
481                        return new TagBuffer( "a" )
482                                        .add( "href"    , newHref )
483                                        .add( "name"    , name )
484                                        .add( "target"  , target )
485                                        .add( "onClick" , CHANGE_TAB_SCRIPT + "( this, \"" + selClass + "\" );" )
486                                        .add( "id"              , FIRST_TAB_ID  , isFirst )
487                                        .addBody( label )
488                                        .makeTag();
489                }
490        }
491
492        /**
493         * 【TAG】タブの一覧をどこから取得するか[AUTO/DB/TAG]を指定します(初期値:AUTO)。
494         *
495         * @og.tag
496         * タブの一覧をどこから取得するかを指定します。
497         * 現状の実装では、クエリを発行して一覧を生成する「DB」と、子タグである
498         * tabListタグを列挙してタブを定義する「TAG」が実装されています。
499         *
500         * また、「AUTO」と指定した場合は、Body部分の内容に応じて自動的に判定されます。
501         * 初期値は、「AUTO」です。
502         *
503         * @og.rev 6.4.3.4 (2016/03/11) CSV形式の文字連結を、stream 経由で行います。
504         *
505         * @param       tp 取得方法 [AUTO/DB/TAG]
506         */
507        public void setListType( final String tp ) {
508                final String typeStr = nval( getRequestParameter( tp ), null );
509                try {
510                        type = LIST_TYPE.valueOf( typeStr );
511                }
512                catch( final IllegalArgumentException ex ) {
513                        final String errMsg = Arrays.stream( LIST_TYPE.values() )
514                                                                        .map( obj -> obj.name() )
515                                                                        .collect( Collectors.joining( "," , "listType は " , " から選んでください。" ) );  // 連結文字 , 最初 , 最後
516                        throw new HybsSystemException( errMsg, ex );
517                }
518        }
519
520        /**
521         * 【TAG】リンク先のJSPを指定します(初期値:result.jsp)。
522         *
523         * @og.tag
524         * リンク先のJSPを指定します。
525         * このタブリンクは、あくまで「タブの形をしたリンク」なので、
526         * target属性と合わせてセットする必要があります。
527         * 初期値は、「result.jsp」です。
528         *
529         * @param       hr リンク先のJSP
530         */
531        public void setHref( final String hr ) {
532                href = nval( getRequestParameter( hr ), href );
533        }
534
535        /**
536         * 【TAG】リンクのターゲットを指定します(初期値:RESULT)。
537         *
538         * @og.tag
539         * リンクのターゲットを指定します。
540         * このタブリンクは、あくまで「タブの形をしたリンク」なので、
541         * target属性を設定し、別のフレームに実画面を表示するようにします。
542         * 初期値は、「RESULT」です。
543         *
544         * @param       tgt リンクターゲット
545         */
546        public void setTarget( final String tgt ) {
547                target = nval( getRequestParameter( tgt ), target );
548        }
549
550        /**
551         * 【TAG】リンク表示にタブリンクを自動で開くかどうか[true/false]を指定します(初期値:true[=開く])。
552         *
553         * @og.tag
554         * リンク表示にタブリンクを自動で開くかを指定します。
555         * openTabName属性が指定されていない場合、自動で開くタブは
556         * 「1番目に表示されたタブリンク」です。
557         * 指定されている場合は、その名前を持つ「1番目」のタブが自動で開かれます。
558         * タブが選択不可能な状態の場合は、「1番目」の条件から除外されます。
559         * 初期値は、「true(開く)」です。
560         *
561         * @param       flag 自動タブオープン [true:自動で開く/false:開かない]
562         */
563        public void setOpenTab( final String flag ) {
564                openTab = nval( getRequestParameter( flag ), openTab );
565        }
566
567        /**
568         * 【TAG】最初に開くタブリンクの名前を指定します。
569         *
570         * @og.tag
571         * 最初に開くタブリンクのキーを指定します。
572         *
573         * @param       name 初期表示タブ名前
574         */
575        public void setOpenTabName( final String name ) {
576                openTabName = nval( getRequestParameter( name ), openTabName );
577        }
578
579        /**
580         * 【TAG】次画面に渡す定数パラメーターのキーを指定します。
581         *
582         * @og.tag
583         * 次画面に渡す定数パラメーターのキーを指定します。
584         * キーはCSV形式で複数指定が可能です。
585         * パラメーターの値は、constVals属性の数と一致している必要があります。
586         *
587         * @param       keys 定数キー (CSV形式)
588         * @see         #setConstVals( String )
589         */
590        public void setConstKeys( final String keys ) {
591                constKeys = getCSVParameter( keys );
592        }
593
594        /**
595         * 【TAG】次画面に渡す定数パラメーターの値を指定します。
596         *
597         * @og.tag
598         * 次画面に渡す定数パラメーターの値を指定します。
599         * 値はCSV形式で複数指定が可能です。
600         * パラメーターの値は、constKeys属性の数と一致している必要があります。
601         *
602         * @param       vals 定数値 (CSV形式)
603         * @see         #setConstKeys( String )
604         */
605        public void setConstVals( final String vals ) {
606                constVals = getCSVParameter( vals );
607        }
608
609        /**
610         * 【TAG】1行辺りに表示するタブの数を指定します(初期値:10)。
611         *
612         * @og.tag
613         * 1行辺りに表示するタブの数を指定します。
614         * 1行辺りのタブの数がこの設定を超えると、自動的に折り返します。
615         * また、折り返し毎に、左に10pxのマージンを設けます。
616         * 初期値は、10です。
617         * この属性は、orientationがHorizontal(水平方向)の場合のみ有効です。
618         *
619         * @param       cnt 1行タブ数
620         */
621        public void setListCount( final String cnt ) {
622                listCount = nval( getRequestParameter( cnt ), listCount );
623        }
624
625        /**
626         * 【TAG】選択タブのクラスを指定します(初期値:selTab)。
627         *
628         * @og.tag
629         * タブが選択されている状態にある場合の、タブ部分のクラス名を指定します。
630         * このクラス名を変更する場合は、そのクラスをcustom/custom.css等で再定義して下さい。
631         * 初期値は、selTabです。
632         *
633         * @param       cls 選択タブのクラス名
634         */
635        public void setSelClass( final String cls ) {
636                selClass = nval( getRequestParameter( cls ), selClass );
637        }
638
639        /**
640         * 【TAG】非選択タブのクラスを指定します(初期値:unselTab)。
641         *
642         * @og.tag
643         * タブが選択されていない状態にある場合の、タブ部分のクラス名を指定します。
644         * このクラス名を変更する場合は、そのクラスをcustom/custom.css等で再定義して下さい。
645         * 初期値は、unselTabです。
646         *
647         * @param       cls 選択タブのクラス名
648         */
649        public void setUnselClass( final String cls ) {
650                unselClass = nval( getRequestParameter( cls ), unselClass );
651        }
652
653        /**
654         * 【TAG】タブの方向[Horizontal(or H):横型/Vertical(or V):縦型]を指定します(初期値:Horizontal:横型)。
655         *
656         * @og.tag
657         * タブは、上にタブが並ぶ横型と左にタブが並ぶ縦型があります。
658         * この属性では、横型は、Horizontal 、縦型は、Vertical を指定します。
659         * 指定は、文字列の最初の一文字を見ているだけですので、HかVでも構いません。
660         *
661         * 縦型(Vertical)にした場合、各タブ要素は、フレームサイズの幅に合わせて
662         * 最大で表示されます。幅を固定する場合は、width属性を指定して下さい。
663         *
664         * 初期値は、横型(Horizontal) です。
665         *
666         * @param       ori タブの方向 [Horizontal(or H):横型/Vertical(or V):縦型]
667         */
668        public void setOrientation( final String ori ) {
669                final String ori2 = nval( getRequestParameter( ori ),null );
670                if( ori2 != null && ori2.length() > 0 ) {
671                        final char ch = ori2.toUpperCase(Locale.JAPAN).charAt(0);
672                        if( ch == 'H' ) { isHorizontal = true; }
673                        else if( ch == 'V' ) { isHorizontal = false; }
674                        else {
675                                final String errMsg = "orientation の指定は、H(orizontal) または、V(ertical) です。"
676                                                        + " orientation=" + ori2 ;                      // 5.1.8.0 (2010/07/01) errMsg 修正
677                                throw new HybsSystemException( errMsg );
678                        }
679                }
680        }
681
682        /**
683         * 【TAG】タブリンクの幅を % 、px 、または "auto" で指定します(初期値:auto)。
684         *
685         * @og.tag
686         * 初期値は、"auto"(自動設定) です。
687         * autoの場合、横型表示では、文字の幅に合わせて自動的に調整され、
688         * 縦型表示の場合は、フレームサイズに合わせて拡大して表示されます。
689         *
690         * @param       wh      幅 (% 、px 、または "auto" )
691         */
692        public void setWidth( final String wh ) {
693                width = nval( getRequestParameter( wh ),width );
694        }
695
696        /**
697         * 【TAG】タブの高さを、% 、px 、または "auto" で指定します(初期値:auto)。
698         *
699         * @og.tag
700         * タブの高さを、% 、px 、または "auto" で指定します
701         * 初期値は、"auto"(自動設定) です。
702         *
703         * @param       ht      高さ (% 、px 、または "auto" )
704         */
705        public void setHeight( final String ht ) {
706                height = nval( getRequestParameter( ht ),height );
707        }
708
709        /**
710         * シリアライズ用のカスタムシリアライズ読み込みメソッド
711         *
712         * ここでは、transient 宣言された内部変数の内、初期化が必要なフィールドのみ設定します。
713         *
714         * @og.rev 5.1.8.0 (2010/07/01) tabData の初期化処理 追加
715         * @serialData 一部のオブジェクトは、シリアライズされません。
716         *
717         * @param       strm    ObjectInputStreamオブジェクト
718         * @see #release2()
719         * @throws IOException  シリアライズに関する入出力エラーが発生した場合
720         * @throws ClassNotFoundException       クラスを見つけることができなかった場合
721         */
722        private void readObject( final ObjectInputStream strm ) throws IOException, ClassNotFoundException {
723                strm.defaultReadObject();
724                tabData         = new ArrayList<>();
725        }
726
727        /**
728         * このオブジェクトの文字列表現を返します。
729         * 基本的にデバッグ目的に使用します。
730         *
731         * @return このクラスの文字列表現
732         * @og.rtnNotNull
733         */
734        @Override
735        public String toString() {
736                return ToString.title(this.getClass().getName() )
737                .println( "VERSION"       , VERSION )
738                .println( "listType"      , type.toString() )
739                .println( "href"          , href )
740                .println( "target"        , target )
741                .println( "openTab"       , openTab )
742                .println( "openTabName"   , openTabName )
743                .println( "constKeys"     , constKeys )
744                .println( "constVals"     , constVals )
745                .println( "listCount"     , listCount )
746                .println( "selClass"      , selClass )
747                .println( "unselClass"    , unselClass )
748                .println( "isHorizontal"  , isHorizontal )
749                .println( "width"         , width )
750                .println( "height"        , height )
751                .println( "Other...", getAttributes().getAttribute() ).fixForm().toString();
752        }
753}