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.html;
017
018import org.opengion.hayabusa.common.HybsSystem;
019import org.opengion.hayabusa.db.DBTableModel;
020import org.opengion.hayabusa.db.DBColumn;
021import org.opengion.fukurou.util.StringUtil;
022import org.opengion.fukurou.util.Attributes;
023import org.opengion.fukurou.model.Formatter;
024
025import java.util.Map;
026import java.util.HashMap;
027import java.util.List;
028import java.util.ArrayList;
029import java.util.Arrays ;
030
031/**
032 * ViewMarker インターフェース の実装オブジェクトです。
033 * これを,共通のスーパークラスとして 各種表示フォーム(例:HTML表示等)に使います。
034 *
035 * このクラスは、setter/getterメソッドのデフォルト実装を提供しています。
036 * 各種表示フォームに対応したサブクラス上で, create() をオーバーライドして下さい。
037 *
038 * @og.group 画面表示
039 *
040 * @version  4.0
041 * @author   Kazuhiko Hasegawa
042 * @since    JDK5.0,
043 */
044public class ViewMarker_MARKER implements ViewMarker {
045
046        private List<Attributes>                markData        = null;         // 4.0.0 (2005/08/31)
047        private Map<Integer,Formatter>  formMap         = new HashMap<Integer,Formatter>();
048        private DBTableModel            table       = null;
049        private int[]                           markCmlNo       = null;
050        private int[]                           isMark          = null;
051        private static final int        MARK_NULL   = -1;       // マーカー未設定
052        private static final int        MARK_TRUE   = 1;        // マーカー作成
053        private static final int        MARK_FALSE  = 0;        // マーカー作成せず
054        // 3.5.2.0 (2003/10/20)
055        private String[]                        markKey         = null;
056        private String[]                        markLists       = null;
057        private String[]                        instrVals       = null;         // 3.8.8.1 (2007/01/06)
058        private int[]                           markListNo      = null;
059        private boolean[]                       useFmtDeco      = null;         // 5.6.3.0 (2013/04/01) [$XXXX],[#XXXX]機能を有効にするかどうか(true:有効)
060
061        private Map<Integer,List<Integer>>      clmMap  = new HashMap<Integer,List<Integer>>(); // 4.0.0 (2005/08/31)
062
063        /**
064         * 内容をクリア(初期化)します。
065         *
066         * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。
067         * @og.rev 3.5.2.0 (2003/10/20) markLists,markListNo,markKey属性を追加
068         * @og.rev 3.5.6.1 (2004/06/25) formMap属性を追加
069         * @og.rev 3.8.8.1 (2007/01/06) instrVals属性を追加
070         * @og.rev 5.6.3.0 (2013/04/01) useFmtDeco属性を追加
071         *
072         */
073        public void clear() {
074                markData        = null;         // 4.0.0 (2005/08/31)
075                formMap         = new HashMap<Integer,Formatter>();
076                table           = null;
077                isMark          = null;
078                markKey         = null;
079                markLists       = null;
080                instrVals       = null;         // 3.8.8.1 (2007/01/06)
081                markListNo      = null;
082                clmMap          = new HashMap<Integer,List<Integer>>(); // 4.0.0 (2005/08/31)
083                useFmtDeco      = null;         // 5.6.3.0 (2013/04/01) [$XXXX],[#XXXX]機能を有効にするかどうか(true:有効)
084        }
085
086        /**
087         * カラムに対するマーカーアトリビュートをセットします。
088         *
089         * @og.rev 3.1.0.0 (2003/03/20) Hashtable を使用している箇所で、非同期でも構わない箇所を、HashMap に置換え。
090         * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。
091         *
092         * @param       attri   アトリビュート
093         */
094        public void addAttribute( final Attributes attri ) {
095                if( markData == null ) { markData = new ArrayList<Attributes>(); }
096                markData.add( attri );
097        }
098
099        /**
100         * 内部に DBTableModel をセットします。
101         *
102         * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。
103         * @og.rev 3.5.2.0 (2003/10/20) markLists,markListNo,markKey属性を追加
104         * @og.rev 3.5.6.1 (2004/06/25) DBTableModel の再設定に対応。
105         * @og.rev 3.8.8.1 (2007/01/06) instrVals属性を追加
106         * @og.rev 5.6.3.0 (2013/04/01) useFmtDeco属性を追加
107         *
108         * @param  tbl DBTableModelオブジェクト
109         */
110        public void setDBTableModel( final DBTableModel tbl ) {
111                table = tbl;
112                int count = markData.size();                    // 4.0.0 (2005/08/31)
113
114                isMark          = new int[ count ];
115                markKey         = new String[ count ];
116                markCmlNo       = new int[ count ];
117                markLists       = new String[ count ];
118                instrVals       = new String[ count ];
119                markListNo      = new int[ count ];
120                useFmtDeco      = new boolean[ count ];         // 5.6.3.0 (2013/04/01) [$XXXX],[#XXXX]機能を有効にするかどうか(true:有効)
121
122                Arrays.fill( isMark,MARK_FALSE );       // マーカーの表示可否
123                Arrays.fill( markCmlNo,-1 );            // マーカーの可否を判断するカラム番号
124                Arrays.fill( useFmtDeco,false );        // [$XXXX],[#XXXX]機能を無効にする。(互換性のため)
125
126                for( int intKey=0; intKey<count; intKey++ ) {
127                        Attributes attri = markData.get( intKey );
128
129                        String column = attri.get( "column" );
130                        int clm = table.getColumnNo( column );
131                        List<Integer> list = clmMap.get( clm );
132                        if( list == null ) { list = new ArrayList<Integer>(); }
133                        list.add( intKey );
134                        clmMap.put( clm,list );
135
136                        String body = attri.get( "body" );
137                        Formatter formatter = new Formatter( table );
138                        formatter.setFormat( body );
139                        formMap.put( intKey, formatter );
140
141                        makeOnMarkFormat( intKey,attri );
142
143                        useFmtDeco[intKey] = "true".equalsIgnoreCase( attri.get( "useFormatDeco" ) );   // 5.6.3.0 (2013/04/01)
144                }
145        }
146
147        /**
148         * 指定の行列に対するマーカー文字列を返します。
149         * この値は,すでにマーカー文字列処理されている為, RendererValue で
150         * 変換する必要はありません。
151         * 引数の value はそのカラムの値として利用されます。この値は、修飾済みの
152         * 値を与えることが可能です。
153         *
154         * @og.rev 3.5.6.1 (2004/06/25) formMap属性を使用します。
155         * @og.rev 3.8.8.1 (2007/01/06) instrVals属性を追加
156         * @og.rev 5.3.9.0 (2011/09/01) カラム名の先頭に'$'を付加した場合に、URLEncodeされた値を返すように対応
157         * @og.rev 5.6.3.0 (2013/04/01) useFmtDeco属性を追加([$XXXX],[#XXXX]機能を有効にするかどうか)
158         *
159         * @param   row 指定の行
160         * @param   clm 指定の列
161         * @param   value カラムの値
162         *
163         * @return  row行,colum列 のマーカー文字列
164         */
165        public String getMarkerString( final int row,final int clm,final String value ) {
166                int intKey = isOnMark(row,clm) ;
167                if( intKey < 0 ) { return value; }
168
169                Formatter formatter = formMap.get( intKey );
170                int[]    clmNo  = formatter.getClmNos();
171                String[] format = formatter.getFormat();
172
173                char[] types = formatter.getType();
174
175                StringBuilder buf = new StringBuilder( HybsSystem.BUFFER_LARGE );
176                int j=0;
177                String val ;
178                for( ; j<clmNo.length; j++ ) {
179                        if( clm == clmNo[j] ) {
180                                val = value;
181                        }
182                        else {
183                                val = formatter.getValue(row,clmNo[j]);
184                        }
185
186                        // 5.6.3.0 (2013/04/01) useFmtDeco属性を追加(trueの場合は、[$XXXX],[#XXXX]機能を有効にする)
187                        if( useFmtDeco[intKey] ) {
188                                DBColumn dbClm = table.getDBColumn( clmNo[j] );
189                                if( types[j] == '$' ) {
190                                        val = dbClm.getRendererValue( row,val );
191                                }
192                                else if( types[j] == '#' ) {
193                                        val = dbClm.getLabel();
194                                }
195                        }
196                        // false が以前と同じ処理(互換処理)ただし、view などのフォーマット処理とは異なる。
197                        else {
198                                // 5.3.9.0 (2011/09/01) カラム名の先頭に'$'を付加した場合URLEncodeされた値を返すように対応
199                                if( types[j] == '$' ) {
200                                        val = StringUtil.urlEncode( val );
201                                }
202                        }
203
204                        buf.append( format[j] );
205                        buf.append( val );
206                }
207                if( j < format.length ) { buf.append( format[j] ); }
208                String rtn = StringUtil.replace( buf.toString(),"{I}",String.valueOf( row ) );
209
210                // 3.8.8.1 (2007/01/06) instrVals属性を追加
211                if( instrVals[intKey] != null ) {
212                        String[] vals = StringUtil.csv2Array( instrVals[intKey],' ' );
213                        for( int i=0; i<vals.length; i++ ) {
214                                String css = "<span class=\"instr" + i + "\">" + vals[i] + "</span>";
215                                rtn = StringUtil.replace( rtn,vals[i],css );
216                        }
217                }
218                return rtn ;
219        }
220
221        /**
222         * マーカーを作成する/作成しないの指定カラム番号を求めます。
223         * また、int[列番号] isMark を初期化します。
224         *
225         * @og.rev 3.5.2.0 (2003/10/20) markLists,markListNo,markKey属性を追加
226         * @og.rev 3.8.8.1 (2007/01/06) instrVals属性を追加
227         *
228         * @param       intKey  カラムキーの番号
229         * @param       attri   アトリビュート
230         */
231        private void makeOnMarkFormat( final int intKey,final Attributes attri ) {
232                String onMark   = attri.get( "onMark" );
233                String markList = attri.get( "markList" );
234                instrVals[intKey] = attri.get( "instrVals" );   // 3.8.8.1 (2007/01/06)
235
236                // 3.5.6.0 (2004/06/18) nullポインタの参照外しバグの対応
237                // このロジックで値が設定済みであれば、以下の処理は不要である。
238                isMark[intKey] = MARK_NULL;
239                if( onMark == null || onMark.length() == 0 ||
240                        markList == null || markList.length() == 0 ) {
241                                isMark[intKey] = MARK_FALSE;
242                                return ;        // 3.5.6.0 (2004/06/18)
243                }
244                else if( onMark.charAt( 0 ) != '[' && markList.charAt( 0 ) != '[' ) {
245                        isMark[intKey] = ( markList.indexOf( onMark ) >= 0 ) ? MARK_TRUE : MARK_FALSE;
246                        return ;        // 3.5.6.0 (2004/06/18)
247                }
248
249                if( onMark.charAt( 0 ) == '[' ) {
250                        markCmlNo[intKey] = table.getColumnNo( onMark.substring( 1,onMark.length()-1 ));
251                }
252                else {
253                        markCmlNo[intKey]  = -1;
254                        markKey[intKey]    = onMark ;
255                }
256
257                if( markList.charAt( 0 ) == '[' ) {
258                        markListNo[intKey] = table.getColumnNo( markList.substring( 1,markList.length()-1 ));
259                }
260                else {
261                        markListNo[intKey] = -1;
262                        markLists[intKey] = markList;
263                }
264        }
265
266        /**
267         * マーカーを作成するかどうかを判断します。
268         * int[列番号] isMark には、 未設定 FALSE TRUE の状態を持っており、
269         * 列でマーカーを作成する状態が固定の場合(例えば,onMark属性がデフォルト "true" の場合)
270         * カラムに関係なく、同じ値を返すときに、使用します。
271         *
272         * @og.rev 3.5.2.0 (2003/10/20) markLists,markListNo,markKey属性を追加
273         * @og.rev 3.5.4.0 (2003/11/25) onMark ,markList が null(またはゼロストリング)の場合は、false とする。
274         * @og.rev 4.0.0.0 (2005/08/31) 同一カラムの複数登録を許可します。
275         *
276         * @param       row     列番号
277         * @param       clm     カラムキーの名称
278         *
279         * @return      処理するリスト番号、-1 の場合は、該当なし
280         */
281        private int isOnMark( final int row,final int clm ) {
282                List<Integer> list = clmMap.get( clm );
283                if( list == null ) { return -1; }
284
285                for( int i=0; i<list.size(); i++ ) {
286                        int intKey = list.get( i );
287                        if( isMark[intKey] != MARK_NULL ) {
288                                if( isMark[intKey] == MARK_TRUE ) { return intKey; }
289                                else { continue; }
290                        }
291
292                        final String onMark ;
293                        if( markCmlNo[intKey] < 0 ) { onMark = markKey[intKey] ; }
294                        else { onMark = table.getValue( row,markCmlNo[intKey] ); }
295
296                        // 3.5.4.0 (2003/11/25) 追加
297                        if( onMark == null || onMark.length() == 0 ) { continue; }
298
299                        final String markList ;
300                        if( markListNo[intKey] < 0 ) { markList = markLists[intKey] ; }
301                        else { markList = table.getValue( row,markListNo[intKey] ); }
302
303                        // 3.5.4.0 (2003/11/25) 修正
304                        if( markList == null || markList.length() == 0 ) { continue; }
305
306                        if( markList.indexOf( onMark ) >= 0 ) { return intKey; }
307                }
308                return -1;
309        }
310}