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