    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.column;
    017
    018import org.opengion.fukurou.util.StringUtil;
    019import org.opengion.hayabusa.db.AbstractEditor;
    020import org.opengion.hayabusa.db.CellEditor;
    021import org.opengion.hayabusa.db.DBColumn;
    022import org.opengion.fukurou.util.XHTMLTag;
    023
    024import java.text.DecimalFormat;
    025
    026/**
    027 * DECIMAL エディターは、カラムのデータをDecimal(１０進数、小数)表示する場合に
    028 * 使用するクラスです。
    029 *
    030 * 編集パラメータに与えられた文字列は、java.text.DecimalFormat を使用して
    031 * フォーマットされます。
    032 * フォーマット変換前に、カンマなどの数値変換時にエラーになる情報を削除しておきます。
    033 * 標準のフォーマットは"#,##0.#"です。
    034 * default値が設定されていない場合の初期値は0.0にフォーマット処理をしたものです。
    035 *
    036 * フォーマットルールは、{@link java.text.DecimalFormat} を参照願います。
    037 *
    038 * 7.4.2.3 (2021/06/09)
    039 *  ﾌｫｰﾏｯﾄは、表示桁数 に応じて決定します。
    040 *  ただし、ﾊﾟﾗﾒｰﾀ指定 が優先されます。
    041 *
    042 *  カラムの表示に必要な属性は, DBColumn オブジェクト より取り出します。
    043 * このクラスは、DBColumn オブジェクト毎に１つ作成されます。
    044 *
    045 * @og.group データ編集
    046 * @og.rev 3.8.8.5 (2007/03/09) 新規作成
    047 * @og.rev 5.4.3.6 (2012/01/19) コメント修正
    048 *
    049 * @version  4.0
    050 * @author       Kazuhiko Hasegawa
    051 * @since    JDK5.0,
    052 */
    053public class Editor_DECIMAL extends AbstractEditor {
    054        /** このプログラムのVERSION文字列を設定します。   {@value} */
    055        private static final String VERSION = "7.4.2.3 (2021/06/09)" ;
    056
    057        // 7.4.2.3 (2021/06/09) ﾌｫｰﾏｯﾄは、表示桁数 に応じて決定します(小数6桁以上の精度は受け付けられない)
    058        private static final String[] FRMT = new String[] { "#,##0" , "#,##0.0" , "#,##0.00" , "#,##0.000" , "#,##0.0000" , "#,##0.00000" , "#,##0.000000" } ;
    059
    060        private final int       minFraction;
    061        private final DecimalFormat format ;
    062        private final String    defValue ;
    063
    064        /**
    065         * デフォルトコンストラクター。
    066         * このコンストラクターで、基本オブジェクトを作成します。
    067         *
    068         */
    069        public Editor_DECIMAL() {
    070                super();                // 6.4.1.1 (2016/01/16) PMD refactoring. It is a good practice to call super() in a constructor
    071                // 4.3.4.4 (2009/01/01)
    072                minFraction = 0;
    073                format = null;
    074                defValue   = null;
    075        }
    076
    077        /**
    078         * DBColumnオブジェクトを指定したprivateコンストラクター。
    079         *
    080         * @og.rev 5.3.1.0 (2009/12/01) 初期値がnullの場合は、defValueはnullとする。
    081         * @og.rev 5.4.0.0 (2011/10/01) RendererParamが読み込まれているバグを修正
    082         * @og.rev 7.4.2.3 (2021/06/09) ﾌｫｰﾏｯﾄは、表示桁数 に応じて決定します(ﾊﾟﾗﾒｰﾀ指定 が優先)。
    083         *
    084         * @param       clm     DBColumnオブジェクト
    085         */
    086        private Editor_DECIMAL( final DBColumn clm ) {
    087                super( clm );
    088                minFraction = clm.getSizeY();
    089
    090                final String fm = makeFormat( clm );
    091//              String fm = clm.getEditorParam();
    092//              if( fm == null || fm.isEmpty() || fm.equals( "_" ) ) {
    093//                      fm = "#,##0.#";
    094//              }
    095                format = new DecimalFormat( fm );
    096
    097                // 5.3.1.0 (2009/12/01)
    098                final String defv = clm.getDefault();
    099                if( defv == null || defv.isEmpty() ) {
    100                        defValue = "";
    101                }
    102                else {
    103                        double dd = 0.0;
    104                        // 6.0.2.5 (2014/10/31) null でないことがわかっている値の冗長な null チェックがあります。
    105                        if( !"_".equals( defv ) ) {
    106                                dd  = StringUtil.parseDouble( defv );
    107                        }
    108                        defValue = format.format( dd );
    109                }
    110
    111                // -XXX,XXX,XXX.YYY 形式では、カンマ、小数点、マイナスなどの項目が入ります。
    112                final int maxlength = (int)(clm.getSizeX() * 4.0/3.0) + minFraction + 2 ;       // +2 は、マイナスと小数点
    113                attributes.set( "maxlength"   ,String.valueOf( maxlength ) );
    114                tagBuffer.add( XHTMLTag.inputAttri( attributes ) );
    115        }
    116
    117        /**
    118         * フォーマット文字列を返します。
    119         *
    120         * ﾌｫｰﾏｯﾄは、表示桁数 に応じて決定します。
    121         * ただし、ﾊﾟﾗﾒｰﾀ指定 が優先されます。
    122         *
    123         * @og.rev 7.4.2.3 (2021/06/09) ﾌｫｰﾏｯﾄは、表示桁数 に応じて決定します(ﾊﾟﾗﾒｰﾀ指定 が優先)。
    124         *
    125         * @param       clm     DBColumnオブジェクト
    126         *
    127         * @return      フォーマット文字列
    128         */
    129        private String makeFormat( final DBColumn clm ) {
    130                String fm = clm.getEditorParam();                                                       // ﾊﾟﾗﾒｰﾀ指定 が優先
    131
    132                if( fm == null || fm.isEmpty() || fm.equals( "_" ) ) {
    133                        fm = "#,##0.##";                                                                                // 初期値：桁を増やしておきます。
    134
    135                        // 7.4.2.3 (2021/06/09) ﾌｫｰﾏｯﾄは、表示桁数 に応じて決定します。
    136                        final String viewLen = clm.getViewLength();
    137                        if( viewLen != null ) {
    138                                final int ad = viewLen.indexOf( '.' );
    139                                if( ad >= 0 ) {
    140                                        final String st = viewLen.substring( ad+1 );            // 小数点以下の桁数取得
    141                                        try {
    142                                                final int su = Integer.parseInt( st );
    143                                                fm = su < FRMT.length ? FRMT[su] : FRMT[FRMT.length-1] ;
    144                                        }
    145                                        catch( final Throwable th ) {
    146                                                final String errMsg = "表示桁数の小数部の変換に失敗しました" + CR
    147                                                                                        + "viewLen=" + viewLen
    148                                                                                        + CR
    149                                                                                        + th.getMessage() ;
    150                                                System.err.println( errMsg );
    151                                        }
    152                                }
    153                        }
    154                }
    155
    156                return fm;
    157        }
    158
    159        /**
    160         * 各オブジェクトから自分のインスタンスを返します。
    161         * 自分自身をキャッシュするのか、新たに作成するのかは、各サブクラスの実装に
    162         * まかされます。
    163         *
    164         * @param       clm     DBColumnオブジェクト
    165         *
    166         * @return      CellEditorオブジェクト
    167         * @og.rtnNotNull
    168         */
    169        public CellEditor newInstance( final DBColumn clm ) {
    170                return new Editor_DECIMAL( clm );
    171        }
    172
    173        /**
    174         * データの編集用文字列を返します。
    175         *
    176         * @param   value 入力値
    177         *
    178         * @return  データの編集用文字列
    179         */
    180        @Override
    181        public String getValue( final String value ) {
    182                return super.getValue( formatValue( value ) );
    183        }
    184
    185        /**
    186         * name属性を変えた、データ表示/編集用のHTML文字列を作成します。
    187         * テーブル上の name に 行番号を付加して、名前_行番号 で登録するキーを作成し,
    188         * リクエスト情報を１つ毎のフィールドで処理できます。
    189         *
    190         * @param       row   行番号
    191         * @param       value 入力値
    192         *
    193         * @return      データ表示/編集用の文字列
    194         */
    195        @Override
    196        public String getValue( final int row,final String value ) {
    197                return super.getValue( row,formatValue( value ) );
    198        }
    199
    200        /**
    201         * 内部的なフォーマット変換後の文字列を返します。
    202         *
    203         * @og.rev 5.3.1.0 (2009/12/01) 値が0の場合は、初期値を適用する。
    204         *
    205         * @param       value 入力値
    206         *
    207         * @return      データの表示用文字列
    208         */
    209        private String formatValue( final String value ) {
    210                if( value == null || value.trim().isEmpty() || "0".equals( value ) ) {
    211                        return defValue;
    212                }
    213
    214                final double dd = StringUtil.parseDouble( value );
    215
    216                final String rtn ;
    217                synchronized( format ) {
    218                        rtn = format.format( dd );
    219                }
    220
    221                return rtn;
    222        }
    223}