    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.plugin.view;
    017
    018import org.opengion.hayabusa.common.HybsSystem;
    019import org.opengion.fukurou.util.StringUtil;
    020// import org.opengion.fukurou.util.XHTMLTag;
    021import org.opengion.hayabusa.html.AbstractViewForm;
    022import org.opengion.hayabusa.html.ViewCalendarParam;
    023import static org.opengion.fukurou.system.HybsConst.BR; // 6.1.0.0 (2014/12/26) refactoring
    024
    025import java.util.Calendar;
    026
    027/**
    028 * １ヶ月分のカレンダー形式で、検索結果を表示する、カレンダー表示クラスです。
    029 *
    030 * AbstractViewForm により、setter/getterメソッドのデフォルト実装を提供しています。
    031 * 各HTMLのタグに必要な setter/getterメソッドのみ，追加定義しています。
    032 *
    033 * AbstractViewForm を継承している為,ロケールに応じたラベルを出力させる事が出来ます。
    034 *
    035 * @og.group 画面表示
    036 *
    037 * @version  4.0
    038 * @author   Kazuhiko Hasegawa
    039 * @since    JDK5.0,
    040 */
    041public class ViewForm_HTMLCalendar extends AbstractViewForm {
    042        /** このプログラムのVERSION文字列を設定します。   {@value} */
    043        private static final String VERSION = "7.0.1.0 (2018/10/15)" ;
    044
    045        private static final String[] WEEK_JA = { "日" ,"月" ,"火" ,"水" ,"木" ,"金" ,"土" ,"日" ,"月" };        // 6.4.1.1 (2016/01/16) WEEK_ja  → WEEK_JA  refactoring
    046        private static final String[] WEEK_EN = { "SUN","MON","TUE","WED","THU","FRI","SAT","SUN","MON" };      // 6.4.1.1 (2016/01/16) WEEK_en  → WEEK_EN  refactoring
    047        private static final String[] WEEK_MK = { "SUN","",   "",   "",   "",   "",   "SAT","SUN",""    };
    048
    049        private String[] week              ;
    050        private String[] viewKeys          ;            // カレンダを指定するキー配列        // 3.6.0.0 (2004/09/17)
    051        private String   ymKey             ;            // 年月のカラム名
    052        private String   dayKey            ;            // 休日(0:通常、1:休日)のカラム名
    053        private String   valKey            ;            // カレンダに表示する値のカラム名
    054        private boolean  valueBrFlag   ;                // 日付けと値の間に、BRタグを入れるかどうか
    055        private int              firstWeek         ;            // 曜日の開始(0:日曜 1:月曜)
    056        private int              columnSize        ;            // カレンダの横方向の繰り返し数       // 3.6.0.0 (2004/09/17)
    057
    058        /**
    059         * デフォルトコンストラクター
    060         *
    061         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
    062         */
    063        public ViewForm_HTMLCalendar() { super(); }             // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
    064
    065        /**
    066         * DBTableModel から HTML文字列を作成して返します。
    067         * startNo(表示開始位置)から、pageSize(表示件数)までのView文字列を作成します。
    068         * 表示残りデータが pageSize 以下の場合は,残りのデータをすべて出力します。
    069         *
    070         * @og.rev 3.5.2.1 (2003/10/27) 属性値の指定のシングルクオートをダブルクオートに変更。
    071         * @og.rev 3.6.0.0 (2004/09/17) 複数カレンダに対応
    072         * @og.rev 3.6.0.5 (2004/10/18) calenderParam の viewKeys バグ対応。
    073         * @og.rev 3.7.0.1 (2005/01/31) 全件チェックコントロール処理変更
    074         * @og.rev 7.0.1.0 (2018/10/15) XHTML → HTML5 対応(空要素の、"／＞" 止めを、"＞" に変更します)。
    075         * @og.rev 5.10.7.1 (2019/01/18) 1件の場合でもチェックボックスを表示
    076         *
    077         * @param  startNo    表示開始位置
    078         * @param  pageSize   表示件数
    079         *
    080         * @return  DBTableModelから作成された HTML文字列
    081         * @og.rtnNotNull
    082         */
    083        public String create( final int startNo, final int pageSize )  {
    084                if( getRowCount() == 0 ) { return ""; } // 暫定処置
    085
    086                paramInit();
    087
    088                final int lastNo = getLastNo( startNo, pageSize );
    089
    090                final StringBuilder out = new StringBuilder( BUFFER_LARGE )
    091                        .append( "<table><tr>" ).append( CR );
    092
    093//              final boolean onlyOne = ( lastNo - startNo ) == 1 ;     // 互換性のため、１件の処理のみ変更
    094                final boolean onlyOne = lastNo - startNo == 1 ;         // 互換性のため、１件の処理のみ変更             // 6.9.7.0 (2018/05/14) PMD Useless parentheses.
    095
    096                // 3.7.0.1 (2005/01/31) 全件チェックコントロール処理変更
    097                if( ! onlyOne && isUseCheckControl() && "checkbox".equals( getSelectedType() ) ) {
    098                        out.append( "<tr><td>" ).append( getAllCheckControl() ).append( "</td></tr>");
    099                }
    100
    101                for( int row=startNo; row<lastNo; row++ ) {
    102                        out.append( "<td valign=\"top\">" );
    103
    104                        if( isWritable( row ) ) {
    105                                // 5.10.7.1 (2019/01/18) 1件でもチェックボックス表示に変更
    106        //                      if( onlyOne ) {
    107        //                              out.append( XHTMLTag.hidden( HybsSystem.ROW_SEL_KEY,String.valueOf( row ) ) )
    108        //                                      .append( CR );
    109        //                      }
    110        //                      else {
    111                                        out.append( "<input type=\"" ).append( getSelectedType() )
    112                                                .append( "\" name=\"" ).append( HybsSystem.ROW_SEL_KEY ).append( '"' );
    113                                        if( isChecked( row ) ) { out.append( " checked=\"checked\"" ); }
    114//                                      out.append( " value=\"" ).append( row ).append( "\" />" );
    115                                        out.append( " value=\"" ).append( row ).append( "\" >" );                       // 7.0.1.0 (2018/10/15)
    116        //                      }
    117                        }
    118
    119                        // 3.6.0.5 (2004/10/18)
    120                        // 7.2.9.4 (2020/11/20) PMD:This for loop can be replaced by a foreach loop
    121                        for( final String vkey : viewKeys ) {
    122                                if( "_".equals( vkey ) ) { continue; }
    123                                final int newCol = getColumnNo( vkey );
    124//                      for( int col=0; col<viewKeys.length; col++ ) {
    125//                              if( "_".equals( viewKeys[col] ) ) { continue; }
    126//                              final int newCol = getColumnNo( viewKeys[col] );
    127                                out.append("<span id=\"label\">")
    128                                        .append( getColumnLabel( newCol ) )
    129                                        .append( ":</span>" )
    130                                        .append( getValueLabel(row,newCol) )
    131                                        .append( "&nbsp;" );
    132                        }
    133                        out.append( BR )
    134                                .append( makeCalendarData( row ) )
    135                                .append( "</td>" );
    136                        if( (row+1) % columnSize == 0 ) {
    137                                out.append( "</tr><tr>" ).append( CR );
    138                        }
    139                }
    140                out.append( "</tr></table>" ).append( CR );
    141
    142                return out.toString();
    143        }
    144
    145        /**
    146         * DBTableModel の指定の行番号より、カレンダのHTML文字列を作成して返します。
    147         *
    148         * @og.rev 3.6.0.0 (2004/09/17) create( int startNo, int pageSize ) のロジックを移動
    149         * @og.rev 3.6.0.5 (2004/10/18) 印刷時の罫線出力関連機能の追加。id 属性を出力します。
    150         * @og.rev 7.0.1.0 (2018/10/15) XHTML → HTML5 対応(空要素の、"／＞" 止めを、"＞" に変更します)。
    151         *
    152         * @param  row    指定の行番号
    153         *
    154         * @return  指定の行番号のカレンダのHTML文字列
    155         * @og.rtnNotNull
    156         */
    157        private String makeCalendarData( final int row ) {
    158                final String yyyymm = getValue( row,getColumnNo( ymKey ));
    159                final Calendar currentCal = getCalendar( yyyymm );
    160
    161                final StringBuilder out = new StringBuilder( BUFFER_LARGE )
    162                        .append( "<table id=\"viewCalendar\" border=\"0\" cellpadding=\"1\" cellspacing=\"2\">" )
    163                        .append( CR )                                                                           // 3.6.0.5 (2004/10/18)
    164                        .append( " <tr><td class=\"titleStyle\" colspan=\"7\">" )
    165                        .append( getValueLabel( row,getColumnNo( ymKey )) )
    166                        .append( "</td></tr>" ).append( CR );
    167
    168                // 今月の最終日
    169                final int daysInMonth = currentCal.getActualMaximum(Calendar.DAY_OF_MONTH);
    170                // カレンダーの週の初めを設定する。月曜開始のカレンダーを作成するときに利用
    171                currentCal.setFirstDayOfWeek( Calendar.SUNDAY + firstWeek );
    172
    173                // 週を表す番号  ０～６ の間
    174                int culDay = ( currentCal.get(Calendar.DAY_OF_WEEK)
    175                                                + ( 7 - currentCal.getFirstDayOfWeek() ) ) % 7 ;
    176
    177                // 曜日欄を記述します。
    178                out.append(" <tr>").append( CR );
    179                for( int i=0; i<7; i++ ) {
    180                        out.append("  <td width=\"14%\" class=\"dayHead" )
    181                                .append( WEEK_MK[i+firstWeek] ).append( "\">" )
    182                                .append( week[i+firstWeek] ).append( "</td>" )
    183                                .append( CR );
    184                }
    185                out.append(" </tr>").append( CR )
    186                        .append(" <tr>").append( CR );                          // 6.1.0.0 (2014/12/26) refactoring
    187
    188                // 第一週の日付欄の空きスペースの計算
    189                if( culDay != 0 ) {
    190                        out.append("  <td colspan=\"" ).append( culDay ).append( "\">&nbsp;</td>" ).append( CR );
    191                }
    192
    193                // 日付欄を埋めます。
    194//              final String BR = valueBrFlag ? "<br />" : "" ;
    195                final String BR = valueBrFlag ? "<br>" : "" ;                           // 7.0.1.0 (2018/10/15)
    196                for( int day=1; day <= daysInMonth; day++ ) {
    197                        final int    daycol = getColumnNo( dayKey + day );              // 動的日付けカラム番号取得
    198                        final String daylbl = getValueLabel( row,daycol,day );  // ローカルの日付けラベルを求めるメソッド
    199                        // 6.3.9.1 (2015/11/27) Found 'DD'-anomaly for variable(PMD)
    200                        final String vallbl = valKey == null ? "" : BR + getValueLabel( row,getColumnNo( valKey + day ) );              // 動的値カラム番号取得
    201
    202                        if( "1".equals( getValue( row,daycol ))) {
    203                                out.append("  <td class=\"holyday\">" );
    204                        } else {
    205                                out.append("  <td class=\"day" )
    206                                        .append( WEEK_MK[culDay+firstWeek] )
    207                                        .append("\">");
    208                        }
    209                        out.append( daylbl )
    210                                .append( vallbl )
    211                                .append("</td>")
    212                                .append( CR );
    213
    214                        // 週の終わりで、行を折り返す。
    215                        if( culDay == 6 ) {
    216                                out.append(" </tr>" ).append( CR )
    217                                        .append( " <tr>").append( CR );                 // 6.1.0.0 (2014/12/26) refactoring
    218                                culDay = 0;
    219                        } else {
    220                                culDay++;
    221                        }
    222                }
    223
    224                // 最終週の日付欄の空きスペースの計算
    225                if( 7 != culDay ) {                             // 6.4.2.1 (2016/02/05) PMD refactoring. Useless parentheses.
    226                        out.append( "  <td colspan=\"" ).append( 7-culDay ).append( "\">&nbsp;</td>" );
    227                }
    228                out.append( CR )
    229                        .append( " </tr>" ).append( CR )
    230                        .append( "</table>" ).append( CR );
    231
    232                return out.toString();
    233        }
    234
    235        /**
    236         * このビーに対する特別な初期化を行う。
    237         *
    238         * @og.rev 3.5.4.0 (2003/11/25) TableFormatter クラスを使用するように変更。
    239         * @og.rev 3.5.5.9 (2004/06/07) ヘッダーの日付け表示に、Locale を加味できるように変更
    240         * @og.rev 3.6.0.0 (2004/09/17) viewKeys , columnSize 属性の追加
    241         *
    242         */
    243        private void paramInit() {
    244
    245                final String viewKeysCd = getParam( ViewCalendarParam.VIEW_KEYS                 ,ViewCalendarParam.VIEW_VALUES                  );      // 3.6.0.0 (2004/09/17)
    246                ymKey                           = getParam( ViewCalendarParam.YM_KEY                    ,ViewCalendarParam.YM_VALUE                             );
    247                dayKey                          = getParam( ViewCalendarParam.DAY_KEY                   ,ViewCalendarParam.DAY_VALUE                    );
    248                valKey                          = getParam( ViewCalendarParam.VALUE_KEY                 ,null                                                                   );
    249                final String valueBrCd  = getParam( ViewCalendarParam.VALUE_BR_FLAG_KEY ,ViewCalendarParam.VALUE_BR_FLAG_VALUE  );
    250                final String firstWeekCd        = getParam( ViewCalendarParam.FIRSTWEEK_KEY             ,ViewCalendarParam.FIRSTWEEK_VALUE              );
    251                final String headerLocale       = getParam( ViewCalendarParam.HEADER_LOCALE_KEY ,ViewCalendarParam.HEADER_LOCALE_VALUE  );
    252                final String columnSizeCd       = getParam( ViewCalendarParam.COLUMN_SIZE_KEY   ,ViewCalendarParam.COLUMN_SIZE_VALUE    );      // 3.6.0.0 (2004/09/17)
    253
    254                viewKeys    = StringUtil.csv2Array( viewKeysCd );
    255                firstWeek   = Integer.parseInt( firstWeekCd );
    256                valueBrFlag = Boolean.parseBoolean( valueBrCd );                // 6.1.0.0 (2014/12/26) refactoring
    257                columnSize  = Integer.parseInt( columnSizeCd );                 // 3.6.0.0 (2004/09/17)
    258
    259                // 曜日ヘッダーをコピーして作成します。
    260                if( "ja".equals( headerLocale ) ) {
    261                        week = WEEK_JA;
    262                }
    263                else {
    264                        week = WEEK_EN;
    265                }
    266        }
    267
    268        /**
    269         * row行，colum列 のデータの値をHTML文字列に変換して返します。
    270         * リソースバンドルが登録されている場合は,リソースに応じた
    271         * HTML文字列を作成します。
    272         * カレンダーViewに特化した、ラベル値を返します。
    273         *
    274         * @og.rev 3.8.0.9 (2005/10/17) writableControl 追加による引数変更
    275         *
    276         * @param       row             行番号
    277         * @param       column  カラム番号
    278         * @param       day             日付
    279         *
    280         * @return      row行，colum列 のデータの値
    281         * @og.rtnNotNull
    282         */
    283        private String getValueLabel( final int row, final int column, final int day ) {
    284                // 6.3.9.1 (2015/11/27) A method should have only one exit point, and that should be the last statement in the method.(PMD)
    285                final String rtn ;
    286                if( isColumnWritable( column ) && isWritable( row ) ) {
    287                        final String val = getValue( row,column ) ;
    288                        rtn = day + getEditorValue( row,column,val );
    289                }
    290                else {
    291                        rtn = String.valueOf( day );
    292                }
    293                return rtn ;
    294        }
    295
    296        /**
    297         * 指定のYYYYMM文字列から、カレンダーオブジェクトを作成して返します。
    298         * 日にちは、１日にセットされます。
    299         *
    300         * @param   ym YYYYMM文字列
    301         *
    302         * @return  カレンダーオブジェクト
    303         */
    304        private Calendar getCalendar( final String ym ) {
    305                final Calendar cal = Calendar.getInstance();
    306
    307                if( ym != null && ym.length() == 6 ) {
    308                        final int yyyy = Integer.parseInt( ym.substring( 0,4 ) );
    309                        final int mm   = Integer.parseInt( ym.substring( 4,6 ) ) - 1;
    310                        final int dd   = 1;
    311                        cal.set( yyyy,mm,dd,0,0,0 );
    312                }
    313                else {
    314                        // カレンダーを今月の１日に設定する。
    315                        cal.set(Calendar.DAY_OF_MONTH, 1);
    316                }
    317
    318                return cal ;
    319        }
    320
    321        /**
    322         * フォーマットメソッドを使用できるかどうかを問い合わせます。
    323         *
    324         * @og.rev 3.6.0.0 (2004/09/17) 親クラス変更に伴なう、追加
    325         *
    326         * @return  使用可能(true)/ 使用不可能 (false)
    327         */
    328        public boolean canUseFormat() {
    329                return false;
    330        }
    331
    332        /**
    333         * 表示項目の編集(並び替え)が可能かどうかを返します。
    334         *
    335         * @og.rev 5.1.6.0 (2010/05/01) 新規追加
    336         *
    337         * @return      表示項目の編集(並び替え)が可能かどうか(false:不可能)
    338         */
    339        @Override
    340        public boolean isEditable() {
    341                return false;
    342        }
    343}