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 *   <og:editConfig
068 *       command          ○【TAG】command を指定します(必須)
069 *       gamenId          ○【TAG】画面ID を指定します(必須)
070 *       editName           【TAG】編集名 を指定します
071 *       orderOnly          【TAG】チェックボックスのリードオンリー化を行います(初期値:false)
072 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
073 *   />
074 *
075 * ●使用例
076 *     <og:editConfig command="{@command}" gamenId="{@GAMENID}" editName="{@editName}" />
077 *
078 *     <og:editConfig
079 *         command        = command設定 (GET/LIST/SET/REMOVE)
080 *         gamenId        = "GE0000"    画面ID
081 *       [ editName ]     = "EDITNAME"  編集名
082 *     />
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 = "6.9.2.1 (2018/03/12)" ;
095        private static final long serialVersionUID = 692120180312L ;
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         *
251         * @param viewClms 表示カラム(CSV形式)
252         * @param config DBEditConfigオブジェクト
253         *
254         * @return 編集情報のHTML
255         * @og.rtnNotNull
256         */
257        private String makeEditTable( final String viewClms , final DBEditConfig config ) {
258                final boolean useSum = getUseSum( viewClms );
259                final String[] viewGroups = StringUtil.csv2Array( viewClms, '|' );
260
261                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE )
262                        .append( "<input type=\"hidden\" name=\"viewClms\" id=\"viewClms\" value=\"" )
263                        .append( viewClms )
264                        .append( "\"/><div /><div style=\"float:left;\">" )                             // 6.4.5.0 (2016/04/08) そのdiv がないと、配置が狂うため、復活。
265                        .append( makeLabelRow( useSum , config ) )                                              // 6.4.5.0 (2016/04/08)
266                        .append( "</div><div id=\"clmLayer\" style=\"float:left; width:670px; overflow-x:scroll;\">" );
267
268                for( int i=0; i<viewGroups.length; i++ ) {
269                        if( i > 0 ) {
270                                buf.append( makeSeparateRow( useSum ) );
271                        }
272                        buf.append( "<table class=\"clmGroup\" style=\"float:left;\"><tr>" );
273                        final String[] clms = StringUtil.csv2Array( viewGroups[i] );
274                        for( int j=0; j<clms.length; j++ ) {
275                                // 6.1.0.0 (2014/12/26) refactoring : Avoid if(x != y) ..; else ..;
276                                final boolean isView = !StringUtil.startsChar( clms[j] , '!' ) ;                                        // 6.4.1.1 (2016/01/16) 1文字 String.startsWith
277                                // 6.4.1.1 (2016/01/16) 1文字 String.startsWith と、処理順の入れ替え
278                                final String clm = isView ? clms[j] : clms[j].substring( 1 ) ;
279                                if( "rowCount".equals( clm ) ) { continue; }
280                                // 6.1.0.0 (2014/12/26) refactoring : Avoid if(x != y) ..; else ..;
281                                buf.append( makeColumnRow( clm, isView, useSum, config ) );
282                        }
283                        buf.append( "</tr></table>" );
284                }
285                buf.append( "</div>" );
286
287                // 6.1.1.0 (2015/01/17) useSum==true の場合のみ、表示する。
288                if( useSum ) {
289                        // 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
290                        if( config == null ) {
291                                final String errMsg = "DBEditConfigが設定されていません。" ;
292                                throw new OgRuntimeException( errMsg );
293                        }
294
295                        final String grandTotalLabel = "<b>" + getDBColumn( GRANDTOTAL_PREFIX + "LABEL" ).getLongLabel() + ":</b>";
296                        final String firstTotalLabel = "<b>" + getDBColumn( FIRSTTOTAL_PREFIX + "LABEL" ).getLongLabel() + ":</b>";     // 6.1.1.0 (2015/01/17)
297                        buf.append( "<div style=\"clear:both;\"><table>" )
298                                .append( makeCheckbox( GRANDTOTAL_PREFIX, config.useGrandTotal(), "h", grandTotalLabel, orderOnly ) )   // 5.5.5.2 (2012/08/10)
299                                .append( makeCheckbox( FIRSTTOTAL_PREFIX, config.useFirstTotal(), "h", firstTotalLabel, orderOnly ) )   // 6.1.1.0 (2015/01/17)
300                                .append( "</table></div>" );
301                }
302
303                return buf.toString();
304        }
305
306        /**
307         * 編集情報のヘッダー(ラベル行)のHTMLを生成します。
308         *
309         * @og.rev 5.4.2.0 (2011/12/01) 表示項目の全チェック機能を追加
310         * @og.rev 5.5.5.2 (2012/08/10) orderOnly対応
311         * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
312         * @og.rev 6.4.5.0 (2016/04/08) 共通ラベルは、共通チェックボックスを使用しないときは消します。
313         * @og.rev 6.4.5.0 (2016/04/08) DBEditConfigのローカル化。
314         *
315         * @param useSum 集計対象のカラム(=NUMBER型)が存在しているか [true:存在/false:存在しない]
316         * @param config DBEditConfigオブジェクト
317         *
318         * @return 編集情報のヘッダー(ラベル行)のHTML
319         * @og.rtnNotNull
320         */
321        private String makeLabelRow( final boolean useSum , final DBEditConfig config ) {
322                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE )
323                                                                        .append( "<table><tr><td style=\"margin:0px; padding:0px;\"><table>" );
324
325                // 6.4.5.0 (2016/04/08) static final String CAN_EDIT_COMMON を使用
326                if( getUser().isAccess( CAN_EDIT_COMMON ) ) {
327                        // 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
328                        if( config == null ) {
329                                final String errMsg = "DBEditConfigが設定されていません。" ;
330                                throw new OgRuntimeException( errMsg );
331                        }
332
333                        final String commonLabel = "<b>" + getDBColumn( COMMON_PREFIX + "LABEL" ).getLongLabel() + ":</b>";             // 6.4.5.0 (2016/04/08) else で使わなくなったので。
334                        buf.append( makeCheckbox( COMMON_PREFIX, config.isCommon(), "h", commonLabel, orderOnly ) );                    // 5.5.5.2 (2012/08/10)
335                }
336                else {
337                        // 6.4.5.0 (2016/04/08) 共通ラベルは、共通チェックボックスを使用しないときは消します。
338        //              buf.append( makeLabel( commonLabel ) );
339                        buf.append( makeLabel( "" ) );
340                }
341                final String viewLabel = "<b>" + getDBColumn( VIEW_PREFIX + "LABEL" ).getLongLabel() + ":</b>";
342                buf.append( makeCheckbox( "VIEW_ALL_CHECK", true, "h", viewLabel, orderOnly ) ); // 5.5.5.2 (2012/08/10)
343                if( useSum ) {
344                        buf.append( makeLabel( SUM_PREFIX               + "LABEL" ) );
345                }
346
347                // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid declaring a variable if it is unreferenced before a possible exit point.
348                final String groupLabel = "<b>" + getDBColumn( GROUP_PREFIX + "LABEL" ).getLongLabel() + "</b>"
349                                                                + "<img id=\"groupBtn\" src=\"" + HybsSystem.sys( "JSP" ) + "/image/ball-green.gif\" />";
350                buf.append(  makeCell   ( groupLabel, "h" ) )
351                        .append( makeLabel      ( SUBTOTAL_PREFIX       + "LABEL" ) )
352                        .append( makeLabel      ( TOTAL_PREFIX          + "LABEL" ) )
353                        .append( makeLabel      ( ORDERBY_PREFIX        + "LABEL" ) )
354                        .append( makeLabel      ( DESC_PREFIX           + "LABEL" ) )
355                        .append( "</table></td></tr></table>" );
356                return buf.toString();
357        }
358
359        /**
360         * 編集情報のカラム列のHTMLを生成します。
361         * 
362         * @og.rev 5.5.5.2 (2012/08/10) orderOnly対応
363         * @og.rev 5.7.5.2 (2014/04/11) 降順はorderOnlyに関わらず編集可能にする
364         * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
365         * @og.rev 6.4.4.1 (2016/03/18) StringBuilderの代わりに、OgBuilderを使用する。
366         *
367         * @param clm カラム
368         * @param isView 表示のチェックボックス [true:初期ON/false:初期OFF]
369         * @param useSum 集計対象のカラム(=NUMBER型)が存在しているか [true:存在/false:存在しない]
370         * @param config 編集設定オブジェクト
371         *
372         * @return 編集情報のカラム列のHTMLを生成します。
373         * @og.rtnNotNull
374         */
375        private String makeColumnRow( final String clm, final boolean isView, final boolean useSum, final DBEditConfig config ) {
376                // 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
377                if( table == null ) {
378                        final String errMsg = "DBTableModelが設定されていません。" ;
379                        throw new OgRuntimeException( errMsg );
380                }
381
382                final int clmNo = table.getColumnNo( clm, false  );
383                final DBColumn column = ( clmNo < 0 ? getDBColumn( clm ) : table.getDBColumn( clmNo ) );
384
385                return new OgBuilder()
386                        .append( "<td name=\"" , clm )
387                        .append( "\" class=\"sortItem\" style=\"margin:0px; padding:0px;\">" )
388                        .append( "<table>" )
389                        .append( makeLabel      ( column.getLongLabel() ) )
390                        .append( makeCheckbox( VIEW_PREFIX + clm, isView , "0", "", orderOnly ) )               // 5.5.5.2 (2012/08/10)
391                        .appendIf( useSum , clm , 
392                                                v -> makeCheckbox( SUM_PREFIX + v, config.isSumClm( v ) , "1", "", orderOnly, isNumberClm( v ) ) )      // 5.5.5.2 (2012/08/10)
393                        .append( makeCheckbox( GROUP_PREFIX             + clm, config.isGroupClm( clm )         , "0", "", orderOnly ) )        // 5.5.5.2 (2012/08/10)
394                        .append( makeCheckbox( SUBTOTAL_PREFIX  + clm, config.isSubTotalClm( clm )      , "1", "", orderOnly ) )        // 5.5.5.2 (2012/08/10)
395                        .append( makeCheckbox( TOTAL_PREFIX             + clm, config.isTotalClm( clm )         , "0", "", orderOnly ) )        // 5.5.5.2 (2012/08/10)
396                        .append( makeInput       ( ORDERBY_PREFIX       + clm, config.getOrder( clm )           , "1", "" ) )
397                        .append( makeCheckbox( DESC_PREFIX              + clm, config.isOrderByDesc( clm )      , "0", "", false ) )            // 5.7.5.1 (2014/04/11)
398                        .append( "</table></td>" )
399                        .toString();
400
401        }
402
403        /**
404         * チェックボックスのHTML文字列を生成します。
405         * 生成したHTMLは以下のようになります。
406         * 例)&lt;tr&gt;&lt;td class="row_[bgCnt]" ...&gt;[prefix]&lt;input type="checkbox" name="[clm]" ... /&gt;&lt;/td&gt;&lt;/tr&gt;
407         *
408         * @param clm           カラム
409         * @param checked       初期チェック [true:チェック済み/false:通常]
410         * @param bgCnt         ゼブラ指定 [0/1/h]
411         * @param prefix        チェックボックスのタグの前に挿入するHTML文字列
412         * @param readonly      リードオンリー指定 [true:読取専用/false:読書可]
413         * 
414         * @og.rev 5.5.5.2 (2012/08/10) readOnly追加
415         * @og.rev 6.1.1.0 (2015/01/17) 内部構造を見直します。
416         *
417         * @return チェックボックスのHMTL文字列
418         */
419        private String makeCheckbox( final String clm, final boolean checked, final String bgCnt, final String prefix, final boolean readonly ) {
420                return makeCheckbox( clm, checked, bgCnt, prefix, readonly, true );
421        }
422
423        /**
424         * チェックボックスのHTML文字列を生成します。
425         * 生成したHTMLは以下のようになります。
426         * 例)&lt;tr&gt;&lt;td class="row_[bgCnt]" ...&gt;[prefix]&lt;input type="checkbox" name="[clm]" ... /&gt;&lt;/td&gt;&lt;/tr&gt;
427         * 
428         * isChbox(チェックボックス生成) を、true に指定すると、チェックボックスのinputタグを生成します。
429         * 
430         * @og.rev 5.5.5.2 (2012/08/10) readOnly追加
431         * @og.rev 6.1.1.0 (2015/01/17) 内部構造を見直します。
432         *
433         * @param clm           カラム
434         * @param checked       初期チェック [true:チェック済み/false:通常]
435         * @param bgCnt         ゼブラ指定 [0/1/h]
436         * @param prefix        チェックボックスのタグの前に挿入するHTML文字列(nullは禁止)
437         * @param readonly      リードオンリー指定 [true:読取専用/false:読書可]
438         * @param isChbox       チェックボックス生成 [true:生成する/false:生成しない]
439         *
440         * @return チェックボックスのHMTL文字列
441         */
442        private String makeCheckbox( final String clm, final boolean checked, final String bgCnt, final String prefix, final boolean readonly, final boolean isChbox ) {
443                if( isChbox ) {
444
445                        // 6.1.1.0 (2015/01/17) TagBufferの連結記述
446                        final String tag = new TagBuffer( "input" )
447                                                                .add( "type"    , "checkbox" )
448                                                                .add( "name"    , clm )
449                                                                .add( "value"   , "1" )
450                                                                .add( "checked" , "checked" , checked )
451                                                                .add( "disabled", "disabled", readonly )
452                                                                .makeTag();
453
454                        // 6.1.1.0 (2015/01/17) TagBufferの連結記述
455                        final String cell = readonly && checked                 // 6.1.1.0 (2015/01/17) suffix 処理を変更
456                                        ? tag + new TagBuffer( "input" )
457                                                                .add( "type", "hidden" )
458                                                                .add( "name", clm )
459                                                                .add( "value", "1" )
460                                                                .makeTag()
461                                        : tag ;
462
463                        return makeCell( prefix + cell , bgCnt );                       // 6.1.1.0 (2015/01/17) prefix に、null は禁止
464                }
465                else {
466                        return makeCell( prefix + "&nbsp;", bgCnt );            // 6.1.1.0 (2015/01/17) prefix に、null は禁止
467                }
468        }
469
470        /**
471         * テキスト入力HTML文字列を生成します。
472         * 生成したHTMLは以下のようになります。
473         * 例)&lt;tr&gt;&lt;td class="row_[bgCnt]" ...&gt;[prefix]&lt;input type="text" name="[clm]" ... /&gt;&lt;/td&gt;&lt;/tr&gt;
474         *
475         * @param clm           カラム
476         * @param value         値
477         * @param bgCnt         ゼブラ指定 [0/1/h]
478         * @param prefix        チェックボックスのタグの前に挿入するHTML文字列(nullは禁止)
479         *
480         * @return チェックボックスのHMTL文字列
481         */
482        private String makeInput( final String clm, final String value, final String bgCnt, final String prefix ) {
483                // 6.1.1.0 (2015/01/17) TagBufferの連結記述
484                final String tag = new TagBuffer( "input" )
485                                                        .add( "type"            , "text" )
486                                                        .add( "name"            , clm )
487                                                        .add( "value"           , value )
488                                                        .add( "style"           , "width:10px; font-size:10px;" )
489                                                        .add( "maxlength"       , "2" )
490                                                        .add( "class"           , "S9" )
491                                                        .makeTag();
492
493                return makeCell( prefix + tag , bgCnt );                // 6.1.1.0 (2015/01/17) prefix に、null は禁止
494
495        }
496
497        /**
498         * 左右分割されている際の分割列のHTML文字列を生成します。
499         *
500         * @og.rev 6.4.4.1 (2016/03/18) StringBuilderの代わりに、OgBuilderを使用する。
501         *
502         * @param useSum 集計対象のカラム(=NUMBER型)が存在しているか [true:存在している/false:存在していない]
503         *
504         * @return チェックボックスのHMTL文字列
505         * @og.rtnNotNull
506         */
507        private String makeSeparateRow( final boolean useSum ) {
508                final String ROW_H = makeCell( "&nbsp", "h" ) ;
509
510                return new OgBuilder()
511                        .append( "<table style=\"float:left;\"><tr><td style=\"margin:0px; padding:0px;\"><table>" )
512                        .append( ROW_H )                        // ラベル
513                        .append( ROW_H )                        // 表示
514                        .appendIf( useSum , ROW_H )     // 集計項目
515                        .append( ROW_H )                        // 集計キー
516                        .append( ROW_H )                        // 小計キー
517                        .append( ROW_H )                        // 合計キー
518                        .append( ROW_H )                        // 表示順
519                        .append( ROW_H )                        // 昇順・降順
520                        .append( "</table></td></tr></table>")
521                        .toString();
522
523        }
524
525        /**
526         * ラベルのHTML文字列を生成します。
527         *
528         * @param clm カラム
529         *
530         * @return ラベルのHTML文字列
531         */
532        private String makeLabel( final String clm ) {
533                return makeCell( getDBColumn( clm ).getLongLabel(), "h" );
534        }
535
536        /**
537         * セルのHTML文字列を生成します。
538         *
539         * body 属性は、HTML文字列を指定します。
540         * bgCnt は、背景色のゼブラカラーの指定の為の class 属性で、[0/1/h] が指定できます。
541         * 例えば、"0" を指定した場合は、class="row_0" のように、属性を付与します。
542         * 標準の CSSファイルで設定しているのが、[0/1/h] なだけで、上記 class 属性を
543         * custom.css で設定すれば、どのような文字列でも指定可能です。
544         *
545         * @og.rev 6.1.1.0 (2015/01/17) 内部構造を見直します。
546         *
547         * @param body tdタグ内のHTML文字列
548         * @param bgCnt ゼブラ指定 [0/1/h]
549         *
550         * @return セルのHTML文字列
551         * @og.rtnNotNull
552         */
553        private String makeCell( final String body, final String bgCnt ) {
554                return "<tr><td align=\"center\" style=\"height:22px;\" class=\"row_" + bgCnt + "\">" + body + "</td></tr>";
555        }
556
557        /**
558         * この編集設定で集計対象のカラム(=NUMBER型)が存在しているかを返します。
559         *
560         * @param viewClms カラム
561         *
562         * @return 集計対象のカラム(=NUMBER型)が存在しているか
563         */
564        private boolean getUseSum( final String viewClms ) {
565                if( viewClms == null ) { return false; }
566
567                final String[] clms = StringUtil.csv2Array( viewClms.replace( '|', ',' ) );
568                for( int j=0; j<clms.length; j++ ) {
569                        // 6.1.0.0 (2014/12/26) refactoring : Avoid if(x != y) ..; else ..;
570                        final String clm = StringUtil.startsChar( clms[j] , '!' ) ? clms[j].substring( 1 ) : clms[j] ;                  // 6.4.1.1 (2016/01/16) 1文字 String.startsWith
571                        if( isNumberClm( clm ) ) { return true; }               // ひとつでも見つかれば、true
572                }
573                return false;
574        }
575
576        /**
577         * 引数のカラムがNUMBER型かどうかをチェックします。
578         *
579         * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
580         * @og.rev 6.4.4.2 (2016/04/01) contains 判定を行う新しいメソッドを使用します。
581         * @og.rev 6.4.6.0 (2016/05/27) isNumber , isDate 追加。
582         *
583         * @param clm カラム
584         *
585         * @return NUMBER型かどうか
586         */
587        private boolean isNumberClm( final String clm ) {
588                if( clm == null ) { return false; }
589                // 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
590                if( table == null ) {
591                        final String errMsg = "DBTableModelが設定されていません。" ;
592                        throw new OgRuntimeException( errMsg );
593                }
594
595                final int no = table.getColumnNo( clm, false );
596                if( no >= 0 ) {
597                        final DBColumn dbClm = table.getDBColumn( no ); 
598                        // 6.0.0.1 (2014/04/25) These nested if statements could be combined
599                        // 6.4.4.2 (2016/04/01) contains 判定を行う新しいメソッドを使用します。
600                        return dbClm != null && dbClm.isNumberType();
601                }
602                return false;
603        }
604
605        /**
606         * 編集設定情報を保存します。
607         *
608         * @og.rev 6.1.1.0 (2015/01/17) 総合計を最初の行に追加するかどうか(FirstTotal)の属性を追加
609         * @og.rev 6.4.5.0 (2016/04/08) UserInfo のEditConfig関連機能を、DBEditConfigManagerに移植します。
610         * @og.rev 5.9.18.1 (2017/03/24) 共通の編集名対応
611         * @og.rev 6.9.2.1 (2018/03/12) DBEditConfigManagerを直接取り出す処理を、廃止します
612         *
613         */
614//      private void saveEditConfig( final DBEditConfigManager dbConfMgr ) {
615        private void saveEditConfig() {
616                final String viewClms           = getRequest().getParameter( "viewClms" );
617                final String sumClms            = getColumns( SUM_PREFIX );
618                final String groupClms          = getColumns( GROUP_PREFIX );
619                final String subTotalClms       = getColumns( SUBTOTAL_PREFIX );
620                final String totalClms          = getColumns( TOTAL_PREFIX );
621                final String useGrandTotal      = getRequest().getParameter( GRANDTOTAL_PREFIX );
622                final String useFirstTotal      = getRequest().getParameter( FIRSTTOTAL_PREFIX );               // 6.1.1.0 (2015/01/17)
623                final String orderByClms        = getOrderByColumns();
624                final String isCommon           = getRequest().getParameter( COMMON_PREFIX );
625
626                // 5.9.18.1 (2017/03/24) ADD 編集名の共通判別対応
627                // 共通で、編集名の頭に「*」が無い場合
628                if("1".equals( isCommon ) && !('*' == editName.charAt( 0 ))){
629                        // 編集名の頭に「*」を付与 
630                        editName        = "*"+editName;
631                }
632                // 編集名をリクエストスコープに設定
633                setRequestAttribute("regEditName", editName);
634
635                final DBEditConfig config
636                        = new DBEditConfig( editName, viewClms, sumClms, groupClms
637                                                                , subTotalClms, totalClms, useGrandTotal, useFirstTotal, orderByClms, isCommon );
638
639                getUser().addEditConfig( gamenId, editName, config );   // 6.4.5.0 (2016/04/08) 暫定的に残す
640        //      dbConfMgr.addEditConfig( gamenId, editName, config );
641        }
642
643        /**
644         * 編集設定情報を削除します。
645         *
646         * ※ org.opengion.hayabusa.resource.UserInfo#deleteEditConfig( String  , String )でも
647         *    処理しているが、本来は、UserInfoでは処理しないほうが良いため、
648         *    今回は、こちらで判定して処理します。
649         *
650         * @og.rev 6.4.5.0 (2016/04/08) 共通設定した editName が削除できてしまうため、ロール制御を追加します。
651         * @og.rev 6.4.5.0 (2016/04/08) UserInfo のEditConfig関連機能を、DBEditConfigManagerに移植します。
652         * @og.rev 6.9.2.1 (2018/03/12) DBEditConfigManagerを直接取り出す処理を、廃止します
653         *
654         * @param       config DBEditConfigオブジェクト
655         */
656//      private void deleteEditConfig( final DBEditConfigManager dbConfMgr , final DBEditConfig config ) {
657        private void deleteEditConfig( final DBEditConfig config ) {
658                final boolean isCommon = config.isCommon();
659                // 共通で、かつ、共通設定ロールを持っていない場合は、エラーにします。
660                if( isCommon && !getUser().isAccess( CAN_EDIT_COMMON ) ) {
661                        final String errMsg = "共通設定されている編集名を削除する権限がありません。";
662                        throw new HybsSystemException( errMsg );
663                }
664                else {
665                        getUser().deleteEditConfig( gamenId, editName );        // 6.4.5.0 (2016/04/08) 暫定的に残す
666        //              dbConfMgr.deleteEditConfig( gamenId, editName );
667                }
668        }
669
670        /**
671         * パラメーターから引数のプレフィックスをキーに、チェックされたカラム一覧(CSV形式)を返します。
672         *
673         * @param prefixKey 各キーの取得するためのプレフィックス
674         *
675         * @return カラム一覧(CSV形式)
676         * @og.rtnNotNull
677         */
678        private String getColumns( final String prefixKey ) {
679                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
680
681                final Enumeration<?> enume = getParameterNames();
682                while( enume.hasMoreElements() ) {
683                        final String key = (String)(enume.nextElement());
684                        if( key.startsWith( prefixKey ) ) {
685                                final String val = getRequest().getParameter( key );
686                                if( "1".equals( val ) ) {
687                                        final String clm = key.substring( prefixKey.length() );
688                                        if( buf.length() > 0 ) { buf.append( ',' ); }           // 6.0.2.5 (2014/10/31) char を append する。
689                                        buf.append( clm );
690                                }
691                        }
692                }
693
694                return buf.toString();
695        }
696
697        /**
698         * 表示順のカラム一覧(CSV形式)を返します。
699         *
700         * @og.rev 6.4.3.4 (2016/03/11) CSV形式の文字連結を、stream 経由で行います。
701         *
702         * @return 表示順のカラム一覧(CSV形式)
703         * @og.rtnNotNull
704         */
705        private String getOrderByColumns() {
706                final Enumeration<?> enume = getParameterNames();
707                final List<Integer> orderNo = new ArrayList<>();
708                final Map<Integer,String> odrClmMap = new HashMap<>();
709                while( enume.hasMoreElements() ) {
710                        final String key = (String)(enume.nextElement());
711                        if( key.startsWith( ORDERBY_PREFIX ) ) {
712                                final String val = getRequest().getParameter( key );
713                                if( val != null && val.length() > 0 ) {
714                                        String clm = key.substring( ORDERBY_PREFIX.length() );
715                                        final String desc = getRequest().getParameter( DESC_PREFIX + clm );
716                                        if( "1".equals( desc ) ) {
717                                                clm = "!"  + clm;
718                                        }
719                                        // 数字項目以外が入力された場合は無視
720                                        Integer odno = null;
721                                        try {
722                                                odno = Integer.valueOf( val );
723                                        }
724                                        catch( final NumberFormatException ex ) {
725                                                continue;
726                                        }
727                                        String str = odrClmMap.get( odno );
728                                        // 同じ番号の場合でも重ならないように振り直しする。
729                                        while( str != null ) {
730                                                odno = Integer.valueOf( odno.intValue() + 1 );
731                                                str = odrClmMap.get( odno );
732                                        }
733                                        odrClmMap.put( odno, clm );
734                                        orderNo.add( odno );
735                                }
736                        }
737                }
738
739                Collections.sort( orderNo );
740
741                // 6.4.3.4 (2016/03/11) CSV形式の文字連結を、stream 経由で行います。
742                return orderNo.stream()
743                                                .map( no -> odrClmMap.get( no ) )
744                                                .collect( Collectors.joining( "," ) );
745
746        }
747
748        /**
749         * 編集設定一覧のプルダウンメニューを作成します。
750         *
751         * @param       configs DBEditConfig配列(可変長引数)
752         *
753         * @return      編集一覧のプルダウン
754         * @og.rtnNotNull
755         */
756        private String getEditSelect( final DBEditConfig... configs ) {
757                final DBColumn column = getDBColumn( "editName" );
758
759                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE )
760                        .append( "<span class=\"label editName\">" )
761                        .append( column.getLongLabel() )
762                        .append( ":</span><span class=\"editName\">" )
763                        .append( "<select name=\"editName\">" )
764                        .append( "<option />" );
765                for( final DBEditConfig config : configs ) {
766                        final String name = config.getEditName();
767                        buf.append( "<option value=\"" ).append( name ).append( '"' );          // 6.0.2.5 (2014/10/31) char を append する。
768                        if( config.isCommon() ) {
769                                buf.append( " class=\"commonEdit\"" );
770                        }
771                        buf.append( "\">" ).append( name ).append( "</option>" );
772                }
773                buf.append( "</select></span>" );
774                return buf.toString();
775        }
776
777        /**
778         * 【TAG】command を指定します。
779         *
780         * @og.tag
781         * command を指定します。
782         * [GET/LIST/SET/DELETE]のみが設定可能です。それ以外の場合、何も処理されません。
783         *
784         * @param       cmd コマンド [GET/LIST/SET/DELETE]
785         */
786        public void setCommand( final String cmd ) {
787                command = nval( getRequestParameter( cmd ),command );
788        }
789
790        /**
791         * 【TAG】画面ID を指定します。
792         *
793         * @og.tag
794         * 画面ID を指定します。
795         *
796         * @param       key 画面ID
797         */
798        public void setGamenId( final String key ) {
799                gamenId = nval( getRequestParameter( key ),gamenId );
800        }
801
802        /**
803         * 【TAG】編集名を指定します。
804         *
805         * @og.tag
806         * 編集名 を指定します。
807         * commandがSETまたはDELETEの場合は必須です。
808         * commandがGETまたはLISTの場合は無効です。
809         *
810         * @param       name 編集名
811         */
812        public void setEditName( final String name ) {
813                editName = nval( getRequestParameter( name ),editName );
814        }
815
816        /**
817         * 【TAG】順番の入れ替えと、表示順の設定のみを行う場合にtrueにします(初期値:false)。
818         *
819         * @og.tag
820         * 順番の入れ替えと、表示順の設定のみを行う場合にtrueにします。
821         * 表示/非表示切替や、集計機能は利用できなくなります。
822         * (チェックボックスのリードオンリーはできないため、実際にはdisable+hiddenで出力しています)
823         * 初期値は、false:通常 です。
824         *
825         * @og.rev 5.5.5.2 (2012/08/10) 新規追加
826         *
827         * @param flag  順番入替のみ [true:入替のみ/false:通常]
828         */
829        public void setOrderOnly( final String flag ) {
830                orderOnly = nval( getRequestParameter( flag ),orderOnly );
831        }
832
833        /**
834         * このオブジェクトの文字列表現を返します。
835         * 基本的にデバッグ目的に使用します。
836         *
837         * @return このクラスの文字列表現
838         * @og.rtnNotNull
839         */
840        @Override
841        public String toString() {
842                return ToString.title( this.getClass().getName() )
843                                .println( "VERSION"             ,VERSION                )
844                                .println( "command"             ,command                )
845                                .println( "gamenId"             ,gamenId                )
846                                .println( "editName"    ,editName               )
847                                .println( "Other..."    ,getAttributes().getAttribute() )
848                                .fixForm().toString() ;
849        }
850}