• R/O
  • HTTP
  • SSH
  • HTTPS

提交

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

タイニー番組ナビゲータ本体


Commit MetaInfo

修訂39db50f56ff34fc20ad15f63caa4463168cb5940 (tree)
時間2021-11-03 20:32:51
作者Masahiko Kimura <mkimura@u01....>
CommiterMasahiko Kimura

Log Message

Ver.1.13.3 (2021/11/3)
1. [全般]管理対象の番組記号を増やす
2. [全般]番組記号の表示/非表示をタイトルの前後で独立して設定できるようにする
3. [全般]ツリービューの隠れている部分やリストの末尾省略されているセルをツールチップで表示する
4. [新聞形式]番組のツールチップのレイアウトを改善し、表示内容を増やす(終了時刻、番組長、マーク)

Change Summary

差異

--- a/TinyBannavi/src/tainavi/AbsListedView.java
+++ b/TinyBannavi/src/tainavi/AbsListedView.java
@@ -5,7 +5,10 @@ import java.awt.Color;
55 import java.awt.Component;
66 import java.awt.Desktop;
77 import java.awt.Dimension;
8+import java.awt.FontMetrics;
9+import java.awt.Insets;
810 import java.awt.Point;
11+import java.awt.Rectangle;
912 import java.awt.event.ActionEvent;
1013 import java.awt.event.ActionListener;
1114 import java.awt.event.ComponentAdapter;
@@ -4203,7 +4206,12 @@ public abstract class AbsListedView extends JPanel implements TickTimerListener
42034206 if (jTree_tree == null) {
42044207
42054208 // ツリーの作成
4206- jTree_tree = new JTree();
4209+ jTree_tree = new JTree(){
4210+ @Override public String getToolTipText(MouseEvent e) {
4211+ return CommonUtils.GetTreeTooltip(jScrollPane_tree, jTree_tree, e);
4212+ }
4213+ };
4214+ jTree_tree.setToolTipText("dummy");
42074215 jTree_tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
42084216 jTree_tree.setRootVisible(env.getRootNodeVisible());
42094217 jTree_tree.setCellRenderer(new VWTreeCellRenderer()); // 検索結果が存在するノードの色を変える
@@ -4730,9 +4738,6 @@ public abstract class AbsListedView extends JPanel implements TickTimerListener
47304738 Component comp = super.prepareRenderer(tcr, row, column);
47314739 Color fgColor = (prechknextweek)?(nextweekFgColor):(this.getForeground());
47324740 Color bgColor = (isSepRowColor && row%2 == 1)?(evenColor):(super.getBackground());
4733- int mrow = this.convertRowIndexToModel(row);
4734- int mcol = convertColumnIndexToModel(column);
4735- ListedItem item = rowData.get(mrow);
47364741
47374742 isRowPassed(row);
47384743
@@ -4765,30 +4770,58 @@ public abstract class AbsListedView extends JPanel implements TickTimerListener
47654770 comp.setBackground(bgColor);
47664771 }
47674772
4773+ return comp;
4774+ }
4775+
4776+ // getToolTipText()をオーバーライド
4777+ @Override
4778+ public String getToolTipText(MouseEvent e){
4779+ int row = rowAtPoint(e.getPoint());
4780+ int column = columnAtPoint(e.getPoint());
4781+ if (row == -1 || column == -1)
4782+ return null;
4783+
4784+ int mrow = this.convertRowIndexToModel(row);
4785+ int mcol = convertColumnIndexToModel(column);
4786+ ListedItem item = rowData.get(mrow);
4787+
47684788 // ツールチップテキストを生成する
47694789 ListColumnInfo info = lvitems.getVisibleAt(column);
47704790
4771- String text = null;
4772- if (item != null && info != null && comp instanceof JComponent){
4773- int cindex = info.getId()-1;
4774- if (cindex == ListedColumn.RSVMARK.getColumn())
4775- text = item.marker != null ? item.marker.getTooltipText() : null;
4776- else if (cindex >= ListedColumn.RSVMARK1.getColumn() && cindex < ListedColumn.RSVMARK1.getColumn()+marker_num){
4777- int n = cindex-ListedColumn.RSVMARK1.getColumn();
4778- text = item.marker_array[n] != null ? item.marker_array[n].getTooltipText() : null;
4779- }
4780- else if (cindex == ListedColumn.PICKMARK.getColumn() || cindex == ListedColumn.DUPMARK.getColumn()){
4781- Object o = getModel().getValueAt(mrow, mcol);
4782- String s = (o != null) ? o.toString() : null;
4783- text = RsvMark.getTooltipText(s);
4784- }
4785-
4786- if (text != null)
4787- ((JComponent) comp).setToolTipText(text);
4788- }
4789-
4790- return comp;
4791- }
4791+ int cindex = info.getId()-1;
4792+ if (cindex == ListedColumn.RSVMARK.getColumn())
4793+ return item.marker != null ? item.marker.getTooltipText() : null;
4794+ else if (cindex >= ListedColumn.RSVMARK1.getColumn() && cindex < ListedColumn.RSVMARK1.getColumn()+marker_num){
4795+ int n = cindex-ListedColumn.RSVMARK1.getColumn();
4796+ return item.marker_array[n] != null ? item.marker_array[n].getTooltipText() : null;
4797+ }
4798+ else if (cindex == ListedColumn.PICKMARK.getColumn() || cindex == ListedColumn.DUPMARK.getColumn()){
4799+ Object o = getModel().getValueAt(mrow, mcol);
4800+ String s = (o != null) ? o.toString() : null;
4801+ return RsvMark.getTooltipText(s);
4802+ }
4803+ else if (cindex == ListedColumn.TITLE.getColumn()){
4804+ if (item.title == null)
4805+ return null;
4806+
4807+ String text = String.join("", item.title.split("\0", 8));
4808+ if (text == null)
4809+ return null;
4810+
4811+ Insets i = getInsets();
4812+ Rectangle rect = getCellRect(row, column, false);
4813+ FontMetrics fm = getFontMetrics(getFont());
4814+
4815+ int width = fm.stringWidth(text);
4816+
4817+ if (width > rect.width-(i.left+i.right))
4818+ return text;
4819+ else
4820+ return null;
4821+ }
4822+ else
4823+ return super.getToolTipText(e);
4824+ }
47924825
47934826 // 直接rowDataを見に行くようになったから、このisRowPassed()はもういらないんじゃ…
47944827
--- a/TinyBannavi/src/tainavi/AbsPaperView.java
+++ b/TinyBannavi/src/tainavi/AbsPaperView.java
@@ -2188,20 +2188,8 @@ public abstract class AbsPaperView extends JPanel implements TickTimerListener,H
21882188 b2.setVBounds(col,row,1,tvd.length);
21892189
21902190 // ツールチップを付加する
2191- if ( env.getTooltipEnable() == true && ! tvd.title.equals("") && ! tvd.start.equals("") ) {
2192- String t = "";
2193- int tlen = bounds.getTooltipWidth();
2194- for (int i=0; i<tvd.title.length(); i+=tlen) {
2195- t += tvd.title.substring(i, (i+tlen<tvd.title.length())?(i+tlen):(tvd.title.length()))+"<BR>";
2196- }
2197- String d = "";
2198- int dlen = tlen+2;
2199- for (int i=0; i<tvd.detail.length(); i+=dlen) {
2200- d += "&nbsp;&nbsp;&nbsp;&nbsp;"+tvd.detail.substring(i, (i+dlen<tvd.detail.length())?(i+dlen):(tvd.detail.length()))+"<BR>";
2201- }
2202- String e = getExtensionMark(tvd);
2203- b2.setToolTipText(("<html>"+tvd.start+"&nbsp;<FONT COLOR=RED><EM>"+e+"</EM></FONT><BR>&nbsp;<FONT COLOR=BLUE><STRONG><U>"+t+"</U></STRONG></FONT>"+d+"</html>"));
2204- }
2191+ if (Env.TheEnv.getTooltipEnable() && ! tvd.title.isEmpty() && ! tvd.start.isEmpty())
2192+ b2.setToolTipText("dummy");
22052193 }
22062194
22072195
@@ -2626,7 +2614,7 @@ public abstract class AbsPaperView extends JPanel implements TickTimerListener,H
26262614 else if (byCenter && !value.equals("")){
26272615 c = CommonUtils.getCalendar(value, 3600*24);
26282616 if (c != null)
2629- redrawByDateWithCenter(node.getLabel(), CommonUtils.getDate(c));
2617+ redrawByDateWithCenter(null, CommonUtils.getDate(c));
26302618 }
26312619 else
26322620 redrawByCurrentSelection();
@@ -3255,7 +3243,13 @@ public abstract class AbsPaperView extends JPanel implements TickTimerListener,H
32553243 if (jTree_tree == null) {
32563244
32573245 // ツリーの作成
3258- jTree_tree = new JTree();
3246+ jTree_tree = new JTree(){
3247+ @Override public String getToolTipText(MouseEvent e) {
3248+ return CommonUtils.GetTreeTooltip(jScrollPane_tree, jTree_tree, e);
3249+ }
3250+ };
3251+ jTree_tree.setToolTipText("dummy");
3252+
32593253 jTree_tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
32603254 jTree_tree.setCellRenderer(new TreeCellRenderer()); // 検索結果が存在するノードの色を変える
32613255 jTree_tree.setRootVisible(env.getRootNodeVisible());
--- a/TinyBannavi/src/tainavi/AbsReserveListView.java
+++ b/TinyBannavi/src/tainavi/AbsReserveListView.java
@@ -25,7 +25,6 @@ import java.util.HashMap;
2525 import java.util.Map.Entry;
2626
2727 import javax.swing.ImageIcon;
28-import javax.swing.JComponent;
2928 import javax.swing.JLabel;
3029 import javax.swing.JMenuItem;
3130 import javax.swing.JPanel;
@@ -1936,35 +1935,44 @@ public abstract class AbsReserveListView extends JPanel implements TickTimerList
19361935 c.setBackground(bgColor);
19371936 }
19381937
1938+ return c;
1939+ }
1940+
1941+ // getToolTipText()をオーバーライド
1942+ @Override
1943+ public String getToolTipText(MouseEvent e){
1944+ int row = rowAtPoint(e.getPoint());
1945+ int column = columnAtPoint(e.getPoint());
1946+ if (row == -1 || column == -1)
1947+ return null;
1948+
19391949 // ツールチップテキストを生成する
19401950 if (column == RsvedColumn.DUPMARK.getColumn()){
1941- if (c instanceof JComponent) {
1942- int mr = convertRowIndexToModel(row);
1943- int mc = convertColumnIndexToModel(column);
1944- Object o = getModel().getValueAt(mr, mc);
1945-
1946- String text = null;
1947- if (o != null){
1948- String s = o.toString();
1949- if (s == null)
1950- ;
1951- else if (s.startsWith("□")){
1952- text = "□:開始時間と終了時間が同じ";
1953- }
1954- else if (s.startsWith("■")){
1955- text = "■:時間が重なっている";
1956- }
1957- else if (s.startsWith("★")){
1958- text = "★:エンコーダの数を超える予約がある";
1959- }
1960- }
1961-
1962- ((JComponent) c).setToolTipText(text);
1963- }
1964- }
1951+ int mr = convertRowIndexToModel(row);
1952+ int mc = convertColumnIndexToModel(column);
1953+ Object o = getModel().getValueAt(mr, mc);
1954+
1955+ String text = null;
1956+ if (o != null){
1957+ String s = o.toString();
1958+ if (s == null)
1959+ ;
1960+ else if (s.startsWith("□")){
1961+ text = "□:開始時間と終了時間が同じ";
1962+ }
1963+ else if (s.startsWith("■")){
1964+ text = "■:時間が重なっている";
1965+ }
1966+ else if (s.startsWith("★")){
1967+ text = "★:エンコーダの数を超える予約がある";
1968+ }
1969+ }
19651970
1966- return c;
1967- }
1971+ return text;
1972+ }
1973+ else
1974+ return super.getToolTipText(e);
1975+ }
19681976
19691977 // 連続して同じ行へのアクセスがあったら計算を行わず前回のままにする
19701978 private boolean isRowPassed(int prow) {
--- a/TinyBannavi/src/tainavi/AbsSettingView.java
+++ b/TinyBannavi/src/tainavi/AbsSettingView.java
@@ -1512,7 +1512,8 @@ public abstract class AbsSettingView extends JScrollPane {
15121512 env.setSyncTreeWidth(jCBP_syncTreeWidth.isSelected());
15131513 env.setShortExtMark(jCBP_shortExtMark.isSelected());
15141514 for (int row=0; row<jTable_showmarks.getRowCount(); row++) {
1515- env.getOptMarks().put((TVProgram.ProgOption) jTable_showmarks.getValueAt(row, 2), (Boolean) jTable_showmarks.getValueAt(row, 0));
1515+ env.getOptMarks().put((TVProgram.ProgOption) jTable_showmarks.getValueAt(row, 3), (Boolean) jTable_showmarks.getValueAt(row, 0));
1516+ env.getOptPostfixMarks().put((TVProgram.ProgOption) jTable_showmarks.getValueAt(row, 3), (Boolean) jTable_showmarks.getValueAt(row, 1));
15161517 }
15171518 for (int row=0; row<jTable_clipboard.getRowCount(); row++) {
15181519 cbitems.get(row).setB((Boolean)jTable_clipboard.getValueAt(row, 0));
@@ -2584,32 +2585,127 @@ public abstract class AbsSettingView extends JScrollPane {
25842585 }
25852586 private JNETable getJTable_showmarks() {
25862587 if (jTable_showmarks == null) {
2587- jTable_showmarks = getDispTable(null);
2588+ jTable_showmarks = getDispTable_showmarks();
25882589
25892590 DefaultTableModel model = (DefaultTableModel)jTable_showmarks.getModel();
25902591
25912592 //
25922593 for (Object[] obj : TVProgram.optMarks) {
2593- Entry<ProgOption,Boolean> entry = null;
2594+ Entry<ProgOption,Boolean> entryPrefix = null;
25942595 for (Entry<ProgOption,Boolean> e : env.getOptMarks().entrySet()) {
25952596 if (e.getKey() == obj[0]) {
2596- entry = e;
2597+ entryPrefix = e;
25972598 break;
25982599 }
25992600 }
2600- if ( entry != null ) {
2601- Object[] data = { entry.getValue(),obj[1],obj[0] };
2602- model.addRow(data);
2603- }
2604- else {
2605- Object[] data = { Boolean.TRUE,obj[1],obj[0] };
2606- model.addRow(data);
2601+
2602+ Entry<ProgOption,Boolean> entryPostfix = null;
2603+ for (Entry<ProgOption,Boolean> e : env.getOptPostfixMarks().entrySet()) {
2604+ if (e.getKey() == obj[0]) {
2605+ entryPostfix = e;
2606+ break;
2607+ }
26072608 }
2609+
2610+ Object label = obj.length > 1 ? obj[1] : ((ProgOption)obj[0]).getProgLabel();
2611+ Object [] data = {
2612+ entryPrefix != null ? entryPrefix.getValue() : Boolean.FALSE,
2613+ entryPostfix != null ? entryPostfix.getValue() : Boolean.FALSE,
2614+ label,
2615+ obj[0]
2616+ };
2617+
2618+ model.addRow(data);
26082619 }
26092620 }
26102621 return(jTable_showmarks);
26112622 }
26122623
2624+ /**
2625+ * 表示マーク用のテーブルを生成する
2626+ *
2627+ * @return 生成したJNETableオブジェクト
2628+ */
2629+ private JNETable getDispTable_showmarks() {
2630+ String prefix = "前";
2631+ String postfix = "後";
2632+
2633+ // ヘッダの設定
2634+ String[] colname = {prefix, postfix, "アイテム", "ID"};
2635+ int[] colwidth = {30,30,240,0};
2636+
2637+ //
2638+ DefaultTableModel model = new DefaultTableModel(colname, 0);
2639+ JNETable jTable = new JNETable(model, false) {
2640+ private static final long serialVersionUID = 1L;
2641+
2642+ @Override
2643+ public boolean isCellEditable(int row, int column) {
2644+ return (column == 0 || column == 1);
2645+ }
2646+ };
2647+
2648+ jTable.setAutoResizeMode(JNETable.AUTO_RESIZE_OFF);
2649+ DefaultTableColumnModel columnModel = (DefaultTableColumnModel)jTable.getColumnModel();
2650+ TableColumn column = null;
2651+ for (int i = 0 ; i < columnModel.getColumnCount() ; i++){
2652+ column = columnModel.getColumn(i);
2653+ column.setPreferredWidth(colwidth[i]);
2654+ }
2655+
2656+ // にゃーん
2657+ jTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
2658+
2659+ // エディタに手を入れる
2660+ DefaultCellEditor editor = new DefaultCellEditor(new JCheckBox() {
2661+
2662+ private static final long serialVersionUID = 1L;
2663+
2664+ @Override
2665+ public int getHorizontalAlignment() {
2666+ return JCheckBox.CENTER;
2667+ }
2668+ });
2669+
2670+ jTable.getColumn(prefix).setCellEditor(editor);
2671+ jTable.getColumn(postfix).setCellEditor(editor);
2672+
2673+ // レンダラに手を入れる
2674+ DefaultTableCellRenderer renderer = new DefaultTableCellRenderer() {
2675+ private static final long serialVersionUID = 1L;
2676+
2677+ @Override
2678+ public Component getTableCellRendererComponent(JTable table, Object value,
2679+ boolean isSelected, boolean hasFocus, int row, int column) {
2680+ //
2681+ JCheckBox cBox = new JCheckBox();
2682+ cBox.setHorizontalAlignment(JCheckBox.CENTER);
2683+ //
2684+ Boolean b = (Boolean)value;
2685+ cBox.setSelected(b.booleanValue());
2686+ //
2687+ if (isSelected) {
2688+ cBox.setBackground(table.getSelectionBackground());
2689+ }
2690+ else {
2691+ cBox.setBackground(table.getBackground());
2692+ }
2693+
2694+ // 【新】【終】は後ろには表示できない
2695+ if (column == 1 && (row == 0 || row == 1)){
2696+ cBox.setEnabled(false);
2697+ cBox.setSelected(false);
2698+ }
2699+
2700+ return cBox;
2701+ }
2702+ };
2703+ jTable.getColumn(prefix).setCellRenderer(renderer);
2704+ jTable.getColumn(postfix).setCellRenderer(renderer);
2705+
2706+ return jTable;
2707+ }
2708+
26132709 /*
26142710 * クリップボードアイテムの選択
26152711 */
--- a/TinyBannavi/src/tainavi/Bounds.java
+++ b/TinyBannavi/src/tainavi/Bounds.java
@@ -10,6 +10,8 @@ import java.util.HashMap;
1010 * 【結論】ちゃんと設計しないとメンバの変更で簡単に例外が起きる。できるならシリアライズは自前で組もう!
1111 */
1212 public class Bounds {
13+ public static Bounds TheBounds = null;
14+
1315 //
1416 private static final String BOUNDS_FILE = "env"+File.separator+"bounds.xml";
1517 private static final String BOUNDS_TEXT = "env"+File.separator+"bounds.txt";
--- a/TinyBannavi/src/tainavi/CommonUtils.java
+++ b/TinyBannavi/src/tainavi/CommonUtils.java
@@ -3,6 +3,9 @@ package tainavi;
33
44 import java.awt.Color;
55 import java.awt.Desktop;
6+import java.awt.Point;
7+import java.awt.Rectangle;
8+import java.awt.event.MouseEvent;
69 import java.beans.XMLDecoder;
710 import java.beans.XMLEncoder;
811 import java.io.BufferedInputStream;
@@ -33,12 +36,18 @@ import java.util.Calendar;
3336 import java.util.GregorianCalendar;
3437 import java.util.HashMap;
3538 import java.util.Map.Entry;
39+import java.util.Objects;
3640 import java.util.regex.Matcher;
3741 import java.util.regex.Pattern;
3842 import java.util.zip.ZipEntry;
3943 import java.util.zip.ZipFile;
4044 import java.util.zip.ZipOutputStream;
4145
46+import javax.swing.JScrollPane;
47+import javax.swing.JTree;
48+import javax.swing.JViewport;
49+import javax.swing.tree.TreePath;
50+
4251 /**
4352 * <P>頻繁に使用する雑多なメソッドをstaticで提供します。
4453 * <P>パッケージを小分けにしておけばよかった…
@@ -1784,4 +1793,25 @@ public class CommonUtils {
17841793 public static void closing(HttpURLConnection ucon) {
17851794 if ( ucon != null ) ucon.disconnect();
17861795 }
1796+
1797+ public static String GetTreeTooltip(JScrollPane pane, JTree tree, MouseEvent e){
1798+ Object o = null;
1799+ TreePath path = tree.getPathForLocation(e.getX(), e.getY());
1800+ if (Objects.nonNull(path) && pane != null) {
1801+ JViewport vp = pane.getViewport();
1802+ if (vp == null)
1803+ return null;
1804+
1805+ Point pt = vp.getViewPosition();
1806+ Rectangle rp = tree.getPathBounds(path);
1807+ Rectangle rt = pane.getViewportBorderBounds();
1808+ rt.setLocation(pt);
1809+ if (rt.contains(rp))
1810+ return null;
1811+
1812+ o = path.getLastPathComponent();
1813+ }
1814+
1815+ return Objects.toString(o, null);
1816+ }
17871817 }
--- a/TinyBannavi/src/tainavi/Env.java
+++ b/TinyBannavi/src/tainavi/Env.java
@@ -674,10 +674,17 @@ public class Env {
674674 public boolean getShortExtMark() { return shortExtMark; }
675675 public void setShortExtMark(boolean b) { shortExtMark = b; }
676676 private boolean shortExtMark = false;
677+
677678 // 表示マークの選択
678679 public HashMap<TVProgram.ProgOption,Boolean> getOptMarks() { return optMarks; }
679680 public void setOptMarks(HashMap<TVProgram.ProgOption,Boolean> h) { optMarks = h; }
680681 private HashMap<TVProgram.ProgOption,Boolean> optMarks = new HashMap<TVProgram.ProgOption, Boolean>();
682+
683+ // 表示マークの選択(後付け)
684+ public HashMap<TVProgram.ProgOption,Boolean> getOptPostfixMarks() { return optPostfixMarks; }
685+ public void setOptPostfixMarks(HashMap<TVProgram.ProgOption,Boolean> h) { optPostfixMarks = h; }
686+ private HashMap<TVProgram.ProgOption,Boolean> optPostfixMarks = new HashMap<TVProgram.ProgOption, Boolean>();
687+
681688 // クリップボードアイテムの選択(->clipboardItem)
682689 // 右クリックメニューの実行アイテム
683690 public ArrayList<TextValueSet> getTvCommand() { return tvCommand; }
--- a/TinyBannavi/src/tainavi/JNETable.java
+++ b/TinyBannavi/src/tainavi/JNETable.java
@@ -2,6 +2,10 @@ package tainavi;
22
33 import java.awt.Color;
44 import java.awt.Component;
5+import java.awt.FontMetrics;
6+import java.awt.Insets;
7+import java.awt.Rectangle;
8+import java.awt.event.MouseEvent;
59
610 import javax.swing.JTable;
711 import javax.swing.ListSelectionModel;
@@ -116,6 +120,40 @@ public class JNETable extends JTable {
116120 }
117121 }
118122
123+
124+ // getToolTipText()をオーバーライド
125+ @Override
126+ public String getToolTipText(MouseEvent e){
127+ int row = rowAtPoint(e.getPoint());
128+ int column = columnAtPoint(e.getPoint());
129+ if (row == -1 || column == -1)
130+ return null;
131+
132+ try{
133+ String text = (String)getModel().getValueAt(row, column);
134+ if (text == null)
135+ return null;
136+
137+ String[] xs = text.split("\0", 4);
138+ if (xs.length <= 0 || xs[0] == null)
139+ return null;
140+
141+ Insets i = getInsets();
142+ Rectangle rect = getCellRect(row, column, false);
143+ FontMetrics fm = getFontMetrics(getFont());
144+
145+ int width = fm.stringWidth(xs[0]);
146+
147+ if (width > rect.width-(i.left+i.right))
148+ return xs[0];
149+ else
150+ return null;
151+ }
152+ catch(ClassCastException ex){
153+ return null;
154+ }
155+ }
156+
119157 /*
120158 * コンストラクタ
121159 */
--- a/TinyBannavi/src/tainavi/JTXTButton.java
+++ b/TinyBannavi/src/tainavi/JTXTButton.java
@@ -9,6 +9,7 @@ import java.awt.Graphics;
99 import java.awt.Graphics2D;
1010 import java.awt.Rectangle;
1111 import java.awt.RenderingHints;
12+import java.awt.event.MouseEvent;
1213 import java.awt.font.FontRenderContext;
1314 import java.awt.font.GlyphMetrics;
1415 import java.awt.font.GlyphVector;
@@ -30,7 +31,7 @@ public class JTXTButton extends JLabel {
3031 /*******************************************************************************
3132 * 定数
3233 ******************************************************************************/
33-
34+
3435 /**
3536 * フォントスタイル
3637 */
@@ -38,23 +39,23 @@ public class JTXTButton extends JLabel {
3839 BOLD ("太字"),
3940 ITALIC ("斜体"),
4041 UNDERLINE ("下線");
41-
42+
4243 private String name;
43-
44+
4445 private FontStyle(String name) {
4546 this.name = name;
4647 }
47-
48+
4849 @Override
4950 public String toString() {
5051 return name;
5152 }
52-
53-
53+
54+
5455 public String getId() {
5556 return super.toString();
5657 }
57-
58+
5859 public static FontStyle get(String id) {
5960 for ( FontStyle fs : FontStyle.values() ) {
6061 if ( fs.getId().equals(id) ) {
@@ -64,62 +65,62 @@ public class JTXTButton extends JLabel {
6465 return null;
6566 }
6667 };
67-
68+
6869 private static final float DRAWTAB = 2.0F;
69-
70-
70+
71+
7172 /*******************************************************************************
7273 * 部品
7374 ******************************************************************************/
74-
75+
7576 // 描画バッファ
7677 private BufferedImage image = null; // ビットマップ
77-
78+
7879 private int vrow; // 仮想座標縦位置
7980 private int vcolumn; // 仮想座標横位置
8081 private int vheight; // 仮想座標高さ
8182 private int vwidth; // 仮想座標幅
82-
83+
8384 // 番組情報
8485 private ProgDetailList tvd = null; // 番組情報そのまま
85-
86+
8687 // 表示設定
8788 private static boolean showStart = true;
8889 private static boolean splitEpno = false;
8990 private static boolean showDetail = true;
9091 private static float detailTab = 2.0F;
91-
92+
9293 private static Font defaultFont = new JLabel().getFont();
93-
94+
9495 private static Font titleFont = defaultFont;
9596 private static int titleFontSize = defaultFont.getSize();
9697 private static Color titleFontColor = Color.BLUE;
9798 private static int titleFontStyle = Font.BOLD;
98-
99+
99100 private static Font detailFont = defaultFont;
100101 private static int detailFontSize = defaultFont.getSize();
101102 private static Color detailFontColor = Color.DARK_GRAY;
102103 private static int detailFontStyle = defaultFont.getStyle();
103-
104+
104105 private static Font startFont = defaultFont;
105-
106+
106107 private static FontRenderContext frc = new FontRenderContext(null, RenderingHints.VALUE_TEXT_ANTIALIAS_ON, RenderingHints.VALUE_FRACTIONALMETRICS_DEFAULT);
107108
108109 private static int columnWidth = 0;
109110 private static float heightMultiplier = 0;
110-
111-
111+
112+
112113 /*******************************************************************************
113114 * コンストラクタ
114115 ******************************************************************************/
115-
116+
116117 // ないよ
117-
118-
118+
119+
119120 /*******************************************************************************
120121 * メソッド
121122 ******************************************************************************/
122-
123+
123124 // 内容をリセットする
124125 // setVisible(false)するとリソースが解放されてしまうのか再描画に時間がかかるようになるので表示範囲外に出して隠してしまう
125126 public void clean() {
@@ -127,13 +128,13 @@ public class JTXTButton extends JLabel {
127128 image = null;
128129 setBounds(-1,-1,0,0);
129130 }
130-
131+
131132 // フラグを変えた後に再描画させる
132133 public void forceRepaint() {
133134 image = null;
134135 super.repaint();
135136 }
136-
137+
137138 // 仮想位置の変更
138139 //public void setVRow(int n) { vrow = n; }
139140 public int getVRow() { return vrow; }
@@ -141,10 +142,10 @@ public class JTXTButton extends JLabel {
141142 public int getVColumn() { return vcolumn; }
142143 //public void setVHeight(int n) { vheight = n; }
143144 public int getVHeight() { return vheight; }
144-
145+
145146 public static void setColumnWidth(int n) { columnWidth = n; }
146147 public static void setHeightMultiplier(float f) { heightMultiplier = f; }
147-
148+
148149 public void setVBounds(int x, int y, int width, int height) {
149150 vrow = y;
150151 vcolumn = x;
@@ -156,7 +157,7 @@ public class JTXTButton extends JLabel {
156157 vwidth*columnWidth,
157158 (int) Math.ceil(((float)vheight)*heightMultiplier));
158159 }
159-
160+
160161 public void reVBounds() {
161162 super.setBounds(
162163 vcolumn*columnWidth,
@@ -164,12 +165,12 @@ public class JTXTButton extends JLabel {
164165 vwidth*columnWidth,
165166 (int) Math.ceil(((float)vheight)*heightMultiplier));
166167 }
167-
168+
168169 // 番組情報のやりとり
169170 public void setInfo(ProgDetailList tvd) {
170171 this.tvd = tvd;
171172 this.setText(null); // 簡易表示時代の名残
172-
173+
173174 this.setVerticalAlignment(JButton.TOP);
174175 this.setHorizontalAlignment(JButton.LEFT);
175176 //this.setBorder(new LineBorder(Color.BLACK,1));
@@ -178,7 +179,7 @@ public class JTXTButton extends JLabel {
178179 public ProgDetailList getInfo() {
179180 return tvd;
180181 }
181-
182+
182183 // 予約待機枠を表示するかどうかの確認
183184 public boolean isStandby() { return tvd.marked && tvd.showinstandby; }
184185 public boolean isStandbyByTrace() { return tvd.markedByTrace; }
@@ -196,7 +197,7 @@ public class JTXTButton extends JLabel {
196197 public static void setDetailTab(float n) {
197198 detailTab = n;
198199 }
199-
200+
200201 // フォントスタイル
201202 public static void setTitleFont(String fn) {
202203 if ( fn != null && ! fn.equals("") ) {
@@ -234,7 +235,7 @@ public class JTXTButton extends JLabel {
234235 public static void setDetailFontColor(Color c) {
235236 detailFontColor = c;
236237 }
237-
238+
238239 // フォントスタイルの変更
239240 public static void setTitleFontStyle(ArrayList<FontStyle> fsa) {
240241 titleFont = setFontStyle(titleFont, (float)titleFontSize, fsa);
@@ -242,7 +243,7 @@ public class JTXTButton extends JLabel {
242243 public static void setDetailFontStyle(ArrayList<FontStyle> fsa) {
243244 detailFont = setFontStyle(detailFont, (float)detailFontSize, fsa);
244245 }
245-
246+
246247 private static Font setFontStyle(Font f, float size, ArrayList<FontStyle> fsa) {
247248 Map<TextAttribute, Object> attributes = new HashMap<TextAttribute, Object>();
248249 attributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_REGULAR);
@@ -264,25 +265,25 @@ public class JTXTButton extends JLabel {
264265 attributes.put(TextAttribute.SIZE, size);
265266 return f.deriveFont(attributes);
266267 }
267-
268+
268269 // フォントエイリアスの変更
269270 public static void setAAHint(Object o) {
270271 frc = new FontRenderContext(null, o, RenderingHints.VALUE_FRACTIONALMETRICS_DEFAULT);
271272 }
272-
273-
273+
274+
274275 /*******************************************************************************
275276 * メソッド
276277 ******************************************************************************/
277-
278+
278279 /**
279280 * ビットマップの描画処理
280281 */
281282 @Override
282- protected void paintComponent(Graphics g) {
283-
283+ protected void paintComponent(Graphics g) {
284+
284285 super.paintComponent(g);
285-
286+
286287 // 初回描画時
287288 if (image == null) {
288289 //
@@ -295,12 +296,12 @@ public class JTXTButton extends JLabel {
295296
296297 image = new BufferedImage(imgw, imgh, BufferedImage.TYPE_INT_ARGB);
297298 Graphics2D g2 = (Graphics2D)image.createGraphics();
298-
299+
299300 g2.setRenderingHint(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_SPEED);
300301 g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
301-
302+
302303 float baseline = 0.0F;
303-
304+
304305 // 開始時刻と延長警告の描画
305306 if (showStart && tvd.start != null && tvd.start.length() > 0) {
306307 FontMetrics fm = g2.getFontMetrics(startFont);
@@ -310,31 +311,31 @@ public class JTXTButton extends JLabel {
310311 float startx = Float.valueOf(DRAWTAB);
311312 float startw = draww;
312313 float xposstartx = 0.0F;
313-
314- baseline = as; // 初期垂直位置
315-
314+
315+ baseline = as; // 初期垂直位置
316+
316317 {
317318 WrappedGlyphVector wgv = getWrappedGlyphVector(tvd.start, startw, xposstartx, startFont, as, frc);
318319 GlyphVector gv = wgv.getGv();
319320 g2.setPaint(Color.BLACK);
320321 g2.drawGlyphVector(gv, startx, baseline);
321-
322+
322323 xposstartx = wgv.getLastX(); // 後続有り
323324 baseline += wgv.getLastY();
324325 }
325-
326+
326327 {
327328 WrappedGlyphVector wgv = getWrappedGlyphVector(" "+tvd.extension_mark, startw, xposstartx, startFont, as, frc);
328329 GlyphVector gv = wgv.getGv();
329330 g2.setPaint(Color.RED);
330331 g2.drawGlyphVector(gv, startx, baseline);
331-
332+
332333 baseline += wgv.getLastY();
333334 }
334-
335+
335336 baseline += hi;
336337 }
337-
338+
338339 // タイトルの描画
339340 String title = ( splitEpno ) ? tvd.splitted_title : tvd.title;
340341 if ( title.length() > 0 ) {
@@ -351,19 +352,19 @@ public class JTXTButton extends JLabel {
351352 aMark = tvd.prefix_mark + tvd.newlast_mark;
352353 }
353354 }
354-
355+
355356 FontMetrics fm = g2.getFontMetrics(titleFont);
356357 float hi = Float.valueOf(fm.getHeight());
357358 float as = Float.valueOf(fm.getAscent());
358-
359+
359360 float titlex = Float.valueOf(DRAWTAB);
360361 float titlew = draww;
361362 float xpos = 0.0F;
362-
363+
363364 if ( baseline == 0.0F ) {
364365 baseline = as; // 初期垂直位置
365366 }
366-
367+
367368 if ( aMark.length() > 0 ) {
368369 WrappedGlyphVector wgv = getWrappedGlyphVector(aMark, titlew, xpos, titleFont, as, frc);
369370 GlyphVector gv = wgv.getGv();
@@ -373,20 +374,20 @@ public class JTXTButton extends JLabel {
373374 xpos = wgv.getLastX(); // 後続有り
374375 baseline += wgv.getLastY();
375376 }
376-
377+
377378 {
378379 WrappedGlyphVector wgv = getWrappedGlyphVector(title+tvd.postfix_mark, titlew, xpos, titleFont, as, frc);
379380 GlyphVector gv = wgv.getGv();
380381 g2.setPaint(titleFontColor);
381-
382+
382383 drawString(g2, wgv, titlex, baseline);
383384
384385 baseline += wgv.getLastY();
385386 }
386-
387+
387388 baseline += hi;
388389 }
389-
390+
390391 // 番組詳細の描画
391392 if ( showDetail ) {
392393 String detail;
@@ -417,35 +418,35 @@ public class JTXTButton extends JLabel {
417418 float as = Float.valueOf(fm.getAscent());
418419 float detailx = Float.valueOf(DRAWTAB+detailTab);
419420 float detailw = draww-detailTab;
420-
421+
421422 if ( baseline == 0.0F ) {
422423 baseline = as; // 初期垂直位置
423424 }
424425
425426 WrappedGlyphVector wgv = getWrappedGlyphVector(detail, detailw, 0.0f, detailFont, as, frc);
426427 g2.setPaint(detailFontColor);
427-
428+
428429 drawString(g2, wgv, detailx, baseline);
429430 }
430431 }
431-
432+
432433 // 反映
433434 g.drawImage(image, 0, 0, this);
434435 }
435-
436+
436437 /**
437- *
438+ *
438439 */
439440 private void drawString(Graphics2D g2, WrappedGlyphVector wgv, float x, float y) {
440441 g2.drawGlyphVector(wgv.getGv(), x, y);
441-
442+
442443 if ( wgv.getGv().getFont().getAttributes().get(TextAttribute.UNDERLINE) != null ) {
443444 for ( Rectangle r : wgv.getLinePositions() ) {
444445 g2.drawLine((int)x+r.x, (int)y+r.y+1, (int)x+r.x+r.width-1, (int)y+r.y+1);
445446 }
446447 }
447448 }
448-
449+
449450 /**
450451 * 参考:てんぷらメモ/JTableのセル幅で文字列を折り返し ( http://terai.xrea.jp/Swing/TableCellRenderer.html )
451452 * @param str 描画する文字列
@@ -485,34 +486,60 @@ public class JTXTButton extends JLabel {
485486 gmPos.setLocation(xpos, ypos);
486487 gv.setGlyphPosition(i, gmPos);
487488 xpos = xpos + advance;
488-
489+
489490 wgv.setLastX(xpos);
490491 wgv.setLastY(ypos);
491492 }
492493 return wgv;
493494 }
494-
495+
495496 private class WrappedGlyphVector {
496-
497+
497498 public WrappedGlyphVector(GlyphVector gv) {
498499 super();
499500 this.gv = gv;
500501 }
501-
502+
502503 private GlyphVector gv;
503-
504+
504505 public GlyphVector getGv() { return gv; }
505-
506+
506507 private float lastx;
507508 private float lasty;
508-
509+
509510 public void setLastX(float x) { lastx = x; }
510511 public float getLastX() { return lastx; }
511512 public void setLastY(float y) { lasty = y; }
512513 public float getLastY() { return lasty; }
513-
514+
514515 private ArrayList<Rectangle> linePositions = new ArrayList<Rectangle>();
515516 public ArrayList<Rectangle> getLinePositions() { return linePositions; }
516517 public void addLinePosition(Rectangle r) { linePositions.add(r); }
517518 }
519+
520+ @Override
521+ public String getToolTipText(MouseEvent e){
522+ // ツールチップを付加する
523+ if (! Env.TheEnv.getTooltipEnable() || tvd == null || tvd.title.isEmpty() || tvd.start.isEmpty())
524+ return null;
525+
526+ int tlen = Bounds.TheBounds.getTooltipWidth()*15;
527+ StringBuilder sb = new StringBuilder("");
528+
529+ sb.append("<html>");
530+ sb.append(tvd.start + "~" + tvd.end + " (" + tvd.recmin + "分)");
531+ sb.append("&nbsp;<FONT COLOR=RED><EM>" + tvd.extension_mark + "</EM></FONT><BR>");
532+
533+ sb.append("<DIV width=\"" + String.valueOf(tlen+10) + "\"><STRONG><U><FONT COLOR=RED>");
534+ sb.append(tvd.prefix_mark);
535+ sb.append("</FONT><FONT COLOR=BLUE>");
536+ sb.append(tvd.title + tvd.postfix_mark);
537+ sb.append("</FONT></U></STRONG></DIV>");
538+
539+ sb.append("<DIV style=\"margin-left: 10px;\" width=\"" + String.valueOf(tlen) + "\">");
540+ sb.append(tvd.detail);
541+ sb.append("</DIV></html>");
542+
543+ return sb.toString();
544+ }
518545 }
--- a/TinyBannavi/src/tainavi/MarkChar.java
+++ b/TinyBannavi/src/tainavi/MarkChar.java
@@ -1,5 +1,7 @@
11 package tainavi;
22
3+import java.util.HashMap;
4+
35 import tainavi.TVProgram.ProgFlags;
46 import tainavi.TVProgram.ProgOption;
57 import tainavi.TVProgram.ProgScrumble;
@@ -36,13 +38,10 @@ public class MarkChar {
3638 MULTIVOICE ( "[多]" ),
3739 STANDIN ( "[吹]" ),
3840 DATA ( "[デ]" ),
39- SURROUND ( "[5.1]" ),
41+ SURROUND ( "[SS]" ),
4042 PRECEDING ( "【先】" ),
4143
4244 REPEATED ( "[再]" ),
43-
44- BS4K ( "[4K]"),
45- BS8K ( "[8K]"),
4645 ;
4746
4847 private String name;
@@ -98,138 +97,50 @@ public class MarkChar {
9897 * 普通のマークの取得
9998 */
10099 public String getOptionMark(ProgDetailList tvd) {
101-
102- String mkNewArr = "";
103- String mkModified = "";
104- String mkNoscr = "";
105- String mkSpecial = "";
106- String mkNoSyobo = "";
107- String mkRating = "";
108-
109- String mkFirst = "";
110- String mkLive = "";
111- String mkSubtitle = "";
112- String mkBilingual = "";
113- String mkTextbc = "";
114- String mkMultivoice = "";
115- String mkStandin = "";
116- String mkPv = "";
117- String mkData = "";
118- String mkSurround = "";
119- String mkNonrepeated = "";
120- String mkMoved = "";
121- String mkPrec = "";
122- String mk4k = "";
123- String mk8k = "";
124-
125- if (tvd.noscrumble == ProgScrumble.NOSCRUMBLE && env.getOptMarks().get(ProgOption.HIDDEN_NOSCRUMBLE) == Boolean.TRUE) {
126- mkNoscr = MarkItem.NOSCRUMBLE.getName();
127- }
128-
129- if ( tvd.newarrival && env.getOptMarks().get(ProgOption.NEWARRIVAL) == Boolean.TRUE ) {
130- mkNewArr = ((env.getShortExtMark())?(MarkItem.NEWARRIVAL_S.getName()):(MarkItem.NEWARRIVAL.getName()));
131- }
132- if ( tvd.modified && env.getOptMarks().get(ProgOption.MODIFIED) == Boolean.TRUE ) {
133- mkModified = MarkItem.MODIFIED.getName();
134- }
135- if ( tvd.nonrepeated && env.getOptMarks().get(ProgOption.NONREPEATED) == Boolean.TRUE ) {
136- mkNonrepeated = MarkItem.NONREPEATED.getName();
137- }
138- for ( ProgOption opt : tvd.getOption() ) {
139- if ( env.getOptMarks().get(opt) != null && env.getOptMarks().get(opt) == Boolean.FALSE ) {
140- continue;
141- }
142- switch (opt) {
143- case SPECIAL:
144- // 特別番組
145- mkSpecial = MarkItem.SPECIAL.getName();
146- break;
147- case RATING:
148- // 視聴年齢制限
149- mkRating = MarkItem.RATING.getName();
150- break;
151- case FIRST:
152- // 初回放送
153- mkFirst = MarkItem.FIRST.getName();
154- break;
155-
156- case NOSYOBO:
157- mkNoSyobo = MarkItem.NOSYOBO.getName();
158- break;
159-
160- case LIVE:
161- // 生放送
162- mkLive = MarkItem.LIVE.getName();
163- break;
164- case PV:
165- // ペイパービュー
166- mkPv = MarkItem.PV.getName();
167- break;
168- case SUBTITLE:
169- // 字幕放送
170- mkSubtitle = MarkItem.SUBTITLE.getName();
171- break;
172- case BILINGUAL:
173- // 二か国語放送
174- mkBilingual = MarkItem.BILINGUAL.getName();
175- break;
176- case MULTIVOICE:
177- // 音声多重放送
178- mkMultivoice = MarkItem.MULTIVOICE.getName();
179- break;
180- case STANDIN:
181- // 吹き替え
182- mkStandin = MarkItem.STANDIN.getName();
183- break;
184- case DATA:
185- // データ放送
186- mkData = MarkItem.DATA.getName();
187- break;
188- case SURROUND:
189- // 5.1chサラウンド
190- mkSurround = MarkItem.SURROUND.getName();
191- break;
192- case MOVED:
193- // 先週無かったか時間が違う
194- mkMoved = MarkItem.MOVED.getName();
195- break;
196- case PRECEDING:
197- // 先行放送
198- mkPrec = MarkItem.PRECEDING.getName();
199- break;
200- case BS4K:
201- mk4k = MarkItem.BS4K.getName();
202- break;
203- case BS8K:
204- mk8k = MarkItem.BS8K.getName();
205- break;
206- default:
207- break;
208- }
209- }
210-
211- return(mkNewArr+mkNoSyobo+mkMoved+mkModified+mkFirst+mkNonrepeated+mkNoscr+mkSpecial+mkRating+mkPrec+mkLive+
212- mkPv+mkSubtitle+mkBilingual+mkTextbc+mkMultivoice+mkStandin+mkData+mkSurround+mk4k+mk8k);
100+ return getOptionMark(tvd, env.getOptMarks());
213101 }
214102
215103 /**
216104 * タイトルの後ろにつくマークの取得
217105 */
218106 public String getPostfixMark(ProgDetailList tvd) {
107+ return getOptionMark(tvd, env.getOptPostfixMarks());
108+ }
109+
110+ /**
111+ * 前後のマークの取得
112+ *
113+ * @param tvd 番組詳細情報
114+ * @param options 表示オプション
115+ * @return マーク
116+ */
117+ public String getOptionMark(ProgDetailList tvd, HashMap<TVProgram.ProgOption,Boolean> options) {
118+
119+ StringBuilder sb = new StringBuilder("");
120+
121+ if (tvd.noscrumble == ProgScrumble.NOSCRUMBLE && options.get(ProgOption.HIDDEN_NOSCRUMBLE) == Boolean.TRUE) {
122+ sb.append(MarkItem.NOSCRUMBLE.getName());
123+ }
219124
220- String mkRep = "";
125+ if ( tvd.newarrival && options.get(ProgOption.NEWARRIVAL) == Boolean.TRUE ) {
126+ sb.append(((env.getShortExtMark())?(MarkItem.NEWARRIVAL_S.getName()):(MarkItem.NEWARRIVAL.getName())));
127+ }
128+
129+ if ( tvd.modified && options.get(ProgOption.MODIFIED) == Boolean.TRUE ) {
130+ sb.append(MarkItem.MODIFIED.getName());
131+ }
132+ if ( tvd.nonrepeated && options.get(ProgOption.NONREPEATED) == Boolean.TRUE ) {
133+ sb.append(MarkItem.NONREPEATED.getName());
134+ }
221135
222136 for ( ProgOption opt : tvd.getOption() ) {
223- switch (opt) {
224- case REPEAT:
225- mkRep = MarkItem.REPEATED.getName();
226- break;
227- default:
228- break;
137+ if ( options.get(opt) != null && options.get(opt) == Boolean.FALSE ) {
138+ continue;
229139 }
140+
141+ sb.append(opt.getMark());
230142 }
231143
232- return(mkRep);
144+ return sb.toString();
233145 }
234-
235146 }
--- a/TinyBannavi/src/tainavi/TVProgram.java
+++ b/TinyBannavi/src/tainavi/TVProgram.java
@@ -20,31 +20,76 @@ public interface TVProgram {
2020 * NOSCRUMBLEは間違って(?)ProgScrumbleを使うこととなってしまったのだ。ここにあるのはマーク表示のための一覧用なのだ。
2121 */
2222 public enum ProgOption {
23- HIDDEN_NEW,
24- HIDDEN_LAST,
25- HIDDEN_NOSCRUMBLE,
26- FIRST,
27- REPEAT,
28- LIVE,
29- SPECIAL,
30- NOSYOBO,
31- SUBTITLE,
32- BILINGUAL,
33- STANDIN,
34- PV,
35- MULTIVOICE,
36- DATA,
37- SURROUND,
38- NEWARRIVAL,
39- MODIFIED,
40- NONREPEATED,
41- MOVED,
42- PRECEDING,
43- RATING,
44- BS4K,
45- BS8K,
46- NOOPTION
47- };
23+ HIDDEN_NEW ("【新】", "新番組" ),
24+ HIDDEN_LAST ("【終】", "最終回" ),
25+ HIDDEN_NOSCRUMBLE ("【無料】", "無料放送" ),
26+ FIRST ("【初】", "初回放送" ),
27+ REPEAT ("[再]", "再放送" ),
28+ LIVE ("[生]", "生放送" ),
29+ SPECIAL ("[特]", "特番" ),
30+ NOSYOBO ("[!]", "しょぼかる未定義" ),
31+ SUBTITLE ("[字]", "字幕放送" ),
32+ BILINGUAL ("[二]", "二か国語放送" ),
33+ STANDIN ("[吹]", "吹替放送" ),
34+ PV ("[PV]", "ペイパービュー" ),
35+ MULTIVOICE ("[多]", "音声多重放送" ),
36+ DATA ("[デ]", "番組連動データ放送" ),
37+ SURROUND ("[SS]", "サラウンドステレオ" ),
38+ NEWARRIVAL ("[NEW]", "予約待機の新着" ),
39+ MODIFIED ("(更)", "番組詳細に更新あり - 予約待機分のみ" ),
40+ NONREPEATED ("[初]", "リピート放送の初回放送回" ),
41+ MOVED ("(移)", "先週無かったか時間が違う" ),
42+ PRECEDING ("【先】", "先行放送" ),
43+ RATING ("[R]", "視聴制限あり" ),
44+
45+ BS4K ("[4K]", "BS/CS 4K放送" ),
46+ BS8K ("[8K]", "BS 8K放送"),
47+
48+ NOOPTION ("", ""),
49+
50+ BMODE ("[B]", "圧縮Bモードステレオ" ),
51+ NEWS ("[N]", "ニュース" ),
52+ PROGRESSIVE ("[P]", "プログレッシブ放送" ),
53+ STEREO ("[S]", "ステレオ放送" ),
54+ WIDE ("[W]", "ワイド放送" ),
55+ HDTV ("[HV]", "HDTV" ),
56+ MULTIVIEW ("[MV]", "マルチビューテレビ" ),
57+ SDTV ("[SD]", "SDTV" ),
58+ PPV ("[PPV]", "ペイパービュー" ),
59+ SIGN ("[手]", "手話通訳放送" ),
60+ TWOWAY ("[双]", "双方向放送" ),
61+ COMMENTARY ("[解]", "音声解説" ),
62+ WEATHER ("[天]", "天気予報" ),
63+ TRAFFIC ("[交]", "交通情報" ),
64+ MOVIE ("[映]", "劇映画" ),
65+ FREE ("[無]", "無料放送" ),
66+ PAY ("[料]", "有料放送"),
67+ SHOPPING ("[販]", "通販" ),
68+ SURROUND51 ("[5.1]", "5.1chサラウンド" ),
69+ SURROUND222 ("[22.2]", "22.2chサラウンド" ),
70+ HDR ("[HDR]", "ハイダイナミックレンジ" ),
71+ ;
72+
73+ String mark;
74+ String desc;
75+
76+ ProgOption(String m, String d){
77+ mark = m;
78+ desc = d;
79+ }
80+
81+ public String getProgLabel(){ return mark + desc; }
82+ public String getMark(){ return mark; }
83+
84+ public static ProgOption GetProgOptionFromMark(String mark){
85+ for (ProgOption po : ProgOption.values()){
86+ if (po.getMark().equals(mark))
87+ return po;
88+ }
89+
90+ return null;
91+ }
92+ };
4893
4994 public static enum ProgGenre {
5095 NEWS ("ニュース/報道", "0"),
@@ -293,29 +338,52 @@ public interface TVProgram {
293338 };
294339
295340 public static final Object[][] optMarks = {
296- { ProgOption.HIDDEN_NEW, "【新】新番組" },
297- { ProgOption.HIDDEN_LAST, "【終】最終回" },
298- { ProgOption.HIDDEN_NOSCRUMBLE, "【無料】無料放送" },
299- { ProgOption.FIRST, "【初】初回放送" },
300- { ProgOption.PRECEDING, "【先】先行放送" },
301- { ProgOption.NONREPEATED, "[初]リピート放送の初回放送回" },
341+ { ProgOption.HIDDEN_NEW },
342+ { ProgOption.HIDDEN_LAST },
343+ { ProgOption.HIDDEN_NOSCRUMBLE },
344+ { ProgOption.FIRST },
345+ { ProgOption.PRECEDING },
346+ { ProgOption.NONREPEATED },
302347 //{ false, ProgOption.REPEAT, "[再]再放送" },
303- { ProgOption.LIVE, "[生]生放送" },
304- { ProgOption.SPECIAL, "[特]特番" },
305- { ProgOption.RATING, "[R]視聴制限あり" },
306- { ProgOption.SUBTITLE, "[字]文字多重放送" },
307- { ProgOption.MULTIVOICE, "[多]音声多重放送" },
308- { ProgOption.BILINGUAL, "[二]二か国語放送" },
309- { ProgOption.STANDIN, "[吹]吹替放送" },
310- { ProgOption.SURROUND, "[5.1]5.1chサラウンド" },
311- { ProgOption.DATA, "[デ]データ放送" },
312- { ProgOption.PV, "[PV]ペイパービュー" },
313- { ProgOption.NOSYOBO, "[!]しょぼかる未定義" },
314- { ProgOption.NEWARRIVAL, "[NEW]予約待機の新着" },
315- { ProgOption.MODIFIED, "(更)番組詳細に更新あり - 予約待機分のみ" },
316- { ProgOption.MOVED, "(移)先週無かったか時間が違う" },
317- { ProgOption.BS4K, "[4K]BS/CS 4K放送"},
318- { ProgOption.BS8K, "[8K]BS 8K放送"},
348+ { ProgOption.LIVE },
349+ { ProgOption.SPECIAL },
350+ { ProgOption.RATING },
351+ { ProgOption.SUBTITLE },
352+ { ProgOption.MULTIVOICE },
353+ { ProgOption.BILINGUAL },
354+ { ProgOption.STANDIN },
355+ { ProgOption.SURROUND },
356+ { ProgOption.DATA },
357+ { ProgOption.PV },
358+ { ProgOption.NOSYOBO },
359+ { ProgOption.NEWARRIVAL },
360+ { ProgOption.MODIFIED },
361+ { ProgOption.MOVED },
362+ { ProgOption.BS4K},
363+ { ProgOption.BS8K},
364+
365+ { ProgOption.REPEAT },
366+ { ProgOption.BMODE },
367+ { ProgOption.NEWS },
368+ { ProgOption.PROGRESSIVE },
369+ { ProgOption.STEREO },
370+ { ProgOption.WIDE },
371+ { ProgOption.HDTV },
372+ { ProgOption.MULTIVIEW },
373+ { ProgOption.SDTV },
374+ { ProgOption.PPV },
375+ { ProgOption.SIGN },
376+ { ProgOption.TWOWAY },
377+ { ProgOption.COMMENTARY } ,
378+ { ProgOption.WEATHER },
379+ { ProgOption.TRAFFIC },
380+ { ProgOption.MOVIE },
381+ { ProgOption.FREE },
382+ { ProgOption.PAY },
383+ { ProgOption.SHOPPING },
384+ { ProgOption.SURROUND51 },
385+ { ProgOption.SURROUND222 },
386+ { ProgOption.HDR },
319387 };
320388
321389 public static final String[] OKINIIRI = {"★★★★★","★★★★","★★★","★★","★",""};
--- a/TinyBannavi/src/tainavi/TVProgramUtils.java
+++ b/TinyBannavi/src/tainavi/TVProgramUtils.java
@@ -1047,49 +1047,48 @@ public class TVProgramUtils implements Cloneable {
10471047 /*
10481048 * UNIODEの番組記号のマッピング情報
10491049 *
1050- * 無視するオプション:S|N|B|映|双|解|手|天|英|日|録|HV
10511050 */
10521051 enum UnicodeCharMap{
1053- BS4K ("4K" ,0x0001F19E, ProgOption.BS4K),
1054- BS8K ("8K" ,0x0001F19F, ProgOption.BS8K),
1055-
1056- BMODE ("B" ,0x0001F131, ProgOption.NOOPTION),
1057- NEWS ("N" ,0x0001F13D, ProgOption.NOOPTION),
1058-// PROGRESSIVE ("P" ,0x0001F13F),
1059- STEREO ("S" ,0x0001F142, ProgOption.NOOPTION),
1060-// WIDE ("W" ,0x0001F146),
1061- HDTV ("HV" ,0x0001F14A, ProgOption.NOOPTION),
1062-// MULTIVIEW ("MV" ,0x0001F14B),
1063-// SDTV ("SD" ,0x0001F14C),
1052+ BMODE ("B" ,0x0001F131, ProgOption.BMODE),
1053+ NEWS ("N" ,0x0001F13D, ProgOption.NEWS),
1054+ PROGRESSIVE ("P" ,0x0001F13F,ProgOption.PROGRESSIVE),
1055+ STEREO ("S" ,0x0001F142, ProgOption.STEREO),
1056+ WIDE ("W" ,0x0001F146, ProgOption.WIDE),
1057+ HDTV ("HV" ,0x0001F14A, ProgOption.HDTV),
1058+ MULTIVIEW ("MV" ,0x0001F14B, ProgOption.MULTIVIEW),
1059+ SDTV ("SD" ,0x0001F14C, ProgOption.SDTV),
10641060 SURROUND ("SS" ,0x0001F14D, ProgOption.SURROUND),
1065-// PPV ("PPV" ,0x0001F14E),
1061+ PPV ("PPV" ,0x0001F14E, ProgOption.PPV),
10661062
1067- SIGN ("手" ,0x0001F210, ProgOption.NOOPTION),
1063+ SIGN ("手" ,0x0001F210, ProgOption.SIGN),
10681064 SUBTITLE ("字" ,0x0001F211, ProgOption.SUBTITLE),
1069- TWOWAY ("双" ,0x0001F212, ProgOption.NOOPTION),
1065+ TWOWAY ("双" ,0x0001F212, ProgOption.TWOWAY),
10701066 DATA ("デ" ,0x0001F213, ProgOption.DATA),
10711067 BILINGUAL ("二" ,0x0001F214, ProgOption.BILINGUAL),
1072- MULTIPLEX ("多" ,0x0001F215, ProgOption.MULTIVOICE),
1073- COMMENTARY ("解" ,0x0001F216, ProgOption.NOOPTION),
1074- WEATHER ("天" ,0x0001F217, ProgOption.NOOPTION),
1075-// TRAFFIC ("交" ,0x0001F218),
1076- MOVIE ("映" ,0x0001F219, ProgOption.NOOPTION),
1077- FREE ("無" ,0x0001F21A, ProgOption.NOOPTION),
1078- PAY ("料" ,0x0001F21B, ProgOption.PV),
1079-// FORMER ("前" ,0x0001F21C),
1080-// LATTER ("後" ,0x0001F21D),
1081- REAIR ("再" ,0x0001F21E, ProgOption.REPEAT),
1068+ MULTIVOICE ("多" ,0x0001F215, ProgOption.MULTIVOICE),
1069+ COMMENTARY ("解" ,0x0001F216, ProgOption.COMMENTARY),
1070+ WEATHER ("天" ,0x0001F217, ProgOption.WEATHER),
1071+ TRAFFIC ("交" ,0x0001F218, ProgOption.TRAFFIC),
1072+ MOVIE ("映" ,0x0001F219, ProgOption.MOVIE),
1073+ FREE ("無" ,0x0001F21A, ProgOption.FREE),
1074+ PAY ("料" ,0x0001F21B, ProgOption.PAY),
1075+ FORMER ("前" ,0x0001F21C, ProgOption.NOOPTION),
1076+ LATTER ("後" ,0x0001F21D, ProgOption.NOOPTION),
1077+ REPEAT ("再" ,0x0001F21E, ProgOption.REPEAT),
10821078 NEW ("新" ,0x0001F21F, ProgOption.NOOPTION),
10831079 FIRST ("初" ,0x0001F220, ProgOption.FIRST),
10841080 END ("終" ,0x0001F221, ProgOption.NOOPTION),
10851081 LIVE ("生" ,0x0001F222, ProgOption.LIVE),
1086-// SHOPPING ("販" ,0x0001F223),
1087-// VOICE ("声" ,0x0001F224),
1088- DUBBED ("吹" ,0x0001F225, ProgOption.STANDIN),
1082+ SHOPPING ("販" ,0x0001F223, ProgOption.SHOPPING),
1083+ VOICE ("声" ,0x0001F224, ProgOption.NOOPTION),
1084+ STANDIN ("吹" ,0x0001F225, ProgOption.STANDIN),
10891085
1090- SURROUND51 ("5.1" ,0x0001F1A0, ProgOption.NOOPTION),
1091- SURROUND222 ("22.2" ,0x0001F1A2, ProgOption.NOOPTION),
1092- HDR ("HDR" ,0x0001F1A7, ProgOption.NOOPTION),
1086+ // テレビ王国の独自コード
1087+ BS4K ("4K" ,0x0001F19E, ProgOption.BS4K),
1088+ BS8K ("8K" ,0x0001F19F, ProgOption.BS8K),
1089+ SURROUND51 ("5.1" ,0x0001F1A0, ProgOption.SURROUND51),
1090+ SURROUND222 ("22.2" ,0x0001F1A2, ProgOption.SURROUND222),
1091+ HDR ("HDR" ,0x0001F1A7, ProgOption.HDR),
10931092 ;
10941093
10951094 String label; // ラベル
@@ -1109,12 +1108,9 @@ public class TVProgramUtils implements Cloneable {
11091108 progOption = po;
11101109 }
11111110
1112- /**
1113- * ラベルを取得する
1114- *
1115- * @return ラベル
1116- */
11171111 public String getLabel(){ return label; }
1112+ public String getCode(){ return cp2s(codePoint); }
1113+ public ProgOption getProgOption(){ return progOption; }
11181114
11191115 /**
11201116 * 指定した文字列で検索する
@@ -1145,10 +1141,44 @@ public class TVProgramUtils implements Cloneable {
11451141 *
11461142 * @param pdl 番組情報
11471143 */
1144+ private static String codeList = null;
11481145 public static void ExtractAllSymbols(ProgDetailList pdl){
1146+ if (codeList == null){
1147+ StringBuilder sb = new StringBuilder("");
1148+ for (UnicodeCharMap chm : UnicodeCharMap.values()){
1149+ sb.append(chm.getCode());
1150+ }
1151+
1152+ codeList = sb.toString();
1153+ }
1154+
1155+ Matcher md = Pattern.compile("[" + codeList + "]").matcher(pdl.title);
1156+ boolean found = false;
1157+ while (md.find()){
1158+ UnicodeCharMap chm = getMapFromCode(md.group());
1159+ if (chm != null && chm.getProgOption() != ProgOption.NOOPTION)
1160+ pdl.addOption(chm.getProgOption());
1161+ found = true;
1162+ }
1163+
1164+ if (found)
1165+ pdl.title = md.replaceAll("");
1166+ }
1167+
1168+ /**
1169+ * 文字コードからマップ情報を取得する
1170+ *
1171+ * @param code 文字コード
1172+ * @return マップ情報
1173+ */
1174+ public static UnicodeCharMap getMapFromCode(String code){
11491175 for (UnicodeCharMap chm : UnicodeCharMap.values()){
1150- chm.extractSymbol(pdl);
1176+ if (code.equals(chm.getCode())){
1177+ return chm;
1178+ }
11511179 }
1180+
1181+ return null;
11521182 }
11531183 }
11541184
@@ -1184,6 +1214,7 @@ public class TVProgramUtils implements Cloneable {
11841214 * タイトルからフラグを抽出する
11851215 */
11861216 protected void doSplitFlags(ProgDetailList pdl, HashMap<String, String> nf) {
1217+ // テレビ王国のUNICODE記号を抽出する
11871218 ExtractAllUnicodeSymbols(pdl);
11881219
11891220 Matcher md = Pattern.compile("(#1|第1話)\\b").matcher(pdl.title);
@@ -1233,78 +1264,60 @@ public class TVProgramUtils implements Cloneable {
12331264
12341265 HashMap<String, String> xf = new HashMap<String, String>();
12351266
1236- String flagExpr = "[\\[[((【](.{1,3})[\\]]))】]";
1267+ String flagExpr = "[\\[[((【]([^\\]]))】]{1,4})[\\]]))】]";
12371268 Matcher mx = Pattern.compile(flagExpr).matcher(pdl.title);
12381269 while (mx.find()) {
1239- if (mx.group(1).equals("新") || mx.group(1).equals("新番組")) {
1270+ String mark = mx.group(1);
1271+ ProgOption po = ProgOption.GetProgOptionFromMark("[" + mark + "]");
1272+
1273+ if (mark.equals("新") || mark.equals("新番組")) {
12401274 pdl.flag = ProgFlags.NEW;
12411275 }
1242- else if (mx.group(1).equals("終") || mx.group(1).equals("完") || mx.group(1).equals("最終回")) {
1276+ else if (mark.equals("終") || mark.equals("完") || mark.equals("最終回")) {
12431277 pdl.flag = ProgFlags.LAST;
12441278 }
1245- else if (mx.group(1).equals("再")) {
1279+ else if (mark.equals("再")) {
12461280 pdl.addOption(ProgOption.REPEAT);
12471281 }
1248- else if (mx.group(1).equals("初")) {
1282+ else if (mark.equals("初")) {
12491283 pdl.addOption(ProgOption.FIRST);
12501284 }
1251- else if (mx.group(1).equals("生")) {
1252- pdl.addOption(ProgOption.LIVE);
1285+ else if (mark.equals("無") || mark.equals("無料")) {
1286+ //pdl.addOption(ProgOption.NOSCRUMBLE);
1287+ pdl.noscrumble = ProgScrumble.NOSCRUMBLE;
12531288 }
1254-
1255- else if (mx.group(1).equals("二/吹")) {
1289+ else if (mark.equals("二/吹")) {
12561290 pdl.addOption(ProgOption.BILINGUAL);
12571291 pdl.addOption(ProgOption.STANDIN);
12581292 }
1259- else if (mx.group(1).equals("字") || mx.group(1).equals("字幕") || mx.group(1).equals("字幕版")) {
1293+ else if (mark.equals("字幕") || mark.equals("字幕版")) {
12601294 pdl.addOption(ProgOption.SUBTITLE);
12611295 }
1262- else if (mx.group(1).equals("二")) {
1263- pdl.addOption(ProgOption.BILINGUAL);
1264- }
1265- else if (mx.group(1).equals("多")) {
1266- pdl.addOption(ProgOption.MULTIVOICE);
1267- }
1268- else if (mx.group(1).equals("SS") || mx.group(1).equals("5.1")) {
1269- pdl.addOption(ProgOption.SURROUND);
1270- }
1271- else if (mx.group(1).equals("吹") || mx.group(1).equals("吹替") || mx.group(1).equals("吹替版")) {
1296+ else if (mark.equals("吹替") || mark.equals("吹替版")) {
12721297 pdl.addOption(ProgOption.STANDIN); // (ないよ)
12731298 }
1274- else if (mx.group(1).equals("デ")) {
1275- pdl.addOption(ProgOption.DATA);
1276- }
1277- else if (mx.group(1).equals("無") || mx.group(1).equals("無料")) {
1278- //pdl.addOption(ProgOption.NOSCRUMBLE);
1279- pdl.noscrumble = ProgScrumble.NOSCRUMBLE;
1280- }
1281- else if (mx.group(1).equals("4K")) {
1282- pdl.addOption(ProgOption.BS4K);
1283- }
1284- else if (mx.group(1).equals("8K")) {
1285- pdl.addOption(ProgOption.BS8K);
1286- }
1287-
1288- else if (mx.group(1).matches("^(S|N|B|映|双|解|手|天|英|日|録|HV)$")) {
1299+ else if (po != null && po != ProgOption.NOOPTION)
1300+ pdl.addOption(po);
1301+ else if (mark.matches("^(S|N|B|映|双|解|手|天|英|日|録|HV)$")) {
12891302 // 無視するフラグ
1290- if ( mx.group(1).equals("日") && ( ! pdl.title.matches(String.format("^(%s)*[((]日[))].*", flagExpr)) && ! pdl.title.matches(".*[\\[[]日[\\]]].*")) ) {
1303+ if ( mark.equals("日") && ( ! pdl.title.matches(String.format("^(%s)*[((]日[))].*", flagExpr)) && ! pdl.title.matches(".*[\\[[]日[\\]]].*")) ) {
12911304 // 削除しないフラグ(特殊)
12921305 continue;
12931306 }
12941307 }
1295- else if (mx.group(1).matches("^(韓|仮|[前後][編篇半]|[月火水木金土]|[0-90-9]+)$")) {
1308+ else if (mark.matches("^(韓|仮|[前後][編篇半]|[月火水木金土]|[0-90-9]+)$")) {
12961309 // 削除しないフラグ
12971310 continue;
12981311 }
12991312
13001313 else {
13011314 // 未知のフラグ
1302- nf.put(mx.group(1),null);
1315+ nf.put(mark, null);
13031316 continue;
13041317 }
13051318
13061319 // 削除するフラグ
1307- xf.put(mx.group(1), null);
1320+ xf.put(mark, null);
13081321 }
13091322 {
13101323 // 認識されたフラグだけ削除する.
--- a/TinyBannavi/src/tainavi/VersionInfo.java
+++ b/TinyBannavi/src/tainavi/VersionInfo.java
@@ -5,7 +5,7 @@ import java.util.regex.Pattern;
55
66
77 public class VersionInfo {
8- private static final String Version = "タイニー番組ナビゲータ for DBR-T2007 3.22.18β+1.13.2";
8+ private static final String Version = "タイニー番組ナビゲータ for DBR-T2007 3.22.18β+1.13.3";
99
1010 private static final String OSname = System.getProperty("os.name");
1111 private static final String OSvers = System.getProperty("os.version");
--- a/TinyBannavi/src/tainavi/Viewer.java
+++ b/TinyBannavi/src/tainavi/Viewer.java
@@ -114,7 +114,7 @@ public class Viewer extends JFrame implements ChangeListener,TickTimerListener,H
114114
115115 // 設定値をいれるところ
116116 private final Env env = Env.TheEnv = new Env(); // 主要な設定
117- private final Bounds bounds = new Bounds(); // ウィンドウサイズとか動的に変化するもの
117+ private final Bounds bounds = Bounds.TheBounds = new Bounds(); // ウィンドウサイズとか動的に変化するもの
118118 private final ClipboardInfoList cbitems = new ClipboardInfoList(); // クリップボード対応機能でどの項目をコピーするかとかの設定
119119 private final ListedColumnInfoList lvitems = new ListedColumnInfoList(); // リスト形式ビューの表示項目
120120 private final ReserveListColumnInfoList rlitems = new ReserveListColumnInfoList();
@@ -2746,13 +2746,20 @@ public class Viewer extends JFrame implements ChangeListener,TickTimerListener,H
27462746 for (final TextValueSet tv : env.getTvCommand()) {
27472747 JMenuItem menuItem = new JMenuItem(tv.getText());
27482748
2749+ String body = "";
2750+ Matcher ma = Pattern.compile("^(.*)[  ]").matcher(tvd.title);
2751+ if (ma.find())
2752+ body = ma.group(1);
2753+
27492754 String escepedTitle = "";
27502755 String escepedChName = "";
27512756 String escepedDetail = "";
2757+ String escepedBody = "";
27522758 try {
27532759 escepedTitle = URLEncoder.encode(tvd.title,"UTF-8");
27542760 escepedDetail = URLEncoder.encode(tvd.detail,"UTF-8");
27552761 escepedChName = URLEncoder.encode(tvd.center,"UTF-8");
2762+ escepedBody = URLEncoder.encode(body,"UTF-8");
27562763 } catch (UnsupportedEncodingException e2) {
27572764 //
27582765 }
@@ -2776,6 +2783,7 @@ public class Viewer extends JFrame implements ChangeListener,TickTimerListener,H
27762783 cmd = cmd.replaceAll("%END%", tvd.end);
27772784 cmd = cmd.replaceAll("%DETAILURL%", tvd.link);
27782785 cmd = cmd.replaceAll("%SYOBODETAILURL%", tvd.linkSyobo != null ? tvd.linkSyobo : "");
2786+ cmd = cmd.replaceAll("%ENCBODY%", escepedBody);
27792787
27802788 // CHAN-TORU対応
27812789 if ( cmd.matches(".*%TVKAREACODE%.*") && cmd.matches(".*%TVKPID%.*") ) {
@@ -4942,6 +4950,8 @@ public class Viewer extends JFrame implements ChangeListener,TickTimerListener,H
49424950 if ( reload_prog ) {
49434951 loadTVProgram(false, LoadFor.ALL, false); // 部品呼び出し
49444952 }
4953+ else
4954+ loadTVProgramPostProcess(false);
49454955
49464956 // Web番組表の再構築
49474957 mpList.setHistoryOnlyUpdateOnce(env.getHistoryOnlyUpdateOnce());