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     */
016    package org.opengion.fukurou.model;
017    
018    import java.util.ArrayList;
019    import java.util.List;
020    
021    
022    /**
023     * [PN],[OYA] などの [] でæŒ?®šされたカラãƒ?�§表されたフォーマットデータに対してã€?
024     * DataModel オブジェクトを適用して å�?‚«ラãƒ?�«実データを割り当てるオブジェクトですã?
025     *
026     * カラãƒ?��には、特殊カラãƒ?��が使用できますã?これは、DataModel に存在しなã�?‚«ラãƒ?��
027     * ですが、å?を返すことがå?来ますã?
028     * <pre>
029     * [KEY.カラãƒ?��] : 行番号付きカラãƒ?��
030     * [I]            : 行番号
031     * [ROW.ID]       : 行毎ã?チェãƒ?‚¯ボックスのID
032     * [ROW.JSON]     : 行毎ã?全ãƒ??タのJavaScriptオブジェクト形å¼?{ key:val,key:val,... }
033     * カラãƒ??前に修飾記号(#,$,!)を付けるとフォーマットを変更できますã?
034     * ただしã?FormatTextField 系 と FormatTable 系で、å?力される形式が異なりますã?
035     *                  FormatTextField 系               FormatTable 系
036     * [#カラãƒ?��]    : TDなしã?ラベルと入力フィールãƒ?  ラベルをå?åŠ?
037     * [$カラãƒ?��]    : TDなしã?入力フィールドã?み       レンãƒ?ƒ©ーをå?åŠ?
038     * [!カラãƒ?��]    : TDなしã?値のみ                   値をå?åŠ?
039     *
040     * </pre>
041     * @og.group 画面表示
042     *
043     * @version  4.0
044     * @author   Kazuhiko Hasegawa
045     * @since    JDK5.0,
046     */
047    public class Formatter {
048            /** カラãƒ?D(連結文字å?)行番号の連結文字å?を定義 {@value} */
049            public static final String JOINT_STRING = "__" ;
050    
051            /** ãƒ??ブル表示のチェãƒ?‚¯ボックスを特定すã‚?id の 名称( id は、この名称?‹行番号) {@value} */
052            public static final String ROW_ID_KEY = "cb";   // 3.6.0.0 (2004/09/17)
053    
054            /** 特殊カラãƒ?��の定義: 行番号 [I] */
055            public static final int SYS_ROWNUM      = -1;           // [KEY.カラãƒ?��],[I],[ROW.ID]
056            /** 特殊カラãƒ?��の定義: [ROW.JSON]        */
057            public static final int SYS_JSON        = -2;           // [ROW.JSON]
058    
059            private final DataModel<?>        model   ;                       // 4.3.3.6 (2008/11/15) Generics警告対å¿?
060            private int[]                           clmNos  = null;         // フォーマットã?カラãƒ?•ª号配å?
061            private String[]                        format  = null;
062            private String[]                        clmKeys = null;         // フォーマットã?カラãƒ?��配å?
063            private char[]                          type    = null;         // '#':ラベルのみ  '$':レンãƒ?ƒ©ー '!':値のみ  そã?ä»?通常
064    
065            /**
066             * ãƒ??タモãƒ?ƒ«を指定してフォーマッターを構築しますã?
067             *
068             * @param  model ãƒ??タモãƒ?ƒ«
069             */
070            public Formatter( final DataModel<?> model ) {            // 4.3.3.6 (2008/11/15) Generics警告対å¿?
071                    this.model = model;
072            }
073    
074            /**
075             * フォーマットをセãƒ?ƒˆしますã?
076             *
077             * @param       fmt  [カラãƒ?��] 形式ã?フォーマットデータ
078             */
079            public void setFormat( final String fmt ) {
080                    makeFormatList( fmt );
081                    advanceFormat();
082            }
083    
084            /**
085             * フォーマットをセãƒ?ƒˆしますã?
086             *
087             * @param       fmt  [カラãƒ?��] 形式ã?フォーマットデータ
088             */
089            private void makeFormatList( final String fmt ) {
090                    int start = 0;
091                    int index = fmt.indexOf( '[' );
092                    List<String> clmKeyList = new ArrayList<String>();
093                    List<String> formatList = new ArrayList<String>();
094                    while( index >= 0 ) {
095                            int end = fmt.indexOf( ']',index );
096                            if( end < 0 ) {
097                                    String errMsg = "[ と ] との対応関係がずれてã�?�¾すã?"
098                                                            + "format=[" + fmt + "] : index=" + index ;
099                                    throw new RuntimeException( errMsg );
100                            }
101    
102                            // [ より前方のæ–?­—å?は、formatList へ
103                            if( index > 0 ) { formatList.add( fmt.substring( start,index ) ); }
104                            else                    { formatList.add( "" ); }       // ][ と連続してã�?‚‹ケース
105    
106                            // [XXXX] の XXXX部åˆ?‚’処ç�?
107                            clmKeyList.add( fmt.substring( index+1,end ) );
108    
109                            start = end+1 ;
110                            index = fmt.indexOf( '[',start );
111                    }
112                    // ] の後方部åˆ??、formatList へ
113                    formatList.add( fmt.substring( start ) );
114    
115                    format  = formatList.toArray( new String[formatList.size()] );
116                    clmKeys = clmKeyList.toArray( new String[clmKeyList.size()] );
117            }
118    
119            /**
120             * 追åŠ?©Ÿè?フォーマットを作æ?しますã?
121             *
122             */
123            private void advanceFormat() {
124    
125                    int size = clmKeys.length ;
126                    clmNos = new int[size];
127                    type   = new char[size];
128    
129                    // カラãƒ?•ª号の設定と、特殊カラãƒ?��処ç�?
130                    String clm ;
131                    for( int i=0; i<size; i++ ) {
132                            clm = clmKeys[i];
133                            char ch = clm.charAt(0);
134                            if( ch == '#' || ch == '$' || ch == '!' ) {
135                                    type[i] = ch;
136                                    clm = clm.substring(1);
137                                    clmKeys[i]      = clm;
138                                    clmNos[i] = model.getColumnNo( clm );
139                            }
140                            // [KEY.カラãƒ?��] 機è?追åŠ?
141                            else if( clm.startsWith( "KEY." ) ) {
142                                    clmNos[i]       = SYS_ROWNUM;
143                                    format[i]       = format[i] + clm.substring(4) + JOINT_STRING ;
144                            }
145                            // [I] 機è?追åŠ?
146                            else if( "I".equals( clm ) ) {
147                                    clmNos[i]       = SYS_ROWNUM;
148                            }
149                            // [ROW.ID] 機è?追åŠ?
150                            else if( "ROW.ID".equals( clm ) ) {
151                                    clmNos[i] = SYS_ROWNUM;
152                                    format[i] = format[i] + ROW_ID_KEY ;
153                            }
154                            // [ROW.JSON] 機è?追åŠ?
155                            else if( "ROW.JSON".equals( clm ) ) {
156                                    clmNos[i] = SYS_JSON;
157                            }
158                            else {
159                                    clmNos[i] = model.getColumnNo( clm );
160                            }
161                    }
162            }
163    
164            /**
165             * column にあるセルの属æ?値をStringに変換して返しますã?
166             *
167             * @param       row     処ç�?¸­の行番号
168             * @param       clm     値が参照されるカラãƒ?•ª号
169             *
170             * @return      æŒ?®šされたセルの値
171             *
172             */
173            public String getValue( final int row,final int clm ) {
174                    final String rtn ;
175                    if( clm >= 0 ) {
176                            rtn = String.valueOf( model.getValue( row,clm ) );
177                    }
178                    else if( clm == SYS_ROWNUM ) {
179                            rtn = String.valueOf( row );
180                    }
181                    else if( clm == SYS_JSON ) {
182                            rtn = getJson( row );
183                    }
184                    else {
185                            String errMsg = "æŒ?®šã?カラãƒ?•ª号に該当するå?ç�?�Œ見つかりませんã€?
186                                                    + "clm=[" + clm + "]" ;
187                            throw new RuntimeException( errMsg );
188                    }
189    
190                    return rtn ;
191            }
192    
193            /**
194             * æŒ?®šã? 行番号に対する、DataModel をå?に作æ?したフォーマット文字å?を返しますã?
195             *
196             * @param       row     行番号( [I]フォーマットå?ç�?”¨ )
197             *
198             * @return  æŒ?®šã?Object配å?をå?に作æ?したフォーマット文字å?
199             */
200            public String getFormatString( final int row ) {
201    //              StringBuilder rtnStr = new StringBuilder( 200 );
202    //
203    //              int count = clmNos.length;
204    //              for( int i=0; i<count; i++ ) {
205    //                      rtnStr.append( format[i] );
206    //                      if( clmNos[i] == SYS_ROWNUM ) {
207    //                              rtnStr.append( row );
208    //                      }
209    //                      else if( clmNos[i] == SYS_JSON ) {
210    //                              rtnStr.append( getJson( row ) );
211    //                      }
212    //                      else {
213    //                              rtnStr.append( model.getValue( row,clmNos[i] ) );
214    //                      }
215    //              }
216    //              rtnStr.append( format[count] );
217    //
218    //              return rtnStr.toString();
219                    return getFormatString( row, null );
220            }
221    
222            /**
223             * æŒ?®šã? 行番号に対する、DataModel をå?に作æ?したフォーマット文字å?を返しますã?
224             * ãƒ??タはseparatorでæŒ?®šされた区åˆ?‚Šæ–?­—で囲まれて返されますã?
225             *
226             * @og.rev 4.3.1.1 (2008/08/23) switch に、default label が存在しなã�?�Ÿめã?追åŠ?
227             *
228             * @param       row     行番号( [I]フォーマットå?ç�?”¨ )
229             * @param       separator       セパレーター
230             *
231             * @return  æŒ?®šã?Object配å?をå?に作æ?したフォーマット文字å?
232             */
233            public String getFormatString( final int row, final String separator ) {
234                    StringBuilder rtnStr = new StringBuilder( 200 );
235    
236                    int count = clmNos.length;
237                    for( int i=0; i<count; i++ ) {
238                            rtnStr.append( format[i] );
239                            if( clmNos[i] == SYS_ROWNUM ) {
240                                    rtnStr.append( row );
241                            }
242                            else if( clmNos[i] == SYS_JSON ) {
243                                    rtnStr.append( getJson( row ) );
244                            }
245                            else {
246                                    if( separator == null || separator.length() == 0 ) {
247                                            rtnStr.append( model.getValue( row,clmNos[i] ) );
248                                    }
249                                    else {
250                                            // 4.3.1.1 (2008/08/23) default label が存在しなã�?�Ÿめã?追åŠ?
251                                            switch( model.getNativeType( clmNos[i] ) ) {
252                                                    case INT:
253                                                    case LONG:
254                                                    case DOUBLE:
255                                                            rtnStr.append( model.getValue( row,clmNos[i] ) );
256                                                            break;
257                                                    case STRING:
258                                                    case CALENDAR:
259                                                            rtnStr.append( separator ).append( model.getValue( row,clmNos[i] ) ).append( separator );
260                                                            break;
261                                                    default:
262                                                            throw new AssertionError( "Unexpected enumrated value! " + model.getNativeType( clmNos[i] ) );
263                                            }
264                                    }
265                            }
266                    }
267                    rtnStr.append( format[count] );
268    
269                    return rtnStr.toString();
270            }
271    
272            /**
273             * 先ã?フォーマット情報の[カラãƒ?��]をã?? に置き換えたフォーマットを返しますã?
274             * これは、java.sql.PreparedStatement 形式ã?Queryæ–?­—å?を合成するå?合に使用しますã?
275             *
276             * @return  PreparedStatement形式ã?Queryæ–?­—å?
277             */
278            public String getQueryFormatString() {
279                    StringBuilder rtnStr = new StringBuilder( 200 );
280    
281                    int count = clmKeys.length;
282                    for( int i=0; i<count; i++ ) {
283                            rtnStr.append( format[i] ).append( '?' );
284                    }
285                    rtnStr.append( format[count] );
286    
287                    return rtnStr.toString();
288            }
289    
290            /**
291             * フォーマットã?カラãƒ?��配å?を返しますã?
292             *
293             * @return      フォーマットã?カラãƒ?��配å?
294             */
295            public String[] getClmKeys() {
296                    return clmKeys.clone();
297            }
298    
299            /**
300             * フォーマットã?カラãƒ?•ª号配å?を返しますã?
301             *
302             * @return      フォーマットã?カラãƒ?•ª号配å?
303             */
304            public int[] getClmNos() {
305                    return clmNos.clone();
306            }
307    
308            /**
309             * フォーマットé?列を返しますã?
310             *
311             * @return      フォーマットé?åˆ?
312             */
313            public String[] getFormat() {
314                    return format.clone();
315            }
316    
317            /**
318             * タイプ文字å?配å?を返しますã?
319             * タイプとは、[XXX] の記述で、[#XXX] は、XXXカラãƒ??ラベルをã?[$XXX]は、XXXカラãƒ??
320             * レンãƒ?ƒ©ーをã?[!XXX} は、å?のみ取り出す指定を行いますã?
321             * 主に、TextField系のフォーマットとTable系では、意味合いが異なりますã?でã€?
322             * ご注意くã�?�•ã�??
323             *
324             * @return タイプ文字å?配å? '#':ラベルのみ  '$':レンãƒ?ƒ©ー '!':値のみ  そã?ä»?通常
325             */
326            public char[] getType() {
327                    return type.clone();
328            }
329    
330            /**
331             * 行毎ã?全ãƒ??タのJavaScriptオブジェクト形å¼?を返しますã?
332             *
333             * JavaScriptオブジェクト形式とは、{ key:val,key:val,... }の形式でã€?
334             * ここでは、å?部設定された DataModel のすべてのカラãƒ?��をキーにã€?
335             * 引数で渡されã�?配å?ã‚?値として使用しますã?
336             *
337             * @param       row     (DataModelの)行番号
338             *
339             * @return  æŒ?®šã?行番号に対応するå?ãƒ??タのJSON形式データ
340             */
341            public String getJson( final int row ) {
342                    String[] names = model.getNames();
343                    Object[] vals  = model.getValues( row );
344    
345                    StringBuilder rtnStr = new StringBuilder( 200 );
346    
347                    rtnStr.append( "{'I':'" ).append( row ).append( "'" );  // 行番号
348    
349                    for( int i=0; i<names.length; i++ ) {
350                            rtnStr.append( ",'" ).append( names[i] ).append( "':'" );
351                            rtnStr.append( vals[i] ).append( "'" );
352                    }
353                    rtnStr.append( "}" );
354    
355                    return rtnStr.toString();
356            }
357    }