OSDN Git Service

新聞形式の予約待機枠を、番組追跡とキーワード検索それぞれに個別の色を設定できるようにした。
[tainavi/TinyBannavi.git] / TinyBannavi / src / tainavi / JTXTButton.java
1 package tainavi;\r
2 \r
3 import java.awt.AlphaComposite;\r
4 import java.awt.Color;\r
5 import java.awt.Dimension;\r
6 import java.awt.Font;\r
7 import java.awt.FontMetrics;\r
8 import java.awt.Graphics;\r
9 import java.awt.Graphics2D;\r
10 import java.awt.Rectangle;\r
11 import java.awt.RenderingHints;\r
12 import java.awt.font.FontRenderContext;\r
13 import java.awt.font.GlyphMetrics;\r
14 import java.awt.font.GlyphVector;\r
15 import java.awt.font.TextAttribute;\r
16 import java.awt.geom.Point2D;\r
17 import java.awt.image.BufferedImage;\r
18 import java.util.ArrayList;\r
19 import java.util.HashMap;\r
20 import java.util.Map;\r
21 \r
22 import javax.swing.JButton;\r
23 import javax.swing.JLabel;\r
24 \r
25 \r
26 public class JTXTButton extends JLabel {\r
27 \r
28         private static final long serialVersionUID = 1L;\r
29 \r
30         /*******************************************************************************\r
31          * 定数\r
32          ******************************************************************************/\r
33         \r
34         /**\r
35          *  フォントスタイル\r
36          */\r
37         public static enum FontStyle {\r
38                 BOLD            ("太字"),\r
39                 ITALIC          ("斜体"),\r
40                 UNDERLINE       ("下線");\r
41                 \r
42                 private String name;\r
43                 \r
44                 private FontStyle(String name) {\r
45                         this.name = name;\r
46                 }\r
47                 \r
48                 @Override\r
49                 public String toString() {\r
50                         return name;\r
51                 }\r
52                 \r
53                 \r
54                 public String getId() {\r
55                         return super.toString();\r
56                 }\r
57                 \r
58                 public static FontStyle get(String id) {\r
59                         for ( FontStyle fs : FontStyle.values() ) {\r
60                                 if ( fs.getId().equals(id) ) {\r
61                                         return fs;\r
62                                 }\r
63                         }\r
64                         return null;\r
65                 }\r
66         };\r
67         \r
68         private static final float DRAWTAB = 2.0F; \r
69         \r
70         \r
71         /*******************************************************************************\r
72          * 部品\r
73          ******************************************************************************/\r
74         \r
75         // 描画バッファ\r
76         private BufferedImage image = null;             // ビットマップ\r
77         \r
78         private int vrow;                                               // 仮想座標縦位置\r
79         private int vcolumn;                                    // 仮想座標横位置\r
80         private int vheight;                                    // 仮想座標高さ\r
81         private int vwidth;                                             // 仮想座標幅\r
82         \r
83         // 番組情報\r
84         private ProgDetailList tvd = null;              // 番組情報そのまま\r
85         \r
86         // 表示設定\r
87         private static boolean showStart = true;\r
88         private static boolean splitEpno = false;\r
89         private static boolean showDetail = true;\r
90         private static float detailTab = 2.0F;\r
91         \r
92         private static Font defaultFont = new JLabel().getFont();\r
93         \r
94         private static Font titleFont = defaultFont;\r
95         private static int titleFontSize = defaultFont.getSize();\r
96         private static Color titleFontColor = Color.BLUE;\r
97         private static int titleFontStyle = Font.BOLD;\r
98         \r
99         private static Font detailFont = defaultFont;\r
100         private static int detailFontSize = defaultFont.getSize();\r
101         private static Color detailFontColor = Color.DARK_GRAY;\r
102         private static int detailFontStyle = defaultFont.getStyle();\r
103         \r
104         private static Font startFont = defaultFont;\r
105         \r
106         private static FontRenderContext frc = new FontRenderContext(null, RenderingHints.VALUE_TEXT_ANTIALIAS_ON, RenderingHints.VALUE_FRACTIONALMETRICS_DEFAULT);\r
107 \r
108         private static int columnWidth = 0;\r
109         private static float heightMultiplier = 0;\r
110         \r
111         \r
112         /*******************************************************************************\r
113          * コンストラクタ\r
114          ******************************************************************************/\r
115         \r
116         // ないよ\r
117         \r
118         \r
119         /*******************************************************************************\r
120          * メソッド\r
121          ******************************************************************************/\r
122         \r
123         // 内容をリセットする\r
124         // setVisible(false)するとリソースが解放されてしまうのか再描画に時間がかかるようになるので表示範囲外に出して隠してしまう\r
125         public void clean() {\r
126                 tvd = null;\r
127                 image = null;\r
128                 setBounds(-1,-1,0,0);\r
129         }\r
130         \r
131         // フラグを変えた後に再描画させる\r
132         public void forceRepaint() {\r
133                 image = null;\r
134                 super.repaint();\r
135         }\r
136         \r
137         // 仮想位置の変更\r
138         //public void setVRow(int n) { vrow = n; }\r
139         public int getVRow() { return vrow; }\r
140         //public void setVColumn(int n) { vcolumn = n; }\r
141         public int getVColumn() { return vcolumn; }\r
142         //public void setVHeight(int n) { vheight = n; }\r
143         public int getVHeight() { return vheight; }\r
144         \r
145         public static void setColumnWidth(int n) { columnWidth = n; }\r
146         public static void setHeightMultiplier(float f) { heightMultiplier = f; }\r
147         \r
148         public void setVBounds(int x, int y, int width, int height) {\r
149                 vrow = y;\r
150                 vcolumn = x;\r
151                 vheight = height;\r
152                 vwidth = width;\r
153                 super.setBounds(\r
154                                 vcolumn*columnWidth,\r
155                                 (int) Math.ceil(((float)vrow)*heightMultiplier),\r
156                                 vwidth*columnWidth,\r
157                                 (int) Math.ceil(((float)vheight)*heightMultiplier));\r
158         }\r
159         \r
160         public void reVBounds() {\r
161                 super.setBounds(\r
162                                 vcolumn*columnWidth,\r
163                                 (int) Math.ceil(((float)vrow)*heightMultiplier),\r
164                                 vwidth*columnWidth,\r
165                                 (int) Math.ceil(((float)vheight)*heightMultiplier));\r
166         }\r
167         \r
168         // 番組情報のやりとり\r
169         public void setInfo(ProgDetailList tvd) {\r
170                 this.tvd = tvd;\r
171                 this.setText(null);     // 簡易表示時代の名残\r
172                 \r
173                 this.setVerticalAlignment(JButton.TOP);\r
174                 this.setHorizontalAlignment(JButton.LEFT);\r
175                 //this.setBorder(new LineBorder(Color.BLACK,1));\r
176                 this.setOpaque(true);\r
177         }\r
178         public ProgDetailList getInfo() {\r
179                 return tvd;\r
180         }\r
181         \r
182         // 予約待機枠を表示するかどうかの確認\r
183         public boolean isStandby() { return tvd.marked && tvd.showinstandby; }\r
184         public boolean isStandbyByTrace() { return tvd.markedByTrace; }\r
185 \r
186         // 表示スタイル\r
187         public static void setShowStart(boolean b) {\r
188                 showStart = b;\r
189         }\r
190         public static void setSplitEpno(boolean b) {\r
191                 splitEpno = b;\r
192         }\r
193         public static void setShowDetail(boolean b) {\r
194                 showDetail = b;\r
195         }\r
196         public static void setDetailTab(float n) {\r
197                 detailTab = n;\r
198         }\r
199         \r
200         // フォントスタイル\r
201         public static void setTitleFont(String fn) {\r
202                 if ( fn != null && ! fn.equals("") ) {\r
203                         Font f = new Font(fn,titleFontStyle,titleFontSize);\r
204                         if ( f != null ) {\r
205                                 titleFont = f;\r
206                                 return;\r
207                         }\r
208                 }\r
209                 //titleFont = this.getFont();\r
210         }\r
211         public static void setTitleFontSize(int n) {\r
212                 titleFontSize = n;\r
213                 titleFont = titleFont.deriveFont((float)titleFontSize);\r
214         }\r
215         public static void setTitleFontColor(Color c) {\r
216                 titleFontColor = c;\r
217         }\r
218         public static void setDetailFont(String fn) {\r
219                 if ( fn != null && ! fn.equals("") ) {\r
220                         Font f = new Font(fn,detailFontStyle,detailFontSize);\r
221                         if ( f != null ) {\r
222                                 detailFont = f;\r
223                                 startFont = f.deriveFont(Font.BOLD);\r
224                                 return;\r
225                         }\r
226                 }\r
227                 //detailFont = new JLabel().getFont();\r
228         }\r
229         public static void setDetailFontSize(int n) {\r
230                 detailFontSize = n;\r
231                 detailFont = detailFont.deriveFont((float)detailFontSize);\r
232                 startFont = startFont.deriveFont((float)detailFontSize);\r
233         }\r
234         public static void setDetailFontColor(Color c) {\r
235                 detailFontColor = c;\r
236         }\r
237         \r
238         // フォントスタイルの変更\r
239         public static void setTitleFontStyle(ArrayList<FontStyle> fsa) {\r
240                 titleFont = setFontStyle(titleFont, (float)titleFontSize, fsa);\r
241         }\r
242         public static void setDetailFontStyle(ArrayList<FontStyle> fsa) {\r
243                 detailFont = setFontStyle(detailFont, (float)detailFontSize, fsa);\r
244         }\r
245         \r
246         private static Font setFontStyle(Font f, float size, ArrayList<FontStyle> fsa) {\r
247                 Map<TextAttribute, Object>  attributes = new HashMap<TextAttribute, Object>();\r
248                 attributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_REGULAR);\r
249                 attributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_REGULAR);\r
250                 attributes.remove(TextAttribute.UNDERLINE);\r
251                 for ( FontStyle fs : fsa ) {\r
252                         switch (fs) {\r
253                         case BOLD:\r
254                                 attributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD);\r
255                                 break;\r
256                         case ITALIC:\r
257                                 attributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE);\r
258                                 break;\r
259                         case UNDERLINE:\r
260                                 attributes.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);//LOW_ONE_PIXEL);\r
261                                 break;\r
262                         }\r
263                 }\r
264                 attributes.put(TextAttribute.SIZE, size);\r
265                 return f.deriveFont(attributes);\r
266         }\r
267         \r
268         // フォントエイリアスの変更\r
269         public static void setAAHint(Object o) {\r
270                 frc = new FontRenderContext(null, o, RenderingHints.VALUE_FRACTIONALMETRICS_DEFAULT);\r
271         }\r
272         \r
273         \r
274         /*******************************************************************************\r
275          * メソッド\r
276          ******************************************************************************/\r
277         \r
278         /**\r
279          * ビットマップの描画処理\r
280          */\r
281         @Override\r
282         protected void paintComponent(Graphics g) { \r
283                 \r
284                 super.paintComponent(g);\r
285                 \r
286                 // 初回描画時\r
287                 if (image == null) {\r
288                         //\r
289                         Dimension  d  = getSize();\r
290                         int imgw = d.width;\r
291                         int imgh = d.height;\r
292 \r
293                         float draww = (float)imgw-DRAWTAB*2.0F;\r
294                         float drawh = (float)imgh;\r
295 \r
296                         image = new BufferedImage(imgw, imgh, BufferedImage.TYPE_INT_ARGB);\r
297                         Graphics2D g2 = (Graphics2D)image.createGraphics();\r
298                         \r
299                         g2.setRenderingHint(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_SPEED);\r
300                         g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));\r
301                         \r
302                         float baseline = 0.0F;\r
303                         \r
304                         // 開始時刻と延長警告の描画\r
305                         if (showStart && tvd.start != null && tvd.start.length() > 0) {\r
306                                 FontMetrics fm = g2.getFontMetrics(startFont);\r
307                                 float hi = Float.valueOf(fm.getHeight());\r
308                                 float as = Float.valueOf(fm.getAscent());\r
309                                 \r
310                                 float startx = Float.valueOf(DRAWTAB);\r
311                                 float startw = draww;\r
312                                 float xposstartx = 0.0F;\r
313                                 \r
314                                 baseline = as;  // 初期垂直位置 \r
315                                 \r
316                                 {\r
317                                         WrappedGlyphVector wgv = getWrappedGlyphVector(tvd.start, startw, xposstartx, startFont, as, frc);\r
318                                         GlyphVector gv = wgv.getGv();\r
319                                         g2.setPaint(Color.BLACK);\r
320                                         g2.drawGlyphVector(gv, startx, baseline);\r
321                                         \r
322                                         xposstartx = wgv.getLastX();    // 後続有り\r
323                                         baseline += wgv.getLastY();\r
324                                 }\r
325                                 \r
326                                 {\r
327                                         WrappedGlyphVector wgv = getWrappedGlyphVector(" "+tvd.extension_mark, startw, xposstartx, startFont, as, frc);\r
328                                         GlyphVector gv = wgv.getGv();\r
329                                         g2.setPaint(Color.RED);\r
330                                         g2.drawGlyphVector(gv, startx, baseline);\r
331                                         \r
332                                         baseline += wgv.getLastY();\r
333                                 }\r
334                                 \r
335                                 baseline += hi;\r
336                         }\r
337                         \r
338                         // タイトルの描画\r
339                         String title = ( splitEpno ) ? tvd.splitted_title : tvd.title;\r
340                         if ( title.length() > 0 ) {\r
341                                 //\r
342                                 String aMark;\r
343                                 if (showStart && tvd.start.length() > 0) {\r
344                                         aMark = tvd.prefix_mark + tvd.newlast_mark;\r
345                                 }\r
346                                 else {\r
347                                         if (tvd.start.length() > 0) {\r
348                                                 aMark = tvd.extension_mark + tvd.prefix_mark + tvd.newlast_mark;\r
349                                         }\r
350                                         else {\r
351                                                 aMark = tvd.prefix_mark + tvd.newlast_mark;\r
352                                         }\r
353                                 }\r
354                                 \r
355                                 FontMetrics fm = g2.getFontMetrics(titleFont);\r
356                                 float hi = Float.valueOf(fm.getHeight());\r
357                                 float as = Float.valueOf(fm.getAscent());\r
358                                 \r
359                                 float titlex = Float.valueOf(DRAWTAB);\r
360                                 float titlew = draww;\r
361                                 float xpos = 0.0F;\r
362                                 \r
363                                 if ( baseline == 0.0F ) {\r
364                                         baseline = as;  // 初期垂直位置\r
365                                 }\r
366                                 \r
367                                 if ( aMark.length() > 0 ) {\r
368                                         WrappedGlyphVector wgv = getWrappedGlyphVector(aMark, titlew, xpos, titleFont, as, frc);\r
369                                         GlyphVector gv = wgv.getGv();\r
370                                         g2.setPaint(Color.RED);\r
371                                         g2.drawGlyphVector(gv, titlex, baseline);\r
372                                         \r
373                                         xpos = wgv.getLastX();  // 後続有り\r
374                                         baseline += wgv.getLastY();\r
375                                 }\r
376                                 \r
377                                 {\r
378                                         WrappedGlyphVector wgv = getWrappedGlyphVector(title+tvd.postfix_mark, titlew, xpos, titleFont, as, frc);\r
379                                         GlyphVector gv = wgv.getGv();\r
380                                         g2.setPaint(titleFontColor);\r
381                                         \r
382                                         drawString(g2, wgv, titlex, baseline);\r
383 \r
384                                         baseline += wgv.getLastY();\r
385                                 }\r
386                                 \r
387                                 baseline += hi;\r
388                         }\r
389                         \r
390                         // 番組詳細の描画\r
391                         if ( showDetail ) {\r
392                                 String detail;\r
393                                 if ( splitEpno ) {\r
394                                         detail = tvd.splitted_detail;\r
395                                 }\r
396                                 else {\r
397                                         detail = tvd.detail;\r
398                                 }\r
399                                 \r
400                                 FontMetrics fm = g2.getFontMetrics(detailFont);\r
401                                 float as = Float.valueOf(fm.getAscent());\r
402                                 float detailx = Float.valueOf(DRAWTAB+detailTab);\r
403                                 float detailw = draww-detailTab;\r
404                                 \r
405                                 if ( baseline == 0.0F ) {\r
406                                         baseline = as;  // 初期垂直位置\r
407                                 }\r
408                                 \r
409                                 WrappedGlyphVector wgv = getWrappedGlyphVector(detail, detailw, 0.0f, detailFont, as, frc);\r
410                                 g2.setPaint(detailFontColor);\r
411                                 \r
412                                 drawString(g2, wgv, detailx, baseline);\r
413                         }\r
414                 }\r
415                 \r
416                 // 反映\r
417                 g.drawImage(image, 0, 0, this);\r
418         }\r
419         \r
420         /**\r
421          * \r
422          */\r
423         private void drawString(Graphics2D g2, WrappedGlyphVector wgv, float x, float y) {\r
424                 g2.drawGlyphVector(wgv.getGv(), x, y);\r
425                 \r
426                 if ( wgv.getGv().getFont().getAttributes().get(TextAttribute.UNDERLINE) != null ) {\r
427                         for ( Rectangle r : wgv.getLinePositions() ) {\r
428                                 g2.drawLine((int)x+r.x, (int)y+r.y+1, (int)x+r.x+r.width-1, (int)y+r.y+1);\r
429                         }\r
430                 }\r
431         }\r
432         \r
433         /**\r
434          * 参考:てんぷらメモ/JTableのセル幅で文字列を折り返し  ( http://terai.xrea.jp/Swing/TableCellRenderer.html )\r
435          * @param str                   描画する文字列\r
436          * @param width                 描画領域の幅\r
437          * @param xstart                1行目の描画開始位置\r
438          * @param font                  描画フォント\r
439          * @param lineHeight    1行あたりの高さ\r
440          * @param frc                   FontRenderContext\r
441          * @return\r
442          */\r
443     private WrappedGlyphVector getWrappedGlyphVector(String str, float width, float xstart, Font font, float lineHeight, FontRenderContext frc) {\r
444         Point2D gmPos    = new Point2D.Double(0.0d, 0.0d);\r
445         GlyphVector gv   = font.createGlyphVector(frc, str);\r
446         WrappedGlyphVector wgv = new WrappedGlyphVector(gv);\r
447         float xpos       = xstart;\r
448         float ypos       = 0.0F;\r
449         float advance    = 0.0F;\r
450         GlyphMetrics gm;\r
451         for( int i=0; i <= gv.getNumGlyphs(); i++ ) {\r
452                 if ( i == gv.getNumGlyphs() ) {\r
453                         int x = (int) ((ypos == 0.0F) ? xstart : 0.0F);\r
454                         int y = (int) ypos;\r
455                         int w = (int) (xpos - x);\r
456                         wgv.addLinePosition(new Rectangle(x, y, w, 1));\r
457                         break;\r
458                 }\r
459             gm = gv.getGlyphMetrics(i);\r
460             advance = gm.getAdvance();\r
461             if( xpos < width && width <= xpos+advance ) {\r
462                         int x = (int) ((ypos == 0.0F) ? xstart : 0.0F);\r
463                         int y = (int) ypos;\r
464                         int w = (int) (xpos - x);\r
465                         wgv.addLinePosition(new Rectangle(x, y, w, 1));\r
466                 ypos += lineHeight;\r
467                 xpos = 0.0f;\r
468             }\r
469             gmPos.setLocation(xpos, ypos);\r
470             gv.setGlyphPosition(i, gmPos);\r
471             xpos = xpos + advance;\r
472             \r
473             wgv.setLastX(xpos);\r
474             wgv.setLastY(ypos);\r
475         }\r
476         return wgv;\r
477     }\r
478     \r
479     private class WrappedGlyphVector {\r
480         \r
481         public WrappedGlyphVector(GlyphVector gv) {\r
482                 super();\r
483                 this.gv = gv;\r
484         }\r
485         \r
486         private GlyphVector gv;\r
487         \r
488         public GlyphVector getGv() { return gv; }\r
489         \r
490         private float lastx;\r
491         private float lasty;\r
492         \r
493         public void setLastX(float x) { lastx = x; }\r
494         public float getLastX() { return lastx; }\r
495         public void setLastY(float y) { lasty = y; }\r
496         public float getLastY() { return lasty; }\r
497         \r
498         private ArrayList<Rectangle> linePositions = new ArrayList<Rectangle>();\r
499         public ArrayList<Rectangle> getLinePositions() { return linePositions; }\r
500         public void addLinePosition(Rectangle r) { linePositions.add(r); }\r
501     }\r
502 }\r