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.plugin.view;
017    
018    import org.opengion.hayabusa.common.HybsSystem;
019    import org.opengion.hayabusa.common.HybsSystemException;
020    import org.opengion.fukurou.util.StringUtil;
021    
022    import java.util.Calendar;
023    import java.util.Map;
024    import java.util.TreeMap;
025    import java.util.Collection;
026    import java.util.Locale ;
027    import java.util.Date;
028    import java.text.DateFormat;
029    import java.text.SimpleDateFormat;
030    
031    import java.awt.Graphics2D;
032    import java.awt.Color;
033    import java.awt.FontMetrics;
034    import java.awt.Stroke;
035    import java.awt.BasicStroke;
036    import java.awt.image.BufferedImage;
037    
038    import javax.imageio.ImageIO;
039    import java.io.File;
040    import java.io.IOException;
041    
042    
043    /**
044     * キー、日時ã?状況コードを持つ稼働状況ã?表示を行うクラスですã?
045     *
046     * パラメータがå¿?¦�な場合ã?、ViewTimeBarParamTag を使用してくださいã€?
047     *
048     * パラメータが設定されてã�?�ªã�??合ã?、ViewForm_ImageTimeBar の初期値が使用されますã?
049     * (パラメータを使用するには、viewタグのuseParam 属æ?をtrueに設定するå¿?¦�がありますã?)
050     *
051     * SELECTæ–??、キー、日時ã?状況コードが、å¿??é ?›®で、カラãƒ??並びé ??、完å?に固定ですã?
052     * よって、カラãƒ?½�置を指定するå¿?¦�ã?ありませんがã?SELECTæ–?‚’自由に設定することã‚?
053     * 出来ませんので、ご注意くã�?�•ã�??
054     * こã?固定化に伴ã�??WRITABLE æŒ?®šも使用できません。(そもそも書き込み不可ですï¼?
055     * それ以降ã?カラãƒ?�«つã�?�¦は、å?部処ç�?�¨しては、使用してã�?�¾せんã€?
056     * ただしã?パラメータで、カラー色æŒ?®šã?ラベル表記部、イメージ重ã?合わせã?
057     * ポップアãƒ??表記ã?リンク表記に使えますã?
058     *
059     * ãƒ??タの並びé ?ORDER BY)もã?キー、日時é?にしてくださいã€?
060     * ãƒ??タは、キー単位に?‘レコード作æ?されますã??ˆキーブレイク?‰その間ã?日時é?に
061     * ãƒ??タをå?ç�?�—ますã?
062     *
063     * ãƒ??タの表示は、今ã?レコードã?日時からã?次のレコードã?日時までをä¸?�¤の状態と
064     * して表しますã?今ã?レコードを表示するには、次のレコードがå¿?¦�になりますã?
065     * 画面表示は、表示開始日æ™?minStartTime) から 表示期間(timeSpan)åˆ?‚’表示しますã?
066     * 通常ã€?–‹始時刻は、表示開始時刻より前より始まりã?次のレコードで、終äº?™‚刻が決å®?
067     * されますã?æœ?¾Œã?ãƒ??タは、期間æº?º?�¾で続いてã�?‚‹と仮定されますã?
068     * ãƒ??タが存在しなã�??であれば、ã?存在しなã�?ƒ‡ータ」を作æ?してくださいã€?
069     * 
070     * ImageTimeBar では、キーでまとめた値につã�?�¦、各状況コードをカラー化し、積み上げ
071     * 帯グラフ形式でPNG画像化しますã?
072     * こã?画像を、読み込ã‚?HTML をå?力することで、画面上に、積み上げ帯グラフを表示しますã?
073     * 状況コードに対応する色は、標準では自動作æ?ですが、外部から色æ–?­—å?(colorClm)を与えることで
074     * 自由にæŒ?®šする事も可能ですã?
075     *
076     * ポップアãƒ??表è¨?tipsClm)、リンク表è¨?linkClm)は、この画像に対するエリアæŒ?®šタグをå?力する事で実現しますã?
077     * 画像ファイルは、å?ãƒ??タに対してã€?¼‘画像だけなので、サイズは大きくなりますがã€?¼‘レコーãƒ?
078     * 単位に画像を作æ?しなã�?�Ÿめã?レスポンスは向上しますã?
079     * それぞれ、viewMarker , viewLink を利用することが可能ですã?特に、リンク表è¨?linkClm) につã�?�¦はã€?
080     * linkタグの hrefTarget 属æ?ã‚?true に設定することで適用できますã?
081     *
082     * 画像ファイルは、java.io.File.createTempFile( File ) で作æ?するため、JavaVM(=Tomcat)ã�?
083     * 正常終äº?�™るときに、削除されますã?異常終äº?™‚には残りますが、temp フォルãƒ?‚’定期çš?�«
084     * 整ç�?�™れã?、それほど大量ã?ファイルが残ることはなã�?�¨思われますã?
085     *
086     * ãƒ??タは、イベント発生時に作æ?されると仮定してã�?�¾すã?つまりã?書き込まれた日時からã?
087     * 状況コードに対応する状況が発生し、次の状æ³?�•ã�??レコードまで継続してã�?‚‹とè€?�ˆますã?
088     * よって、データをé?中でåˆ?‚Š出すå?合ã?åˆ?‚Š出すç¯?›²の前ã?状態がå¿?¦�になりますã?
089     * ä¸?•ªæœ??の状態ã?ã€?不æ?" として扱ã�?�¾すã??ˆ空æ¬?¼�白色??
090     *
091     * @og.rev 5.5.5.6 (2012/08/31) 新規追åŠ?
092     * @og.group 画面表示
093     *
094     * @version  4.0
095     * @author       Kazuhiko Hasegawa
096     * @since    JDK5.0,
097     */
098    public class ViewForm_ImageTimeBar extends ViewForm_HTMLTable {
099            //* こã?プログラãƒ??VERSIONæ–?­—å?を設定しますã?       {@value} */
100            private static final String VERSION = "5.6.5.0 (2013/06/07)" ;
101    
102            private static final Color LABEL_COLOR = Color.BLACK;           // ラベル記述時ã?色
103            private static final Color NULL_COLOR  = Color.WHITE;           // 5.6.1.1 (2013/02/08) 不æ?(空æ¬?時ã?色
104    
105            private long startDate          ;       // タイãƒ?ƒ†ーブルの表示開始日時から求めã�?long 値(1=åˆ?�˜ä½?
106            private long timeSpan           ;       // タイãƒ?ƒ†ーブルの表示期間。å?は時間æŒ?®šであるがã?åˆ?�˜位で持つã€?1=åˆ?�˜ä½?
107    
108            private boolean useLegend       ;       // カラーの凡例を使用するかどã�?�‹[true/false]
109            private int maxLabelWidth       ;       // ラベル表記部のæœ?¤§サイズをpxでæŒ?®šã?何もなければ、可変長サイズ
110            private int maxTimeWidth        ;       // タイãƒ?¡¨記部のæœ?¤§サイズをpxでæŒ?®šã?
111            private int chartHeight         ;       // ?‘レコードã?チャートã?間隔をpxでæŒ?®šã?実際のå¹??、CHART_HEIGHT?‹MARGIN?Šï¼?
112            private int chartPadding        ;       // イメージ作æ?の 全体テーブルの隙間
113            private int recodeMargin        ;       // å�?ƒ¬コードã?æ–?­—等ã?å†?ƒ¨の間隔
114            private boolean useLastData     ;       // 5.6.1.1 (2013/02/08) 行ã?æœ?¾Œã?æƒ??がã?継続してã�?‚‹として使ã�?�‹どã�?�‹[true/false]
115    
116            private String tempDir          ;       // 画像ファイルを作æ?するãƒ?ƒ³ポラリãƒ?‚£レクトリ(相対パス)
117            private String tempUrl          ;       // 作æ?した画像ファイルを取得するときに使用するURL(コンãƒ?‚­スãƒ?相対パス)
118    
119            // SELECTæ–??、キー、日時ã?状況コードが、å¿??é ?›®
120            private static final int        keyClmNo        = 0;    // ヘッãƒ??1?šキーカラãƒ?o
121            private static final int        dyClmNo         = 1;    // ヘッãƒ??2?š日時カラãƒ?o
122            private static final int        fgjClmNo        = 2;    // ヘッãƒ??3?š状況コードカラãƒ?o
123    
124            private int[] labelClmsNo       = null;                         // 初期値は、キーカラãƒ?
125            private int[] maxClmWidth       = null;                         // labelClms 単位ã?æœ?¤§æ–?­—å?長
126            private int   colClmNo          = -1;                           // カラーコード直接æŒ?®šするå?合に色æ–?­—å?を指定するカラãƒ?o
127            private int   tipsClmNo         = -1;                           // マウスオーバã?時ã?Tips表示を行うカラãƒ?o
128            private int   linkClmNo         = -1;                           // クリãƒ?‚«ブルリンクを設定するカラãƒ?o
129    
130            private int str2DateTime        ;       // getStr2Date(String)処ç�?‚’おこなった時の、引数の時刻æƒ??(åˆ?�˜ä½?をセãƒ?ƒˆするãƒ?ƒ³ポラリ変数ã€?
131            private int startTime           ;       // startDate の時刻æƒ??。上記å?ç�?�§、startDate ã‚?getStr2Date(String) 処ç�?�—たときã?値を持っておくための変数ã€?
132    
133            private int MAX_X       ;       // イメージのæœ?¤§横å¹?X)方向ã?サイズpx。chartPadding*2 + maxLabelWidth + maxTimeWidth
134            private int MAX_Y       ;       // イメージのæœ?¤§縦å¹?Y)方向ã?サイズpx。chartPadding*2 + (chartHeight+recodeMargin*2)*(レコード数?‹ã?ãƒ?ƒ€ー数)
135    
136            /**
137             * å†?®¹をクリア(初期åŒ?しますã?
138             *
139             */
140    //      @Override
141    //      public void clear() {
142    //              super.clear();
143    //      }
144    
145            /**
146             * DBTableModel から HTMLæ–?­—å?を作æ?して返しますã?
147             * startNo(表示開始位置)から、pageSize(表示件数)までのViewæ–?­—å?を作æ?しますã?
148             * 表示残りãƒ??タã�?pageSize 以下ã?場合ã?,残りのãƒ??タをすべて出力しますã?
149             *
150             * @og.rev 5.6.1.0 (2013/02/01) tips ã‚?link は、ã?とつ前ã?ãƒ??タで作æ?するå¿?¦�がる為、最初ã?1件目は、å?ç�?�—なã�?‚ˆã�?�«修正
151             * @og.rev 5.6.1.1 (2013/02/08) 初期値の色をã?直接の値ではなくã?static final で定義された色を使用する。色自体ã?変えてã�?�¾せん
152             * @og.rev 5.6.1.1 (2013/02/08) useLastData 追åŠ?
153             * @og.rev 5.6.3.0 (2013/04/01) tipsのシングルクォーãƒ??ション のエスケーãƒ?
154             * @og.rev 5.6.3.1 (2013/04/05) 短縮ラベルなどã€?lt;span>タグが付与される値から、spanタグを削除しますã?
155             *
156             * @param  startNo        表示開始位置
157             * @param  pageSize   表示件数
158             *
159             * @return      DBTableModelから作æ?されã�?HTMLæ–?­—å?
160             */
161            @Override
162            public String create( final int startNo, final int pageSize )  {
163                    if( getRowCount() == 0 ) { return ""; } // 暫定å?置
164    
165                    // パラメータのæƒ??をå?期化??�–得しますã?
166                    paramInit();
167    
168                    int lastNo = getLastNo( startNo, pageSize );
169    
170                    // イメージの æœ?¤§?¸ã€?¼¹サイズを求め、結果をã?MAX_X,MAX_Y 変数に設定するã?
171                    calcImageSize( startNo,lastNo );
172    
173                    BufferedImage img = new BufferedImage( MAX_X, MAX_Y, BufferedImage.TYPE_INT_ARGB);
174                    Graphics2D g2 = img.createGraphics();
175    
176                    // chartPadding をè?慮した領域のクリãƒ???ˆクリãƒ??外にDrowされても無視されますã???
177                    g2.setClip( chartPadding , chartPadding , MAX_X-chartPadding*2+1 , MAX_Y-chartPadding*2+1 );    // ?? 座æ¨?y 座æ¨?å¹?高さ) ?‹1ã?罫線ã?åˆ?
178    
179                    StringBuilder out = new StringBuilder( HybsSystem.BUFFER_LARGE );
180    
181                    String oldKeyVal = "";                          // 初期値。1回目にキーブレイクさせるã?
182                    long   oldTime   = 0L;                          // 日付é?目のä¸?�¤前ã?値
183    
184    //              Color  oldColor  = Color.WHITE;         // 色のä¸?�¤前ã?値(初期値)
185                    Color  oldColor  = NULL_COLOR;          // 5.6.1.1 (2013/02/08) 不æ?(空æ¬?時ã?色(初期値)
186    
187                    ColorMap colMap = new ColorMap();       // 状況コードã?ラベル、カラーを管ç�?�™るクラス
188    
189                    int rowCnt = (useLegend) ? 2 : 1;               // 凡ä¾?useLegend)を使ã�?true)場合ã?ã€?¼’行å?、使わなã�??合ã?、ã?ãƒ?ƒ€ーの?‘行が初期値
190                    int imgX   = 0;                                                 // イメージ出力時の X軸の左端 px数
191                    int imgY   = 0;                                                 // イメージ出力時の Y軸の上端 px数
192                    int imgW   = 0;                                                 // イメージ出力時の å¹?fillRectで使用)
193                    int imgH   = chartHeight;                               // イメージ出力時の 高さ(fillRectで使用)
194                    int rowH   = chartHeight+recodeMargin*2;        // 罫線å?力時の高さ(drawRectで使用)
195    
196                    double timeScale = (double)maxTimeWidth/(double)timeSpan;
197                    boolean useTipsLink = (tipsClmNo >= 0 || linkClmNo >= 0) ;                // tipsClm ã�?linkClm かどちらかを使用する場合ã?true
198                    for( int row=startNo; row<lastNo; row++ ) {
199                            // キーブレイクの判å®?
200                            String keyVal  = getValue( row,keyClmNo );
201                            String dyVal   = getValue( row,dyClmNo );
202    
203                            // キーブレイク判定ã?キーブレイクは、ä¸?•ª初めから来るã?
204                            if( !oldKeyVal.equals( keyVal ) ) {
205                                    // キーブレイクでæœ??に行うのは、前のレコードã?未出力å?の処ç�???‘行目は、å?ç�?¸�è¦?
206                                    if( row > startNo ) {
207                                            imgX = chartPadding + maxLabelWidth + (int)(oldTime*timeScale);
208                                            imgW = (int)((timeSpan-oldTime)*timeScale) ;
209    
210                                            // å¹?�Œ0以上ã?場合ã?み描画するã€?
211                                            if( imgW > 0 ) {
212                                                    // 5.6.1.1 (2013/02/08) useLastData 追åŠ?
213                                                    if( useLastData ) { g2.setColor( oldColor ); }                                  // 色の設定ã?、旧色を使ã�?
214                                                    else {                          g2.setColor( NULL_COLOR ); }                            // NULL色を使ã�?
215                                                    g2.fillRect( imgX , imgY+recodeMargin , imgW, imgH );                   // (実際の状æ…?左端x,上端y,å¹?,高さh
216    
217                                                    // tipsClm ã�?linkClm を使用するã€?
218                                                    // 5.6.1.0 (2013/02/01) tips ã‚?link は、ã?とつ前ã?ãƒ??タで作æ?するå¿?¦�がる為、最初ã?1件目は、å?ç�?�—なã�?‚ˆã�?�«修正
219    //                                              if( useTipsLink ) {
220    //                                              if( useTipsLink && row > 0 ) {
221                                                    if( useLastData && useTipsLink && row > 0 ) {        // 5.6.1.1 (2013/02/08) useLastData 追åŠ?
222                                                            // tips ã‚?link は、ã?とつ前ã?ãƒ??タで作æ?するå¿?¦�があるã€?row-1)
223                                                            String tips = (tipsClmNo >= 0) ? getValueLabel( row-1,tipsClmNo ) : getValueLabel( row-1,fgjClmNo ) ;
224                                                            if( tips != null && tips.indexOf( "'" ) >= 0 ) {     // 5.6.3.0 (2013/04/01) シングルクォーãƒ??ション のエスケーãƒ?
225                                                                    tips = tips.replaceAll( "'","&#39;" );
226                                                            }
227                                                            tips = StringUtil.spanCut( tips );                                      // 5.6.3.1 (2013/04/05) spanタグを削除
228    
229                                                            out.append( "<area shape='rect' alt='" ).append( tips ).append( "'" );
230                                                            if( linkClmNo >= 0 ) {
231                                                                    String hrefVal = getValueLabel( row-1,linkClmNo );
232                                                                    if( hrefVal != null && hrefVal.startsWith( "href" ) ) {         // linkClmの値の先é?がã?html の場合ã?み追åŠ?�™るã?
233                                                                            out.append( hrefVal );
234                                                                    }
235                                                            }
236                                                            out.append( " coords='" ).append( imgX ).append( "," ).append( imgY+recodeMargin ).append( "," );               // 左端x1,上端y1
237                                                            out.append( imgX+imgW ).append( "," ).append( imgY+recodeMargin+chartHeight ).append( "' />" );                      // 右端x2,下段y2
238                                                    }
239                                            }
240                                    }
241    
242                                    // 次に、新しい行ã?出力(ラベルは、ブレイク時に出力しておきますã???
243                                    oldKeyVal = keyVal;                     // null は来なã�??ã�?
244                                    imgY = chartPadding+(rowH)*rowCnt ;
245                                    rowCnt++ ;
246    
247                                    // レコードã?ラベルåˆ?� けã?繰返し描画するã€?
248                                    int clmSu = labelClmsNo.length;
249                                    int posX  = chartPadding ;                                              // ラベルæ–?­—å?の書きå?し位置の初期値
250                                    int posY2 = imgY+chartHeight+recodeMargin ;             // ラベルのY軸基準ã?
251                                    g2.setColor( LABEL_COLOR );
252                                    for( int col=0; col<clmSu; col++ ) {
253                                            String lbl = getValueLabel( row,labelClmsNo[col] );             // そã?行ã?値のRenderer値
254                                            lbl = StringUtil.spanCut( lbl );                                                // 5.6.3.1 (2013/04/05) spanタグを削除
255                                            g2.drawString( lbl , posX + recodeMargin, posY2 );              // æ–?­—å?,ベã?スラインのx座æ¨?y座æ¨?
256                                            posX += recodeMargin*2 + maxClmWidth[col] ;                             // 次の書きå?し位置は、文字最大長?‹ã?ージン
257                                    }
258    
259                                    // レコードã?æž?·?
260                                    g2.drawRect( chartPadding , imgY , MAX_X-chartPadding*2 , rowH );               // (レコード枠)左端x,上端y,å¹?,高さh
261    
262                                    oldTime = 0L;                           // キーブレイクによる初期åŒ?
263    //                              oldColor= Color.WHITE;          // キーブレイクによる初期åŒ?
264                                    oldColor= NULL_COLOR;           // 5.6.1.1 (2013/02/08) キーブレイクによる初期åŒ?不æ?(空æ¬?時ã?色
265                            }
266    
267                            long newTime = getStr2Date( dyVal ) - startDate;                // 次の時刻
268                            if( newTime < oldTime ) { newTime = oldTime; }                       // 前ã?時刻より小さã�??合ã?、前の時刻までã€??めておくã€?
269    
270                            imgX = chartPadding + maxLabelWidth + (int)(oldTime*timeScale);         // old時刻から書き始めã‚?左端x)
271                            imgW = (int)((newTime-oldTime)*timeScale) ;                                                     // 差åˆ?¹?� け描画するã€?
272    
273                            // å¹?�Œ0以上ã?場合ã?み描画するã€?
274                            if( imgW > 0 ) {
275                                    g2.setColor( oldColor );                                                                                // 色の設å®?
276                                    g2.fillRect( imgX , imgY+recodeMargin , imgW, chartHeight );    // (実際の状æ…?左端x,上端y,å¹?,高さh
277    
278                                    // tipsClm ã�?linkClm を使用するã€?
279                                    // 5.6.1.0 (2013/02/01) tips ã‚?link は、ã?とつ前ã?ãƒ??タで作æ?するå¿?¦�がる為、最初ã?1件目は、å?ç�?�—なã�?‚ˆã�?�«修正
280    //                              if( useTipsLink ) {
281                                    if( useTipsLink && row > 0 ) {
282                                            // tips ã‚?link は、ã?とつ前ã?ãƒ??タで作æ?するå¿?¦�があるã€?row-1)
283                                            String tips = (tipsClmNo >= 0) ? getValueLabel( row-1,tipsClmNo ) : getValueLabel( row-1,fgjClmNo ) ;
284                                            if( tips != null && tips.indexOf( "'" ) >= 0 ) {     // 5.6.3.0 (2013/04/01) シングルクォーãƒ??ション のエスケーãƒ?
285                                                    tips = tips.replaceAll( "'","&#39;" );
286                                            }
287                                            tips = StringUtil.spanCut( tips );                                      // 5.6.3.1 (2013/04/05) spanタグを削除
288    
289                                            out.append( "<area shape='rect' alt='" ).append( tips ).append( "'" );
290                                            if( linkClmNo >= 0 ) {
291                                                    String hrefVal = getValueLabel( row-1,linkClmNo );
292                                                    if( hrefVal != null && hrefVal.startsWith( "href" ) ) {         // linkClmの値の先é?がã?html の場合ã?み追åŠ?�™るã?
293                                                            out.append( hrefVal );
294                                                    }
295                                            }
296                                            out.append( " coords='" ).append( imgX ).append( "," ).append( imgY+recodeMargin ).append( "," );               // 左端x1,上端y1
297                                            out.append( imgX+imgW ).append( "," ).append( imgY+recodeMargin+chartHeight ).append( "' />" );                      // 右端x2,下段y2
298                                    }
299                            }
300    
301                            oldTime   = newTime ;
302    
303                            String fgjVal  = getValue( row,fgjClmNo );                      // 状況コードã?キー
304                            String fgjLbl  = getValueLabel( row,fgjClmNo );         // 状況コードã?ラベル
305                            if( colClmNo >= 0 ) {
306                                    oldColor  = colMap.getColor( fgjVal,fgjLbl,getValue( row,colClmNo ) );          // 色æ–?­—å?を指定するå?å�?
307                            }
308                            else {
309                                    oldColor  = colMap.getColor( fgjVal,fgjLbl );                                                           // 色æ–?­—å?を指定しなã�?¼�è?動設å®?
310                            }
311                    }
312    
313                    // レコードã?ã�?�¡ばん最後ã?出力ã?ä¸?¿œã?ジャストã?場å�?oldTime == maxEdTime)は、å?ç�?�—なã�?
314                    // 5.6.1.1 (2013/02/08) レコードã?ã�?�¡ばん最後ã?出力ã?、NULL色を使ã�?‚ˆã�?�«変更
315                    if( oldTime < timeSpan ) {
316                            imgX = chartPadding + maxLabelWidth + (int)(oldTime*timeScale);
317                            imgW = (int)((timeSpan-oldTime)*timeScale) ;
318                            // 5.6.1.1 (2013/02/08) useLastData 追åŠ?
319                            if( useLastData ) { g2.setColor( oldColor ); }                                  // 色の設定ã?、旧色を使ã�?
320                            else {                          g2.setColor( NULL_COLOR ); }                            // NULL色を使ã�?
321                            g2.fillRect( imgX , imgY+recodeMargin , imgW, chartHeight );    // (実際の状æ…?左端,上端,å¹?高さ
322    
323                            // tipsClm ã�?linkClm を使用するã€?
324    //                      if( useTipsLink ) {
325                            if( useLastData && useTipsLink ) {                      // 5.6.1.1 (2013/02/08) useLastData 追åŠ?
326                                    // tips ã‚?link æœ?¾Œã?出力ã?、最後ã?ãƒ??タなので、lastNo-1 となるã?
327                                    String tips = (tipsClmNo >= 0) ? getValueLabel( lastNo-1,tipsClmNo ) : getValueLabel( lastNo-1,fgjClmNo ) ;
328                                    if( tips != null && tips.indexOf( "'" ) >= 0 ) {     // 5.6.3.0 (2013/04/01) シングルクォーãƒ??ション のエスケーãƒ?
329                                            tips = tips.replaceAll( "'","&#39;" );
330                                    }
331                                    tips = StringUtil.spanCut( tips );                                      // 5.6.3.1 (2013/04/05) spanタグを削除
332    
333                                    out.append( "<area shape='rect' alt='" ).append( tips ).append( "'" );
334                                    if( linkClmNo >= 0 ) {
335                                            String hrefVal = getValueLabel( lastNo-1,linkClmNo );
336                                            if( hrefVal != null && hrefVal.startsWith( "href" ) ) {         // linkClmの値の先é?がã?html の場合ã?み追åŠ?�™るã?
337                                                    out.append( hrefVal );
338                                            }
339                                    }
340                                    out.append( " coords='" ).append( imgX ).append( "," ).append( imgY+recodeMargin ).append( "," );               // 左端x1,上端y1
341                                    out.append( imgX+imgW ).append( "," ).append( imgY+recodeMargin+chartHeight ).append( "' />" );                      // 右端x2,下段y2
342                            }
343                    }
344    
345                    // ヘッãƒ??æƒ??のイメージを作æ?しますã?
346                    imageHeaderPaint( g2 , timeScale , colMap );
347    
348                    // イメージファイルをå?力し、URLを返しますã?
349                    File file = null;
350                    try {
351                            File dir = new File( tempDir );         // 画像ファイル出力å?のフォルãƒ?
352                            dir.mkdirs();                                           // なければ作æ?するã€?
353    
354                            file = File.createTempFile( "Img",".png", dir );        // ãƒ?ƒ³ポラリファイルの作æ?
355                            file.deleteOnExit();                                                            // JavaVM 停止時にãƒ?ƒ³ポラリファイルの削除
356    
357                            ImageIO.write(img, "PNG", file );
358                            g2.dispose();
359                    }
360                    catch( IOException ex ) {
361                            System.out.println( "エラー:" + ex );
362                    }
363    
364                    // imgタグを作æ?しますã?
365                    int width  = MAX_X;
366                    int height = MAX_Y;
367    
368                    StringBuilder out2 = new StringBuilder( HybsSystem.BUFFER_LARGE );
369                    out2.append( "<img id='ImageTimeBar' alt='ImageTimeBar' border='0'" );
370                    out2.append( " width='" ).append( width ).append( "px' height='" ).append( height ).append( "px'" );
371                    out2.append( " src='" ).append( tempUrl ).append( file.getName() ).append( "'" );
372    
373                    // area タグのãƒ??タが作æ?されてã�?‚Œば、å?力しますã?
374                    if( out.length() > 0 ) {
375                            out2.append( " usemap='#TimeBarMap' />" );   // img タグにusemap 属æ?を追åŠ?�—て、終äº?ƒ¨åˆ?‚’追è¨?
376    
377                            out2.append( "<map name='TimeBarMap'>" );
378                            out2.append( out );
379                            out2.append( "</map>" );
380                    }
381                    else {
382                            out2.append( " />" );                                                // img タグの終äº?ƒ¨åˆ?‚’追è¨?
383                    }
384    
385                    return out2.toString();
386            }
387    
388            /**
389             * パラメータå†?®¹をå?期化しますã?
390             *
391             * @og.rev 5.6.1.1 (2013/02/08) useLastData 追åŠ?
392             */
393            private void paramInit() {
394                    String s_startDate      = getParam( "START_DATE"                );      // タイãƒ?ƒ†ーブルの表示開始日時をセãƒ?ƒˆしまã�?初期値:ãƒ??タのæœ?°�日æ™?ã€?
395                    int timeSpanHour        = getIntParam( "TIME_SPAN"              );      // タイãƒ?ƒ†ーブルの表示期間を時間でæŒ?®šしまã�?初期値:{@og.value TIME_SPAN})ã€?
396    
397                    String[] s_labelClms    = StringUtil.csv2Array( getParam( "LABEL_CLMS" ) );     // ä¸?¦§表のラベル表示部に表示するカラãƒ?��をCSV形式でæŒ?®šしますã?
398                    String s_colClm                 = getParam( "COLOR_CLM"         );      // レコードに付ける色を色æ–?­—å?でæŒ?®šするå?合ã?カラãƒ?��を指定しますã?
399                    String s_tipsClm                = getParam( "TIPS_CLM"          );      // レコード単位に、ã?ウスオーバã?時ã?Tips表示を行うカラãƒ?��を指定しますã?
400                    String s_linkClm                = getParam( "LINK_CLM"          );      // レコード単位に、クリãƒ?‚«ブルリンクを設定するカラãƒ?��を指定しますã?
401    
402                    useLegend               = getBoolParam( "USE_LEGEND"            );      // カラーの凡例を使用するかどã�?�‹[true/false]
403                    maxLabelWidth   = getIntParam( "MAX_LABEL_WIDTH"        );      // ラベル表記部のæœ?¤§サイズをpxでæŒ?®šã?何もなければ、可変長サイズ
404                    maxTimeWidth    = getIntParam( "MAX_TIME_WIDTH"         );      // タイãƒ?¡¨記部のæœ?¤§サイズをpxでæŒ?®šã?
405                    chartHeight             = getIntParam( "CHART_HEIGHT"           );      // ?‘レコードã?チャートã?間隔をpxでæŒ?®šã?実際のå¹??、CHART_HEIGHT?‹MARGIN?Šï¼?
406                    chartPadding    = getIntParam( "CHART_PADDING"          );      // イメージ作æ?の 全体テーブルの隙間
407                    recodeMargin    = getIntParam( "RECODE_MARGIN"          );      // å�?ƒ¬コードã?æ–?­—等ã?å†?ƒ¨の間隔
408                    useLastData             = getBoolParam( "USE_LAST_DATA"         );      // 5.6.1.1 (2013/02/08) 行ã?æœ?¾Œã?æƒ??がã?継続してã�?‚‹として使ã�?�‹どã�?�‹[true/false]
409    
410                    tempDir                 = getParam( "TEMP_DIR"                          );      // 画像ファイルを作æ?するãƒ?ƒ³ポラリãƒ?‚£レクトリ(相対パス)
411                    tempUrl                 = getParam( "TEMP_URL"                          );      // 作æ?した画像ファイルを取得するときに使用するURL(コンãƒ?‚­スãƒ?相対パス)
412    
413                    startDate               = getStr2Date( s_startDate );                   // åˆ?�˜位に変換するã€?
414                    startTime               = str2DateTime ;                                                // 開始日時ã?時刻æƒ??(åˆ?�˜ä½?の値。str2DateTime は、getStr2Date(String)メソãƒ?ƒ‰実行後にセãƒ?ƒˆされるã?
415                    timeSpan                = timeSpanHour * 60L ;                                  // åˆ?�˜位に変換するã€?
416    
417                    int len = s_labelClms.length;
418                    if( len > 0 ) {
419                            labelClmsNo = new int[len];
420                            for( int i=0; i<len; i++ ) {
421                                    labelClmsNo[i] = getColumnNo( s_labelClms[i] );
422                            }
423                    }
424                    else {
425                            labelClmsNo = new int[] { keyClmNo };           // 初期値は、キーカラãƒ?
426                    }
427    
428                    // æŒ?®šã?カラãƒ?��に対するカラãƒ?•ª号を取得ã?なければã€?1 を設定しておくã€?
429                    if( s_colClm  != null ) { colClmNo  = getColumnNo( s_colClm  ); }                       // レコードに付ける色を色æ–?­—å?でæŒ?®šするå?合ã?カラãƒ?o
430                    if( s_tipsClm != null ) { tipsClmNo = getColumnNo( s_tipsClm ); }                       // レコード単位に、ã?ウスオーバã?時ã?Tips表示を行うカラãƒ?o
431                    if( s_linkClm != null ) { linkClmNo = getColumnNo( s_linkClm ); }                       // レコード単位に、クリãƒ?‚«ブルリンクを設定するカラãƒ?o
432            }
433    
434            /**
435             * イメージの ?¸?¹サイズを求め、結果をã?MAX_X,MAX_Y 変数に設定しますã?
436             *
437             * またã?ラベルæ–?­—å?のæœ?¤§長が指定されてã�?�ªã�??合ï¼?axLabelWidth == -1?‰最大長をè?動計算し、maxLabelWidth変数にセãƒ?ƒˆしますã?
438             *
439             * maxLabelWidth : -1 の場合ã?、ラベルæ–?­—å?のæœ?¤§長を求めて、この値を計算するã?= (recodeMargin*2 + ラベルæ–?­—å?のæœ?¤§長)
440             * MAX_X : イメージのæœ?¤§横å¹?X)方向ã?サイズpx。chartPadding*2 + maxLabelWidth + maxTimeWidth
441             * MAX_Y : イメージのæœ?¤§縦å¹?Y)方向ã?サイズpx。chartPadding*2 + (chartHeight+recodeMargin*2)*(レコード数?‹ã?ãƒ?ƒ€ー数)
442             *
443             * @og.rev 5.6.3.1 (2013/04/05) 短縮ラベルなどã€?span>タグが付与される値から、spanタグを削除しますã?
444             * 
445             * @param       startNo 計算ã?開始å?番号
446             * @param       lastNo  計算ã?終äº??番号
447             */
448            private void calcImageSize( final int startNo , final int lastNo ) {
449                    String oldKeyVal = "";  // 初期値。1回目にキーブレイクさせるã?
450    
451                    int clmSu = labelClmsNo.length;
452                    maxClmWidth = new int[clmSu];
453    
454                    int rowCnt = (useLegend) ? 2 : 1;               // 凡ä¾?useLegend)を使ã�?true)場合ã?ã€?¼’行å?、使わなã�??合ã?、ã?ãƒ?ƒ€ーの?‘行が初期値
455    
456                    // ラベル領域の長さをå�?ƒ©ベル長を積み上げて計算するã?
457                    if( maxLabelWidth < 0 ) {
458                            // FontMetrics を取得する為ã�?�‘の BufferedImage
459                            BufferedImage img = new BufferedImage( 1, 1, BufferedImage.TYPE_INT_ARGB);
460                            Graphics2D g2 = img.createGraphics();
461                            FontMetrics fontM = g2.getFontMetrics();
462    
463                            // 初期値の計算ã?、ã?ãƒ?ƒ€ーのラベルのå¹?‚’使用するã€?
464                            for( int col=0; col<clmSu; col++ ) {
465                                    String lbl = getColumnLabel( labelClmsNo[col] );        // ヘッãƒ??のラベル
466                                    lbl = StringUtil.spanCut( lbl );                                        // 5.6.3.1 (2013/04/05) spanタグを削除
467                                    maxClmWidth[col] = fontM.stringWidth( lbl );            // æœ?¤§値の初期値として、ã?ãƒ?ƒ€ーラベルのå¹?‚’セãƒ?ƒˆしておくã€?
468                            }
469    
470                            for( int row=startNo; row<lastNo; row++ ) {
471                                    // キーブレイク判定ã?キーブレイクは、ä¸?•ª初めから来るã?
472                                    String keyVal = getValue( row,keyClmNo );
473                                    if( !oldKeyVal.equals( keyVal ) ) {
474                                            oldKeyVal = keyVal;
475                                            rowCnt++;                               // レコード数
476    
477                                            // ラベルは、キーブレイク時ã?値のみ採用するã€?
478                                            for( int col=0; col<clmSu; col++ ) {
479                                                    String lbl = getValueLabel( row,labelClmsNo[col] );     // そã?行ã?値のRenderer値
480                                                    lbl = StringUtil.spanCut( lbl );                                        // 5.6.3.1 (2013/04/05) spanタグを削除
481                                                    int fontW = fontM.stringWidth( lbl );
482                                                    if( maxClmWidth[col] < fontW ) { maxClmWidth[col] = fontW; }
483                                            }
484                                    }
485                            }
486                            g2.dispose();
487    
488                            // æœ?¤§ラベルå¹??、各ラベルのæœ?¤§値?‹(ã?ージン?Š2)*カラãƒ?•°
489                            maxLabelWidth = recodeMargin * 2 * clmSu ;
490                            for( int col=0; col<clmSu; col++ ) {
491                                    maxLabelWidth += maxClmWidth[col];
492                            }
493                    }
494                    else  {
495                            for( int row=startNo; row<lastNo; row++ ) {
496                                    // キーブレイク判定ã?キーブレイクは、ä¸?•ª初めから来るã?
497                                    String keyVal = getValue( row,keyClmNo );
498                                    if( !oldKeyVal.equals( keyVal ) ) {
499                                            oldKeyVal = keyVal;
500                                            rowCnt++;                               // レコード数
501                                    }
502                            }
503    
504                            // æœ?¤§ラベルå¹??、均等割り付け。端数は無視(どã�?�›、ラベル部は、maxLabelWidth で計算するã?で。ï¼?
505                            int clmWidth = ( maxLabelWidth - recodeMargin * 2 * clmSu ) / clmSu ;
506                            for( int col=0; col<clmSu; col++ ) {
507                                    maxClmWidth[col] = clmWidth;
508                            }
509                    }
510    
511                    MAX_X = chartPadding*2 + maxLabelWidth + maxTimeWidth ;
512                    MAX_Y = chartPadding*2 + (chartHeight+recodeMargin*2)*rowCnt ;
513            }
514    
515            /**
516             * ヘッãƒ??æƒ??のイメージを作æ?しますã?
517             *
518             * 全体ã?æž?‚‚ここで作æ?しておきますã?
519             * イメージは、キーカラãƒ??ラベルと、時間軸になりますã?時間軸は縦方向にすべて線を引きますã?
520             * 時間軸の間隔は、timeScale によって、å?り替わりますã?
521             * 凡例を使ã�??合ï¼?seLegend=true?‰ã?、引数の ColorMap を利用して作æ?しますã?
522             *
523             * @og.rev 5.6.3.1 (2013/04/05) 短縮ラベルなどã€?span>タグが付与される値から、spanタグを削除しますã?
524             * @og.rev 5.6.5.0 (2013/06/07) 年月日æƒ??を表示しますã?なおã?日単位ã?場合ã?、年月ã?省略しますã?
525             *
526             * @param       g2                      描画するGraphics2Dオブジェクãƒ?
527             * @param       timeScale       時間(åˆ?当たりã?ピクセル数
528             * @param       colMap          状況コードに対応したカラーマッãƒ?
529             */
530            private void imageHeaderPaint( final Graphics2D g2 , final double timeScale , final ColorMap colMap ) {
531    
532                    int posY1 = chartPadding  ;
533                    int posY2 = chartPadding+chartHeight+recodeMargin ;
534    
535                    // 凡例を使ã�??å�?
536                    if( useLegend && colMap != null ) {
537                            // 凡例を並べる間隔を求めるã?
538                            FontMetrics fontM = g2.getFontMetrics();
539                            int maxSize = fontM.stringWidth( colMap.getMaxLengthLabel() ) ;         // æ–?­—å?のæœ?¤§長ラベルのå¹?
540                            int imgW  = chartHeight ;                               // 凡例■のå¹?高さと同じにしてã�?‚‹ので真四è§?
541                            int mgnW  = recodeMargin ;                              // 凡例■からæ–?­—までのé–?
542                            int spanW = maxSize + recodeMargin ;    // 凡例■から凡例■までの間隔。文字最大長?‹α
543    
544                            int legX  = chartPadding ;
545                            for( Object[] obj : colMap.values() ) {
546                                    String lbl = (String)obj[0];
547                                    Color  col = (Color)obj[1];
548    
549                                    g2.setColor( col );                                                                                             // 凡例■の色
550                                    g2.fillRect( legX , posY1+recodeMargin , imgW , chartHeight );  // (実際の状æ…?左端x,上端y,å¹?,高さh
551    
552                                    legX += imgW + mgnW ;
553                                    g2.setColor( LABEL_COLOR );
554                                    g2.drawString( lbl , legX , posY2 );            // æ–?­—å?,ベã?スラインのx座æ¨?y座æ¨?
555    
556                                    legX += spanW ;
557                            }
558                            posY1 += chartHeight+recodeMargin*2 ;   // ?‘レコードå?の高さを加算しておくã€?
559                            posY2 += chartHeight+recodeMargin*2 ;   // ?‘レコードå?の高さを加算しておくã€?
560                    }
561    
562                    // まずã?、å?体ã?æž?·šã?描画
563                    g2.setColor( LABEL_COLOR );
564                    g2.drawRect( chartPadding, posY1, MAX_X-chartPadding*2, MAX_Y-posY1-chartPadding );                             // 左端,上端,å¹?高さ
565    
566                    // ヘッãƒ??のラベルåˆ?� けã?繰返し描画するã€?
567                    int clmSu = labelClmsNo.length;
568                    int posX  = chartPadding ;              // ラベルæ–?­—å?の書きå?し位置の初期値
569                    for( int col=0; col<clmSu; col++ ) {
570                            String lbl = getColumnLabel( labelClmsNo[col] );                        // ヘッãƒ??のラベル
571                            lbl = StringUtil.spanCut( lbl );                                                        // 5.6.3.1 (2013/04/05) spanタグを削除
572                            g2.drawString( lbl , posX + recodeMargin, posY2 );                      // æ–?­—å?,ベã?スラインのx座æ¨?y座æ¨?
573                            posX += recodeMargin*2 + maxClmWidth[col] ;                                     // 次の書きå?し位置は、文字最大長?‹ã?ージン*2
574                            g2.drawLine( posX, posY1, posX, MAX_Y-chartPadding );           // 始点(x 座æ¨?y 座æ¨?,終点(x 座æ¨?y 座æ¨?
575                    }
576    
577                    int step = TimeScaleStep.getStep( timeScale );                  // 時間スケールに対応したSTEP数
578    
579                    // 日付ã?ãƒ?ƒ€ー部の描画のためのカレンãƒ??
580                    Calendar cal = Calendar.getInstance();
581                    cal.setTimeInMillis( startDate * 60000L );
582    
583                    int week = cal.get( Calendar.DAY_OF_WEEK );     // 開始曜日
584    
585                    String fmt = ( step < 1440 ) ? "yyyy/MM/dd(EE)" : "dd" ;             // 上段フォーマットã?、時間ã?ースの場合ã?ã€?yyyy/MM/dd(EE)" 、日ベã?スの場合ã?ã€?dd"
586                    DateFormat format1 = new SimpleDateFormat( fmt,Locale.JAPAN );
587    
588                    // グラフé?域ã?日付ã?ãƒ?ƒ€ー部の描画
589                    g2.setStroke( DSAH_STROK );                             // 日付部は、ç?ç·?
590                    posX = chartPadding+maxLabelWidth ;             // グラフé?域ã?、chartPadding+maxLabelWidth からã€?
591                    for( int tm = 0; tm < timeSpan; tm+=step ) {
592    
593                            int offset = chartHeight / 2 + recodeMargin;    // ヘッãƒ??の表示基準ã?オフセãƒ?ƒˆ?ˆチャートå¹??半å???
594    
595                            // 上段?šã?ãƒ?ƒ€ー出åŠ?
596                            if( ( tm % 1440 ) == 0 ) {
597                                    Date dt = new Date( (startDate + tm) * 60000L );
598                                    g2.drawString( format1.format( dt ) , posX + recodeMargin , posY2-offset );                     // æ–?­—å?,ベã?スラインのx座æ¨?y座æ¨?
599                                    offset = 0;             // ヘッãƒ??を表示する場合ã?み上まで線を引くã€?
600                            }
601    
602                            g2.drawString( getTime2Str(startTime+tm,step,week) , posX + recodeMargin , posY2 );             // æ–?­—å?,ベã?スラインのx座æ¨?y座æ¨?
603                            g2.drawLine( posX, posY1+offset, posX, MAX_Y-chartPadding );                                                    // 始点(x 座æ¨?y 座æ¨?,終点(x 座æ¨?y 座æ¨?
604    
605    //                      g2.drawString( getTime2Str(startTime+tm,step) , posX + recodeMargin , posY2 );  // æ–?­—å?,ベã?スラインのx座æ¨?y座æ¨?
606    //                      g2.drawLine( posX, posY1-10, posX, MAX_Y-chartPadding-10 );                                             // 始点(x 座æ¨?y 座æ¨?,終点(x 座æ¨?y 座æ¨?
607                            posX += (int)(step*timeScale);
608                    }
609            }
610    
611            // imageHeaderPaintメソãƒ?ƒ‰で使用する 破線ã?定義
612            private static final Stroke DSAH_STROK = new BasicStroke(
613                                    1.0f                                            , // BasicStroke のå¹?
614                                    BasicStroke.CAP_BUTT            , // 両端のè£?£¾
615                                    BasicStroke.JOIN_MITER          , // 輪郭線セグメントã?接合部のè£?£¾
616                                    1.0f                                            , // 接合トリミングの制限å?
617                                    new float[] {2.0f, 1.0f}        , // 破線パターンを表すé?åˆ?
618                                    0.0f                                              // 破線パターン開始位置のオフセãƒ?ƒˆ
619            );
620    
621            /**
622             * 時間スケールに対応したSTEP数を管ç�?�™るためã?å†?ƒ¨クラス
623             *
624             * 時間ヘッãƒ??を表示する場合ã?ある程度意味のある間隔でラベル表示したã�?�¨思いますã?
625             * 全体ã?描画領域の長さと、時間当たりã?スケールファクター?ˆピクセル数?‰からã?
626             * ラベルの描画間隔を求めますã?
627             * 意味のある間隔は、STEPS で定義しã?10åˆ?30åˆ?60åˆ?1/4日,1/2日,1日 まで定義してã�?�¾すã?
628             * ä¸?•ª大きな単位以上ã?場合ã?、そのæœ?¤§単位ã?整数倍を返しますã?
629             *
630             * ä¸?™‚間当たりã?表示å¹?‚’、MIN_PX としてã�?�¾すã?で、この値以下ã?間隔では描画されませんã€?
631             * 初期値はã€?00px ã‚?24時間表示できる 600px/24h = 25px にしてã�?�¾すã?
632             */
633            private static final class TimeScaleStep {
634                                                                                                            // åˆ?  åˆ?  æ™?  1/4   1/2  ?‘日
635                    private static final int[] STEPS = new int[] { 10 , 30 , 60 , 360 , 720 , 1440 };
636                    private static final int MIN_PX = 25;           // スケールに対するæœ?°�å?
637    
638                    /**
639                     * 時間を意味のあるç¯?›²の整数として返しますã?
640                     *
641                     * 全体ã?描画領域の長さと、時間当たりã?スケールファクター?ˆピクセル数?‰からã?
642                     * 10åˆ?30åˆ?60åˆ?1/4日,1/2日,1日 までの整数値で返しますã?
643                     * ä¸?•ª大きな単位以上ã?場合ã?、そのæœ?¤§単位ã?整数倍を返しますã?
644                     *
645                     * @param       timeScale       時間(åˆ?当たりã?ピクセル数
646                     * @return      時間スケールに対応した意味のあるç¯?›²の整数
647                     */
648                    public static final int getStep( final double timeScale ) {
649                            int tmStep = (int)Math.ceil(MIN_PX/(timeScale));        // 整数åˆ?‚Š上げ
650    
651                            for( int i=0; i<STEPS.length; i++ ) {
652                                    if( tmStep <= STEPS[i] ) { return STEPS[i]; }        // 配å?の数字にåˆ?‚Š上げ
653                            }
654    
655                            // 未設定ã?場合ã?、最上位ã?値の整数倍にåˆ?‚Š上げ
656                            return (int)Math.ceil( tmStep / STEPS[STEPS.length-1] ) * STEPS[STEPS.length-1];
657                    }
658            }
659    
660            /**
661             * 状況コードã?ラベル、色を管ç�?�™るためã?å†?ƒ¨クラス
662             *
663             * 状況に応じたコードã?ラベル、色を管ç�?�—ますã?
664             * これは、getColor(状況コーãƒ?ラベル) またã?、getColor(状況コーãƒ?ラベル,色æ–?­—å?) で
665             * 要求されたæƒ??をå?部で管ç�?�—、同じコードã?場合に同じ色を返しますã?
666             * またã?凡例作æ?用に、最も文字数が長ã�?ƒ©ベルを管ç�?�—ますã?
667             * 色æ–?­—å?を指定したå?合でもã?æœ??に要求された状況コードに対応する色を返しますã?
668             * これは、同ä¸?ж況コードで色違いを作æ?することができなã�?�“とを意味しますã?
669             * 色æ–?­—å?を指定しなã�??合ã?、å?部の色配å?からã€??番に色を割り当てますã?
670             * 色を割り当てるé?番は、状況コードã?発生é?ですã?よって、検索条件によってã€?
671             * 状況コードã?現れるé ?•ªが異なると、色も毎回異なることになりますã?
672             *
673             * 自動割り当ての色は、BLUE,CYAN,GRAY,GREEN,LIGHT_GRAY,MAGENTA,DARK_GRAY,ORANGE,PINK,RED,YELLOW 
674             * となっており、それをè¶?�ˆると、RGBをランãƒ?ƒ に発生させて色を作æ?しますã?
675             * よって、どのような色になるかは全くわかりませんã€?
676             */
677            private static final class ColorMap {
678                    private static final Color[] CLR_ARY = new Color[] {
679                                    Color.BLUE      ,Color.CYAN   ,Color.GRAY ,Color.GREEN ,Color.LIGHT_GRAY ,Color.MAGENTA ,
680                                    Color.DARK_GRAY ,Color.ORANGE ,Color.PINK ,Color.RED   ,Color.YELLOW
681                    };
682                    private int lastCnt = 0;
683                    private final Map<String,Object[]> colMap = new TreeMap<String,Object[]>();
684                    private String maxLabel = "" ;          // æœ?¤§長のラベル
685                    private int    maxlen   = -1 ;          // æœ?¤§長のラベルのlength()
686    
687                    /**
688                     * 状況コードに対応した色オブジェクトを返しますã?
689                     *
690                     * 状況コードが初めてæŒ?®šされた場合ã?ã€??番にå†?ƒ¨の色を割り当てますã?
691                     * またã?そã?時ã?ラベルも管ç�?�—ますã?ラベルと色のセãƒ?ƒˆは、å?例作æ?時に利用されますã?
692                     *
693                     * 自動割り当ての色は、BLUE,CYAN,GRAY,GREEN,LIGHT_GRAY,MAGENTA,DARK_GRAY,ORANGE,PINK,RED,YELLOW 
694                     * となっており、それをè¶?�ˆると、RGBをランãƒ?ƒ に発生させて色を作æ?しますã?
695                     * よって、どのような色になるかは全くわかりませんã€?
696                     *
697                     * @param       fgj     状況コーãƒ?
698                     * @param       lbl     状況コードã?ラベル
699                     * @return      状況コードに対応した色オブジェクãƒ?
700                     */
701                    public Color getColor( final String fgj,final String lbl ) {
702                            return getColor( fgj,lbl,null );
703                    }
704    
705                    /**
706                     * 状況コードに対応した色オブジェクトを返しますã?
707                     *
708                     * 状況コードが初めてæŒ?®šされた場合ã?、引数の色æ–?­—å?の色を割り当てますã?
709                     * またã?そã?時ã?ラベルも管ç�?�—ますã?ラベルと色のセãƒ?ƒˆは、å?例作æ?時に利用されますã?
710                     *
711                     * 色æ–?­—å?を指定したå?合でもã?æœ??に要求された状況コードに対応する色を返しますã?
712                     * これは、同ä¸?ж況コードで色違いを作æ?することができなã�?�“とを意味しますã?
713                     * 色æ–?­—å? ã�?null の場合ã?、è?動割り当てのメソãƒ?ƒ‰と同じですã?
714                     * よって、色æ–?­—å?のæŒ?®šと、è?動割り当てが同時に発生すると、異なる状況コードで
715                     * 同じ色が指定される可能性がありますã?で、混在して使用しなã�?�§くださいã€?
716                     *
717                     * @param       fgj             状況コーãƒ?
718                     * @param       lbl             状況コードã?ラベル
719                     * @param       colStr  状況コードに対応した色æ–?­—å?(nullの場合ã?、è?動割り当て)
720                     * @return      状況コードに対応した色オブジェクãƒ?
721                     */
722                    public Color getColor( final String fgj,final String lbl,final String colStr ) {
723                            if( fgj == null ) { return LABEL_COLOR; }
724                            if( lbl != null ) {
725                                    int len = lbl.length();
726                                    if( len > maxlen ) { maxLabel = lbl; maxlen = len; }
727                            }
728    
729                            Object[] obj = colMap.get( fgj );
730                            if( obj == null ) {
731                                    obj = new Object[2];
732                                    obj[0] = lbl;
733                                    obj[1] = (colStr != null) ? StringUtil.getColorInstance( colStr ) : uniqColor();
734    
735                                    colMap.put( fgj,obj );
736                            }
737    
738                            return (Color)obj[1] ;
739                    }
740    
741                    /**
742                     * å†?ƒ¨のシーケンスに対応したã?ユニã?クな色オブジェクトを返しますã?
743                     *
744                     * å†?ƒ¨カウンターを+ï¼?しながら、å?部の色オブジェクトを返しますã?
745                     *
746                     * 自動割り当ての色は、BLUE,CYAN,GRAY,GREEN,LIGHT_GRAY,MAGENTA,DARK_GRAY,ORANGE,PINK,RED,YELLOW 
747                     * となっており、それをè¶?�ˆると、RGBをランãƒ?ƒ に発生させて色を作æ?しますã?
748                     * よって、どのような色になるかは全くわかりませんã€?
749                     *
750                     * @return      ユニã?クな色オブジェクãƒ?
751                     */
752                    public Color uniqColor() {
753                            Color col = null;
754                            if( lastCnt < CLR_ARY.length ) {
755                                    col = CLR_ARY[lastCnt++];
756                            }
757                            else {
758                                    int R=(int)(Math.random()*256);
759                                    int G=(int)(Math.random()*256);
760                                    int B=(int)(Math.random()*256);
761                                    col = new Color(R,G,B);
762                            }
763    
764                            return col;
765                    }
766    
767                    /**
768                     * å†?ƒ¨で管ç�?�—てã�?‚‹、ラベル(String)と色オブジェクãƒ?Color)の コレクションを返しますã?
769                     *
770                     * å†?ƒ¨で管ç�?�—てã�?‚‹コレクションですã?
771                     * こã?コレクションは、状況コードでソートされてã�?�¾すã?
772                     * コレクションの中身は、オブジェクトé?列となっており、[0]は、String型ã?ラベル、[1]はã€?
773                     * Color型ã?色ですã?
774                     *
775                     * @return      ラベル(String)と色オブジェクãƒ?Color)の コレクション
776                     */
777                    public Collection<Object[]> values() {
778                            return colMap.values();
779                    }
780    
781                    /**
782                     * 登録されたラベルæ–?­—å?で、最も文字数が長ã�?ƒ©ベルを返しますã?
783                     *
784                     * 凡例で、ラベルのæœ?¤§長を求めるã?に利用できますã?
785                     * ただしã?簡易的に、length() 計算してã�?‚‹ã�?�‘なので、英語ã?日本語混在ã‚??
786                     * プロポã?ショナルフォント使用時ã?厳å¯?�ªæœ?¤§長のæ–?­—å?ではありませんã€?
787                     *
788                     * @return      æœ?‚‚æ–?­—数が長ã�?ƒ©ベル
789                     */
790                    public String getMaxLengthLabel() { return maxLabel; }
791            }
792    
793            /**
794             * 時間æ–?­—å?を数字に変換しますã?
795             *
796             * "0800" はã€?80にã€?2100" はã€?260 に変換しますã?
797             * つまりã?åˆ?�˜位ã?値に変換しますã?秒ã?単位ã?、å?り捨てますã?
798             * ここでは、時間文字å?がã?08:00 の様にã€?:" を含ã‚??合ã?、削除しã?
799             * ?”ケタ以上ã?場合ã?、前から?”ケタåˆ?‚’使ã�?�¾すã?
800             * ?”ケタ以下(1,2,3ケタ?‰でもã?先é?に 0 埋めで、時間文字å?にしますã?
801             * ?�ケタ、およã?、null の場合ã?、defTm 初期値 を返しますã?
802             *
803             * @param       val     時間æ–?­—å?の値(0800 など)
804             * @param       defTm   引数の時間æ–?­—å?ã�?null の場合ã?初期値
805             *
806             * @return      時間æ–?­—å?を数字に変換した結果( 80 など)
807             */
808            private int getStr2Time( final String val , final int defTm ) {
809                    if( val == null || val.isEmpty() ) { return defTm; }
810    
811                    // 桁数によって、å?ç�??仕方が変わるためã?
812                    int rtnInt = 0;
813                    switch( val.length() ) {
814                            case    1:
815                            case    2:      rtnInt = Integer.parseInt( val ); break;
816                            case    3:      rtnInt = Integer.parseInt( val.substring( 0,1 ) )*60 + Integer.parseInt( val.substring( 1,3 ) ); break;
817                            default  :      rtnInt = Integer.parseInt( val.substring( 0,2 ) )*60 + Integer.parseInt( val.substring( 2,4 ) ); break;
818                    }
819    
820                    return rtnInt ;
821            }
822    
823            /**
824             * 日時文字å?を数字に変換しますã?
825             *
826             * 日時文字å?は、yyyyMMdd またã?、yyyyMMddhhmmss 形式としますã?
827             * これをã?エポックタイãƒ?�‹らã?経過時間の åˆ?�˜位ã?値を求めますã?
828             * 具体的には、Calendar オブジェクトã? getTimeInMillis() の結果をã?
829             * 60000 で割り算したå?を作æ?しますã?
830             * よって、Calendar オブジェクト作æ?時も、秒ã?単位ã?åˆ?‚Š捨てますã?
831             * 引数ã�?null の場合ã?、現在時刻より、作æ?しますã?
832             *
833             * @param       val     日時文字å?の値(yyyyMMdd またã?、yyyyMMddhhmmss 形å¼?など)
834             *
835             * @return      日時文字å?をå?換算した数å­?
836             */
837            private long getStr2Date( final String val ) {
838                    Calendar cal = Calendar.getInstance();
839                    str2DateTime = 0;
840                    if( val == null ) {
841                            cal.set( Calendar.HOUR_OF_DAY, 0 );             // 5.3.5.0 (2011/05/01) 時間の解決規則が適用されるためã??¢時」ã�?�‘は、setメソãƒ?ƒ‰で 0 にセãƒ?ƒˆするã€?
842                            cal.clear( Calendar.MINUTE );
843                            cal.clear( Calendar.SECOND );
844                            cal.clear( Calendar.MILLISECOND );
845                    }
846                    else if( val.length() == 8 ) {
847                            cal.clear();
848                            cal.set( Integer.parseInt( val.substring( 0,4 ) ) ,                     // 年
849                                             Integer.parseInt( val.substring( 4,6 ) ) - 1,          // æœ?0から始まã‚?
850                                             Integer.parseInt( val.substring( 6,8 ) )                       // 日
851                            );
852                    }
853                    else {
854                            cal.clear();
855                            cal.set( Integer.parseInt( val.substring( 0,4 ) ) ,                     // 年
856                                             Integer.parseInt( val.substring( 4,6 ) ) - 1,          // æœ?0から始まã‚?
857                                             Integer.parseInt( val.substring( 6,8 ) ) ,                     // 日
858                                             Integer.parseInt( val.substring( 8,10 ) ) ,            // æ™?
859                                             Integer.parseInt( val.substring( 10,12 ) )             // �
860                            );
861                            str2DateTime = Integer.parseInt( val.substring( 8,10 ) ) * 60 + Integer.parseInt( val.substring( 10,12 ) ) ;
862                    }
863                    return (cal.getTimeInMillis() / 60000L);                // åˆ?�˜位に変換するã€?
864            }
865    
866            // 5.6.5.0 (2013/06/07) 曜日ãƒ??タをé?列で持っておきますã?
867            private static final String[] DAY_OF_WEEK_ja = new String[] { "åœ?,"日","æœ?,"火","水","木","é‡?,"åœ? };    // [0]="åœ? はã€??? の余計算でã€?7=0 になる為ã€?
868    
869            /**
870             * 数å­?åˆ?を時間文字å?に変換しますã?
871             *
872             * 480 はã€?08" にã€?260 はã€?21" に変換しますã?
873             * 引数の時間は、å?を表す整数ですã??’4時間表記であればã€? ??1440 のç¯?›²で収まりますがã€?
874             * 期間が長ã�??合ã?、その値をè¶?�ˆますã?またã??’4時間をè¶?�ˆるå?合ã?ã€? に戻りますã?
875             * æ–?­—å?にする場合ã?æœ?°�単位ã?ã€?æ™?なのでã€?0(åˆ?で割り算して、余ã?、å?り捨てますã?
876             * step はã€?0(åˆ?単位ã?表示時に飛ã?す数ですã?step=1 ならã?60(åˆ?単位ã?step=2 ならã?120(åˆ?
877             * 単位となりますã?stepがã?24 以下ã?場合ã?、そのままã€?4時間表記で構いませんがã?
878             * それをè¶?�ˆると時間ではなくã?日数表記にåˆ?‚Š替わりますã?
879             *
880             * @og.rev 5.6.5.0 (2013/06/07) 月単位ã?場合ã?、曜日を表示しますã?
881             *
882             * @param       timeVal 引数の時間整数(åˆ?
883             * @param       step    60åˆ?�˜位ã?スãƒ?ƒƒプ数( 10,30,60,720,1440 単位となるよã�?�«調整)
884             * @param       week    カレンãƒ?‚¯ラスの曜日フィールãƒ?DAY_OF_WEEK)
885             *
886             * @return      数字を時間æ–?­—å?に変換した結果( "08" など)
887             */
888    //      private String getTime2Str( final int timeVal, final int step ) {
889            private String getTime2Str( final int timeVal, final int step, final int week ) {
890    
891                    int dtm = (timeVal / 60 / 24 );                 // 日
892                    int htm = ((timeVal / 60) % 24 );               // æ™??’4時間制)
893                    int mtm = (timeVal % 60 );                              // åˆ??–0å?制)
894    
895                    StringBuilder rtn = new StringBuilder();
896    
897                    if( step >= 1440 ) {
898    //                      rtn.append( dtm ).append( "d" );                                                        // 5.6.5.0 (2013/06/07) 相対日付å»?­¢
899                            rtn.append( DAY_OF_WEEK_ja[ ( dtm + week ) % 7 ] );                     // 曜日を表示
900                    }
901                    else {
902                            if( htm < 10 ) { rtn.append( "0" ); }
903                            rtn.append( htm );
904    
905                            if( step < 60 ) { 
906                                    rtn.append( ":" );
907                                    if( mtm < 10 ) { rtn.append( "0" ); }
908                                    rtn.append( mtm );
909                            }
910                    }
911    
912                    return rtn.toString();
913            }
914    
915            // 引数にã€?を追åŠ?�™るã?
916    
917            /**
918             * 表示é ?›®の編é›?並び替ã�?が可能かどã�?�‹を返しまã�?
919             *
920             * @return      表示é ?›®の編é›?並び替ã�?が可能かどã�?�‹(false:不可能)
921             */
922            @Override
923            public boolean isEditable() {
924                    return false;
925            }
926    }