    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 java.util.ArrayList;
    019import java.util.Collections;
    020import java.util.Enumeration;
    021import java.util.HashMap;
    022import java.util.List;
    023import java.util.Map;
    024import java.util.stream.Collectors;                                                     // 6.4.3.4 (2016/03/11)
    025
    026import org.opengion.fukurou.system.OgBuilder ;                          // 6.4.4.1 (2016/03/18)
    027import org.opengion.fukurou.system.OgRuntimeException ;         // 6.4.2.0 (2016/01/29)
    028import org.opengion.fukurou.util.StringUtil;
    029import org.opengion.fukurou.util.TagBuffer;
    030import org.opengion.fukurou.util.ToString;                                      // 6.1.1.0 (2015/01/17)
    031import org.opengion.hayabusa.common.HybsSystem;
    032import org.opengion.hayabusa.common.HybsSystemException;
    033import org.opengion.hayabusa.db.DBColumn;
    034import org.opengion.hayabusa.db.DBEditConfig;
    035// import org.opengion.hayabusa.db.DBEditConfigManager;         // 6.4.5.0 (2016/04/08) 6.9.2.1 (2018/03/12) 廃止
    036import org.opengion.hayabusa.db.DBLastSql;
    037import org.opengion.hayabusa.db.DBTableModel;
    038
    039import static org.opengion.fukurou.util.StringUtil.nval;
    040
    041/**
    042 * 画面表示、集計に関する設定情報の表示、登録を行うためのタグです。
    043 * (このタグは標準の設定編集画面に組み込んで使用され、各画面JSPから呼び出すことはありません)
    044 *
    045 * このタグは、ユーザー単位に管理される編集設定オブジェクトに対するI/Fの機能を
    046 * 提供しています。この編集設定オブジェクトについては、画面毎に設定を行うため、
    047 * タグの呼び出しには、画面IDが必須となっています。
    048 *
    049 * 具体的な機能としては、3つの機能を提供します。
    050 * (1)設定画面表示(command="GET")
    051 *    ユーザー単位に管理される編集設定オブジェクトをHTMLに変換して表示
    052 *    また、表示カラムの一覧(CSV形式)については、画面側のJavaScriptで再設定を行うため、
    053 *    その値を"viewClms"という名前のhiddenタグで出力します。
    054 * (2)編集名一覧(command="LIST")
    055 *    指定の画面IDに対して、設定されている編集名の一覧をプルダウン(selectタグ)に
    056 *    変換して表示します。(name="editName")
    057 * (3)設定情報登録/削除(command="SET"/"DELETE")
    058 *    (1)で設定された内容に対して、編集名を指定してその内容を保存/削除します。
    059 *    情報の保存は、command="GET"で表示される項目名と連動していますので、単独での使用は
    060 *    できません。
    061 *
    062 * @og.formSample
    063 * ●形式：一般ユーザーが直接組み込むことはありません。
    064 * ●body：なし
    065 *
    066 * ●Tag定義：
    067 *   &lt;og:editConfig
    068 *       command          ○【TAG】command を指定します(必須)
    069 *       gamenId          ○【TAG】画面ID を指定します(必須)
    070 *       editName           【TAG】編集名 を指定します
    071 *       orderOnly          【TAG】チェックボックスのリードオンリー化を行います(初期値:false)
    072 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
    073 *   /&gt;
    074 *
    075 * ●使用例
    076 *     &lt;og:editConfig command="{&#064;command}" gamenId="{&#064;GAMENID}" editName="{&#064;editName}" /&gt;
    077 *
    078 *     &lt;og:editConfig
    079 *         command        = command設定 (GET/LIST/SET/REMOVE)
    080 *         gamenId        = "GE0000"    画面ID
    081 *       [ editName ]     = "EDITNAME"  編集名
    082 *     /&gt;
    083 *
    084 * @og.group 編集設定
    085 *
    086 * @og.rev 5.3.6.0 (2011/06/01)
    087 *
    088 * @version  5.0
    089 * @author       Hiroki Nakamura
    090 * @since    JDK6.0,
    091 */
    092public class EditConfigTag extends CommonTagSupport {
    093        /** このプログラムのVERSION文字列を設定します。   {@value} */
    094        private static final String VERSION = "7.0.1.0 (2018/10/15)" ;
    095        private static final long serialVersionUID = 701020181015L ;
    096
    097        private static final String CAN_EDIT_COMMON             = HybsSystem.sys( "EDIT_COMMON_ROLES" );        // 6.4.5.0 (2016/04/08)
    098
    099        private static final String VIEW_PREFIX                 = "EDIT_VIEW_";
    100        private static final String SUM_PREFIX                  = "EDIT_SUM_";
    101        private static final String GROUP_PREFIX                = "EDIT_GROUP_";
    102        private static final String SUBTOTAL_PREFIX             = "EDIT_SUBTOTAL_";
    103        private static final String TOTAL_PREFIX                = "EDIT_TOTAL_";
    104        private static final String ORDERBY_PREFIX              = "EDIT_ORDERBY_";
    105        private static final String DESC_PREFIX                 = "EDIT_DESC_";
    106        private static final String GRANDTOTAL_PREFIX   = "EDIT_GRANDTOTAL_";
    107        private static final String COMMON_PREFIX               = "EDIT_COMMON_";
    108        private static final String FIRSTTOTAL_PREFIX   = "EDIT_FIRSTTOTAL_";           // 6.1.1.0 (2015/01/17)
    109
    110        private String  command                 ;                       // GET/LIST/SET/REMOVE
    111        private String  gamenId                 ;
    112        private String  editName                ;
    113
    114        private transient DBTableModel table    ;       // 5.5.2.4 (2012/05/16) transient 定義追加
    115
    116        private boolean orderOnly               ;                       // 5.5.5.2 (2012/08/10)
    117
    118        /**
    119         * デフォルトコンストラクター
    120         *
    121         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
    122         */
    123        public EditConfigTag() { super(); }             // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
    124
    125        /**
    126         * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
    127         *
    128         * @og.rev 5.7.1.2 (2013/12/20) msg ⇒ errMsg 変更
    129         * @og.rev 6.0.2.4 (2014/10/17) JSP修正時の追加カラム対応
    130         * @og.rev 6.4.5.0 (2016/04/08) DBEditConfigのローカル化。
    131         * @og.rev 5.9.18.1 (2017/03/24) ADD 編集名の共通判別対応
    132         * @og.rev 6.9.2.1 (2018/03/12) DBEditConfigManagerを直接取り出す処理を、廃止します
    133         *
    134         * @return      後続処理の指示
    135         */
    136        @Override
    137        public int doEndTag() {
    138                debugPrint();
    139
    140                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
    141
    142                // 6.4.5.0 (2016/04/08) DBEditConfigのローカル化。
    143                // 6.9.2.1 (2018/03/12) DBEditConfigManagerを直接取り出す処理を、廃止します
    144//              final DBEditConfigManager dbConfMgr = getUser().getEditConfigManager();         // 6.4.5.0 (2016/04/08)
    145                DBEditConfig config = getUser().getEditConfig( gamenId, editName );                     // 6.4.5.0 (2016/04/08)
    146        //      DBEditConfig config = dbConfMgr.getEditConfig( gamenId, editName );                     // 6.4.5.0 (2016/04/08)
    147
    148                // 編集情報をHTMLに変換して表示します。
    149                // 表示に当たって、最後に発行されたQUERYのtableId、scopeをチェックした上で
    150                // 表示するかを判断します。
    151                if( "GET".equals( command ) ) {
    152                        final DBLastSql lastSql = (DBLastSql)getSessionAttribute( HybsSystem.DB_LAST_SQL_KEY );
    153                        if( lastSql != null ) {
    154                                // 6.1.1.0 (2015/01/17) PMD Avoid if(x != y) ..; else ..;
    155                                if( lastSql.isViewEditable() && lastSql.isGuiMatch( gamenId ) ) {
    156                                        setScope( lastSql.getScope() );
    157                                        table = (DBTableModel)getObject( lastSql.getTableId() );
    158                                        if( table != null ) {
    159                                                String viewClms = null;
    160                                                if( config == null ) {
    161                                                        config = new DBEditConfig();
    162                                                        viewClms = lastSql.getViewClmNames();
    163                                                }
    164                                                else {
    165                                                        // 6.0.2.4 (2014/10/17) JSP修正時の追加カラム対応
    166                                                        viewClms = config.getViewClms( lastSql.getOrgClmNames() );
    167                                                }
    168
    169                                                buf.append( makeEditTable( viewClms , config ) );
    170                                        }
    171                                }
    172                                else {
    173                                        // この画面は、項目の並び替えはできません。
    174                                        final String rtn = "<b style=\"font-color:red;\">" + getResource().getLabel( "GEE0003" ) + "</b>";
    175                                        jspPrint( rtn );
    176                                }
    177                        }
    178                }
    179                // 編集情報を保存します。
    180                else if( "SET".equals( command ) ) {
    181                        if( editName == null || editName.isEmpty() ) {
    182                                final String errMsg = "編集名が指定されていません。";
    183                                throw new HybsSystemException( errMsg );        // 5.7.1.2 (2013/12/20) msg ⇒ errMsg 変更
    184                        }
    185                        // 5.9.18.1 (2017/03/24) ADD 編集名の共通判別対応
    186                        final String isCommon = getRequest().getParameter( COMMON_PREFIX );
    187                        // 共通以外で、頭文字が'*'でない場合
    188                        if( !"1".equals( isCommon ) && '*' == editName.charAt(0) ){
    189                                final String errMsg = "共通以外の場合は、編集名に頭文字に*を使用できません。";
    190                                throw new HybsSystemException(errMsg);
    191                        }
    192                        // 6.9.2.1 (2018/03/12) DBEditConfigManagerを直接取り出す処理を、廃止します
    193//                      saveEditConfig( dbConfMgr );                                    // 6.4.5.0 (2016/04/08)
    194                        saveEditConfig();                                                               // 6.9.2.1 (2018/03/12)
    195                }
    196                // 編集情報を削除します。
    197                else if( "DELETE".equals( command ) ) {
    198                        if( editName == null || editName.isEmpty() ) {
    199                                final String errMsg = "編集名が指定されていません。";
    200                                throw new HybsSystemException( errMsg );        // 5.7.1.2 (2013/12/20) msg ⇒ errMsg 変更
    201                        }
    202                        // 6.9.2.1 (2018/03/12) DBEditConfigManagerを直接取り出す処理を、廃止します
    203//                      if( dbConfMgr != null && config != null ) {
    204//                              deleteEditConfig( dbConfMgr , config );                 // 6.4.5.0 (2016/04/08)
    205                                deleteEditConfig( config );                                             // 6.9.2.1 (2018/03/12)
    206//                      }
    207                }
    208                // 指定された画面IDに対する編集情報の一覧(プルダウン)を表示します。
    209                else if( "LIST".equals( command ) ) {
    210                        // 6.1.0.0 (2014/12/26) findBugs: null ではなく長さが0の配列を返す。
    211                        // 6.9.2.1 (2018/03/12) DBEditConfigManagerを直接取り出す処理を、廃止します
    212//                      final DBEditConfig[] configs = dbConfMgr.getEditConfigs( gamenId );             // 6.4.5.0 (2016/04/08)
    213                        final DBEditConfig[] configs = getUser().getEditConfigs( gamenId );             // 6.4.5.0 (2016/04/08)
    214                        if( configs.length > 0 ) {
    215                                buf.append( getEditSelect( configs ) ).append( CR );
    216                        }
    217                }
    218
    219                jspPrint( buf.toString() );
    220
    221                return EVAL_PAGE ;
    222        }
    223
    224        /**
    225         * タグリブオブジェクトをリリースします。
    226         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
    227         *
    228         * @og.rev 5.5.5.2 (2012/08/10) orderOnly対応
    229         * @og.rev 6.4.5.0 (2016/04/08) DBEditConfigのローカル化。
    230         */
    231        @Override
    232        protected void release2() {
    233                super.release2();
    234                command         = "GET";
    235                gamenId         = null;
    236                editName        = null;
    237                table           = null;
    238                orderOnly       = false; //5.5.5.2 (2012/08/10)
    239        }
    240
    241        /**
    242         * 編集情報をHTMLに変換して表示します。
    243         *
    244         * @og.rev 5.4.2.0 (2011/12/01) 入替え対象のカラム列でのみスクロールが表示されるように対応します。
    245         * @og.rev 5.5.5.2 (2012/08/10) orderOnly対応
    246         * @og.rev 6.1.1.0 (2015/01/17) 総合計を最初の行に追加するかどうか(FirstTotal)の属性を追加
    247         * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
    248         * @og.rev 6.4.5.0 (2016/04/08) 『6.3.9.0 (2015/11/06) 意味不明の div を削除』の影響でレイアウトが崩れたので、戻します。
    249         * @og.rev 6.4.5.0 (2016/04/08) DBEditConfigのローカル化。
    250         * @og.rev 7.0.1.0 (2018/10/15) XHTML → HTML5 対応(空要素の、"／＞" 止めを、"＞" に変更します)。
    251         *
    252         * @param viewClms 表示カラム(CSV形式)
    253         * @param config DBEditConfigオブジェクト
    254         *
    255         * @return 編集情報のHTML
    256         * @og.rtnNotNull
    257         */
    258        private String makeEditTable( final String viewClms , final DBEditConfig config ) {
    259                final boolean useSum = getUseSum( viewClms );
    260                final String[] viewGroups = StringUtil.csv2Array( viewClms, '|' );
    261
    262                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE )
    263                        .append( "<input type=\"hidden\" name=\"viewClms\" id=\"viewClms\" value=\"" )
    264                        .append( viewClms )
    265//                      .append( "\"/><div /><div style=\"float:left;\">" )                             // 6.4.5.0 (2016/04/08) そのdiv がないと、配置が狂うため、復活。
    266                        .append( "\"><div></div><div style=\"float:left;\">" )                  // 6.4.5.0 (2016/04/08) そのdiv がないと、配置が狂うため、復活。
    267                        .append( makeLabelRow( useSum , config ) )                                              // 6.4.5.0 (2016/04/08)
    268                        .append( "</div><div id=\"clmLayer\" style=\"float:left; width:670px; overflow-x:scroll;\">" );
    269
    270                for( int i=0; i<viewGroups.length; i++ ) {
    271                        if( i > 0 ) {
    272                                buf.append( makeSeparateRow( useSum ) );
    273                        }
    274                        buf.append( "<table class=\"clmGroup\" style=\"float:left;\"><tr>" );
    275                        final String[] clms = StringUtil.csv2Array( viewGroups[i] );
    276                        for( int j=0; j<clms.length; j++ ) {
    277                                // 6.1.0.0 (2014/12/26) refactoring : Avoid if(x != y) ..; else ..;
    278                                final boolean isView = !StringUtil.startsChar( clms[j] , '!' ) ;                                        // 6.4.1.1 (2016/01/16) １文字 String.startsWith
    279                                // 6.4.1.1 (2016/01/16) １文字 String.startsWith と、処理順の入れ替え
    280                                final String clm = isView ? clms[j] : clms[j].substring( 1 ) ;
    281                                if( "rowCount".equals( clm ) ) { continue; }
    282                                // 6.1.0.0 (2014/12/26) refactoring : Avoid if(x != y) ..; else ..;
    283                                buf.append( makeColumnRow( clm, isView, useSum, config ) );
    284                        }
    285                        buf.append( "</tr></table>" );
    286                }
    287                buf.append( "</div>" );
    288
    289                // 6.1.1.0 (2015/01/17) useSum==true の場合のみ、表示する。
    290                if( useSum ) {
    291                        // 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
    292                        if( config == null ) {
    293                                final String errMsg = "DBEditConfigが設定されていません。" ;
    294                                throw new OgRuntimeException( errMsg );
    295                        }
    296
    297                        final String grandTotalLabel = "<b>" + getDBColumn( GRANDTOTAL_PREFIX + "LABEL" ).getLongLabel() + ":</b>";
    298                        final String firstTotalLabel = "<b>" + getDBColumn( FIRSTTOTAL_PREFIX + "LABEL" ).getLongLabel() + ":</b>";     // 6.1.1.0 (2015/01/17)
    299                        buf.append( "<div style=\"clear:both;\"><table>" )
    300                                .append( makeCheckbox( GRANDTOTAL_PREFIX, config.useGrandTotal(), "h", grandTotalLabel, orderOnly ) )   // 5.5.5.2 (2012/08/10)
    301                                .append( makeCheckbox( FIRSTTOTAL_PREFIX, config.useFirstTotal(), "h", firstTotalLabel, orderOnly ) )   // 6.1.1.0 (2015/01/17)
    302                                .append( "</table></div>" );
    303                }
    304
    305                return buf.toString();
    306        }
    307
    308        /**
    309         * 編集情報のヘッダー(ラベル行)のHTMLを生成します。
    310         *
    311         * @og.rev 5.4.2.0 (2011/12/01) 表示項目の全チェック機能を追加
    312         * @og.rev 5.5.5.2 (2012/08/10) orderOnly対応
    313         * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
    314         * @og.rev 6.4.5.0 (2016/04/08) 共通ラベルは、共通チェックボックスを使用しないときは消します。
    315         * @og.rev 6.4.5.0 (2016/04/08) DBEditConfigのローカル化。
    316         * @og.rev 7.0.1.0 (2018/10/15) XHTML → HTML5 対応(空要素の、"／＞" 止めを、"＞" に変更します)。
    317         *
    318         * @param useSum 集計対象のカラム(=NUMBER型)が存在しているか [true:存在/false:存在しない]
    319         * @param config DBEditConfigオブジェクト
    320         *
    321         * @return 編集情報のヘッダー(ラベル行)のHTML
    322         * @og.rtnNotNull
    323         */
    324        private String makeLabelRow( final boolean useSum , final DBEditConfig config ) {
    325                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE )
    326                                                                        .append( "<table><tr><td style=\"margin:0px; padding:0px;\"><table>" );
    327
    328                // 6.4.5.0 (2016/04/08) static final String CAN_EDIT_COMMON を使用
    329                if( getUser().isAccess( CAN_EDIT_COMMON ) ) {
    330                        // 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
    331                        if( config == null ) {
    332                                final String errMsg = "DBEditConfigが設定されていません。" ;
    333                                throw new OgRuntimeException( errMsg );
    334                        }
    335
    336                        final String commonLabel = "<b>" + getDBColumn( COMMON_PREFIX + "LABEL" ).getLongLabel() + ":</b>";             // 6.4.5.0 (2016/04/08) else で使わなくなったので。
    337                        buf.append( makeCheckbox( COMMON_PREFIX, config.isCommon(), "h", commonLabel, orderOnly ) );                    // 5.5.5.2 (2012/08/10)
    338                }
    339                else {
    340                        // 6.4.5.0 (2016/04/08) 共通ラベルは、共通チェックボックスを使用しないときは消します。
    341        //              buf.append( makeLabel( commonLabel ) );
    342                        buf.append( makeLabel( "" ) );
    343                }
    344                final String viewLabel = "<b>" + getDBColumn( VIEW_PREFIX + "LABEL" ).getLongLabel() + ":</b>";
    345                buf.append( makeCheckbox( "VIEW_ALL_CHECK", true, "h", viewLabel, orderOnly ) ); // 5.5.5.2 (2012/08/10)
    346                if( useSum ) {
    347                        buf.append( makeLabel( SUM_PREFIX               + "LABEL" ) );
    348                }
    349
    350                // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid declaring a variable if it is unreferenced before a possible exit point.
    351                final String groupLabel = "<b>" + getDBColumn( GROUP_PREFIX + "LABEL" ).getLongLabel() + "</b>"
    352//                                                              + "<img id=\"groupBtn\" src=\"" + HybsSystem.sys( "JSP" ) + "/image/ball-green.gif\" />";
    353                                                                + "<img id=\"groupBtn\" src=\"" + HybsSystem.sys( "JSP" ) + "/image/ball-green.gif\" >";                // 7.0.1.0 (2018/10/15)
    354                buf.append(  makeCell   ( groupLabel, "h" ) )
    355                        .append( makeLabel      ( SUBTOTAL_PREFIX       + "LABEL" ) )
    356                        .append( makeLabel      ( TOTAL_PREFIX          + "LABEL" ) )
    357                        .append( makeLabel      ( ORDERBY_PREFIX        + "LABEL" ) )
    358                        .append( makeLabel      ( DESC_PREFIX           + "LABEL" ) )
    359                        .append( "</table></td></tr></table>" );
    360                return buf.toString();
    361        }
    362
    363        /**
    364         * 編集情報のカラム列のHTMLを生成します。
    365         *
    366         * @og.rev 5.5.5.2 (2012/08/10) orderOnly対応
    367         * @og.rev 5.7.5.2 (2014/04/11) 降順はorderOnlyに関わらず編集可能にする
    368         * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
    369         * @og.rev 6.4.4.1 (2016/03/18) StringBuilderの代わりに、OgBuilderを使用する。
    370         *
    371         * @param clm カラム
    372         * @param isView 表示のチェックボックス [true:初期ON/false:初期OFF]
    373         * @param useSum 集計対象のカラム(=NUMBER型)が存在しているか [true:存在/false:存在しない]
    374         * @param config 編集設定オブジェクト
    375         *
    376         * @return 編集情報のカラム列のHTMLを生成します。
    377         * @og.rtnNotNull
    378         */
    379        private String makeColumnRow( final String clm, final boolean isView, final boolean useSum, final DBEditConfig config ) {
    380                // 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
    381                if( table == null ) {
    382                        final String errMsg = "DBTableModelが設定されていません。" ;
    383                        throw new OgRuntimeException( errMsg );
    384                }
    385
    386                final int clmNo = table.getColumnNo( clm, false  );
    387                final DBColumn column = ( clmNo < 0 ? getDBColumn( clm ) : table.getDBColumn( clmNo ) );
    388
    389                return new OgBuilder()
    390                        .append( "<td name=\"" , clm )
    391                        .append( "\" class=\"sortItem\" style=\"margin:0px; padding:0px;\">" )
    392                        .append( "<table>" )
    393                        .append( makeLabel      ( column.getLongLabel() ) )
    394                        .append( makeCheckbox( VIEW_PREFIX + clm, isView , "0", "", orderOnly ) )               // 5.5.5.2 (2012/08/10)
    395                        .appendIf( useSum , clm ,
    396                                                v -> makeCheckbox( SUM_PREFIX + v, config.isSumClm( v ) , "1", "", orderOnly, isNumberClm( v ) ) )      // 5.5.5.2 (2012/08/10)
    397                        .append( makeCheckbox( GROUP_PREFIX             + clm, config.isGroupClm( clm )         , "0", "", orderOnly ) )        // 5.5.5.2 (2012/08/10)
    398                        .append( makeCheckbox( SUBTOTAL_PREFIX  + clm, config.isSubTotalClm( clm )      , "1", "", orderOnly ) )        // 5.5.5.2 (2012/08/10)
    399                        .append( makeCheckbox( TOTAL_PREFIX             + clm, config.isTotalClm( clm )         , "0", "", orderOnly ) )        // 5.5.5.2 (2012/08/10)
    400                        .append( makeInput       ( ORDERBY_PREFIX       + clm, config.getOrder( clm )           , "1", "" ) )
    401                        .append( makeCheckbox( DESC_PREFIX              + clm, config.isOrderByDesc( clm )      , "0", "", false ) )            // 5.7.5.1 (2014/04/11)
    402                        .append( "</table></td>" )
    403                        .toString();
    404        }
    405
    406        /**
    407         * チェックボックスのHTML文字列を生成します。
    408         * 生成したHTMLは以下のようになります。
    409         * 例)&lt;tr&gt;&lt;td class="row_[bgCnt]" ...&gt;[prefix]&lt;input type="checkbox" name="[clm]" ... /&gt;&lt;/td&gt;&lt;/tr&gt;
    410         *
    411         * @param clm           カラム
    412         * @param checked       初期チェック [true:チェック済み/false:通常]
    413         * @param bgCnt         ゼブラ指定 [0/1/h]
    414         * @param prefix        チェックボックスのタグの前に挿入するHTML文字列
    415         * @param readonly      リードオンリー指定 [true:読取専用/false:読書可]
    416         *
    417         * @og.rev 5.5.5.2 (2012/08/10) readOnly追加
    418         * @og.rev 6.1.1.0 (2015/01/17) 内部構造を見直します。
    419         *
    420         * @return チェックボックスのHMTL文字列
    421         */
    422        private String makeCheckbox( final String clm, final boolean checked, final String bgCnt, final String prefix, final boolean readonly ) {
    423                return makeCheckbox( clm, checked, bgCnt, prefix, readonly, true );
    424        }
    425
    426        /**
    427         * チェックボックスのHTML文字列を生成します。
    428         * 生成したHTMLは以下のようになります。
    429         * 例)&lt;tr&gt;&lt;td class="row_[bgCnt]" ...&gt;[prefix]&lt;input type="checkbox" name="[clm]" ... /&gt;&lt;/td&gt;&lt;/tr&gt;
    430         *
    431         * isChbox(チェックボックス生成) を、true に指定すると、チェックボックスのinputタグを生成します。
    432         *
    433         * @og.rev 5.5.5.2 (2012/08/10) readOnly追加
    434         * @og.rev 6.1.1.0 (2015/01/17) 内部構造を見直します。
    435         *
    436         * @param clm           カラム
    437         * @param checked       初期チェック [true:チェック済み/false:通常]
    438         * @param bgCnt         ゼブラ指定 [0/1/h]
    439         * @param prefix        チェックボックスのタグの前に挿入するHTML文字列(nullは禁止)
    440         * @param readonly      リードオンリー指定 [true:読取専用/false:読書可]
    441         * @param isChbox       チェックボックス生成 [true:生成する/false:生成しない]
    442         *
    443         * @return チェックボックスのHMTL文字列
    444         */
    445        private String makeCheckbox( final String clm, final boolean checked, final String bgCnt, final String prefix, final boolean readonly, final boolean isChbox ) {
    446                if( isChbox ) {
    447
    448                        // 6.1.1.0 (2015/01/17) TagBufferの連結記述
    449                        final String tag = new TagBuffer( "input" )
    450                                                                .add( "type"    , "checkbox" )
    451                                                                .add( "name"    , clm )
    452                                                                .add( "value"   , "1" )
    453                                                                .add( "checked" , "checked" , checked )
    454                                                                .add( "disabled", "disabled", readonly )
    455                                                                .makeTag();
    456
    457                        // 6.1.1.0 (2015/01/17) TagBufferの連結記述
    458                        final String cell = readonly && checked                 // 6.1.1.0 (2015/01/17) suffix 処理を変更
    459                                        ? tag + new TagBuffer( "input" )
    460                                                                .add( "type", "hidden" )
    461                                                                .add( "name", clm )
    462                                                                .add( "value", "1" )
    463                                                                .makeTag()
    464                                        : tag ;
    465
    466                        return makeCell( prefix + cell , bgCnt );                       // 6.1.1.0 (2015/01/17) prefix に、null は禁止
    467                }
    468                else {
    469                        return makeCell( prefix + "&nbsp;", bgCnt );            // 6.1.1.0 (2015/01/17) prefix に、null は禁止
    470                }
    471        }
    472
    473        /**
    474         * テキスト入力HTML文字列を生成します。
    475         * 生成したHTMLは以下のようになります。
    476         * 例)&lt;tr&gt;&lt;td class="row_[bgCnt]" ...&gt;[prefix]&lt;input type="text" name="[clm]" ... /&gt;&lt;/td&gt;&lt;/tr&gt;
    477         *
    478         * @param clm           カラム
    479         * @param value         値
    480         * @param bgCnt         ゼブラ指定 [0/1/h]
    481         * @param prefix        チェックボックスのタグの前に挿入するHTML文字列(nullは禁止)
    482         *
    483         * @return チェックボックスのHMTL文字列
    484         */
    485        private String makeInput( final String clm, final String value, final String bgCnt, final String prefix ) {
    486                // 6.1.1.0 (2015/01/17) TagBufferの連結記述
    487                final String tag = new TagBuffer( "input" )
    488                                                        .add( "type"            , "text" )
    489                                                        .add( "name"            , clm )
    490                                                        .add( "value"           , value )
    491                                                        .add( "style"           , "width:10px; font-size:10px;" )
    492                                                        .add( "maxlength"       , "2" )
    493                                                        .add( "class"           , "S9" )
    494                                                        .makeTag();
    495
    496                return makeCell( prefix + tag , bgCnt );                // 6.1.1.0 (2015/01/17) prefix に、null は禁止
    497        }
    498
    499        /**
    500         * 左右分割されている際の分割列のHTML文字列を生成します。
    501         *
    502         * @og.rev 6.4.4.1 (2016/03/18) StringBuilderの代わりに、OgBuilderを使用する。
    503         *
    504         * @param useSum 集計対象のカラム(=NUMBER型)が存在しているか [true:存在している/false:存在していない]
    505         *
    506         * @return チェックボックスのHMTL文字列
    507         * @og.rtnNotNull
    508         */
    509        private String makeSeparateRow( final boolean useSum ) {
    510                final String ROW_H = makeCell( "&nbsp", "h" ) ;
    511
    512                return new OgBuilder()
    513                        .append( "<table style=\"float:left;\"><tr><td style=\"margin:0px; padding:0px;\"><table>" )
    514                        .append( ROW_H )                        // ラベル
    515                        .append( ROW_H )                        // 表示
    516                        .appendIf( useSum , ROW_H )     // 集計項目
    517                        .append( ROW_H )                        // 集計キー
    518                        .append( ROW_H )                        // 小計キー
    519                        .append( ROW_H )                        // 合計キー
    520                        .append( ROW_H )                        // 表示順
    521                        .append( ROW_H )                        // 昇順・降順
    522                        .append( "</table></td></tr></table>")
    523                        .toString();
    524        }
    525
    526        /**
    527         * ラベルのHTML文字列を生成します。
    528         *
    529         * @param clm カラム
    530         *
    531         * @return ラベルのHTML文字列
    532         */
    533        private String makeLabel( final String clm ) {
    534                return makeCell( getDBColumn( clm ).getLongLabel(), "h" );
    535        }
    536
    537        /**
    538         * セルのHTML文字列を生成します。
    539         *
    540         * body 属性は、HTML文字列を指定します。
    541         * bgCnt は、背景色のゼブラカラーの指定の為の class 属性で、[0/1/h] が指定できます。
    542         * 例えば、"0" を指定した場合は、class="row_0" のように、属性を付与します。
    543         * 標準の CSSファイルで設定しているのが、[0/1/h] なだけで、上記 class 属性を
    544         * custom.css で設定すれば、どのような文字列でも指定可能です。
    545         *
    546         * @og.rev 6.1.1.0 (2015/01/17) 内部構造を見直します。
    547         *
    548         * @param body tdタグ内のHTML文字列
    549         * @param bgCnt ゼブラ指定 [0/1/h]
    550         *
    551         * @return セルのHTML文字列
    552         * @og.rtnNotNull
    553         */
    554        private String makeCell( final String body, final String bgCnt ) {
    555                return "<tr><td align=\"center\" style=\"height:22px;\" class=\"row_" + bgCnt + "\">" + body + "</td></tr>";
    556        }
    557
    558        /**
    559         * この編集設定で集計対象のカラム(=NUMBER型)が存在しているかを返します。
    560         *
    561         * @param viewClms カラム
    562         *
    563         * @return 集計対象のカラム(=NUMBER型)が存在しているか
    564         */
    565        private boolean getUseSum( final String viewClms ) {
    566                if( viewClms == null ) { return false; }
    567
    568                final String[] clms = StringUtil.csv2Array( viewClms.replace( '|', ',' ) );
    569                for( int j=0; j<clms.length; j++ ) {
    570                        // 6.1.0.0 (2014/12/26) refactoring : Avoid if(x != y) ..; else ..;
    571                        final String clm = StringUtil.startsChar( clms[j] , '!' ) ? clms[j].substring( 1 ) : clms[j] ;                  // 6.4.1.1 (2016/01/16) １文字 String.startsWith
    572                        if( isNumberClm( clm ) ) { return true; }               // ひとつでも見つかれば、true
    573                }
    574                return false;
    575        }
    576
    577        /**
    578         * 引数のカラムがNUMBER型かどうかをチェックします。
    579         *
    580         * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
    581         * @og.rev 6.4.4.2 (2016/04/01) contains 判定を行う新しいメソッドを使用します。
    582         * @og.rev 6.4.6.0 (2016/05/27) isNumber , isDate 追加。
    583         *
    584         * @param clm カラム
    585         *
    586         * @return NUMBER型かどうか
    587         */
    588        private boolean isNumberClm( final String clm ) {
    589                if( clm == null ) { return false; }
    590                // 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
    591                if( table == null ) {
    592                        final String errMsg = "DBTableModelが設定されていません。" ;
    593                        throw new OgRuntimeException( errMsg );
    594                }
    595
    596                final int no = table.getColumnNo( clm, false );
    597                if( no >= 0 ) {
    598                        final DBColumn dbClm = table.getDBColumn( no );
    599                        // 6.0.0.1 (2014/04/25) These nested if statements could be combined
    600                        // 6.4.4.2 (2016/04/01) contains 判定を行う新しいメソッドを使用します。
    601                        return dbClm != null && dbClm.isNumberType();
    602                }
    603                return false;
    604        }
    605
    606        /**
    607         * 編集設定情報を保存します。
    608         *
    609         * @og.rev 6.1.1.0 (2015/01/17) 総合計を最初の行に追加するかどうか(FirstTotal)の属性を追加
    610         * @og.rev 6.4.5.0 (2016/04/08) UserInfo のEditConfig関連機能を、DBEditConfigManagerに移植します。
    611         * @og.rev 5.9.18.1 (2017/03/24) 共通の編集名対応
    612         * @og.rev 6.9.2.1 (2018/03/12) DBEditConfigManagerを直接取り出す処理を、廃止します
    613         *
    614         */
    615//      private void saveEditConfig( final DBEditConfigManager dbConfMgr ) {
    616        private void saveEditConfig() {
    617                final String viewClms           = getRequest().getParameter( "viewClms" );
    618                final String sumClms            = getColumns( SUM_PREFIX );
    619                final String groupClms          = getColumns( GROUP_PREFIX );
    620                final String subTotalClms       = getColumns( SUBTOTAL_PREFIX );
    621                final String totalClms          = getColumns( TOTAL_PREFIX );
    622                final String useGrandTotal      = getRequest().getParameter( GRANDTOTAL_PREFIX );
    623                final String useFirstTotal      = getRequest().getParameter( FIRSTTOTAL_PREFIX );               // 6.1.1.0 (2015/01/17)
    624                final String orderByClms        = getOrderByColumns();
    625                final String isCommon           = getRequest().getParameter( COMMON_PREFIX );
    626
    627                // 5.9.18.1 (2017/03/24) ADD 編集名の共通判別対応
    628                // 共通で、編集名の頭に「*」が無い場合
    629//              if("1".equals( isCommon ) && !('*' == editName.charAt( 0 ))){                           // 7.2.9.4 (2020/11/20)
    630                if( "1".equals( isCommon ) && '*' != editName.charAt( 0 ) ){
    631                        // 編集名の頭に「*」を付与
    632                        editName        = "*"+editName;
    633                }
    634                // 編集名をリクエストスコープに設定
    635                setRequestAttribute("regEditName", editName);
    636
    637                final DBEditConfig config
    638                        = new DBEditConfig( editName, viewClms, sumClms, groupClms
    639                                                                , subTotalClms, totalClms, useGrandTotal, useFirstTotal, orderByClms, isCommon );
    640
    641                getUser().addEditConfig( gamenId, editName, config );   // 6.4.5.0 (2016/04/08) 暫定的に残す
    642        //      dbConfMgr.addEditConfig( gamenId, editName, config );
    643        }
    644
    645        /**
    646         * 編集設定情報を削除します。
    647         *
    648         * ※ org.opengion.hayabusa.resource.UserInfo#deleteEditConfig( String  , String )でも
    649         *    処理しているが、本来は、UserInfoでは処理しないほうが良いため、
    650         *    今回は、こちらで判定して処理します。
    651         *
    652         * @og.rev 6.4.5.0 (2016/04/08) 共通設定した editName が削除できてしまうため、ロール制御を追加します。
    653         * @og.rev 6.4.5.0 (2016/04/08) UserInfo のEditConfig関連機能を、DBEditConfigManagerに移植します。
    654         * @og.rev 6.9.2.1 (2018/03/12) DBEditConfigManagerを直接取り出す処理を、廃止します
    655         *
    656         * @param       config DBEditConfigオブジェクト
    657         */
    658//      private void deleteEditConfig( final DBEditConfigManager dbConfMgr , final DBEditConfig config ) {
    659        private void deleteEditConfig( final DBEditConfig config ) {
    660                final boolean isCommon = config.isCommon();
    661                // 共通で、かつ、共通設定ロールを持っていない場合は、エラーにします。
    662                if( isCommon && !getUser().isAccess( CAN_EDIT_COMMON ) ) {
    663                        final String errMsg = "共通設定されている編集名を削除する権限がありません。";
    664                        throw new HybsSystemException( errMsg );
    665                }
    666                else {
    667                        getUser().deleteEditConfig( gamenId, editName );        // 6.4.5.0 (2016/04/08) 暫定的に残す
    668        //              dbConfMgr.deleteEditConfig( gamenId, editName );
    669                }
    670        }
    671
    672        /**
    673         * パラメーターから引数のプレフィックスをキーに、チェックされたカラム一覧(CSV形式)を返します。
    674         *
    675         * @param prefixKey 各キーの取得するためのプレフィックス
    676         *
    677         * @return カラム一覧(CSV形式)
    678         * @og.rtnNotNull
    679         */
    680        private String getColumns( final String prefixKey ) {
    681                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
    682
    683                final Enumeration<?> enume = getParameterNames();
    684                while( enume.hasMoreElements() ) {
    685                        final String key = (String)(enume.nextElement());
    686                        if( key.startsWith( prefixKey ) ) {
    687                                final String val = getRequest().getParameter( key );
    688                                if( "1".equals( val ) ) {
    689                                        final String clm = key.substring( prefixKey.length() );
    690                                        if( buf.length() > 0 ) { buf.append( ',' ); }           // 6.0.2.5 (2014/10/31) char を append する。
    691                                        buf.append( clm );
    692                                }
    693                        }
    694                }
    695
    696                return buf.toString();
    697        }
    698
    699        /**
    700         * 表示順のカラム一覧(CSV形式)を返します。
    701         *
    702         * @og.rev 6.4.3.4 (2016/03/11) CSV形式の文字連結を、stream 経由で行います。
    703         *
    704         * @return 表示順のカラム一覧(CSV形式)
    705         * @og.rtnNotNull
    706         */
    707        private String getOrderByColumns() {
    708                final Enumeration<?> enume = getParameterNames();
    709                final List<Integer> orderNo = new ArrayList<>();
    710                final Map<Integer,String> odrClmMap = new HashMap<>();
    711                while( enume.hasMoreElements() ) {
    712                        final String key = (String)(enume.nextElement());
    713                        if( key.startsWith( ORDERBY_PREFIX ) ) {
    714                                final String val = getRequest().getParameter( key );
    715                                if( val != null && val.length() > 0 ) {
    716                                        String clm = key.substring( ORDERBY_PREFIX.length() );
    717                                        final String desc = getRequest().getParameter( DESC_PREFIX + clm );
    718                                        if( "1".equals( desc ) ) {
    719                                                clm = "!"  + clm;
    720                                        }
    721                                        // 数字項目以外が入力された場合は無視
    722                                        Integer odno = null;
    723                                        try {
    724                                                odno = Integer.valueOf( val );
    725                                        }
    726                                        catch( final NumberFormatException ex ) {
    727                                                continue;
    728                                        }
    729                                        String str = odrClmMap.get( odno );
    730                                        // 同じ番号の場合でも重ならないように振り直しする。
    731                                        while( str != null ) {
    732                                                odno = Integer.valueOf( odno.intValue() + 1 );
    733                                                str = odrClmMap.get( odno );
    734                                        }
    735                                        odrClmMap.put( odno, clm );
    736                                        orderNo.add( odno );
    737                                }
    738                        }
    739                }
    740
    741                Collections.sort( orderNo );
    742
    743                // 6.4.3.4 (2016/03/11) CSV形式の文字連結を、stream 経由で行います。
    744                return orderNo.stream()
    745                                                .map( no -> odrClmMap.get( no ) )
    746                                                .collect( Collectors.joining( "," ) );
    747        }
    748
    749        /**
    750         * 編集設定一覧のプルダウンメニューを作成します。
    751         *
    752         * @og.rev 7.0.1.0 (2018/10/15) XHTML → HTML5 対応(空要素の、"／＞" 止めを、"＞" に変更します)。
    753         *
    754         * @param       configs DBEditConfig配列(可変長引数)
    755         *
    756         * @return      編集一覧のプルダウン
    757         * @og.rtnNotNull
    758         */
    759        private String getEditSelect( final DBEditConfig... configs ) {
    760                final DBColumn column = getDBColumn( "editName" );
    761
    762                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE )
    763                        .append( "<span class=\"label editName\">" )
    764                        .append( column.getLongLabel() )
    765                        .append( ":</span><span class=\"editName\">" )
    766                        .append( "<select name=\"editName\">" )
    767//                      .append( "<option />" );
    768                        .append( "<option></option>" );                                                                         // 7.0.1.0 (2018/10/15)
    769                for( final DBEditConfig config : configs ) {
    770                        final String name = config.getEditName();
    771                        buf.append( "<option value=\"" ).append( name ).append( '"' );          // 6.0.2.5 (2014/10/31) char を append する。
    772                        if( config.isCommon() ) {
    773                                buf.append( " class=\"commonEdit\"" );
    774                        }
    775                        buf.append( "\">" ).append( name ).append( "</option>" );
    776                }
    777                buf.append( "</select></span>" );
    778                return buf.toString();
    779        }
    780
    781        /**
    782         * 【TAG】command を指定します。
    783         *
    784         * @og.tag
    785         * command を指定します。
    786         * [GET/LIST/SET/DELETE]のみが設定可能です。それ以外の場合、何も処理されません。
    787         *
    788         * @param       cmd コマンド [GET/LIST/SET/DELETE]
    789         */
    790        public void setCommand( final String cmd ) {
    791                command = nval( getRequestParameter( cmd ),command );
    792        }
    793
    794        /**
    795         * 【TAG】画面ID を指定します。
    796         *
    797         * @og.tag
    798         * 画面ID を指定します。
    799         *
    800         * @param       key 画面ID
    801         */
    802        public void setGamenId( final String key ) {
    803                gamenId = nval( getRequestParameter( key ),gamenId );
    804        }
    805
    806        /**
    807         * 【TAG】編集名を指定します。
    808         *
    809         * @og.tag
    810         * 編集名 を指定します。
    811         * commandがSETまたはDELETEの場合は必須です。
    812         * commandがGETまたはLISTの場合は無効です。
    813         *
    814         * @param       name 編集名
    815         */
    816        public void setEditName( final String name ) {
    817                editName = nval( getRequestParameter( name ),editName );
    818        }
    819
    820        /**
    821         * 【TAG】順番の入れ替えと、表示順の設定のみを行う場合にtrueにします(初期値:false)。
    822         *
    823         * @og.tag
    824         * 順番の入れ替えと、表示順の設定のみを行う場合にtrueにします。
    825         * 表示/非表示切替や、集計機能は利用できなくなります。
    826         * （チェックボックスのリードオンリーはできないため、実際にはdisable+hiddenで出力しています）
    827         * 初期値は、false:通常 です。
    828         *
    829         * @og.rev 5.5.5.2 (2012/08/10) 新規追加
    830         *
    831         * @param flag  順番入替のみ [true:入替のみ/false:通常]
    832         */
    833        public void setOrderOnly( final String flag ) {
    834                orderOnly = nval( getRequestParameter( flag ),orderOnly );
    835        }
    836
    837        /**
    838         * このオブジェクトの文字列表現を返します。
    839         * 基本的にデバッグ目的に使用します。
    840         *
    841         * @return このクラスの文字列表現
    842         * @og.rtnNotNull
    843         */
    844        @Override
    845        public String toString() {
    846                return ToString.title( this.getClass().getName() )
    847                                .println( "VERSION"             ,VERSION                )
    848                                .println( "command"             ,command                )
    849                                .println( "gamenId"             ,gamenId                )
    850                                .println( "editName"    ,editName               )
    851                                .println( "Other..."    ,getAttributes().getAttribute() )
    852                                .fixForm().toString() ;
    853        }
    854}