OSDN Git Service

自動予約編集への対応に伴うレイアウト変更(3)
[tainavi/TinyBannavi.git] / TinyBannavi / src / tainavi / AbsListedView.java
1 package tainavi;\r
2 \r
3 import java.awt.BorderLayout;\r
4 import java.awt.Color;\r
5 import java.awt.Component;\r
6 import java.awt.Desktop;\r
7 import java.awt.Dimension;\r
8 import java.awt.Point;\r
9 import java.awt.event.ActionEvent;\r
10 import java.awt.event.ActionListener;\r
11 import java.awt.event.ComponentAdapter;\r
12 import java.awt.event.ComponentEvent;\r
13 import java.awt.event.ComponentListener;\r
14 import java.awt.event.MouseAdapter;\r
15 import java.awt.event.MouseEvent;\r
16 import java.awt.event.MouseListener;\r
17 import java.io.File;\r
18 import java.io.IOException;\r
19 import java.net.URI;\r
20 import java.net.URISyntaxException;\r
21 import java.util.ArrayList;\r
22 import java.util.Calendar;\r
23 import java.util.Comparator;\r
24 import java.util.GregorianCalendar;\r
25 import java.util.HashMap;\r
26 import java.util.Map.Entry;\r
27 import java.util.regex.Matcher;\r
28 import java.util.regex.Pattern;\r
29 \r
30 import javax.swing.ButtonGroup;\r
31 import javax.swing.JComponent;\r
32 import javax.swing.JMenuItem;\r
33 import javax.swing.JOptionPane;\r
34 import javax.swing.JPanel;\r
35 import javax.swing.JPopupMenu;\r
36 import javax.swing.JRadioButtonMenuItem;\r
37 import javax.swing.JScrollPane;\r
38 import javax.swing.JSplitPane;\r
39 import javax.swing.JTable;\r
40 import javax.swing.JTree;\r
41 import javax.swing.SwingConstants;\r
42 import javax.swing.SwingUtilities;\r
43 import javax.swing.event.ListSelectionEvent;\r
44 import javax.swing.event.ListSelectionListener;\r
45 import javax.swing.event.RowSorterEvent;\r
46 import javax.swing.event.RowSorterEvent.Type;\r
47 import javax.swing.event.RowSorterListener;\r
48 import javax.swing.event.TableModelEvent;\r
49 import javax.swing.event.TreeExpansionEvent;\r
50 import javax.swing.event.TreeExpansionListener;\r
51 import javax.swing.event.TreeSelectionEvent;\r
52 import javax.swing.event.TreeSelectionListener;\r
53 import javax.swing.table.DefaultTableCellRenderer;\r
54 import javax.swing.table.DefaultTableColumnModel;\r
55 import javax.swing.table.DefaultTableModel;\r
56 import javax.swing.table.TableCellRenderer;\r
57 import javax.swing.table.TableColumn;\r
58 import javax.swing.table.TableModel;\r
59 import javax.swing.table.TableRowSorter;\r
60 import javax.swing.tree.DefaultMutableTreeNode;\r
61 import javax.swing.tree.DefaultTreeModel;\r
62 import javax.swing.tree.TreeNode;\r
63 import javax.swing.tree.TreePath;\r
64 import javax.swing.tree.TreeSelectionModel;\r
65 \r
66 import tainavi.TVProgram.ProgFlags;\r
67 import tainavi.TVProgram.ProgGenre;\r
68 import tainavi.TVProgram.ProgSubgenre;\r
69 import tainavi.TVProgram.ProgSubtype;\r
70 import tainavi.TVProgram.ProgType;\r
71 import tainavi.TVProgramIterator.IterationType;\r
72 import tainavi.VWMainWindow.MWinTab;\r
73 \r
74 \r
75 /**\r
76  * リスト形式タブのクラス\r
77  * @since 3.15.4β {@link Viewer}から分離\r
78  */\r
79 public abstract class AbsListedView extends JPanel implements TickTimerListener {\r
80 \r
81         private static final long serialVersionUID = 1L;\r
82         \r
83         public static String getViewName() { return "リスト形式"; } \r
84         \r
85         public void setDebug(boolean b) { debug = b; }\r
86         private static boolean debug = false;\r
87         \r
88         \r
89         /*******************************************************************************\r
90          * 抽象メソッド\r
91          ******************************************************************************/\r
92         \r
93         protected abstract Env getEnv();\r
94         protected abstract Bounds getBoundsEnv();\r
95         protected abstract ChannelSort getChannelSort();\r
96         \r
97         protected abstract MarkedProgramList getMarkedProgramList();\r
98         protected abstract TraceProgram getTraceProgram();\r
99         protected abstract SearchProgram getSearchProgram();\r
100         protected abstract SearchGroupList getSearchGroupList();\r
101         protected abstract ExtProgram getExtProgram();\r
102         \r
103         protected abstract TVProgramList getTVProgramList();\r
104         protected abstract HDDRecorderList getRecorderList();\r
105         \r
106         protected abstract StatusWindow getStWin(); \r
107         protected abstract StatusTextArea getMWin();\r
108         protected abstract AbsReserveDialog getReserveDialog();\r
109         \r
110         protected abstract Component getParentComponent();\r
111         \r
112         protected abstract void ringBeep();\r
113         \r
114         // クラス内のイベントから呼び出されるもの\r
115         \r
116         /**\r
117          * タブが開いた\r
118          */\r
119         protected abstract void onShown();\r
120         /**\r
121          * タブが閉じた\r
122          */\r
123         protected abstract void onHidden();\r
124         \r
125         /**\r
126          * マウス右クリックメニューを表示する\r
127          */\r
128         protected abstract void showPopupForTraceProgram(\r
129                         final JComponent comp,\r
130                         final ProgDetailList tvd, final String keyword, final int threshold,\r
131                         final int x, final int y, final int h\r
132                         );\r
133 \r
134         /**\r
135          * 予約マーク・予約枠を更新してほしい\r
136          */\r
137         protected abstract void updateReserveDisplay(String chname);\r
138 \r
139         /**\r
140          * 番組枠を更新してほしい\r
141          */\r
142         protected abstract void updateBangumiColumns();\r
143 \r
144         \r
145         /**\r
146          * 開けてくれ!\r
147          */\r
148         protected abstract void clearPaper();\r
149         \r
150         /**\r
151          * ぷれびゅりたいお\r
152          */\r
153         protected abstract void previewKeywordSearch(SearchKey search);\r
154         //protected abstract void previewExtensionSearch(SearchKey search);\r
155         /**\r
156          * 新聞形式にジャンプしてほしい\r
157          */\r
158         protected abstract void jumpToPaper(String Center, String StartDateTime);\r
159         \r
160         /**\r
161          * ピックアップに追加してほしい\r
162          */\r
163         protected abstract boolean addToPickup(final ProgDetailList tvd);\r
164         \r
165         protected abstract boolean isTabSelected(MWinTab tab);\r
166         protected abstract void setSelectedTab(MWinTab tab);\r
167 \r
168         /**\r
169          * @see Viewer.VWToolBar#getSelectedRecorder()\r
170          */\r
171         protected abstract String getSelectedRecorderOnToolbar();\r
172         protected abstract boolean isFullScreen();\r
173         //protected abstract void setPagerItems(int total_page, int idx);\r
174         protected abstract void setPagerEnabled(boolean b);\r
175         protected abstract int getPagerCount();\r
176         protected abstract int getSelectedPagerIndex();\r
177 \r
178         /**\r
179          * ツリーペーンの幅の変更を保存してほしい\r
180          */\r
181         protected abstract void setDividerEnvs(int loc);\r
182 \r
183         \r
184         /*******************************************************************************\r
185          * 呼び出し元から引き継いだもの\r
186          ******************************************************************************/\r
187         \r
188         // オブジェクト\r
189         private final Env env = getEnv();\r
190         private final Bounds bounds = getBoundsEnv();\r
191         private final ChannelSort chsort = getChannelSort();\r
192         \r
193         private final MarkedProgramList mpList = getMarkedProgramList();;\r
194         private final TraceProgram trKeys = getTraceProgram();\r
195         private final SearchProgram srKeys = getSearchProgram();\r
196         private final SearchGroupList srGrps = getSearchGroupList();\r
197         private final ExtProgram extKeys = getExtProgram();\r
198         \r
199         private final TVProgramList tvprograms = getTVProgramList();\r
200         private final HDDRecorderList recorders = getRecorderList();\r
201 \r
202         private final StatusWindow StWin = getStWin();                  // これは起動時に作成されたまま変更されないオブジェクト\r
203         private final StatusTextArea MWin = getMWin();                  // これは起動時に作成されたまま変更されないオブジェクト\r
204         private final AbsReserveDialog rD = getReserveDialog(); // これは起動時に作成されたまま変更されないオブジェクト\r
205         \r
206         private final Component parent = getParentComponent();  // これは起動時に作成されたまま変更されないオブジェクト\r
207 \r
208         // メソッド\r
209         private void StdAppendMessage(String message) { System.out.println(message); }\r
210         private void StdAppendError(String message) { System.err.println(message); }\r
211         //private void StWinSetVisible(boolean b) { StWin.setVisible(b); }\r
212         //private void StWinSetLocationCenter(Component frame) { CommonSwingUtils.setLocationCenter(frame, (VWStatusWindow)StWin); }\r
213         \r
214         \r
215         /*******************************************************************************\r
216          * 定数\r
217          ******************************************************************************/\r
218         \r
219         private static final String MSGID = "["+getViewName()+"] ";\r
220         private static final String ERRID = "[ERROR]"+MSGID;\r
221         private static final String DBGID = "[DEBUG]"+MSGID;\r
222         \r
223         \r
224         /**\r
225          * メインテーブルのカラムの定義\r
226          */\r
227         private static final HashMap<String,Integer> lcmap = new HashMap<String, Integer>();\r
228         public static HashMap<String,Integer> getColumnIniWidthMap() {\r
229                 if (lcmap.size() == 0 ) {\r
230                         for ( ListedColumn lc : ListedColumn.values() ) {\r
231                                 lcmap.put(lc.toString(),lc.getIniWidth());      // toString()!\r
232                         }\r
233                 }\r
234                 return lcmap;\r
235         }\r
236         \r
237         /**\r
238          * テーブルのカラムの設定(名前と幅の初期値)。できれば@{link {@link ListedItem}と一体化させたかったのだが無理っぽい\r
239          * @see ListedItem\r
240          */\r
241         public static enum ListedColumn {\r
242                 RSVMARK         ("予約",                      35),\r
243                 DUPMARK         ("重複",                      35),\r
244                 CHNAME          ("チャンネル名",  100),\r
245                 OPTIONS         ("オプション",             100),\r
246                 TITLE           ("番組タイトル",  300),\r
247                 DETAIL          ("番組詳細",                200),\r
248                 START           ("開始時刻",                150),\r
249                 END                     ("終了",                      50),\r
250                 LENGTH          ("長さ",                      50),\r
251                 GENRE           ("ジャンル",                85),\r
252                 SITEM           ("検索アイテム名",       100),\r
253                 STAR            ("お気に入り度",  100),\r
254                 SCORE           ("スコア",                   35),\r
255                 THRESHOLD       ("閾値",                      35),\r
256                 ;\r
257 \r
258                 private String name;\r
259                 private int iniWidth;\r
260 \r
261                 private ListedColumn(String name, int iniWidth) {\r
262                         this.name = name;\r
263                         this.iniWidth = iniWidth;\r
264                 }\r
265 \r
266                 public String getName() {\r
267                         return name;\r
268                 }\r
269 \r
270                 public int getIniWidth() {\r
271                         return iniWidth;\r
272                 }\r
273                 \r
274                 public int getColumn() {\r
275                         return ordinal();\r
276                 }\r
277                 \r
278                 public boolean equals(String s) {\r
279                         return name.equals(s);\r
280                 }\r
281         };\r
282 \r
283         /**\r
284          * 検索範囲(番組追跡か、キーワード検索か、予約待機か)\r
285          */\r
286         private static enum SearchBy { TRACE, KEYWORD, BOTH } ;\r
287         \r
288         public static final String RSVMARK_NOEXEC               = "×"; // 予約無効\r
289         public static final String RSVMARK_NORMAL               = "●";        // ぴったり\r
290         public static final String RSVMARK_OVERRUN              = "◎";        // のりしろより大きく予約時間がとられている\r
291         public static final String RSVMARK_UNDERRUN             = "○";        // 時間延長が考慮されていない\r
292         public static final String RSVMARK_DELAYED              = "◇";        // 開始時刻が一致しない\r
293         public static final String RSVMARK_CLIPPED              = "▲";        // 1分短縮済み\r
294         public static final String RSVMARK_CLIPPED_E    = "△";        // 1分短縮済み(延長警告あり)\r
295         public static final String RSVMARK_SHORTAGE             = "▼";        // 2分以上短かい\r
296         public static final String RSVMARK_SHORTAGE_E   = "▽";        // 2分以上短かい(延長警告あり)\r
297         \r
298         public static final String RSVMARK_PICKUP               = "★";        // ピックアップ\r
299         public static final String RSVMARK_URABAN               = "■";        // 裏番組\r
300         private static final String PICKUP_COLOR                = CommonUtils.color2str(Color.BLACK);\r
301         private static final String URABAN_COLOR                = CommonUtils.color2str(Color.BLACK);\r
302 \r
303         private static final String DUPMARK_NORMAL              = "■";\r
304         private static final String DUPMARK_REP                 = "□";\r
305         private static final String DUPMARK_COLOR               = "#FFB6C1";\r
306         \r
307         private static final String TreeExpRegFile_Listed = "env"+File.separator+"tree_expand_listed.xml";\r
308         \r
309         private final String SearchItemLabel_Passed = JTreeLabel.Nodes.PASSED.getLabel();       // 過去ログの名前\r
310         \r
311         // 定数ではないが\r
312         \r
313         private int vrowInFocus = -1;   // マウスクリックした時のフォーカス行\r
314         \r
315         \r
316         /*******************************************************************************\r
317          * 部品\r
318          ******************************************************************************/\r
319         \r
320         // コンポーネント\r
321         \r
322         private JDetailPanel jTextPane_detail = null;\r
323         private JSplitPane jSplitPane_view = null;\r
324         private JPanel jPanel_tree = null;\r
325         private JScrollPane jScrollPane_tree_top = null;\r
326         private JTreeLabel jLabel_tree = null;\r
327         private JScrollPane jScrollPane_tree = null;\r
328         private JTree jTree_tree = null;\r
329         private JScrollPane jScrollPane_listed = null;\r
330         private JTableRowHeader jTable_rowheader = null;\r
331         private ListedTable jTable_listed = null;\r
332         private VWColorCharCellRenderer2 titleCellRenderer = null;\r
333         \r
334         private VWListedTreeNode listRootNode = null;           // リスト形式のツリー\r
335         \r
336         VWListedTreeNode searchedNode   = null;\r
337         VWListedTreeNode startNode              = null;\r
338         VWListedTreeNode endNode                = null;\r
339         VWListedTreeNode nowNode                = null;\r
340         VWListedTreeNode syobocalNode   = null;\r
341         VWListedTreeNode standbyNode    = null;\r
342         VWListedTreeNode traceNode              = null;\r
343         VWListedTreeNode keywordNode    = null;\r
344         VWListedTreeNode keywordGrpNode = null;\r
345         VWListedTreeNode genreNode              = null;\r
346         VWListedTreeNode centerListNode = null;\r
347         VWListedTreeNode extensionNode  = null;\r
348         \r
349         VWListedTreeNode defaultNode    = null;\r
350         \r
351         private ListedTableModel tableModel_listed = null;\r
352         \r
353         private DefaultTableModel rowheaderModel_listed = null;\r
354         \r
355         // コンポーネント以外\r
356         \r
357         // テーブルの実態\r
358         private final RowItemList<ListedItem> rowData = new RowItemList<ListedItem>();\r
359         \r
360         // ツリーの展開状態の保存場所\r
361         TreeExpansionReg ter = null;\r
362         \r
363         // 現在放送中のタイマー\r
364         private boolean timer_now_enabled = false;\r
365         \r
366         \r
367         /*******************************************************************************\r
368          * コンストラクタ\r
369          ******************************************************************************/\r
370         \r
371         public AbsListedView() {\r
372                 \r
373                 super();\r
374                 \r
375                 // コンポーネントを追加\r
376                 this.setLayout(new BorderLayout());\r
377                 this.add(getJTextPane_detail(), BorderLayout.PAGE_START);\r
378                 this.add(getJSplitPane_view(), BorderLayout.CENTER);\r
379                 \r
380                 // バグ対応\r
381                 if ( bounds.getListedColumnSize() == null ) {\r
382                         StWin.appendError(ERRID+"なんらかの不具合によりテーブルのカラム幅設定が取得できませんでした。設定はリセットされました。申し訳ありません。");\r
383                         bounds.setListedColumnSize(lcmap);\r
384                 }\r
385                 else {\r
386                         for ( Entry<String, Integer> en : lcmap.entrySet() ) {\r
387                                 try {\r
388                                         bounds.getListedColumnSize().get(en.getKey());\r
389                                 }\r
390                                 catch (NullPointerException e) {\r
391                                         System.err.println(ERRID+en.getKey()+", "+e.toString());\r
392                                         bounds.getListedColumnSize().put(en.getKey(),en.getValue());\r
393                                 }\r
394                         }\r
395                 }\r
396                 \r
397                 // タブが開いたり閉じたりしたときの処理\r
398                 this.addComponentListener(cl_tabshownhidden);\r
399         }\r
400         \r
401         \r
402         /*******************************************************************************\r
403          * アクション\r
404          ******************************************************************************/\r
405         \r
406         // このクラスの肝、リスト表示について。\r
407         \r
408         /*\r
409          *  検索総当り版\r
410          */\r
411         \r
412         /**\r
413          * 検索条件\r
414          */\r
415         private class RedrawCond {\r
416                 ProgType progtype = null;\r
417                 SearchKey searchkeyword = null;\r
418                 ProgFlags flag = null;\r
419                 ProgGenre genre = null;\r
420                 ProgSubgenre subgenre = null;\r
421                 String center = null;\r
422                 String targetdate = null;\r
423         }\r
424         \r
425         /**\r
426          *  プレビュー表示とか(親から呼ばれるよ!)\r
427          * @see #redrawListByKeywordDyn(SearchKey, String)\r
428          * @see #redrawListByPassed(SearchKey, String)\r
429          * @see #redrawListByKeywordFilter(SearchKey, String)\r
430          */\r
431         public void redrawListByPreview(SearchKey sKey) {\r
432                 stopTimer(true);\r
433                 jLabel_tree.setView(JTreeLabel.Nodes.SEARCHED, JTreeLabel.PREVIEW);\r
434                 redrawListByKeywordDyn(sKey);\r
435         }\r
436         \r
437         /**\r
438          *  キーワード検索ボックスとか(親から呼ばれるよ!)\r
439          */\r
440         public void redrawListByKeywordDyn(SearchKey sKey, String target) {\r
441                 stopTimer(true);\r
442                 jLabel_tree.setView(JTreeLabel.Nodes.SEARCHED, target);\r
443                 redrawListByKeywordDyn(sKey);\r
444         }       \r
445         \r
446         \r
447         // キーワード検索結果に基づきリストを作成(動的)\r
448         // (1)延長警告管理、(2)ツールバーからの検索\r
449         private void redrawListByKeywordDyn(SearchKey sKey) {\r
450                 rowData.clear();\r
451                 RedrawCond c = new RedrawCond();\r
452                 c.progtype = ProgType.PROG;\r
453                 c.searchkeyword = sKey;\r
454                 _redrawListBy(c);\r
455                 //_redrawListBy(ProgType.RADIO,sKey,null,null,null,null);\r
456                 setReservedMarks();\r
457                 tableModel_listed.fireTableDataChanged();\r
458                 rowheaderModel_listed.fireTableDataChanged();\r
459                 \r
460                 setOverlapMark();\r
461         }\r
462         private void redrawListByExtkeywordAll(ArrayList<SearchKey> sKeys) {\r
463                 rowData.clear();\r
464                 RedrawCond c = new RedrawCond();\r
465                 c.progtype = ProgType.PROG;\r
466                 for (SearchKey sKey : sKeys) { \r
467                         c.searchkeyword = sKey;\r
468                         _redrawListBy(c);\r
469                 }\r
470                 setReservedMarks();\r
471                 tableModel_listed.fireTableDataChanged();\r
472                 rowheaderModel_listed.fireTableDataChanged();\r
473                 \r
474                 setOverlapMark();\r
475         }\r
476         // フラグに基づきリストを作成\r
477         private void redrawListByFlag(ProgFlags flag) {\r
478                 rowData.clear();\r
479                 RedrawCond c = new RedrawCond();\r
480                 c.progtype = ProgType.PROG;\r
481                 c.flag = flag;\r
482                 _redrawListBy(c);\r
483                 setReservedMarks();\r
484                 tableModel_listed.fireTableDataChanged();\r
485                 rowheaderModel_listed.fireTableDataChanged();\r
486                 \r
487                 setOverlapMark();\r
488         }\r
489         // フラグ+ジャンルでリストを作成\r
490         private void redrawListByFlag(ProgFlags flag, ProgGenre genre) {\r
491                 rowData.clear();\r
492                 RedrawCond c = new RedrawCond();\r
493                 c.progtype = ProgType.PROG;\r
494                 c.genre = genre;\r
495                 c.flag = flag;\r
496                 _redrawListBy(c);\r
497                 setReservedMarks();\r
498                 tableModel_listed.fireTableDataChanged();\r
499                 rowheaderModel_listed.fireTableDataChanged();\r
500                 \r
501                 setOverlapMark();\r
502         }\r
503         // 現在時刻で絞り込み\r
504         private void redrawListByNow(ProgGenre genre) {\r
505                 jTable_listed.getRowSorter().setSortKeys(null); // ソーターをリセットする\r
506                 rowData.clear();\r
507                 RedrawCond c = new RedrawCond();\r
508                 c.progtype = ProgType.PROG;\r
509                 c.genre = genre;\r
510                 c.targetdate = "";\r
511                 _redrawListBy(c);       // target == ""は現在日時しぼりこみ\r
512                 setReservedMarks();\r
513                 tableModel_listed.fireTableDataChanged();\r
514                 rowheaderModel_listed.fireTableDataChanged();\r
515                 \r
516                 setOverlapMark();\r
517         }\r
518         // ジャンル検索結果に基づきリストを作成\r
519         private void redrawListByGenre(ProgGenre genre, ProgSubgenre subgenre) {\r
520                 rowData.clear();\r
521                 RedrawCond c = new RedrawCond();\r
522                 c.progtype = ProgType.PROG;\r
523                 c.genre = genre;\r
524                 c.subgenre = subgenre;\r
525                 _redrawListBy(c);\r
526                 setReservedMarks();\r
527                 tableModel_listed.fireTableDataChanged();\r
528                 rowheaderModel_listed.fireTableDataChanged();\r
529                 \r
530                 setOverlapMark();\r
531         }\r
532         // 放送局ごとにリストを作成\r
533         private void redrawListByCenterList(String center) {\r
534                 rowData.clear();\r
535                 RedrawCond c = new RedrawCond();\r
536                 c.progtype = ProgType.PROG;\r
537                 c.center = center;\r
538                 _redrawListBy(c);\r
539                 setReservedMarks();\r
540                 tableModel_listed.fireTableDataChanged();\r
541                 rowheaderModel_listed.fireTableDataChanged();\r
542                 \r
543                 //setOverlapMark();\r
544         }\r
545         \r
546         /**\r
547          *  しょぼーん\r
548          */\r
549         private void redrawSyobocalAll() {\r
550                 rowData.clear();\r
551                 RedrawCond c = new RedrawCond();\r
552                 c.progtype = ProgType.SYOBO;\r
553                 _redrawListBy(c);\r
554                 tableModel_listed.fireTableDataChanged();\r
555                 rowheaderModel_listed.fireTableDataChanged();\r
556                 setReservedMarks();\r
557         }\r
558 \r
559         /**\r
560          * 検索総当り版の本体(全件に対して検索処理をかける)\r
561          */\r
562         private void _redrawListBy(RedrawCond cond) {\r
563                 \r
564                 String curDateTime = CommonUtils.getDateTime(0);\r
565                 String critDateTime = CommonUtils.getCritDateTime();\r
566                 \r
567                 for ( TVProgram tvp : tvprograms ) {\r
568                         if (tvp.getType() != cond.progtype) {\r
569                                 continue;\r
570                         }\r
571                         \r
572                         for ( ProgList tvpl : tvp.getCenters() ) {\r
573                                 if ( ! tvpl.enabled ) {\r
574                                         // 有効局のみだよ\r
575                                         continue;\r
576                                 }\r
577                                 if (cond.center != null && ! cond.center.equals(tvpl.Center)) {\r
578                                         // 放送局指定があれば\r
579                                         continue;\r
580                                 }\r
581                                 \r
582                                 // キーワード検索用\r
583                                 String centerPop = TraceProgram.replacePop(tvpl.Center);\r
584                                 \r
585                                 for ( ProgDateList tvc : tvpl.pdate ) {\r
586 \r
587                                         for ( ProgDetailList tvd : tvc.pdetail ) {\r
588                                                 \r
589                                                 // 過去日のものは表示しない\r
590                                                 if (tvp.getType() != ProgType.PASSED) {\r
591                                                         if (tvd.endDateTime.compareTo(critDateTime) < 0) {\r
592                                                                 continue;\r
593                                                         }\r
594                                                 }\r
595                                                 // 当日過去分は表示しない(オプション)\r
596                                                 if ( ! env.getDisplayPassedEntry()) {\r
597                                                         if (tvp.getType() != ProgType.PASSED) {\r
598                                                                 if (tvd.endDateTime.compareTo(curDateTime) <= 0) {\r
599                                                                         continue;\r
600                                                                 }\r
601                                                         }\r
602                                                 }\r
603                                                 \r
604                                                 // 番組情報がありませんは表示しない\r
605                                                 if (tvd.start.equals("")) {\r
606                                                         continue;\r
607                                                 }\r
608                                                 \r
609                                                 // 放送休止は表示しない\r
610                                                 if (tvd.title.equals("放送休止") || tvd.title.equals("休止") || tvd.title.contains("放送を休止")) {\r
611                                                         continue;\r
612                                                 }\r
613                                                 \r
614                                                 //マッチング\r
615                                                 String label = "";\r
616                                                 String okini = "";\r
617                                                 String matched = null;\r
618                                                 long cur_remain = -1;\r
619                                                 long cur_wait = 0;\r
620                                                 boolean isFind = false;\r
621                                                 if (cond.center != null) {\r
622                                                         isFind = true;\r
623                                                 }\r
624                                                 else if (cond.targetdate != null) {\r
625                                                         // 現在放送中!\r
626                                                         if ( cond.targetdate.length() == 0 ) {\r
627                                                                 String cridt = CommonUtils.getDateTime(-env.getCurrentAfter());\r
628                                                                 String curdt = CommonUtils.getDateTime(0);\r
629                                                                 String nextdt = CommonUtils.getDateTime(env.getCurrentBefore());\r
630                                                                 if ( tvd.endDateTime.compareTo(cridt) <= 0 ) {\r
631                                                                         continue;       // オワタ\r
632                                                                 }\r
633                                                                 if ( tvd.startDateTime.compareTo(cridt) <= 0 && cridt.compareTo(tvd.endDateTime) <= 0 ||\r
634                                                                                 tvd.startDateTime.compareTo(curdt) <= 0 && curdt.compareTo(tvd.endDateTime) <= 0) {\r
635                                                                         cur_remain = CommonUtils.getCompareDateTime(tvd.endDateTime, curdt);\r
636                                                                         isFind = true;\r
637                                                                 }\r
638                                                                 else if ( tvd.startDateTime.compareTo(cridt) > 0 && tvd.startDateTime.compareTo(nextdt) <= 0 ) {\r
639                                                                         cur_wait = CommonUtils.getCompareDateTime(tvd.startDateTime, curdt);\r
640                                                                         isFind = true;  // 今後一時間以内に開始予定のものも表示\r
641                                                                 }\r
642                                                                 else if ( tvd.startDateTime.compareTo(nextdt) < 0 ) {\r
643                                                                         continue;       // これ以上みても無駄\r
644                                                                 }\r
645                                                                 \r
646                                                                 if ( isFind && cond.genre != null && ! tvd.isEqualsGenre(cond.genre, null) ) {\r
647                                                                         continue;\r
648                                                                 }\r
649                                                         }\r
650                                                 }\r
651                                                 else {\r
652                                                         if (cond.searchkeyword != null) {\r
653                                                                 isFind = SearchProgram.isMatchKeyword(cond.searchkeyword, ((cond.searchkeyword.getCaseSensitive()==false)?(centerPop):(tvpl.Center)), tvd);\r
654                                                                 label = ((cond.progtype == ProgType.PASSED)?(SearchItemLabel_Passed):(cond.searchkeyword.getLabel()));\r
655                                                                 okini = cond.searchkeyword.getOkiniiri();\r
656                                                                 matched = SearchProgram.getMatchedString();\r
657                                                         }\r
658                                                         else if (cond.flag != null) {\r
659                                                                 if (tvd.flag == cond.flag) {\r
660                                                                         isFind = true;\r
661                                                                         label = cond.flag.toString();\r
662                                                                 }\r
663                                                                 \r
664                                                                 if ( isFind && cond.genre != null && ! tvd.isEqualsGenre(cond.genre, null) ) {\r
665                                                                         continue;\r
666                                                                 }\r
667                                                         }\r
668                                                         else if (cond.genre != null) {\r
669                                                                 isFind = tvd.isEqualsGenre(cond.genre, cond.subgenre);\r
670                                                         }\r
671                                                         else if ( cond.progtype == ProgType.SYOBO && cond.searchkeyword == null ) {\r
672                                                                 // 全しょぼかる\r
673                                                                 isFind = true;\r
674                                                         }\r
675                                                 }\r
676                                                 \r
677                                                 if (isFind) {\r
678                                                         String[] tStr = new String[3];\r
679                                                         if (matched != null) {\r
680                                                                 int a = tvd.title.indexOf(matched);\r
681                                                                 tStr[0] = tvd.title.substring(0,a);\r
682                                                                 tStr[1] = matched;\r
683                                                                 tStr[2] = tvd.title.substring(a+matched.length());\r
684                                                         }\r
685                                                         else {\r
686                                                                 tStr[0] = tvd.title;\r
687                                                                 tStr[1] = "";\r
688                                                                 tStr[2] = "";\r
689                                                         }\r
690                                                         \r
691                                                         String prefixMark = "";\r
692                                                         if ( cond.targetdate == "" ) {\r
693                                                                 if ( cur_remain > 0 ) {\r
694                                                                         prefixMark = String.format("\0終了まで%3d分",cur_remain/60000);\r
695                                                                 }\r
696                                                                 else if ( cur_wait > 0 ){\r
697                                                                         prefixMark = String.format("\0開始まで%3d分",cur_wait/60000);\r
698                                                                 }\r
699                                                         }\r
700                                                         else {\r
701                                                                 prefixMark = tvd.extension_mark+tvd.prefix_mark;\r
702                                                         }\r
703                                                         \r
704                                                         ListedItem sa = new ListedItem();\r
705                                                         \r
706                                                         sa.tvd = tvd;\r
707                                                         \r
708                                                         sa.rsvmark              = "";\r
709                                                         sa.dupmark              = "";\r
710                                                         sa.prefix               = prefixMark;\r
711                                                         sa.title                = tvd.newlast_mark+"\0"+tStr[0]+"\0"+tStr[1]+"\0"+tStr[2]+tvd.postfix_mark;\r
712                                                         sa.searchlabel  = label;\r
713                                                         sa.okiniiri             = okini;\r
714                                                         sa.score                = "";\r
715                                                         sa.threshold    = "";\r
716                                                         \r
717                                                         sa.hide_rsvmarkcolor    = "";\r
718                                                         \r
719                                                         sa.fireChanged();\r
720                                                         \r
721                                                         addRow(sa);\r
722                                                 }\r
723                                         }\r
724                                 }\r
725                         }\r
726                 }\r
727                 \r
728                 if ( cond.targetdate == "" ) {\r
729                         // 現在放送中の終了済み番組をリストの先頭に移動する\r
730                         RowItemList<ListedItem> passed = new RowItemList<ListedItem>();\r
731                         RowItemList<ListedItem> cur = new RowItemList<ListedItem>();\r
732                         RowItemList<ListedItem> future = new RowItemList<ListedItem>();\r
733                         for ( ListedItem c : rowData ) {\r
734                                 if ( c.prefix == "" ) {\r
735                                         passed.add(c);\r
736                                 }\r
737                                 else if ( c.prefix.startsWith("\0終了まで") ){\r
738                                         cur.add(c);\r
739                                 }\r
740                                 else {\r
741                                         future.add(c);\r
742                                 }\r
743                         }\r
744                         \r
745                         rowData.clear();\r
746                         for ( ListedItem c : passed ) {\r
747                                 rowData.add(c);\r
748                         }\r
749                         \r
750                         int toprow = rowData.size();\r
751                         for ( ListedItem c : cur ) {\r
752                                 int row = toprow;\r
753                                 for ( ; row<rowData.size(); row++ ) {\r
754                                         ListedItem d = rowData.get(row);\r
755                                         if ( c.tvd.endDateTime.compareTo(d.tvd.endDateTime) < 0 ) {\r
756                                                 break;\r
757                                         }\r
758                                 }\r
759                                 rowData.add(row,c);\r
760                         }\r
761                         \r
762                         for ( ListedItem c : future ) {\r
763                                 rowData.add(c);\r
764                         }\r
765                 }\r
766         }\r
767         \r
768         /**\r
769          * 検索総当り版の本体(全件に対して検索処理をかける)\r
770          * <P><B>★将来的には、動的検索結果の表示はすべてこちらに移行する \r
771          */\r
772         public boolean redrawListBySearched(ProgType typ, int index) {\r
773                 \r
774                 stopTimer(true);\r
775                 \r
776                 // 検索結果が入っているところ\r
777                 SearchResult searched = tvprograms.getSearched();\r
778                 \r
779                 // 検索結果の履歴数より大きい番号を指定された場合はエラー\r
780                 if ( searched.getResultBufferSize() < index ) {\r
781                         return false;\r
782                 }\r
783                 \r
784                 JTreeLabel.Nodes desc = ((typ == ProgType.PASSED) ? (JTreeLabel.Nodes.SEARCHHIST):(JTreeLabel.Nodes.SEARCHED));\r
785                 String label = searched.getLabel(index);\r
786                 \r
787                 jLabel_tree.setView(desc, label);\r
788 \r
789                 rowData.clear();\r
790                 \r
791                 for ( ProgDetailList tvd : searched.getResult(index) ) {\r
792                         \r
793                         String[] tStr = new String[3];\r
794                         \r
795                         if (tvd.dynMatched != null) {\r
796                                 int a = tvd.title.indexOf(tvd.dynMatched);\r
797                                 tStr[0] = tvd.title.substring(0,a);\r
798                                 tStr[1] = tvd.dynMatched;\r
799                                 tStr[2] = tvd.title.substring(a+tvd.dynMatched.length());\r
800                         }\r
801                         else {\r
802                                 tStr[0] = tvd.title;\r
803                                 tStr[1] = "";\r
804                                 tStr[2] = "";\r
805                         }\r
806                         \r
807                         String prefixMark = tvd.extension_mark+tvd.prefix_mark;\r
808                         \r
809                         ListedItem sa = new ListedItem();\r
810                         \r
811                         sa.tvd = tvd;\r
812                         \r
813                         sa.rsvmark              = "";\r
814                         sa.dupmark              = "";\r
815                         sa.prefix               = prefixMark;\r
816                         sa.title                = tvd.newlast_mark+"\0"+tStr[0]+"\0"+tStr[1]+"\0"+tStr[2]+tvd.postfix_mark;\r
817                         sa.searchlabel  = tvd.dynKey.getLabel();\r
818                         sa.okiniiri             = tvd.dynKey.getOkiniiri();\r
819                         sa.score                = "";\r
820                         sa.threshold    = "";\r
821                         \r
822                         sa.hide_rsvmarkcolor    = "";\r
823                         \r
824                         sa.fireChanged();\r
825                         \r
826                         addRow(sa);\r
827                 }\r
828                 \r
829                 tableModel_listed.fireTableDataChanged();\r
830                 rowheaderModel_listed.fireTableDataChanged();\r
831                 \r
832                 return true;\r
833         }\r
834         \r
835         /*\r
836          *  検索高速化版\r
837          */\r
838         \r
839         // しょぼかるリストを作成\r
840         private void redrawSyobocalListByTrace() {\r
841                 _redrawListByTraceAndKeyword(ProgType.SYOBO,SearchBy.TRACE,null,null,null);\r
842         }\r
843         private void redrawSyobocalListByKeyword() {\r
844                 _redrawListByTraceAndKeyword(ProgType.SYOBO,SearchBy.KEYWORD,null,null,null);\r
845         }\r
846 \r
847         // しょぼかるのみに存在\r
848         private void redrawSyobocalListByOnly() {\r
849                 _redrawListByTraceAndKeyword(ProgType.SYOBO,SearchBy.BOTH,null,null,null,true);\r
850         }\r
851         \r
852         private void redrawSyobocalListByTraceAndKeyword() {\r
853                 _redrawListByTraceAndKeyword(ProgType.SYOBO,SearchBy.BOTH,null,null,null);\r
854         }\r
855 \r
856         // 番組追跡に基づきリストを作成\r
857         private void redrawListByTrace(TraceKey tKey) {\r
858                 _redrawListByTraceAndKeyword(ProgType.PROG,SearchBy.TRACE,tKey,null,null);\r
859         }\r
860         \r
861         // キーワード検索結果に基づきリストを作成(静的)\r
862         private void redrawListByKeyword(SearchKey sKey) {\r
863                 _redrawListByTraceAndKeyword(ProgType.PROG,SearchBy.KEYWORD,null,sKey,null);\r
864         }\r
865         // キーワードグループに基づきリストを作成(静的)\r
866         private void redrawListByKeywordGrp(SearchGroup gr) {\r
867                 _redrawListByTraceAndKeyword(ProgType.PROG,SearchBy.KEYWORD,null,null,null,false,gr,false,false);\r
868         }\r
869         // ピックアップに基づきリストを作成(静的)\r
870         private void redrawListByPickup() {\r
871                 _redrawListByTraceAndKeyword(ProgType.PICKED,SearchBy.BOTH,null,null,null);\r
872         }\r
873         \r
874         // 番組追跡&キーワード検索結果に基づきリストを作成\r
875         private void redrawListByTraceAndKeywordOkini(String oKey) {\r
876                 _redrawListByTraceAndKeyword(ProgType.PROG,SearchBy.BOTH,null,null,oKey);\r
877                 selectBatchTarget();\r
878         }\r
879         private void redrawListByTraceAndKeyword() {\r
880                 _redrawListByTraceAndKeyword(ProgType.PROG,SearchBy.BOTH,null,null,null);\r
881                 selectBatchTarget();\r
882         }\r
883 \r
884         private void redrawListByTraceAndKeywordNewArrival() {\r
885                 _redrawListByTraceAndKeyword(ProgType.PROG,SearchBy.BOTH,null,null,null,false,null,true,false);\r
886                 selectBatchTarget();\r
887         }\r
888         private void redrawListByTraceAndKeywordModified() {\r
889                 _redrawListByTraceAndKeyword(ProgType.PROG,SearchBy.BOTH,null,null,null,false,null,false,true);\r
890                 selectBatchTarget();\r
891         }\r
892 \r
893         private void _redrawListByTraceAndKeyword(ProgType typ, SearchBy opt, TraceKey tKey, SearchKey sKey, String oKey) {\r
894                 _redrawListByTraceAndKeyword(typ, opt, tKey, sKey, oKey, false, null, false, false); \r
895         }\r
896         private void _redrawListByTraceAndKeyword(ProgType typ, SearchBy opt, TraceKey tKey, SearchKey sKey, String oKey, boolean only) {\r
897                 _redrawListByTraceAndKeyword(typ, opt, tKey, sKey, oKey, only, null, false, false); \r
898         }\r
899         \r
900         /**\r
901          * 検索高速化版の本体(作成済み検索結果から必要なものを選ぶだけ、検索処理は行わない)\r
902          */\r
903         private void _redrawListByTraceAndKeyword(ProgType typ, SearchBy opt, TraceKey tKey, SearchKey sKey, String oKey, boolean only, SearchGroup gr, boolean doChkNewArr, boolean doChkModify) {\r
904                 \r
905                 rowData.clear();\r
906                 \r
907                 String curDateTime = CommonUtils.getDateTime(0);\r
908                 String critDateTime = CommonUtils.getCritDateTime();\r
909                 \r
910                 for (int n=0; n<mpList.size(); n++) {\r
911                         \r
912                         // Web番組表・しょぼかる分岐点\r
913                         if (mpList.getProg(n).type != typ) {\r
914                                 continue;\r
915                         }\r
916                         \r
917                         // 番組追跡・キーワード検索\r
918                         if (opt == SearchBy.TRACE && mpList.getTKey(n) == null) {\r
919                                 continue;\r
920                         }\r
921                         if (opt == SearchBy.KEYWORD && mpList.getSKey(n) == null) {\r
922                                 continue;\r
923                         }\r
924                         \r
925                         ProgDetailList tvd = mpList.getProg(n);\r
926 \r
927                         // 過去日のものは表示しない\r
928                         if (tvd.endDateTime.compareTo(critDateTime) < 0) {\r
929                                 continue;\r
930                         }\r
931                         // 当日過去分は表示しない\r
932                         if ( ! env.getDisplayPassedEntry()) {\r
933                                 if (tvd.endDateTime.compareTo(curDateTime) <= 0) {\r
934                                         continue;\r
935                                 }\r
936                         }\r
937                         \r
938                         // 検索キーワード関連の値算出\r
939                         ArrayList<TraceKey>  td = mpList.getTKey(n);\r
940                         ArrayList<SearchKey> sd = mpList.getSKey(n);\r
941                         \r
942                         String label = "";\r
943                         String okini = "";\r
944                         String matched = null;\r
945                         String fazScore = "";\r
946                         String threshold = "";\r
947                         \r
948                         if ((opt == SearchBy.BOTH  || opt == SearchBy.TRACE) && td.size() > 0) {\r
949                                 int i=0;\r
950                                 if (tKey != null) {\r
951                                         for (i=0; i<td.size(); i++) {\r
952                                                 if (td.get(i) == tKey) {\r
953                                                         break;\r
954                                                 }\r
955                                         }\r
956                                         if (i >= td.size()) {\r
957                                                 continue;       // キー指定で見つからなかったもの\r
958                                         }\r
959                                 }\r
960                                 \r
961                                 label = td.get(i).getLabel();\r
962                                 okini = td.get(i).getOkiniiri();\r
963                                 threshold = String.valueOf(td.get(i).getFazzyThreshold());\r
964                                 fazScore = String.valueOf(mpList.getTScore(n).get(i));\r
965                         }\r
966                         else if ((opt == SearchBy.BOTH  || opt == SearchBy.KEYWORD) && sd.size() > 0) {\r
967                                 int i=0;\r
968                                 if (sKey != null) {\r
969                                         for (i=0; i<sd.size(); i++) {\r
970                                                 if (sd.get(i) == sKey) {\r
971                                                         break;\r
972                                                 }\r
973                                         }\r
974                                         if (i >= sd.size()) {\r
975                                                 continue;       // キー指定で見つからなかったもの\r
976                                         }\r
977                                 }\r
978                                 else if (gr != null) {\r
979                                         for (i=0; i<sd.size(); i++) {\r
980                                                 boolean f = false;\r
981                                                 for ( String gmember : gr ) {\r
982                                                         if (sd.get(i).getLabel().equals(gmember)) {\r
983                                                                 f = true;\r
984                                                                 break;\r
985                                                         }\r
986                                                 }\r
987                                                 if (f) {\r
988                                                         break;\r
989                                                 }\r
990                                         }\r
991                                         if (i >= sd.size()) {\r
992                                                 continue;       // キー指定で見つからなかったもの\r
993                                         }\r
994                                 }\r
995                                 \r
996                                 if ( opt == SearchBy.BOTH && ! sd.get(i).getShowInStandby() ) {\r
997                                         continue;       // 予約待機への表示はYA・DA・YO\r
998                                 }\r
999                                 \r
1000                                 label = sd.get(i).getLabel();\r
1001                                 okini = sd.get(i).getOkiniiri();\r
1002                                 matched = mpList.getSStr(n).get(i);\r
1003                         }\r
1004                         else {\r
1005                                 continue;\r
1006                         }\r
1007                         \r
1008                         if ( doChkNewArr ) {\r
1009                                 if ( ! tvd.newarrival ) {\r
1010                                         // 新着フィルタリング\r
1011                                         continue;\r
1012                                 }\r
1013                         }\r
1014                         else if ( doChkModify ) {\r
1015                                 if ( ! tvd.modified ) {\r
1016                                         // 更新フィルタリング\r
1017                                         continue;\r
1018                                 }\r
1019                         }\r
1020                         else if (oKey != null && oKey.compareTo(okini) > 0) {\r
1021                                 // お気に入り度フィルタリング\r
1022                                 continue;\r
1023                         }\r
1024                         \r
1025                         // しょぼかるのみに存在\r
1026                         if ( typ == ProgType.SYOBO && (env.getSyoboFilterByCenters() || only) ) {\r
1027                                 if ( only && tvd.nosyobo ) {\r
1028                                         // nosyoboって名前と内容が一致していないよね…\r
1029                                         continue;\r
1030                                 }\r
1031                                 // 有効局のみに限定する\r
1032                                 boolean encr = false;\r
1033                                 for ( int x=0; x<tvprograms.size() && encr == false; x++ ) {\r
1034                                         TVProgram tvp = tvprograms.get(x);\r
1035                                         if ( tvp.getType() != ProgType.PROG ) {\r
1036                                                 continue;\r
1037                                         }\r
1038                                         for ( Center cr : tvp.getSortedCRlist() ) {\r
1039                                                 if ( mpList.getProg(n).center.equals(cr.getCenter()) ) {\r
1040                                                         encr = true;\r
1041                                                         break;\r
1042                                                 }\r
1043                                         }\r
1044                                 }\r
1045                                 if ( ! encr ) {\r
1046                                         continue;\r
1047                                 }\r
1048                         }\r
1049                         \r
1050                         // リストに追加\r
1051                         String[] tStr = new String[3];\r
1052                         if (matched != null) {\r
1053                                 int a = tvd.title.indexOf(matched);\r
1054                                 tStr[0] = tvd.title.substring(0,a);\r
1055                                 tStr[1] = matched;\r
1056                                 tStr[2] = tvd.title.substring(a+matched.length());\r
1057                         }\r
1058                         else {\r
1059                                 tStr[0] = tvd.title;\r
1060                                 tStr[1] = "";\r
1061                                 tStr[2] = "";\r
1062                         }\r
1063                         \r
1064                         ListedItem sa = new ListedItem();\r
1065 \r
1066                         sa.tvd = tvd;\r
1067                         \r
1068                         sa.rsvmark              = "";\r
1069                         sa.dupmark              = "";\r
1070                         sa.prefix               = tvd.extension_mark+tvd.prefix_mark;\r
1071                         sa.title                = tvd.newlast_mark+"\0"+tStr[0]+"\0"+tStr[1]+"\0"+tStr[2]+tvd.postfix_mark;\r
1072                         sa.searchlabel  = label;\r
1073                         sa.okiniiri             = okini;\r
1074                         sa.score                = fazScore;\r
1075                         sa.threshold    = threshold;\r
1076                         \r
1077                         sa.hide_rsvmarkcolor    = "";\r
1078                         \r
1079                         sa.fireChanged();\r
1080                         \r
1081                         addRow(sa);\r
1082                 }\r
1083                 \r
1084                 // ピックアップ(予約待機(親)のみで表示)\r
1085                 if ((typ == ProgType.PROG || typ == ProgType.PICKED) && opt == SearchBy.BOTH && oKey == null) {\r
1086                         if ( ! doChkNewArr && ! doChkModify ) {\r
1087                                 addPickedPrograms(curDateTime);\r
1088                         }\r
1089                 }\r
1090                 \r
1091                 // 予約マーク\r
1092                 setReservedMarks();\r
1093                 // テーブルに反映\r
1094                 tableModel_listed.fireTableDataChanged();\r
1095                 rowheaderModel_listed.fireTableDataChanged();\r
1096                 \r
1097                 // 時間重複マーク\r
1098                 setOverlapMark();\r
1099         }\r
1100         \r
1101         private void addPickedPrograms(String curDateTime) {\r
1102                 TVProgram tvp = tvprograms.getPickup();\r
1103                 if ( tvp != null ) {\r
1104                         for ( ProgList tPl : tvp.getCenters() ) {\r
1105                                 for ( ProgDateList tPcl : tPl.pdate ) {\r
1106                                         for ( ProgDetailList tvd : tPcl.pdetail ) {\r
1107                                                 \r
1108                                                 // すでに過去になっているものは表示しない\r
1109                                                 if ( ! env.getDisplayPassedEntry()) {\r
1110                                                         if (tvd.endDateTime.compareTo(curDateTime) <= 0) {\r
1111                                                                 continue;\r
1112                                                         }\r
1113                                                 }\r
1114                                                 \r
1115                                                 // リストに追加\r
1116                                                 ListedItem sa = new ListedItem();\r
1117                                                 \r
1118                                                 sa.tvd = tvd;\r
1119                                                 \r
1120                                                 sa.rsvmark              = "";\r
1121                                                 sa.dupmark              = "";\r
1122                                                 sa.prefix               = tvd.extension_mark+tvd.prefix_mark;\r
1123                                                 sa.title                = tvd.newlast_mark+"\0"+tvd.title+tvd.postfix_mark;\r
1124                                                 sa.searchlabel  = "ピックアップ";\r
1125                                                 sa.okiniiri             = "";\r
1126                                                 sa.score                = "";\r
1127                                                 sa.threshold    = "";\r
1128                                                 \r
1129                                                 sa.hide_rsvmarkcolor    = "";\r
1130                                                 \r
1131                                                 sa.fireChanged();\r
1132                                                 \r
1133                                                 addRow(sa);\r
1134                                         }\r
1135                                 }\r
1136                         }\r
1137                 }\r
1138         }\r
1139         \r
1140         /*\r
1141          * 絞り込み検索\r
1142          */\r
1143         \r
1144         /**\r
1145          * 絞り込み検索の本体(現在リストアップされているものから絞り込みを行う)(親から呼ばれるよ!)\r
1146          */\r
1147         public void redrawListByKeywordFilter(SearchKey keyword, String target) {\r
1148                 \r
1149                 stopTimer(true);\r
1150 \r
1151                 jLabel_tree.setView(JTreeLabel.Nodes.FILTERED, target);\r
1152                 \r
1153                 ArrayList<ListedItem> tmpRowData = new ArrayList<ListedItem>();\r
1154                 \r
1155                 for ( ListedItem c : rowData ) {\r
1156                         \r
1157                         // 表示中の情報を一行ずつチェックする\r
1158                         ProgDetailList tvd = c.tvd;\r
1159                         \r
1160                         // タイトルを整形しなおす\r
1161                         boolean isFind = SearchProgram.isMatchKeyword(keyword, "", tvd);\r
1162                         if ( isFind ) {\r
1163                                 String matched = SearchProgram.getMatchedString();\r
1164                                 String[] tStr = new String[3];\r
1165                                 if (matched != null) {\r
1166                                         int a = tvd.title.indexOf(matched);\r
1167                                         tStr[0] = tvd.title.substring(0,a);\r
1168                                         tStr[1] = matched;\r
1169                                         tStr[2] = tvd.title.substring(a+matched.length());\r
1170                                 }\r
1171                                 else {\r
1172                                         tStr[0] = tvd.title;\r
1173                                         tStr[1] = "";\r
1174                                         tStr[2] = "";\r
1175                                 }\r
1176                                 \r
1177                                 // 修正して仮置き場に入れる\r
1178                                 c.prefix = tvd.extension_mark+tvd.prefix_mark;\r
1179                                 c.title = tvd.newlast_mark+"\0"+tStr[0]+"\0"+tStr[1]+"\0"+tStr[2]+tvd.postfix_mark;\r
1180                                 c.fireChanged();\r
1181                                 tmpRowData.add(c);\r
1182                         }\r
1183                 }\r
1184                 \r
1185                 // 表示データを置き換える\r
1186                 rowData.clear();\r
1187                 for ( ListedItem a : tmpRowData ) {\r
1188                         addRow(a);\r
1189                 }\r
1190                 \r
1191                 // fire!\r
1192                 tableModel_listed.fireTableDataChanged();\r
1193                 rowheaderModel_listed.fireTableDataChanged();\r
1194         }\r
1195         \r
1196         public boolean addRow(ListedItem data) {\r
1197                 // 開始日時でソート\r
1198                 int i=0;\r
1199                 for (; i<rowData.size(); i++) {\r
1200                         ListedItem c = rowData.get(i);\r
1201                         ProgDetailList tvd = c.tvd;\r
1202                         int x = tvd.startDateTime.compareTo(data.tvd.startDateTime);\r
1203                         int y = tvd.endDateTime.compareTo(data.tvd.endDateTime);\r
1204                         boolean isChMatched = c.tvd.center.equals(data.tvd.center);\r
1205                         boolean isTitleMatched = c.tvd.title.equals(data.tvd.title);\r
1206                         if (x == 0 && y == 0 && isChMatched ) {\r
1207                                 // 日またがりで発生した重複エントリを整理 → ピックアップとかも重複するよ\r
1208                                 ProgType typ = tvd.type;\r
1209                                 if ( debug ) {\r
1210                                         if ( isTitleMatched ) {\r
1211                                                 StdAppendMessage("[重複エントリ] 省略しました: "+typ+" "+data.tvd.center+" "+data.tvd.title+" "+data.tvd.startDateTime+" "+data.tvd.endDateTime);\r
1212                                         }\r
1213                                         else {\r
1214                                                 StdAppendMessage("[重複エントリ] 放送局と開始終了日時が同がじでタイトルの異なる情報がありました: "+typ+" "+data.tvd.center+" "+data.tvd.startDateTime+" "+data.tvd.title+" -> "+c.title);\r
1215                                         }\r
1216                                 }\r
1217                                 return false;\r
1218                         }\r
1219                         else if (x > 0) {\r
1220                                 break;  // 挿入位置確定\r
1221                         }\r
1222                 }\r
1223                 \r
1224                 // 有効データ\r
1225                 rowData.add(i, data);\r
1226                 return true;\r
1227         }\r
1228         \r
1229         public void setReservedMarks() {\r
1230                 \r
1231                 for ( ListedItem data : rowData ) {\r
1232                         \r
1233                         // 予約済みマーク\r
1234                         Marker rm = getReservedMarkChar(data);\r
1235                         \r
1236                         if (rm != null) {\r
1237                                 data.rsvmark = rm.mark;\r
1238                                 data.hide_rsvmarkcolor = rm.color;\r
1239                                 data.fireChanged();\r
1240                         }\r
1241                         else {\r
1242                                 data.rsvmark = "";\r
1243                                 data.hide_rsvmarkcolor = "";\r
1244                                 data.fireChanged();\r
1245                         }\r
1246                 }\r
1247         }\r
1248         \r
1249         /**\r
1250          * 重複マークつけてください\r
1251          */\r
1252         private void setOverlapMark() {\r
1253                 \r
1254                 if ( rowData.size() <= 1 ) {\r
1255                         // 1個以下ならソートの意味ないよね\r
1256                         return;\r
1257                 }\r
1258                 \r
1259                 // リセット\r
1260                 for (int vrow=0; vrow<rowData.size(); vrow++) {\r
1261                         ListedItem rf = rowData.get(vrow); \r
1262                         rf.dupmark = "";\r
1263                         rf.fireChanged();\r
1264                 }\r
1265                 \r
1266                 // 時間重複のマーキング\r
1267                 String sDT = "";\r
1268                 String eDT = "";\r
1269                 String sDT2 = "";\r
1270                 String eDT2 = "";\r
1271                 for (int vrow=0; vrow<rowData.size()-1; vrow++) {\r
1272                         ListedItem ra = rowData.get(vrow);\r
1273                         \r
1274                         for ( int vrow2=vrow+1; vrow2<rowData.size(); vrow2++ ) {\r
1275                                 ListedItem rb = rowData.get(vrow2);\r
1276                                 \r
1277                                 if ( CommonUtils.getCompareDateTime(ra.tvd.endDateTime, rb.tvd.startDateTime) < 0) {\r
1278                                         // もう見なくていい\r
1279                                         break;\r
1280                                 }\r
1281                                 \r
1282                                 /*\r
1283                                 if ( ! sDT2.equals("")) {\r
1284                                         sDT = sDT2;\r
1285                                         eDT = eDT2;\r
1286                                 }\r
1287                                 else\r
1288                                 */\r
1289                                 {\r
1290                                         sDT = ra.tvd.startDateTime;\r
1291                                         eDT = ra.tvd.endDateTime;\r
1292                                 }\r
1293                                 \r
1294                                 {\r
1295                                         sDT2 = rb.tvd.startDateTime;\r
1296                                         eDT2 = rb.tvd.endDateTime;\r
1297                                 }\r
1298                                 \r
1299                                 if ( eDT.equals(sDT2) ) {\r
1300                                         if ( ra.dupmark.length() == 0 ) {\r
1301                                                 ra.dupmark = DUPMARK_REP;\r
1302                                                 ra.fireChanged();\r
1303                                         }\r
1304                                         if ( rb.dupmark.length() == 0 ) {\r
1305                                                 rb.dupmark = DUPMARK_REP;\r
1306                                                 rb.fireChanged();\r
1307                                         }\r
1308                                 }\r
1309                                 else if ( CommonUtils.isOverlap(sDT, eDT, sDT2, eDT2, false) ) {\r
1310                                         ra.dupmark = rb.dupmark = DUPMARK_NORMAL;\r
1311                                         ra.fireChanged();\r
1312                                         rb.fireChanged();\r
1313                                 }\r
1314                         }\r
1315                 }\r
1316         }\r
1317         \r
1318         /**\r
1319          * 現在時刻追従スクロールを開始する\r
1320          * @see #stopTimer\r
1321          * @see #pauseTimer\r
1322          */\r
1323         private void startTimer() {\r
1324                 timer_now_enabled = true;\r
1325         }\r
1326         \r
1327         /**\r
1328          * 現在時刻追従スクロールを停止する\r
1329          */\r
1330         private boolean stopTimer(boolean showmsg) {\r
1331                 return (timer_now_enabled = false);\r
1332         }\r
1333         \r
1334         // 主に他のクラスから呼び出されるメソッド\r
1335         \r
1336         /**\r
1337          * サイドツリーの「予約待機」を選択する\r
1338          */\r
1339         public void selectTreeDefault() {\r
1340                 if ( defaultNode != null ) jTree_tree.setSelectionPath(new TreePath(defaultNode.getPath()));\r
1341         }\r
1342         \r
1343         /**\r
1344          * サイドツリーの現在選択中のノードを再度選択して描画しなおす\r
1345          */\r
1346         public void reselectTree() {\r
1347                 JTreeLabel.Nodes node = jLabel_tree.getNode();\r
1348                 String value = jLabel_tree.getValue();\r
1349                 String[] names = new String[] { node.getLabel(), value };\r
1350                 TreeNode[] nodes = ter.getSelectedPath(listRootNode, names, 0);\r
1351                 if (nodes != null) {\r
1352                         TreePath tp = new TreePath(nodes);\r
1353                         if ( tp != null ) {\r
1354                                 jTree_tree.setSelectionPath(null);\r
1355                                 jTree_tree.setSelectionPath(tp);\r
1356                         }\r
1357                 }\r
1358         }\r
1359         \r
1360         /**\r
1361          * 他から検索を実行される時にツリーの選択をはずす\r
1362          */\r
1363         public void clearSelection() {\r
1364                 jTree_tree.clearSelection();\r
1365         }\r
1366         \r
1367         /**\r
1368          * 特定のノードを選択しているか?\r
1369          */\r
1370         public boolean isNodeSelected(JTreeLabel.Nodes node) {\r
1371                 return(node == jLabel_tree.getNode());\r
1372         }\r
1373 \r
1374         /**\r
1375          * サイドツリーを開く\r
1376          */\r
1377         public void setExpandTree() {\r
1378                 jSplitPane_view.setDividerLocation(bounds.getTreeWidth());\r
1379                 jScrollPane_tree.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);\r
1380                 jScrollPane_tree.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);\r
1381         }\r
1382         \r
1383         /**\r
1384          * サイドツリーを閉じる\r
1385          */\r
1386         public void setCollapseTree() {\r
1387                 jSplitPane_view.setDividerLocation(bounds.getMinDivLoc());\r
1388                 jScrollPane_tree.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);\r
1389                 jScrollPane_tree.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);\r
1390         }\r
1391         \r
1392         /**\r
1393          * サイドツリーの展開状態を設定ファイルに保存(鯛ナビ終了時に呼び出される)\r
1394          */\r
1395         public void saveTreeExpansion() {\r
1396                 ter.save();\r
1397         }\r
1398         \r
1399         /**\r
1400          * いまはどんな条件で表示しているのかな?\r
1401          */\r
1402         public String getCurrentView() {\r
1403                 return jLabel_tree.getView();\r
1404         }\r
1405         \r
1406         /**\r
1407          * 画面上部の番組詳細領域の表示のON/OFF\r
1408          */\r
1409         public void setDetailVisible(boolean aFlag) {\r
1410                 jTextPane_detail.setVisible(aFlag);\r
1411         }\r
1412 \r
1413         /**\r
1414          * テーブルの行番号の表示のON/OFF\r
1415          */\r
1416         public void setRowHeaderVisible(boolean b) {\r
1417                 jScrollPane_listed.getRowHeader().setVisible(b);\r
1418         }\r
1419         \r
1420         /**\r
1421          * スクリーンショット用\r
1422          */\r
1423         public Component getTableHeader() {\r
1424                 return jTable_listed.getTableHeader();\r
1425         }\r
1426         \r
1427         /**\r
1428          * スクリーンショット用\r
1429          */\r
1430         public Component getTableBody() {\r
1431                 return jTable_listed;\r
1432         }\r
1433         \r
1434         /*******************************************************************************\r
1435          * リスナー\r
1436          ******************************************************************************/\r
1437         \r
1438         /**\r
1439          * 現在時刻追従スクロール\r
1440          */\r
1441         @Override\r
1442         public void timerRised(TickTimerRiseEvent e) {\r
1443                 \r
1444                 if ( ! timer_now_enabled ) {\r
1445                         return;\r
1446                 }\r
1447                         \r
1448                 stopTimer(false);\r
1449                 \r
1450                 ProgDetailList tvd = null;\r
1451                 \r
1452                 // 更新前に選択していた行を確認する\r
1453                 {\r
1454                         int row = jTable_listed.getSelectedRow();\r
1455                         if ( row >= 0 ) {\r
1456                                 int vrow = jTable_listed.convertRowIndexToModel(row);\r
1457                                 tvd = rowData.get(vrow).tvd;\r
1458                         }\r
1459                 }\r
1460                 \r
1461                 reselectTree(); // タイマーはこの中で再開される\r
1462 \r
1463                 // 更新前に選択していた行を再度選択する\r
1464                 if ( tvd != null ) {\r
1465                         int vrow = -1;\r
1466                         for ( ListedItem c : rowData ) {\r
1467                                 vrow++;\r
1468                                 if ( c.tvd == tvd ) {\r
1469                                         int row = jTable_listed.convertRowIndexToView(vrow);\r
1470                                         jTable_listed.setRowSelectionInterval(row,row);\r
1471                                         break; \r
1472                                 }\r
1473                         }\r
1474                 }\r
1475         }\r
1476 \r
1477         /**\r
1478          * タブを開いたり閉じたりしたときに動くリスナー\r
1479          * ★synchronized(rowData)★\r
1480          * @see #updateReserveMark()\r
1481          */\r
1482         private ComponentListener cl_tabshownhidden = new ComponentAdapter() {\r
1483                 @Override\r
1484                 public void componentShown(ComponentEvent e) {\r
1485                         \r
1486                         // ★★★ イベントにトリガーされた処理がかちあわないように synchronized() ★★★\r
1487                         synchronized ( rowData ) {\r
1488                                 // 終了した予約を整理する\r
1489                                 for (HDDRecorder recorder : recorders) {\r
1490                                         recorder.refreshReserves();\r
1491                                 }\r
1492                                 \r
1493                                 // 他のコンポーネントと連動\r
1494                                 onShown();\r
1495                         }\r
1496                 }\r
1497                 @Override\r
1498                 public void componentHidden(ComponentEvent e) {\r
1499                         // フォーカスは無効にする\r
1500                         vrowInFocus = -1;\r
1501                         \r
1502                         // 他のコンポーネントと連動\r
1503                         onHidden();\r
1504                 }\r
1505         };\r
1506         \r
1507         /**\r
1508          *  行を選択すると詳細が表示されるようにする\r
1509          */\r
1510         private ListSelectionListener lsSelectListner = new ListSelectionListener() {\r
1511                 public void valueChanged(ListSelectionEvent e) {\r
1512                         if(e.getValueIsAdjusting()) return;\r
1513                         if (jTable_listed.getSelectedRow() >= 0) {\r
1514                                 int row = jTable_listed.convertRowIndexToModel(jTable_listed.getSelectedRow());\r
1515                                 ListedItem c = rowData.get(row);\r
1516                                 jTextPane_detail.setLabel(\r
1517                                                 c.tvd.start,\r
1518                                                 c.tvd.end,\r
1519                                                 c.tvd.title);\r
1520                                 jTextPane_detail.setText(c.tvd.detail);\r
1521                         }\r
1522                         else {\r
1523                                 jTextPane_detail.setLabel("","","");\r
1524                                 jTextPane_detail.setText("");\r
1525                         }\r
1526                 }\r
1527         };\r
1528         \r
1529         /**\r
1530          * マウスクリックでメニュー表示\r
1531          */\r
1532         private MouseAdapter lsClickAdapter = new MouseAdapter() {\r
1533                 public void mouseClicked(MouseEvent e) {\r
1534                         \r
1535                         JTable t = (JTable) e.getSource();\r
1536                         Point p = e.getPoint();\r
1537                         int vrow = t.rowAtPoint(p);\r
1538                         \r
1539                         // カーソル位置を記憶する\r
1540                         vrowInFocus = vrow;\r
1541                         \r
1542                         //t.getSelectionModel().setSelectionInterval(vrow,vrow);\r
1543                         int row = t.convertRowIndexToModel(vrow);\r
1544                         ListedItem c = rowData.get(row);\r
1545                         \r
1546                         ProgDetailList tvd = c.tvd;\r
1547                         \r
1548                         // 番組表リストの挿入位置を決める\r
1549                         GregorianCalendar cal = CommonUtils.getCalendar(c.tvd.startDateTime);\r
1550                         if (CommonUtils.isLateNight(cal)) {\r
1551                                 cal.add(Calendar.DATE,-1);\r
1552                         }\r
1553                         \r
1554                         switch ( tvd.type ) {\r
1555                         case PROG:\r
1556                         case SYOBO:\r
1557                         case PASSED:\r
1558                         case PICKED:\r
1559                         case OTHERS:\r
1560                                 break;\r
1561                         default:\r
1562                                 MWin.appendError(ERRID+"未定義の番組表種別です: "+tvd.type);\r
1563                                 return;\r
1564                         };\r
1565                         \r
1566                         if (e.getButton() == MouseEvent.BUTTON3) {\r
1567                                 if (e.getClickCount() == 1) {\r
1568                                         // 右シングルクリックでメニューの表示\r
1569                                         t.getSelectionModel().setSelectionInterval(vrow,vrow);\r
1570                                         \r
1571                                         int threshold = getThrValByRow(row);\r
1572                                         String keyword = (threshold > 0) ? (getKeyValByRow(row)) : (tvd.title);\r
1573                                         showPopupForTraceProgram(t, tvd, keyword, threshold, p.x, p.y, -1);\r
1574                                 }\r
1575                         }\r
1576                         else if (e.getButton() == MouseEvent.BUTTON1) {\r
1577                                 if (e.getClickCount() == 2) {\r
1578                                         // RADIOは閲覧のみ \r
1579                                         if (tvd.type == ProgType.PROG && tvd.subtype == ProgSubtype.RADIO) {\r
1580                                                 return;\r
1581                                         }\r
1582                                         // レコーダが選択されていない場合はなにもしない\r
1583                                         if (recorders.size() == 0) {\r
1584                                                 return;\r
1585                                         }\r
1586 \r
1587                                         // 左ダブルクリックで\r
1588                                         switch ( env.getDblClkCmd() ) {\r
1589                                         \r
1590                                         // 予約ウィンドウを開く\r
1591                                         case SHOWRSVDIALOG:\r
1592                                                 if (tvd.type == ProgType.PASSED) {\r
1593                                                         // 過去ログは閲覧のみ \r
1594                                                         return;\r
1595                                                 }\r
1596                                                 \r
1597                                                 // 類似予約抽出条件の設定\r
1598                                                 String keyword = "";\r
1599                                                 int threshold = getThrValByRow(row);\r
1600                                                 if (threshold > 0) {\r
1601                                                         keyword = getKeyValByRow(row);\r
1602                                                 }\r
1603                                                 \r
1604                                                 // ダイアログを開く\r
1605                                                 //rD.clear();\r
1606                                                 CommonSwingUtils.setLocationCenter(parent,rD);\r
1607                                                 if (rD.open(tvd, keyword, threshold)) {\r
1608                                                         rD.setVisible(true);\r
1609                                                 }\r
1610                                                 else {\r
1611                                                         rD.setVisible(false);\r
1612                                                 }\r
1613                                                 \r
1614                                                 // 予約マークを更新する\r
1615                                                 if (rD.isReserved()) {\r
1616                                                         // 自分\r
1617                                                         setReservedMarks();\r
1618                                                         tableModel_listed.fireTableDataChanged();\r
1619                                                         rowheaderModel_listed.fireTableDataChanged();\r
1620                                                         refocus();\r
1621                                                         // 他人\r
1622                                                         updateReserveDisplay(tvd.center);\r
1623                                                 }\r
1624                                                 break;\r
1625                                          \r
1626                                         // 番組欄にジャンプ\r
1627                                         case JUMPTOPAPER:\r
1628                                                 jumpToPaper(tvd.center,tvd.startDateTime);\r
1629                                                 break;\r
1630                                                 \r
1631                                         // ブラウザで番組詳細を開く\r
1632                                         case JUMPTOWEB:\r
1633                                                 if ( tvd.link.startsWith("http") ) {\r
1634                                                         try {\r
1635                                                                 Desktop desktop = Desktop.getDesktop();\r
1636                                                                 desktop.browse(new URI(tvd.link));\r
1637                                                         } catch (IOException e1) {\r
1638                                                                 e1.printStackTrace();\r
1639                                                         } catch (URISyntaxException e1) {\r
1640                                                                 e1.printStackTrace();\r
1641                                                         }\r
1642                                                 }\r
1643                                                 break;\r
1644                                         }\r
1645                                 }\r
1646                         }\r
1647                         else if (e.getButton() == MouseEvent.BUTTON2) {\r
1648                                 // ピックアップに追加or削除\r
1649                                 addToPickup(tvd);\r
1650                                 setReservedMarks();\r
1651                                 tableModel_listed.fireTableDataChanged();\r
1652                                 rowheaderModel_listed.fireTableDataChanged();\r
1653                                 refocus();\r
1654                         }\r
1655                         \r
1656                         // カーソル位置をリセットする\r
1657                         vrowInFocus = -1;\r
1658                 }\r
1659         };\r
1660         \r
1661         /**\r
1662          * サイドツリーのノードをさわると実行されるリスナー\r
1663          */\r
1664         private final MouseListener ml_nodeselected = new MouseAdapter() {\r
1665                 @Override\r
1666                 public void mouseClicked(MouseEvent e) {\r
1667                         if (SwingUtilities.isRightMouseButton(e)) {\r
1668                                 int selRow = jTree_tree.getRowForLocation(e.getX(), e.getY());\r
1669                                 if (selRow != -1) {\r
1670                                         jTree_tree.setSelectionRow(selRow);\r
1671                                 }\r
1672                                 \r
1673                                 TreePath path = jTree_tree.getPathForLocation(e.getX(), e.getY());\r
1674                                 \r
1675                                 if ( path != null ) {\r
1676                                         \r
1677                                         JTreeLabel.Nodes node = (path.getPathCount() < 2) ? null : JTreeLabel.Nodes.getNode(path.getPathComponent(1).toString());\r
1678                                         String value = path.getLastPathComponent().toString();\r
1679                                         \r
1680                                         switch ( path.getPathCount() ) {\r
1681                                         case 2:\r
1682                                                 switch ( node ) {\r
1683                                                 case TRACE:\r
1684                                                         showPopupForSortTraceKey(e.getX(), e.getY());\r
1685                                                         break;\r
1686                                                 case KEYWORD:\r
1687                                                         showPopupForSortSearchKey(e.getX(), e.getY());\r
1688                                                         break;\r
1689                                                 case KEYWORDGROUP:\r
1690                                                         showPopupForRemoveKeywordGrp(e.getX(), e.getY());\r
1691                                                         break;\r
1692                                                 case EXTENTION:\r
1693                                                         showPopupForSortExtension(e.getX(), e.getY());\r
1694                                                         break;\r
1695                                                 default:\r
1696                                                         break;\r
1697                                                 }\r
1698                                                 break;\r
1699                                                 \r
1700                                         case 3:\r
1701                                                 switch ( node ) {\r
1702                                                 case TRACE:\r
1703                                                         showPopupForRemoveTraceKey(e.getX(), e.getY(), value);\r
1704                                                         break;\r
1705                                                 case KEYWORD:\r
1706                                                         showPopupForRemoveKeyword(e.getX(), e.getY(), value);\r
1707                                                         break;\r
1708                                                 case KEYWORDGROUP:\r
1709                                                         showPopupForRemoveKeywordGrpName(e.getX(), e.getY(), value);\r
1710                                                         break;\r
1711                                                 case EXTENTION:\r
1712                                                         showPopupForRemoveExtension(e.getX(), e.getY(), value);\r
1713                                                         break;\r
1714                                                 default:\r
1715                                                         break;\r
1716                                                 }\r
1717                                                 break;\r
1718                                                 \r
1719                                         case 4:\r
1720                                                 switch ( node ) {\r
1721                                                 case KEYWORDGROUP:\r
1722                                                         showPopupForRemoveKeywordGrpEntry(e.getX(), e.getY(), path.getPathComponent(2).toString(), value);\r
1723                                                         break;\r
1724                                                 default:\r
1725                                                         break;\r
1726                                                 }\r
1727                                                 break;\r
1728                                         }\r
1729                                 }\r
1730                         }\r
1731                 }\r
1732         };\r
1733         \r
1734         /**\r
1735          * サイドツリーにつけるリスナー(ツリーの展開状態を記憶する)\r
1736          */\r
1737         private final TreeExpansionListener tel_nodeexpansion = new TreeExpansionListener() {\r
1738                 \r
1739                 @Override\r
1740                 public void treeExpanded(TreeExpansionEvent event) {\r
1741                         ter.reg();\r
1742                 }\r
1743                 \r
1744                 @Override\r
1745                 public void treeCollapsed(TreeExpansionEvent event) {\r
1746                         ter.reg();\r
1747                 }\r
1748         };\r
1749         \r
1750         /**\r
1751          * サイドツリーにつけるリスナー(クリックで描画実行)\r
1752          */\r
1753         private final TreeSelectionListener tsl_nodeselected = new TreeSelectionListener() {\r
1754                 @Override\r
1755                 public void valueChanged(TreeSelectionEvent e) {\r
1756                         \r
1757                         TreePath path = jTree_tree.getSelectionPath();\r
1758                         \r
1759                         if (path != null) {\r
1760                                 \r
1761                                 // 本当は排他するべきかな\r
1762                                 stopTimer(false);\r
1763                                 boolean stop_timer = true;\r
1764                                 \r
1765                                 JTreeLabel.Nodes node = (path.getPathCount() < 2) ? null : JTreeLabel.Nodes.getNode(path.getPathComponent(1).toString());\r
1766 \r
1767                                 switch ( path.getPathCount() ) {\r
1768                                 \r
1769                                 // 親ノード\r
1770                                 case 2:\r
1771                                         switch ( node ) {\r
1772                                         case START:\r
1773                                                 redrawListByFlag(ProgFlags.NEW);\r
1774                                                 break;\r
1775                                         case END:\r
1776                                                 redrawListByFlag(ProgFlags.LAST);\r
1777                                                 break;\r
1778                                         case NOW:\r
1779                                                 redrawListByNow(null);\r
1780                                                 stop_timer = false;\r
1781                                                 break;\r
1782                                         case SYOBOCAL:\r
1783                                                 redrawSyobocalListByTraceAndKeyword();\r
1784                                                 break;\r
1785                                         case STANDBY:\r
1786                                                 redrawListByTraceAndKeyword();\r
1787                                                 break;\r
1788                                         case TRACE:\r
1789                                                 redrawListByTrace(null);\r
1790                                                 break;\r
1791                                         case KEYWORD:\r
1792                                                 redrawListByKeyword(null);\r
1793                                                 break;\r
1794                                         case EXTENTION:\r
1795                                                 redrawListByExtkeywordAll(extKeys.getSearchKeys());\r
1796                                                 break;\r
1797                                         default:\r
1798                                                 break;\r
1799                                         }\r
1800                                         jLabel_tree.setView(node, null);\r
1801                                         break;\r
1802                                         \r
1803                                 // 子ノード\r
1804                                 case 3:\r
1805                                         switch ( node ) {\r
1806                                         case SEARCHHIST:\r
1807                                                 VWListedTreeNode inode = (VWListedTreeNode) path.getLastPathComponent();\r
1808                                                 VWListedTreeNode parent = (VWListedTreeNode) inode.getParent();\r
1809                                                 redrawListBySearched(ProgType.PASSED,parent.getIndex(inode));\r
1810                                                 break;\r
1811                                         case START:\r
1812                                                 {\r
1813                                                         ProgGenre genre = ProgGenre.get(path.getLastPathComponent().toString());\r
1814                                                         if ( genre != null ) {\r
1815                                                                 redrawListByFlag(ProgFlags.NEW,genre);\r
1816                                                         }\r
1817                                                 }\r
1818                                                 break;\r
1819                                         case END:\r
1820                                                 {\r
1821                                                         ProgGenre genre = ProgGenre.get(path.getLastPathComponent().toString());\r
1822                                                         if ( genre != null ) {\r
1823                                                                 redrawListByFlag(ProgFlags.LAST,genre);\r
1824                                                         }\r
1825                                                 }\r
1826                                                 break;\r
1827                                         case SYOBOCAL:\r
1828                                                 {\r
1829                                                         JTreeLabel.Nodes subnode = JTreeLabel.Nodes.getNode(path.getLastPathComponent().toString());\r
1830                                                         switch ( subnode ) {\r
1831                                                         case TRACE:\r
1832                                                                 redrawSyobocalListByTrace();\r
1833                                                                 break;\r
1834                                                         case KEYWORD:\r
1835                                                                 redrawSyobocalListByKeyword();\r
1836                                                                 break;\r
1837                                                         case SYOBOALL:\r
1838                                                                 redrawSyobocalAll();\r
1839                                                                 break;\r
1840                                                         default:\r
1841                                                                 break;\r
1842                                                         }\r
1843                                                 }\r
1844                                                 break;\r
1845                                         case NOW:\r
1846                                                 {\r
1847                                                         ProgGenre genre = ProgGenre.get(path.getLastPathComponent().toString());\r
1848                                                         if ( genre != null ) {\r
1849                                                                 redrawListByNow(genre);\r
1850                                                                 stop_timer = false;\r
1851                                                         }\r
1852                                                 }\r
1853                                                 break;\r
1854                                         case STANDBY:\r
1855                                                 {\r
1856                                                         JTreeLabel.Nodes subnode = JTreeLabel.Nodes.getNode(path.getLastPathComponent().toString());\r
1857                                                         switch ( subnode ) {\r
1858                                                         case NEWARRIVAL:\r
1859                                                                 redrawListByTraceAndKeywordNewArrival();\r
1860                                                                 break;\r
1861                                                         case MODIFIED:\r
1862                                                                 redrawListByTraceAndKeywordModified();\r
1863                                                                 break;\r
1864                                                         case SYOBOONLY:\r
1865                                                                 redrawSyobocalListByOnly();\r
1866                                                                 break;\r
1867                                                         case PICKUP:\r
1868                                                                 redrawListByPickup();\r
1869                                                                 break;\r
1870                                                         default:\r
1871                                                                 redrawListByTraceAndKeywordOkini(path.getLastPathComponent().toString());\r
1872                                                                 break;\r
1873                                                         }\r
1874                                                 }\r
1875                                                 break;\r
1876                                         case TRACE:\r
1877                                                 for (TraceKey trace : trKeys.getTraceKeys()) {\r
1878                                                         if (path.getLastPathComponent().toString().equals(trace.getLabel())) {\r
1879                                                                 redrawListByTrace(trace);\r
1880                                                                 break;\r
1881                                                         }\r
1882                                                 }\r
1883                                                 break;\r
1884                                         case KEYWORD:\r
1885                                                 for (SearchKey search : srKeys.getSearchKeys()) {\r
1886                                                         if (path.getLastPathComponent().toString().equals(search.getLabel())) {\r
1887                                                                 redrawListByKeyword(search);\r
1888                                                                 break;\r
1889                                                         }\r
1890                                                 }\r
1891                                                 break;\r
1892                                         case KEYWORDGROUP:\r
1893                                                 for (SearchGroup gr : srGrps) {\r
1894                                                         if (gr.getName().equals(path.getLastPathComponent().toString())) {\r
1895                                                                 redrawListByKeywordGrp(gr);\r
1896                                                                 break;\r
1897                                                         }\r
1898                                                 }\r
1899                                                 break;\r
1900                                         case GENRE:\r
1901                                                 for (ProgGenre genre : ProgGenre.values()) {\r
1902                                                         if (path.getLastPathComponent().toString().equals(genre.toString())) {\r
1903                                                                 redrawListByGenre(genre, null);\r
1904                                                                 break;\r
1905                                                         }\r
1906                                                 }\r
1907                                                 break;\r
1908                                         case BCASTLIST:\r
1909                                                 redrawListByCenterList(path.getLastPathComponent().toString());\r
1910                                                 break;\r
1911                                         case EXTENTION:\r
1912                                                 for (SearchKey search : extKeys.getSearchKeys()) {\r
1913                                                         if (path.getLastPathComponent().toString().equals(search.getLabel())) {\r
1914                                                                 redrawListByKeywordDyn(search);\r
1915                                                                 break;\r
1916                                                         }\r
1917                                                 }\r
1918                                                 break;\r
1919                                         default:\r
1920                                                 break;\r
1921                                         }\r
1922                                         jLabel_tree.setView(node, path.getLastPathComponent().toString());\r
1923                                         System.out.println(jLabel_tree.getView());\r
1924                                         break;\r
1925                                         \r
1926                                 // 孫ノード\r
1927                                 case 4:\r
1928                                         switch ( node ) {\r
1929                                         case KEYWORDGROUP:\r
1930                                                 for (SearchKey search : srKeys.getSearchKeys()) {\r
1931                                                         if (path.getLastPathComponent().toString().equals(search.getLabel())) {\r
1932                                                                 redrawListByKeyword(search);\r
1933                                                                 break;\r
1934                                                         }\r
1935                                                 }\r
1936                                                 break;\r
1937                                         case GENRE:\r
1938                                                 ProgGenre genre = ProgGenre.get(path.getPathComponent(2).toString());\r
1939                                                 if ( genre != null ) {\r
1940                                                         ProgSubgenre subgenre = ProgSubgenre.get(path.getLastPathComponent().toString());\r
1941                                                         if ( subgenre != null ) {\r
1942                                                                 redrawListByGenre(genre, subgenre);\r
1943                                                         }\r
1944                                                 }\r
1945                                                 break;\r
1946                                         default:\r
1947                                                 break;\r
1948                                         }\r
1949                                         jLabel_tree.setView(node, path.getLastPathComponent().toString());\r
1950                                         break;\r
1951                                 }\r
1952                                 \r
1953                                 if (stop_timer) {\r
1954                                         stopTimer( ! (path.getPathCount() >= 2 && path.getPathComponent(1).toString().equals(JTreeLabel.Nodes.NOW.toString())));\r
1955                                 }\r
1956                                 else {\r
1957                                         startTimer();\r
1958                                 }\r
1959                         }\r
1960                 }\r
1961         };\r
1962         \r
1963         private final MouseListener ml_treehide = new MouseAdapter() {\r
1964                 public void mouseEntered(MouseEvent e) {\r
1965                         if (isFullScreen()) {\r
1966                                 setExpandTree();\r
1967                                 //StdAppendMessage("Show tree (L)");\r
1968                         }\r
1969                 }\r
1970                 public void mouseExited(MouseEvent e) {\r
1971                         if (isFullScreen()) {\r
1972                                 setCollapseTree();\r
1973                                 //StdAppendMessage("Hide tree (L)");\r
1974                         }\r
1975                 }\r
1976         };\r
1977         \r
1978         \r
1979         /**\r
1980          * ツリーのリスナーを止める\r
1981          */\r
1982         private void stopTreeListener() {\r
1983                 jTree_tree.removeMouseListener(ml_nodeselected);\r
1984                 jTree_tree.removeTreeSelectionListener(tsl_nodeselected);\r
1985         }\r
1986         \r
1987         /**\r
1988          * ツリーのリスナーを動かす\r
1989          */\r
1990         private void startTreeListener() {\r
1991                 jTree_tree.addMouseListener(ml_nodeselected);\r
1992                 jTree_tree.addTreeSelectionListener(tsl_nodeselected);\r
1993         }\r
1994 \r
1995         /**\r
1996          * 検索履歴でサブノード作成\r
1997          */\r
1998         public void redrawTreeByHistory() {\r
1999                 \r
2000                 stopTreeListener();\r
2001                 TreePath tp = jTree_tree.getSelectionPath();\r
2002                 \r
2003                 SearchResult searched = tvprograms.getSearched();\r
2004                 \r
2005                 searchedNode.removeAllChildren();\r
2006                 for ( int i=0; i<searched.getResultBufferSize(); i++) {\r
2007                         searchedNode.add(new VWListedTreeNode(searched.getLabel(i)));\r
2008                 }\r
2009                 \r
2010                 jTree_tree.setSelectionPath(tp);\r
2011                 jTree_tree.updateUI();\r
2012                 startTreeListener();\r
2013         }\r
2014 \r
2015         /**\r
2016          * 新番組/最終回でサブノード作成\r
2017          */\r
2018         private void redrawTreeByGenre() {\r
2019                 \r
2020                 stopTreeListener();\r
2021                 TreePath tp = jTree_tree.getSelectionPath();\r
2022                 \r
2023                 _redrawTreeByGenre(nowNode);\r
2024                 _redrawTreeByGenre(startNode);\r
2025                 _redrawTreeByGenre(endNode);\r
2026                 \r
2027                 jTree_tree.setSelectionPath(tp);\r
2028                 jTree_tree.updateUI();\r
2029                 startTreeListener();\r
2030         }\r
2031         \r
2032         private void _redrawTreeByGenre(DefaultMutableTreeNode parent) {\r
2033                 parent.removeAllChildren();\r
2034                 for ( ProgGenre genre : ProgGenre.values() ) {\r
2035                         parent.add(new VWListedTreeNode(genre.toString()));\r
2036                 }\r
2037         }\r
2038 \r
2039         /**\r
2040          * しょぼかるでサブノード作成\r
2041          */\r
2042         private void redrawTreeBySyobo() {\r
2043                 \r
2044                 stopTreeListener();\r
2045                 TreePath tp = jTree_tree.getSelectionPath();\r
2046                 \r
2047                 syobocalNode.removeAllChildren();\r
2048                 syobocalNode.add(new VWListedTreeNode(JTreeLabel.Nodes.TRACE.getLabel()));\r
2049                 syobocalNode.add(new VWListedTreeNode(JTreeLabel.Nodes.KEYWORD.getLabel()));\r
2050                 syobocalNode.add(new VWListedTreeNode(JTreeLabel.Nodes.SYOBOALL.getLabel()));\r
2051                 \r
2052                 jTree_tree.setSelectionPath(tp);\r
2053                 jTree_tree.updateUI();\r
2054                 startTreeListener();\r
2055         }\r
2056         \r
2057         /**\r
2058          * 予約待機でサブノード作成\r
2059          */\r
2060         private void redrawTreeByStandby() {\r
2061                 \r
2062                 stopTreeListener();\r
2063                 TreePath tp = jTree_tree.getSelectionPath();\r
2064                 \r
2065                 standbyNode.removeAllChildren();\r
2066                 for ( String okini : TVProgram.OKINIIRI ) {\r
2067                         if ( ! "".equals(okini) ) {\r
2068                                 standbyNode.add(new VWListedTreeNode(okini));\r
2069                         }\r
2070                 }\r
2071                 standbyNode.add(new VWListedTreeNode(JTreeLabel.Nodes.PICKUP.getLabel()));\r
2072                 standbyNode.add(new VWListedTreeNode(JTreeLabel.Nodes.NEWARRIVAL.getLabel()));\r
2073                 standbyNode.add(new VWListedTreeNode(JTreeLabel.Nodes.MODIFIED.getLabel()));\r
2074                 if ( env.getUseSyobocal() ) {\r
2075                         standbyNode.add(new VWListedTreeNode(JTreeLabel.Nodes.SYOBOONLY.getLabel()));\r
2076                 }\r
2077                 \r
2078                 jTree_tree.setSelectionPath(tp);\r
2079                 jTree_tree.updateUI();\r
2080                 startTreeListener();\r
2081         }\r
2082         \r
2083         /**\r
2084          * 番組追跡でサブノード作成\r
2085          */\r
2086         public void redrawTreeByTrace() {\r
2087                 \r
2088                 stopTreeListener();\r
2089                 TreePath tp = jTree_tree.getSelectionPath();\r
2090                 \r
2091                 traceNode.removeAllChildren();\r
2092                 for ( TraceKey key : trKeys.getTraceKeys() ) {\r
2093                         traceNode.add(new VWListedTreeNode(key.getLabel(), mpList.isTrKeyUsed(key.getLabel())));\r
2094                 }\r
2095                 \r
2096                 jTree_tree.setSelectionPath(tp);\r
2097                 jTree_tree.updateUI();\r
2098                 startTreeListener();\r
2099         }\r
2100         \r
2101         /**\r
2102          * キーワード検索でサブノード作成\r
2103          */\r
2104         public void redrawTreeByKeyword() {\r
2105                 \r
2106                 stopTreeListener();\r
2107                 TreePath tp = jTree_tree.getSelectionPath();\r
2108                 \r
2109                 keywordNode.removeAllChildren();\r
2110                 for ( SearchKey key : srKeys.getSearchKeys() ) {\r
2111                         keywordNode.add(new VWListedTreeNode(key.getLabel(), mpList.isSrKeyUsed(key.getLabel())));\r
2112                 }\r
2113                 \r
2114                 jTree_tree.setSelectionPath(tp);\r
2115                 jTree_tree.updateUI();\r
2116                 startTreeListener();\r
2117         }\r
2118 \r
2119         /**\r
2120          * サブジャンルでサブノード作成\r
2121          */\r
2122         public void redrawTreeBySubGenre() {\r
2123                 \r
2124                 stopTreeListener();\r
2125                 TreePath tp = jTree_tree.getSelectionPath();\r
2126                 \r
2127                 genreNode.removeAllChildren();\r
2128                 for ( ProgGenre genre : ProgGenre.values() ) {\r
2129                         VWListedTreeNode g = new VWListedTreeNode(genre.toString());\r
2130                         genreNode.add(g);\r
2131                         for ( ProgSubgenre subgenre : ProgSubgenre.values(genre) ) {\r
2132                                 VWListedTreeNode sg = new VWListedTreeNode(subgenre.toString()); \r
2133                                 g.add(sg);\r
2134                         }\r
2135                 }\r
2136                 \r
2137                 jTree_tree.setSelectionPath(tp);\r
2138                 jTree_tree.updateUI();\r
2139                 startTreeListener();\r
2140         }\r
2141 \r
2142         /**\r
2143          * 放送局でサブノード作成\r
2144          */\r
2145         public void redrawTreeByCenter() {\r
2146                 \r
2147                 stopTreeListener();\r
2148                 TreePath tp = jTree_tree.getSelectionPath();\r
2149                 \r
2150                 centerListNode.removeAllChildren();\r
2151                 TVProgramIterator pli = tvprograms.getIterator().build(chsort.getClst(), IterationType.ALL);\r
2152                 for ( ProgList pl : pli ) {\r
2153                         centerListNode.add(new VWListedTreeNode(pl.Center));\r
2154                 }\r
2155                 \r
2156                 jTree_tree.setSelectionPath(tp);\r
2157                 jTree_tree.updateUI();\r
2158                 startTreeListener();\r
2159         }\r
2160 \r
2161         /**\r
2162          * キーワードグループでサブノード作成\r
2163          */\r
2164         public void redrawTreeByKeywordGroup() {\r
2165                 \r
2166                 stopTreeListener();\r
2167                 TreePath tp = jTree_tree.getSelectionPath();\r
2168                 \r
2169                 keywordGrpNode.removeAllChildren();\r
2170                 for ( SearchGroup gr : srGrps ) {\r
2171                         VWListedTreeNode gn = new VWListedTreeNode(gr.getName());\r
2172                         keywordGrpNode.add(gn);\r
2173                         for ( String kw : gr ) {\r
2174                                 gn.add(new VWListedTreeNode(kw));\r
2175                         }\r
2176                 }\r
2177                 \r
2178                 jTree_tree.setSelectionPath(tp);\r
2179                 jTree_tree.updateUI();\r
2180                 startTreeListener();\r
2181         }\r
2182 \r
2183         /**\r
2184          * 放送局でサブノード作成\r
2185          */\r
2186         public void redrawTreeByExtension() {\r
2187                 \r
2188                 stopTreeListener();\r
2189                 TreePath tp = jTree_tree.getSelectionPath();\r
2190                 \r
2191                 extensionNode.removeAllChildren();\r
2192                 for ( SearchKey key : extKeys.getSearchKeys() ) {\r
2193                         extensionNode.add(new VWListedTreeNode(key.getLabel()));\r
2194                 }\r
2195                 \r
2196                 jTree_tree.setSelectionPath(tp);\r
2197                 jTree_tree.updateUI();\r
2198                 startTreeListener();\r
2199         }\r
2200         \r
2201         \r
2202         \r
2203         /**\r
2204          * 現時点でまだ開始していない番組を上から順に選択する。\r
2205          */\r
2206         public void selectBatchTarget() {\r
2207                 \r
2208                 String dt = CommonUtils.getDateTime(0);\r
2209                 \r
2210                 int cnt=1;\r
2211                 for (int row=0; row<rowData.size(); row++) {\r
2212                         ListedItem c = rowData.get(row);\r
2213                         if (dt.compareTo(c.tvd.startDateTime) > 0) {\r
2214                                 // 開始日時が過去のものは対象外\r
2215                                 continue;\r
2216                         }\r
2217                         if ( c.rsvmark.length() == 0 || c.rsvmark.equals(RSVMARK_URABAN) ) {\r
2218                                 int vrow = jTable_listed.convertRowIndexToView(row);\r
2219                                 jTable_listed.getSelectionModel().addSelectionInterval(vrow, vrow);\r
2220                                 if (cnt++ >= env.getRsvTargets()) {\r
2221                                         return;\r
2222                                 }\r
2223                         }\r
2224                 }\r
2225         }\r
2226         \r
2227         /**\r
2228          * ツールバーの一括予約ボタンを押して実行される一括予約処理\r
2229          */\r
2230         public void doBatchReserve() {\r
2231                 //\r
2232                 boolean mod = false;\r
2233                 for (int vrow : jTable_listed.getSelectedRows()) {\r
2234                         \r
2235                         int row = jTable_listed.convertRowIndexToModel(vrow);\r
2236                         ProgDetailList tvd = rowData.get(row).tvd;\r
2237                         \r
2238                         //VWReserveDialog rD = new VWReserveDialog(0, 0, env, tvprograms, recorders, avs, chavs, stwin);\r
2239                         //rD.clear();\r
2240 \r
2241                         if (rD.open(tvd)) {\r
2242                                 rD.doRecord();\r
2243                         }\r
2244                         \r
2245                         // 予約ダイアログは見せないまま更新を実行する\r
2246                         \r
2247                         if ( ! rD.isReserved()) {\r
2248                                 StdAppendError("【警告】予約の登録に失敗しました: "+rowData.get(row).tvd.title);\r
2249                                 break;\r
2250                         }\r
2251                         else {\r
2252                                 mod = true;\r
2253                         }\r
2254                 }\r
2255                 if (mod) {\r
2256                         // 自分\r
2257                         setReservedMarks();\r
2258                         tableModel_listed.fireTableDataChanged();\r
2259                         rowheaderModel_listed.fireTableDataChanged();\r
2260                         refocus();\r
2261                         // 他人\r
2262                         updateReserveDisplay(null);\r
2263                 }\r
2264         }\r
2265         \r
2266         /**\r
2267          * 他のクラスで発生したイベント中に呼び出されてリスト形式の予約マーク表示を更新するためのメソッド。\r
2268          * ★synchronized(rowData)★\r
2269          * @see #cl_tabshownhidden\r
2270          */\r
2271         public void updateReserveMark() {\r
2272                 // ★★★ イベントにトリガーされた処理がかちあわないように synchronized() ★★★\r
2273                 synchronized ( rowData ) {\r
2274                         setReservedMarks();\r
2275                         tableModel_listed.fireTableDataChanged();\r
2276                         rowheaderModel_listed.fireTableDataChanged();\r
2277                 }\r
2278         }\r
2279         \r
2280         /**\r
2281          * テーブルを更新した後、セレクション状態が解除されるので再度セレクションする。\r
2282          */\r
2283         public void refocus() {\r
2284                 if (vrowInFocus >= 0) {\r
2285                         jTable_listed.getSelectionModel().addSelectionInterval(vrowInFocus, vrowInFocus);\r
2286                         vrowInFocus = -1;\r
2287                 }\r
2288         }\r
2289 \r
2290         /**\r
2291          * カラム幅を保存する(鯛ナビ終了時に呼び出されるメソッド)\r
2292          */\r
2293         public void copyColumnWidth() {\r
2294                 //DefaultTableColumnModel columnModel = (DefaultTableColumnModel)jTable_listed.getColumnModel();\r
2295                 TableColumn column = null;\r
2296                 for ( ListedColumn lc : ListedColumn.values() ) {\r
2297                         if ( lc.getIniWidth() < 0 ) {\r
2298                                 continue;\r
2299                         }\r
2300                         try {\r
2301                                 column = jTable_listed.getColumn(lc.getName());\r
2302                                 bounds.getListedColumnSize().put(lc.toString(), column.getPreferredWidth());    // toString()!\r
2303                         }\r
2304                         catch (IllegalArgumentException e) {\r
2305                                 // 非表示のカラムは操作できない\r
2306                         }\r
2307                 }\r
2308         }\r
2309         \r
2310         // キーワードにマッチした箇所の強調色\r
2311         public void setMatchedKeywordColor(Color c) {\r
2312                 titleCellRenderer.setMatchedKeywordColor(c);\r
2313         }\r
2314         \r
2315         // 予約行の強調表示\r
2316         public void setRsvdLineColor(Color c) {\r
2317                 jTable_listed.setReservedColor(c);\r
2318         }\r
2319         \r
2320         // ピックアップ行の強調表示\r
2321         public void setPickedLineColor(Color c) {\r
2322                 jTable_listed.setPickedColor(c);\r
2323         }\r
2324         \r
2325         // 予約行の強調表示\r
2326         public void setCurrentLineColor(Color c) {\r
2327                 jTable_listed.setCurrentColor(c);\r
2328         }\r
2329         \r
2330         // 番組詳細の表示・非表示\r
2331         public void setMarkColumnVisible(boolean b) {\r
2332                 jTable_listed.setColumnVisible(ListedColumn.OPTIONS.getName(), b);\r
2333         }\r
2334         \r
2335         // 番組詳細の表示・非表示\r
2336         public void setDetailColumnVisible(boolean b) {\r
2337                 jTable_listed.setColumnVisible(ListedColumn.DETAIL.getName(), b);\r
2338         }\r
2339 \r
2340         /*\r
2341          * 特定の項目を取得しやすくした感じ?\r
2342          */\r
2343         \r
2344         // 検索結果一覧上のIdNumをintに戻す\r
2345         private int getThrValByRow(int row) { \r
2346                 try {\r
2347                         return Integer.valueOf(rowData.get(row).threshold);\r
2348                 } catch (NumberFormatException e2) {\r
2349                         // No proc.\r
2350                 }\r
2351                 return 0;\r
2352         }\r
2353         private String getKeyValByRow(int row) {\r
2354                 Matcher ma = Pattern.compile("^(.+)\\s*\\([^\\)]+?\\)$").matcher(rowData.get(row).searchlabel);\r
2355                 if (ma.find()) {\r
2356                         return ma.group(1);\r
2357                 }\r
2358                 return "";\r
2359         }\r
2360         \r
2361         \r
2362         \r
2363         \r
2364         \r
2365         /*\r
2366          * 予約マークの取得だお!\r
2367          */\r
2368         \r
2369         private class Marker {\r
2370                 String mark; \r
2371                 String myself;\r
2372                 String color;\r
2373                 \r
2374                 public Marker(String mark, String myself, String color) {\r
2375                         this.mark = mark;\r
2376                         this.myself = myself;\r
2377                         this.color = color;\r
2378                 }\r
2379         }\r
2380         \r
2381         /**\r
2382          * 引数で指定した番組を予約している、または予約に一部時間が重なっている場合に表示する予約マークを取得する。\r
2383          * @param Center チェックする番組の放送局名\r
2384          * @param startDateTime チェックする番組の開始日時\r
2385          * @param endDateTime チェックする番組の終了日時\r
2386          * @param title チェックする番組のタイトル\r
2387          * @param extention 延長警告がなされている番組の場合はtrueを指定。\r
2388          * @return String [0]マーク [1]予約しているレコーダのユニークID({@link HDDRecorder#Myself()}) [2]色({@link CommonUtils#str2color(String)})\r
2389          */\r
2390         private Marker getReservedMarkChar(ListedItem data) {\r
2391                 \r
2392                 //\r
2393                 HDDRecorder recorder = null;                                            // その番組の予約がみつかった最初のレコーダ\r
2394                 ReserveList reserve = null;                                                     // 見つかった予約情報\r
2395                 String start = null;                                                            // 実行予定が複数あったら一番近いのを選ぶ\r
2396                 String end = "";                                                                        // 同上\r
2397                 long diff = 86400L*30L;\r
2398                 \r
2399                 String myself = getSelectedRecorderOnToolbar();\r
2400                 HDDRecorderList recs = recorders.findInstance(myself);\r
2401 \r
2402                 // コンボボックスの指定はピックアップである\r
2403                 boolean isPickupOnly = ( myself != null && myself.length() == 0 ) ;\r
2404                 \r
2405                 if ( ! isPickupOnly ) {\r
2406                         \r
2407                         // 「ピックアップ」が選択されていればここは通らない\r
2408                         \r
2409                         // 基準日時\r
2410                         String critDateTime = CommonUtils.getCritDateTime(env.getDisplayPassedReserve());\r
2411                         \r
2412                         // 全予約をなめて、一番近い予約を探さなければならない\r
2413                         for ( HDDRecorder rec : recs )\r
2414                         {\r
2415                                 if (diff == 0) break;\r
2416                                 \r
2417                                 for ( ReserveList res : rec.getReserves() )\r
2418                                 {\r
2419                                         if (diff == 0) break;\r
2420                                         \r
2421                                         // Exec == ON ?\r
2422                                         if ( env.getDisplayOnlyExecOnEntry() && ! res.getExec()) {\r
2423                                                 continue;\r
2424                                         }\r
2425                                         \r
2426                                         if (res.getCh_name() == null) {\r
2427                                                 // 警告したい!\r
2428                                                 continue;\r
2429                                         }\r
2430                                         \r
2431                                         // 局が一致して\r
2432                                         if ( ! data.tvd.center.equals(res.getCh_name())) {\r
2433                                                 continue;\r
2434                                         }\r
2435                                                 \r
2436                                         // 開始終了日時リストを生成する\r
2437                                         ArrayList<String> starts = new ArrayList<String>();\r
2438                                         ArrayList<String> ends = new ArrayList<String>();\r
2439                                         CommonUtils.getStartEndList(starts, ends, res);\r
2440                                         \r
2441                                         for (int j=0; j<starts.size(); j++) {\r
2442                                                 if (critDateTime.compareTo(ends.get(j)) > 0) {\r
2443                                                         // 終了済みは対象外\r
2444                                                         continue;\r
2445                                                 }\r
2446                                                 if ( CommonUtils.isOverlap(data.tvd.startDateTime, data.tvd.endDateTime, starts.get(j), ends.get(j), true) ) {\r
2447                                                         // より開始時刻が近いものを選ぶ\r
2448                                                         if ( start == null ) {\r
2449                                                                 start = starts.get(j);\r
2450                                                         }\r
2451                                                         long df = CommonUtils.getDiffDateTime(starts.get(j), data.tvd.startDateTime);\r
2452                                                         if ( diff > df ) {\r
2453                                                                 recorder = rec;\r
2454                                                                 reserve = res;\r
2455                                                                 start = starts.get(j);\r
2456                                                                 end = ends.get(j);\r
2457                                                                 diff = df;\r
2458                                                         }\r
2459                                                 }\r
2460                                         }\r
2461                                 }\r
2462                         }\r
2463                 }\r
2464                 \r
2465                 // 予約されている\r
2466                 \r
2467                 Marker mark = null;\r
2468                 Marker pickmark = null;\r
2469                 Marker uramark = null;\r
2470                 \r
2471                 // 予約マーク\r
2472                 if (recorder != null) {\r
2473                         mark = _getReservedMarkCharNormal(data, recorder, reserve, start, end);\r
2474                 }\r
2475                 // ピックアップマーク\r
2476                 if (env.getShowRsvPickup()) {\r
2477                         pickmark = _getReservedMarkCharPickup(data);\r
2478                 }\r
2479                 // 裏番組予約マーク\r
2480                 if (mark == null && pickmark == null && env.getShowRsvUra()) {\r
2481                         uramark = _getReservedMarkCharUra(data);\r
2482                 }\r
2483                 \r
2484                 if ( mark != null ) {\r
2485                         return mark;\r
2486                 }\r
2487                 if ( pickmark != null || isPickupOnly ) {\r
2488                         return pickmark;\r
2489                 }\r
2490                 if ( uramark != null ) {\r
2491                         return uramark;\r
2492                 }\r
2493                 \r
2494                 // 予約されていない\r
2495                 return(null);\r
2496         }\r
2497         /**\r
2498          * @see #getReservedMarkChar(String, String, String, String, boolean) \r
2499          */\r
2500         private Marker _getReservedMarkCharNormal(ListedItem data, HDDRecorder recorder, ReserveList reserve, String start, String end) {\r
2501                 \r
2502                 // ここに入ってくる場合は時間の重なりが確認できているものだけである\r
2503                 \r
2504                 RSVMARK_COND cond = getReservedMarkCond(data, start, end);\r
2505                 \r
2506                 if (debug) System.err.println(DBGID+data.tvd.title+" "+data.tvd.startDateTime+" "+data.tvd.endDateTime+" "+start+" "+end+" "+cond);\r
2507                 \r
2508                 String mark = null;\r
2509                 \r
2510                 switch (cond) {\r
2511                 case PREV:\r
2512                         return null;\r
2513                 case DELAY:\r
2514                         mark = RSVMARK_DELAYED;\r
2515                         break;\r
2516                 case UNDER:\r
2517                         mark = RSVMARK_UNDERRUN;\r
2518                         break;\r
2519                 case OVER:\r
2520                         mark = RSVMARK_OVERRUN;\r
2521                         break;\r
2522                 case CLIP:\r
2523                         mark = (data.tvd.extension) ? (RSVMARK_CLIPPED_E) : (RSVMARK_CLIPPED);\r
2524                         break;\r
2525                 case SHORT:\r
2526                         mark = (data.tvd.extension) ? (RSVMARK_SHORTAGE_E) : (RSVMARK_SHORTAGE);\r
2527                         break;\r
2528                 default:\r
2529                         mark = RSVMARK_NORMAL;\r
2530                         break;\r
2531                 }\r
2532 \r
2533                 return(new Marker((reserve.getExec())?(mark):(RSVMARK_NOEXEC), recorder.Myself(), recorder.getColor(reserve.getTuner())));\r
2534         }\r
2535         private RSVMARK_COND getReservedMarkCond(ListedItem data, String start, String end) {\r
2536                 {\r
2537                         // 番組の終了日時と予約の開始日時(1分は想定内)\r
2538                         int overlap = (int) (CommonUtils.getCompareDateTime(data.tvd.endDateTime,start)/60000L);\r
2539                         if ( env.getOverlapUp() && overlap == 1 )\r
2540                                 return RSVMARK_COND.PREV;\r
2541                 }\r
2542                 {\r
2543                         // 番組の開始日時と予約の開始日時(1分でも遅れちゃだめ)\r
2544                         int overlap = (int) (CommonUtils.getCompareDateTime(data.tvd.startDateTime,start)/60000L);\r
2545                         if ( overlap <= -1 )\r
2546                                 return RSVMARK_COND.DELAY;\r
2547                 }\r
2548                 \r
2549                 // 延長警告がある場合はこんだけ延びる\r
2550                 int spoex_length = (data.tvd.extension)?(Integer.valueOf(env.getSpoexLength())):(0);\r
2551                 \r
2552                 {\r
2553                         // 番組の終了日時と予約の終了日時\r
2554                         int overlap = (int) (CommonUtils.getCompareDateTime(data.tvd.endDateTime,end)/60000L);\r
2555                         \r
2556                         if (data.tvd.extension) {\r
2557                                 // ここは、延長警告で時間が延びるはずが微妙に延びてない感じの予約を探すためのもの\r
2558                                 \r
2559                                 // 通常1分短縮から~延長2分短縮まで\r
2560                                 // 通常1分延長から~延長0分延長まで\r
2561                                 // どちらでもなければ通常0分短縮から~延長1分短縮まで\r
2562                                 if (\r
2563                                                 (env.getOverlapDown2() && ! data.tvd.dontoverlapdown && (overlap <= 1  && (overlap+spoex_length) >= 2)) ||\r
2564                                                 (env.getOverlapDown()  && (overlap <= -1 && (overlap+spoex_length) >= 0)) ||\r
2565                                                 ( ( ! env.getOverlapDown2() || env.getOverlapDown2() && data.tvd.dontoverlapdown) && ! env.getOverlapDown() && (overlap <= 0 && (overlap+spoex_length) >= 1))\r
2566                                                 )\r
2567                                         return RSVMARK_COND.UNDER;\r
2568                         }\r
2569                         \r
2570                         // ケツ短縮で0分以上進んでたらだめ\r
2571                         // ケツ延長で2分以上進んでたらだめ\r
2572                         // どちらでもなければ1分以上進んでたらだめ\r
2573                         if (\r
2574                                         (env.getOverlapDown2() && ! data.tvd.dontoverlapdown && (overlap+spoex_length) <= 0) ||\r
2575                                         (env.getOverlapDown() && (overlap+spoex_length) <= -2) ||\r
2576                                         ( ( ! env.getOverlapDown2() || env.getOverlapDown2() && data.tvd.dontoverlapdown) && ! env.getOverlapDown() && (overlap+spoex_length) <= -1)\r
2577                                         )\r
2578                                 return RSVMARK_COND.OVER;\r
2579                         \r
2580                         if ( env.getOverlapDown2() ) {\r
2581                                 // 1分短縮時に1分なら予定通り\r
2582                                 if ( (overlap+spoex_length) == 1 )\r
2583                                         return RSVMARK_COND.CLIP;\r
2584                                 // 2分はどうかな\r
2585                                 if ( (overlap+spoex_length) >= 2 )\r
2586                                         return RSVMARK_COND.SHORT;\r
2587                         }\r
2588                         else {\r
2589                                 // 1分でもだめ\r
2590                                 if ( (overlap+spoex_length) >= 2 )\r
2591                                         return RSVMARK_COND.SHORT;\r
2592                         }\r
2593                         \r
2594                         if ( env.getOverlapDown() ) {\r
2595                                 // 1分延長時に1分なら予定通り\r
2596                                 if ( (overlap+spoex_length) == -1 )\r
2597                                         return RSVMARK_COND.CLIP;\r
2598                                 // ぴったりはだめでしょ\r
2599                                 if ( (overlap+spoex_length) <= 0 )\r
2600                                         return RSVMARK_COND.SHORT;\r
2601                         }\r
2602                         else {\r
2603                                 // 1分でもだめ\r
2604                                 if ( (overlap+spoex_length) <= -1 )\r
2605                                         return RSVMARK_COND.SHORT;\r
2606                         }\r
2607                         \r
2608                 }\r
2609                 \r
2610                 // それら以外の場合(正常予約)\r
2611                 return RSVMARK_COND.NORMAL;\r
2612         }\r
2613         private static enum RSVMARK_COND { PREV, DELAY, UNDER, OVER, CLIP, SHORT, NORMAL };\r
2614         \r
2615         private Marker _getReservedMarkCharPickup(ListedItem data) {\r
2616                 //return (data.hide_ispickup)?(new Marker(RSVMARK_PICKUP,"",PICKUP_COLOR)):(null);\r
2617                 //\r
2618                 PickedProgram picktvp = tvprograms.getPickup();\r
2619                 \r
2620                 // みつかるかな?\r
2621                 ProgDetailList picktvd = picktvp.find(data.tvd);\r
2622                 if ( picktvd == null ) {\r
2623                         // みつかんねーよ\r
2624                         return null;\r
2625                 }\r
2626                 \r
2627                 return new Marker(RSVMARK_PICKUP,"",PICKUP_COLOR);\r
2628         }\r
2629         \r
2630         private Marker _getReservedMarkCharUra(ListedItem data) {\r
2631                 //\r
2632                 String myself = getSelectedRecorderOnToolbar();\r
2633                 HDDRecorderList recs = recorders.findInstance(myself);\r
2634                 \r
2635                 for ( HDDRecorder rec : recs )\r
2636                 {\r
2637                         for ( ReserveList res : rec.getReserves() ) {\r
2638                                 // Exec == ON ?\r
2639                                 if ( env.getDisplayOnlyExecOnEntry() && ! res.getExec() ) {\r
2640                                         // 無効状態はしらねーよ\r
2641                                         continue;\r
2642                                 }\r
2643                                 if ( data.tvd.center.equals(res.getCh_name()) ) {\r
2644                                         // 局が違うならいらねーよ → 裏番組だろ、逆だろJK\r
2645                                         continue;\r
2646                                 }\r
2647                                         \r
2648                                 // 開始終了日時リストを生成する\r
2649                                 ArrayList<String> starts = new ArrayList<String>();\r
2650                                 ArrayList<String> ends = new ArrayList<String>();\r
2651                                 CommonUtils.getStartEndList(starts, ends, res);\r
2652                                 for (int j=0; j<starts.size(); j++) {\r
2653                                         if ( CommonUtils.isOverlap(data.tvd.startDateTime, data.tvd.endDateTime, starts.get(j), ends.get(j), env.getAdjoiningNotRepetition()) ) {\r
2654                                                 return new Marker(RSVMARK_URABAN,"",URABAN_COLOR);\r
2655                                         }\r
2656                                 }\r
2657                         }\r
2658                 }\r
2659                 return null;\r
2660         }\r
2661         \r
2662         \r
2663         \r
2664         \r
2665         \r
2666         /*\r
2667          *  ここからノード編集系がいっぱいならんでるお!\r
2668          */\r
2669         \r
2670         /**\r
2671          * 番組追跡を編集したい\r
2672          */\r
2673         private void editTraceKey(String keyword) {\r
2674                 \r
2675                 VWTraceKeyDialog tD = new VWTraceKeyDialog(0,0);\r
2676                 CommonSwingUtils.setLocationCenter(parent,tD);\r
2677                 \r
2678                 tD.reopen(keyword, trKeys);\r
2679                 tD.setVisible(true);\r
2680                 \r
2681                 if (tD.isRegistered()) { \r
2682                         // 検索結果の再構築\r
2683                         mpList.clear(env.getDisableFazzySearch(), env.getDisableFazzySearchReverse());\r
2684                         mpList.build(tvprograms, trKeys.getTraceKeys(), srKeys.getSearchKeys());\r
2685                         \r
2686                         //trKeys.save();        // 保存はtDの中でやってるよ\r
2687                         \r
2688                         // 変更したノードを選択するようにしたい\r
2689                         jLabel_tree.setView(JTreeLabel.Nodes.TRACE, tD.getNewLabel());\r
2690                         \r
2691                         // 新聞形式を修正してほしい\r
2692                         updateBangumiColumns();\r
2693 \r
2694                         // ツリーを更新\r
2695                         redrawTreeByTrace();\r
2696                         \r
2697                         // ツリーを再選択\r
2698                         reselectTree();\r
2699                 }\r
2700         }\r
2701         \r
2702         /**\r
2703          * 番組追跡を削除したい\r
2704          */\r
2705         private void removeTraceKey(String keyword) {\r
2706                 \r
2707                 if (env.getShowWarnDialog()) {\r
2708                         //Container cp = frame.getContentPane();\r
2709                         int ret = JOptionPane.showConfirmDialog(parent, "削除しますか?【"+keyword+"】", "確認", JOptionPane.YES_NO_OPTION);\r
2710                         if (ret != JOptionPane.YES_OPTION) {\r
2711                                 return;\r
2712                         }\r
2713                 }\r
2714                 \r
2715                 MWin.appendMessage("番組追跡が削除されました【"+keyword+"】");\r
2716 \r
2717                 // 保存\r
2718                 trKeys.remove(keyword);\r
2719                 trKeys.save();\r
2720                 \r
2721                 // 検索結果の再構築\r
2722                 mpList.clear(env.getDisableFazzySearch(), env.getDisableFazzySearchReverse());\r
2723                 mpList.build(tvprograms, trKeys.getTraceKeys(), srKeys.getSearchKeys());\r
2724                 //mpList.debug();\r
2725                 \r
2726                 // 新聞形式を修正してほしい\r
2727                 updateBangumiColumns();\r
2728                 \r
2729                 // ツリーを更新\r
2730                 redrawTreeByTrace();\r
2731         }\r
2732         \r
2733         /**\r
2734          * 番組追跡のお気に入りを変更したい\r
2735          */\r
2736         private void setTraceKeyOkiniiri(TraceKey tk, String okini) {\r
2737                 \r
2738                 // 保存\r
2739                 tk.setOkiniiri(okini);\r
2740                 trKeys.save();\r
2741                 \r
2742                 // 検索結果の再構築\r
2743                 mpList.clear(env.getDisableFazzySearch(), env.getDisableFazzySearchReverse());\r
2744                 mpList.build(tvprograms, trKeys.getTraceKeys(), srKeys.getSearchKeys());\r
2745                 \r
2746                 // ツリーに反映する\r
2747                 reselectTree();\r
2748         }\r
2749         \r
2750         /**\r
2751          * 番組追跡を並べ替えたい\r
2752          */\r
2753         private void sortTraceKey() {\r
2754                 //\r
2755                 ArrayList<String> oList = new ArrayList<String>();\r
2756                 for ( TraceKey key : trKeys.getTraceKeys() ) {\r
2757                         oList.add(key.getLabel());\r
2758                 }\r
2759                 \r
2760                 // 編集前のリストサイズ\r
2761                 int oCnt = oList.size();\r
2762                 \r
2763                 //\r
2764                 JListSortDialog lsD = new JListSortDialog("番組追跡の並べ替え", oList);\r
2765                 CommonSwingUtils.setLocationCenter(parent,lsD);\r
2766                 \r
2767                 lsD.setVisible(true);\r
2768 \r
2769                 if (lsD.isRegistered()) {\r
2770                         TraceProgram newTrKeys = new TraceProgram();\r
2771                         for ( String label : oList ) {\r
2772                                 for ( TraceKey key : trKeys.getTraceKeys() ) {\r
2773                                         if ( key.getLabel().equals(label) ) {\r
2774                                                 newTrKeys.add(key);\r
2775                                                 break;\r
2776                                         }\r
2777                                 }\r
2778                         }\r
2779                         //trKeys = newTrKeys;\r
2780                         FieldUtils.deepCopy(trKeys, newTrKeys);\r
2781                         trKeys.save();\r
2782                         \r
2783                         if ( oList.size() < oCnt ) {\r
2784                                 // 削除があった場合のみ検索結果の再構築\r
2785                                 mpList.clear(env.getDisableFazzySearch(), env.getDisableFazzySearchReverse());\r
2786                                 mpList.build(tvprograms, trKeys.getTraceKeys(), srKeys.getSearchKeys());\r
2787                         }\r
2788                         \r
2789                         // ツリーを更新\r
2790                         redrawTreeByTrace();\r
2791                 }\r
2792         }\r
2793 \r
2794         /**\r
2795          * キーワード検索を編集したい\r
2796          */\r
2797         private void editSearchKey(String keyword) {\r
2798                 //\r
2799                 AbsKeywordDialog kD = new VWKeywordDialog();\r
2800                 CommonSwingUtils.setLocationCenter(parent,kD);\r
2801                 \r
2802                 kD.reopen(keyword, srKeys);\r
2803                 kD.setVisible(true);\r
2804 \r
2805                 if (kD.isRegistered()) {\r
2806                         // 検索結果の再構築\r
2807                         mpList.clear(env.getDisableFazzySearch(), env.getDisableFazzySearchReverse());\r
2808                         mpList.build(tvprograms, trKeys.getTraceKeys(), srKeys.getSearchKeys());\r
2809                         //mpList.debug();\r
2810                         \r
2811                         // キーワードグループにも反映\r
2812                         if ( ! kD.getNewLabel().equals(keyword) ) {\r
2813                                 if ( srGrps.rename(null, keyword, kD.getNewLabel()) ) {\r
2814                                         srGrps.save();\r
2815                                 }\r
2816                         }\r
2817                         \r
2818                         // srKeys.save();       // 保存はkDの中でやってるよ\r
2819 \r
2820                         // 変更したノードを選択するようにしたい\r
2821                         jLabel_tree.setView(JTreeLabel.Nodes.KEYWORD, kD.getNewLabel());\r
2822                         \r
2823                         // 新聞形式を修正してほしい\r
2824                         updateBangumiColumns();\r
2825                         \r
2826                         // ツリーを更新\r
2827                         redrawTreeByKeyword();\r
2828                         redrawTreeByKeywordGroup();\r
2829                         \r
2830                         // ツリーを再選択\r
2831                         reselectTree();\r
2832                 }\r
2833         }\r
2834 \r
2835         /**\r
2836          * キーワード検索を削除したい\r
2837          */\r
2838         private void removeSearchKey(String keyword) {\r
2839                 \r
2840                 if (env.getShowWarnDialog()) {\r
2841                         //Container cp = getContentPane();\r
2842                         int ret = JOptionPane.showConfirmDialog(parent, "削除しますか?【"+keyword+"】", "確認", JOptionPane.YES_NO_OPTION);\r
2843                         if (ret != JOptionPane.YES_OPTION) {\r
2844                                 return;\r
2845                         }\r
2846                 }\r
2847                 \r
2848                 // 保存\r
2849                 srKeys.remove(keyword);\r
2850                 srKeys.save();\r
2851 \r
2852                 // 検索結果の再構築\r
2853                 mpList.clear(env.getDisableFazzySearch(), env.getDisableFazzySearchReverse());\r
2854                 mpList.build(tvprograms, trKeys.getTraceKeys(), srKeys.getSearchKeys());\r
2855                 //mpList.debug();\r
2856                 \r
2857                 // キーワードグループにも反映\r
2858                 if ( srGrps.remove(null,keyword) ) {\r
2859                         srGrps.save();\r
2860                 }\r
2861                 \r
2862                 // 新聞形式を修正してほしい\r
2863                 updateBangumiColumns();\r
2864                 \r
2865                 // ツリーを更新\r
2866                 redrawTreeByKeyword();\r
2867                 redrawTreeByKeywordGroup();\r
2868         }\r
2869         \r
2870         /**\r
2871          * キーワード検索のお気に入りを変更したい\r
2872          */\r
2873         private void setSearchKeyOkiniiri(SearchKey sr, String okini) {\r
2874                 // 保存\r
2875                 sr.setOkiniiri(okini);\r
2876                 srKeys.save();\r
2877                 \r
2878                 // 検索結果の再構築\r
2879                 mpList.clear(env.getDisableFazzySearch(), env.getDisableFazzySearchReverse());\r
2880                 mpList.build(tvprograms, trKeys.getTraceKeys(), srKeys.getSearchKeys());\r
2881                 \r
2882                 // ツリーに反映する\r
2883                 reselectTree();\r
2884         }\r
2885         \r
2886         /**\r
2887          * キーワード検索を並べ替えたい\r
2888          */\r
2889         private void sortSearchKey() {\r
2890                 //\r
2891                 ArrayList<String> oList = new ArrayList<String>();\r
2892                 for ( SearchKey key : srKeys.getSearchKeys() ) {\r
2893                         oList.add(key.getLabel());\r
2894                 }\r
2895                 //\r
2896                 JListSortDialog lsD = new JListSortDialog("キーワード検索の並べ替え", oList);\r
2897                 CommonSwingUtils.setLocationCenter(parent,lsD);\r
2898                 \r
2899                 lsD.setVisible(true);\r
2900 \r
2901                 if (lsD.isRegistered()) {\r
2902                         SearchProgram newSrKeys = new SearchProgram();\r
2903                         for ( String label : oList ) {\r
2904                                 for ( SearchKey key : srKeys.getSearchKeys() ) {\r
2905                                         if ( key.getLabel().equals(label) ) {\r
2906                                                 newSrKeys.add(key);\r
2907                                                 break;\r
2908                                         }\r
2909                                 }\r
2910                         }\r
2911                         //srKeys = newSrKeys;\r
2912                         FieldUtils.deepCopy(srKeys, newSrKeys);\r
2913                         srKeys.save();\r
2914                         \r
2915                         // ツリーを更新\r
2916                         redrawTreeByKeyword();\r
2917                 }\r
2918         }\r
2919         \r
2920         /**\r
2921          * キーワードグループを追加したい\r
2922          */\r
2923         private void addSearchKeyGroup() {\r
2924                 //\r
2925                 VWKeywordGroupDialog kD = new VWKeywordGroupDialog();\r
2926                 CommonSwingUtils.setLocationCenter(parent,kD);\r
2927                 \r
2928                 kD.reopen("");\r
2929                 kD.setVisible(true);\r
2930 \r
2931                 if (kD.isRegistered()) {\r
2932                         // グループ名を変更する\r
2933                         srGrps.add(kD.getNewName());\r
2934                         srGrps.save();\r
2935                         \r
2936                         // ツリーを更新\r
2937                         redrawTreeByKeywordGroup();\r
2938                         \r
2939                         // 変更したノードを選択するようにしたい\r
2940                         jLabel_tree.setView(JTreeLabel.Nodes.KEYWORDGROUP, kD.getNewName());\r
2941                         \r
2942                         // ツリーを再選択\r
2943                         reselectTree();\r
2944                 }\r
2945         }\r
2946         \r
2947         /**\r
2948          * キーワードグループを編集したい\r
2949          */\r
2950         private void editSeachkeyGroup(String name) {\r
2951                 //\r
2952                 VWKeywordGroupDialog kD = new VWKeywordGroupDialog();\r
2953                 CommonSwingUtils.setLocationCenter(parent,kD);\r
2954                 \r
2955                 kD.reopen(name);\r
2956                 kD.setVisible(true);\r
2957 \r
2958                 if (kD.isRegistered()) {\r
2959                         // グループ名を変更する\r
2960                         srGrps.rename(name, kD.getNewName());\r
2961                         srGrps.save();\r
2962                         \r
2963                         // ツリーを更新\r
2964                         redrawTreeByKeywordGroup();\r
2965                         \r
2966                         // 変更したノードを選択するようにしたい\r
2967                         jLabel_tree.setView(JTreeLabel.Nodes.KEYWORDGROUP, kD.getNewName());\r
2968                         \r
2969                         // ツリーを再選択\r
2970                         reselectTree();\r
2971                 }\r
2972         }\r
2973 \r
2974         /**\r
2975          * キーワードグループを削除したい\r
2976          */\r
2977         private void removeSearchKeyGroup(String name) {\r
2978                 if (env.getShowWarnDialog()) {\r
2979                         //Container cp = getContentPane();\r
2980                         int ret = JOptionPane.showConfirmDialog(parent, "キーワードグループを削除しますか?【"+name+"】", "確認", JOptionPane.YES_NO_OPTION);\r
2981                         if (ret != JOptionPane.YES_OPTION) {\r
2982                                 return;\r
2983                         }\r
2984                 }\r
2985                 for ( SearchGroup gr : srGrps ) {\r
2986                         if ( gr.getName().equals(name) ) {\r
2987                                 srGrps.remove();\r
2988                                 srGrps.save();\r
2989                                 redrawTreeByKeywordGroup();\r
2990                                 return;\r
2991                         }\r
2992                 }\r
2993         }\r
2994         \r
2995         /**\r
2996          * キーワードグループのアイテムを削除したい\r
2997          * @param groupName : nullならグループ登録だけでなくキーワード検索アイテム自体を削除する\r
2998          */\r
2999         private void removeSearchKeyGroupItem(String groupName, String keyword) {\r
3000                 if (env.getShowWarnDialog()) {\r
3001                         //Container cp = getContentPane();\r
3002                         String warn; \r
3003                         if ( groupName == null ) {\r
3004                                 warn = "削除しますか?【"+keyword+"】 ※グループ登録の解除だけでなくアイテム自体が削除されます。";\r
3005                         }\r
3006                         else {\r
3007                                 warn = "削除しますか?【"+keyword+"】 ※グループ登録の解除のみ行います。";\r
3008                         }\r
3009                         int ret = JOptionPane.showConfirmDialog(parent, warn, "確認", JOptionPane.YES_NO_OPTION);\r
3010                         if (ret != JOptionPane.YES_OPTION) {\r
3011                                 return;\r
3012                         }\r
3013                 }\r
3014                 \r
3015                 if ( groupName == null ) {\r
3016                         // nullなら全消し\r
3017                         srKeys.remove(keyword);\r
3018                         srKeys.save();\r
3019                 }\r
3020 \r
3021                 // 検索結果の再構築\r
3022                 mpList.clear(env.getDisableFazzySearch(), env.getDisableFazzySearchReverse());\r
3023                 mpList.build(tvprograms, trKeys.getTraceKeys(), srKeys.getSearchKeys());\r
3024                 //mpList.debug();\r
3025                 \r
3026                 // キーワードグループにも反映\r
3027                 if ( srGrps.remove(groupName,keyword) ) {\r
3028                         srGrps.save();\r
3029                 }\r
3030                 \r
3031                 // ツリーを更新\r
3032                 if ( groupName == null ) {\r
3033                         redrawTreeByKeyword();\r
3034                 }\r
3035                 // ツリーを更新\r
3036                 redrawTreeByKeywordGroup();\r
3037         }\r
3038         \r
3039         /**\r
3040          * キーワードグループのアイテムを追加したい\r
3041          */\r
3042         private void addSearchKeyGroupItem(String groupName, String keyword) {\r
3043                 if ( srGrps.add(groupName,keyword) ) {\r
3044                         srGrps.save();\r
3045                         redrawTreeByKeywordGroup();\r
3046                 }\r
3047         }\r
3048         \r
3049         /**\r
3050          * キーワードグループのアイテムを編集したい\r
3051          */\r
3052         private void editSearchKeyGroupItem(String name, String member) {\r
3053                 //\r
3054                 AbsKeywordDialog kD = new VWKeywordDialog();\r
3055                 CommonSwingUtils.setLocationCenter(parent,kD);\r
3056                 \r
3057                 kD.reopen(member, srKeys);\r
3058                 kD.setVisible(true);\r
3059 \r
3060                 if (kD.isRegistered()) {\r
3061                         // 検索結果の再構築\r
3062                         mpList.clear(env.getDisableFazzySearch(), env.getDisableFazzySearchReverse());\r
3063                         mpList.build(tvprograms, trKeys.getTraceKeys(), srKeys.getSearchKeys());\r
3064                         //mpList.debug();\r
3065                         \r
3066                         // キーワードグループにも反映\r
3067                         if ( ! kD.getNewLabel().equals(member) ) {\r
3068                                 if ( srGrps.rename(null, member, kD.getNewLabel()) ) {\r
3069                                         srGrps.save();\r
3070                                 }\r
3071                         }\r
3072                         \r
3073                         // ツリーを更新\r
3074                         redrawTreeByKeywordGroup();\r
3075                         \r
3076                         // 変更したノードを選択するようにしたい\r
3077                         jLabel_tree.setView(JTreeLabel.Nodes.KEYWORDGROUP, name);\r
3078                         \r
3079                         // ツリーを再選択\r
3080                         reselectTree();\r
3081                 }\r
3082         }\r
3083         \r
3084         /**\r
3085          * 延長警告管理を削除したい\r
3086          */\r
3087         private void removeExtension(String keyword) {\r
3088                 if (env.getShowWarnDialog()) {\r
3089                         //Container cp = getContentPane();\r
3090                         int ret = JOptionPane.showConfirmDialog(parent, "削除しますか?【"+keyword+"】", "確認", JOptionPane.YES_NO_OPTION);\r
3091                         if (ret != JOptionPane.YES_OPTION) {\r
3092                                 return;\r
3093                         }\r
3094                 }\r
3095                         \r
3096                 extKeys.remove(keyword);\r
3097                 extKeys.save();\r
3098                 \r
3099                 // ツリーを更新\r
3100                 redrawTreeByExtension();\r
3101                         \r
3102                 // 番組表の状態を更新する\r
3103                 for (TVProgram tvp : tvprograms) {\r
3104                         if (tvp.getType() == ProgType.PROG) {\r
3105                                 tvp.setExtension(null, null, false, extKeys.getSearchKeys());\r
3106                         }\r
3107                 }\r
3108         }\r
3109         \r
3110         /**\r
3111          * 延長警告管理を追加したい\r
3112          */\r
3113         private void editExtension(String keyword) {\r
3114                 //\r
3115                 AbsExtensionDialog eD = new VWExtensionDialog();\r
3116                 CommonSwingUtils.setLocationCenter(parent,eD);\r
3117                 \r
3118                 eD.reopen(keyword, extKeys);\r
3119                 eD.setVisible(true);\r
3120                 \r
3121                 if (eD.isRegistered()) {\r
3122                         // 番組表の状態を更新する\r
3123                         for (TVProgram tvp : tvprograms) {\r
3124                                 if (tvp.getType() == ProgType.PROG) {\r
3125                                         tvp.setExtension(null, null, false, extKeys.getSearchKeys());\r
3126                                 }\r
3127                         }\r
3128                         \r
3129                         // ツリーを更新\r
3130                         redrawTreeByExtension();\r
3131                 }\r
3132         }\r
3133         \r
3134         /**\r
3135          * 延長警告管理を並べ替えたい\r
3136          */\r
3137         private void sortExtension() {\r
3138                 //\r
3139                 ArrayList<String> oList = new ArrayList<String>();\r
3140                 for ( SearchKey key : extKeys.getSearchKeys() ) {\r
3141                         oList.add(key.getLabel());\r
3142                 }\r
3143                 //\r
3144                 JListSortDialog lsD = new JListSortDialog("延長警告の並べ替え", oList);\r
3145                 CommonSwingUtils.setLocationCenter(parent,lsD);\r
3146                 \r
3147                 lsD.setVisible(true);\r
3148 \r
3149                 if (lsD.isRegistered()) {\r
3150                         ExtProgram newExtKeys = new ExtProgram();\r
3151                         for ( String label : oList ) {\r
3152                                 for ( SearchKey key : extKeys.getSearchKeys() ) {\r
3153                                         if ( key.getLabel().equals(label) ) {\r
3154                                                 newExtKeys.add(key);\r
3155                                                 break;\r
3156                                         }\r
3157                                 }\r
3158                         }\r
3159                         //extKeys = newExtKeys;\r
3160                         FieldUtils.deepCopy(extKeys, newExtKeys);\r
3161                         extKeys.save();\r
3162                         \r
3163                         // ツリーを更新\r
3164                         redrawTreeByExtension();\r
3165                 }\r
3166         }\r
3167         \r
3168         // キーワード削除のポップアップ\r
3169         private void showPopupForRemoveTraceKey(int x, int y, final String keyword)\r
3170         {\r
3171                 JPopupMenu pop = new JPopupMenu();\r
3172                 \r
3173                 {\r
3174                         JMenuItem menuItem = new JMenuItem("番組追跡の編集【"+keyword+"】");\r
3175                         menuItem.addActionListener(new ActionListener() {\r
3176                                 public void actionPerformed(ActionEvent e) {\r
3177                                         editTraceKey(keyword);\r
3178                                 }\r
3179                         });\r
3180                         pop.add(menuItem);\r
3181                 }\r
3182                 \r
3183                 {\r
3184                         JMenuItem menuItem = new JMenuItem("番組追跡の削除【"+keyword+"】");\r
3185                         menuItem.addActionListener(new ActionListener() {\r
3186                                 public void actionPerformed(ActionEvent e) {\r
3187                                         removeTraceKey(keyword);\r
3188                                 }\r
3189                         });\r
3190                         pop.add(menuItem);\r
3191                 }\r
3192                 \r
3193                 pop.addSeparator();\r
3194                 \r
3195                 {\r
3196                         ButtonGroup bg = new ButtonGroup();\r
3197                         \r
3198                         for ( TraceKey t : trKeys.getTraceKeys()) {\r
3199                                 if (t.getLabel().equals(keyword)) {\r
3200                                         final TraceKey tk = t;\r
3201                                         for (String o : TVProgram.OKINIIRI) {\r
3202                                                 final String okini = o; \r
3203                                                 JRadioButtonMenuItem menuItem = new JRadioButtonMenuItem(okini, okini.equals(tk.getOkiniiri()));\r
3204                                                 bg.add(menuItem);\r
3205                                                 menuItem.addActionListener(new ActionListener() {\r
3206                                                         public void actionPerformed(ActionEvent e) {\r
3207                                                                 setTraceKeyOkiniiri(tk,okini);\r
3208                                                         }\r
3209                                                 });\r
3210                                                 pop.add(menuItem);\r
3211                                         }\r
3212                                         break;\r
3213                                 }\r
3214                         }\r
3215                 }\r
3216                 \r
3217                 pop.show(jTree_tree, x, y);\r
3218         }\r
3219 \r
3220         // キーワード検索アイテムの処理\r
3221         private void showPopupForRemoveKeyword(int x, int y, final String keyword)\r
3222         {\r
3223                 JPopupMenu pop = new JPopupMenu();\r
3224                 \r
3225                 {\r
3226                         JMenuItem menuItem = new JMenuItem("キーワードの編集【"+keyword+"】");\r
3227                         menuItem.addActionListener(new ActionListener() {\r
3228                                 public void actionPerformed(ActionEvent e) {\r
3229                                         editSearchKey(keyword);\r
3230                                 }\r
3231                         });\r
3232                         pop.add(menuItem);\r
3233                 }\r
3234                 {\r
3235                         JMenuItem menuItem = new JMenuItem("キーワードの削除【"+keyword+"】");\r
3236                         menuItem.addActionListener(new ActionListener() {\r
3237                                 public void actionPerformed(ActionEvent e) {\r
3238                                         removeSearchKey(keyword);\r
3239                                 }\r
3240                         });\r
3241                         pop.add(menuItem);\r
3242                 }\r
3243                 \r
3244                 pop.addSeparator();\r
3245                 \r
3246                 {\r
3247                         for ( SearchGroup gr : srGrps ) {\r
3248                                 final String groupName = gr.getName();\r
3249                                 if (srGrps.isFind(groupName,keyword) ) {\r
3250                                         JMenuItem menuItem = new JMenuItem("キーワードグループから登録解除【"+groupName+"】");\r
3251                                         menuItem.setForeground(Color.RED);\r
3252                                         menuItem.addActionListener(new ActionListener() {\r
3253                                                 public void actionPerformed(ActionEvent e) {\r
3254                                                         removeSearchKeyGroupItem(groupName,keyword);\r
3255                                                 }\r
3256                                         });\r
3257                                         pop.add(menuItem);\r
3258                                 }\r
3259                                 else {\r
3260                                         JMenuItem menuItem = new JMenuItem("キーワードグループに追加【"+groupName+"】");\r
3261                                         menuItem.addActionListener(new ActionListener() {\r
3262                                                 public void actionPerformed(ActionEvent e) {\r
3263                                                         addSearchKeyGroupItem(groupName,keyword);\r
3264                                                 }\r
3265                                         });\r
3266                                         pop.add(menuItem);\r
3267                                 }\r
3268                         }\r
3269                 }\r
3270                 \r
3271                 pop.addSeparator();\r
3272                 \r
3273                 {\r
3274                         ButtonGroup bg = new ButtonGroup();\r
3275                         \r
3276                         for ( SearchKey s : srKeys.getSearchKeys()) {\r
3277                                 if (s.getLabel().equals(keyword)) {\r
3278                                         final SearchKey sr = s;\r
3279                                         for (String o : TVProgram.OKINIIRI) {\r
3280                                                 final String okini = o; \r
3281                                                 JRadioButtonMenuItem menuItem = new JRadioButtonMenuItem(okini, okini.equals(sr.getOkiniiri()));\r
3282                                                 bg.add(menuItem);\r
3283                                                 menuItem.addActionListener(new ActionListener() {\r
3284                                                         public void actionPerformed(ActionEvent e) {\r
3285                                                                 setSearchKeyOkiniiri(sr,okini);\r
3286                                                         }\r
3287                                                 });\r
3288                                                 pop.add(menuItem);\r
3289                                         }\r
3290                                         break;\r
3291                                 }\r
3292                         }\r
3293                 }\r
3294                 pop.show(jTree_tree, x, y);\r
3295         }\r
3296 \r
3297         // 番組追跡の並べ替え\r
3298         private void showPopupForSortTraceKey(int x, int y) {\r
3299                 JPopupMenu pop = new JPopupMenu();\r
3300                 {\r
3301                         JMenuItem menuItem = new JMenuItem("番組追跡の並べ替え");\r
3302                         menuItem.addActionListener(new ActionListener() {\r
3303                                 public void actionPerformed(ActionEvent e) {\r
3304                                         sortTraceKey();\r
3305                                 }\r
3306                         });\r
3307                         pop.add(menuItem);\r
3308                 }\r
3309                 pop.show(jTree_tree, x, y);\r
3310         }\r
3311 \r
3312         // キーワード検索の並べ替え\r
3313         private void showPopupForSortSearchKey(int x, int y) {\r
3314                 JPopupMenu pop = new JPopupMenu();\r
3315                 {\r
3316                         JMenuItem menuItem = new JMenuItem("キーワード検索の並べ替え");\r
3317                         menuItem.addActionListener(new ActionListener() {\r
3318                                 public void actionPerformed(ActionEvent e) {\r
3319                                         sortSearchKey();\r
3320                                 }\r
3321                         });\r
3322                         pop.add(menuItem);\r
3323                 }\r
3324                 pop.show(jTree_tree, x, y);\r
3325         }\r
3326 \r
3327         // 延長警告の並べ替え\r
3328         private void showPopupForSortExtension(int x, int y) {\r
3329                 JPopupMenu pop = new JPopupMenu();\r
3330                 {\r
3331                         JMenuItem menuItem = new JMenuItem("延長警告の並べ替え");\r
3332                         menuItem.addActionListener(new ActionListener() {\r
3333                                 public void actionPerformed(ActionEvent e) {\r
3334                                         sortExtension();\r
3335                                 }\r
3336                         });\r
3337                         pop.add(menuItem);\r
3338                 }\r
3339                 pop.show(jTree_tree, x, y);\r
3340         }\r
3341         \r
3342         // キーワードグループの処理\r
3343         private void showPopupForRemoveKeywordGrp(int x, int y)\r
3344         {\r
3345                 JPopupMenu pop = new JPopupMenu();\r
3346                 \r
3347                 {\r
3348                         JMenuItem menuItem = new JMenuItem("キーワードグループの追加");\r
3349                         menuItem.addActionListener(new ActionListener() {\r
3350                                 public void actionPerformed(ActionEvent e) {\r
3351                                         addSearchKeyGroup();\r
3352                                 }\r
3353                         });\r
3354                         pop.add(menuItem);\r
3355                 }\r
3356                 pop.show(jTree_tree, x, y);\r
3357         }\r
3358         \r
3359         private void showPopupForRemoveKeywordGrpName(int x, int y, final String name)\r
3360         {\r
3361                 JPopupMenu pop = new JPopupMenu();\r
3362                 \r
3363                 {\r
3364                         JMenuItem menuItem = new JMenuItem("キーワードグループの編集【"+name+"】");\r
3365                         menuItem.addActionListener(new ActionListener() {\r
3366                                 public void actionPerformed(ActionEvent e) {\r
3367                                         editSeachkeyGroup(name);\r
3368                                 }\r
3369                         });\r
3370                         pop.add(menuItem);\r
3371                 }\r
3372                 \r
3373                 pop.addSeparator();\r
3374                 \r
3375                 {\r
3376                         JMenuItem menuItem = new JMenuItem("キーワードグループの削除【"+name+"】");\r
3377                         menuItem.addActionListener(new ActionListener() {\r
3378                                 public void actionPerformed(ActionEvent e) {\r
3379                                         removeSearchKeyGroup(name);\r
3380                                 }\r
3381                         });\r
3382                         pop.add(menuItem);\r
3383                 }\r
3384                 pop.show(jTree_tree, x, y);\r
3385         }\r
3386         \r
3387         private void showPopupForRemoveKeywordGrpEntry(int x, int y, final String name, final String member)\r
3388         {\r
3389                 JPopupMenu pop = new JPopupMenu();\r
3390                 \r
3391                 {\r
3392                         JMenuItem menuItem = new JMenuItem("キーワードの編集【"+member+"】");\r
3393                         menuItem.addActionListener(new ActionListener() {\r
3394                                 public void actionPerformed(ActionEvent e) {\r
3395                                         editSearchKeyGroupItem(name,member);\r
3396                                 }\r
3397                         });\r
3398                         pop.add(menuItem);\r
3399                 }\r
3400                 {\r
3401                         JMenuItem menuItem = new JMenuItem("キーワードの削除【"+member+"】");\r
3402                         menuItem.addActionListener(new ActionListener() {\r
3403                                 public void actionPerformed(ActionEvent e) {\r
3404                                         removeSearchKeyGroupItem(null,member);\r
3405                                 }\r
3406                         });\r
3407                         pop.add(menuItem);\r
3408                 }\r
3409                 \r
3410                 pop.addSeparator();\r
3411                 \r
3412                 {\r
3413                         for ( SearchGroup gr : srGrps ) {\r
3414                                 final String groupName = gr.getName();\r
3415                                 if (srGrps.isFind(groupName,member) ) {\r
3416                                         JMenuItem menuItem = new JMenuItem("キーワードグループから登録解除【"+groupName+"】");\r
3417                                         menuItem.setForeground(Color.RED);\r
3418                                         menuItem.addActionListener(new ActionListener() {\r
3419                                                 public void actionPerformed(ActionEvent e) {\r
3420                                                         removeSearchKeyGroupItem(groupName, member);\r
3421                                                 }\r
3422                                         });\r
3423                                         pop.add(menuItem);\r
3424                                 }\r
3425                                 else {\r
3426                                         JMenuItem menuItem = new JMenuItem("キーワードグループに追加【"+groupName+"】");\r
3427                                         menuItem.addActionListener(new ActionListener() {\r
3428                                                 public void actionPerformed(ActionEvent e) {\r
3429                                                         addSearchKeyGroupItem(groupName,member);\r
3430                                                 }\r
3431                                         });\r
3432                                         pop.add(menuItem);\r
3433                                 }\r
3434                         }\r
3435                 }\r
3436                 \r
3437                 pop.show(jTree_tree, x, y);\r
3438         }\r
3439 \r
3440         // 延長警告アイテムの処理\r
3441         private void showPopupForRemoveExtension(int x, int y, final String keyword)\r
3442         {\r
3443                 JPopupMenu pop = new JPopupMenu();\r
3444                 \r
3445                 {\r
3446                         JMenuItem menuItem = new JMenuItem("延長警告の編集【"+keyword+"】");\r
3447                         menuItem.addActionListener(new ActionListener() {\r
3448                                 public void actionPerformed(ActionEvent e) {\r
3449                                         editExtension(keyword);\r
3450                                 }\r
3451                         });\r
3452                         pop.add(menuItem);\r
3453                 }\r
3454                 {\r
3455                         JMenuItem menuItem = new JMenuItem("延長警告の削除【"+keyword+"】");\r
3456                         menuItem.addActionListener(new ActionListener() {\r
3457                                 public void actionPerformed(ActionEvent e) {\r
3458                                         removeExtension(keyword);\r
3459                                 }\r
3460                         });\r
3461                         pop.add(menuItem);\r
3462                 }\r
3463                 \r
3464                 pop.show(jTree_tree, x, y);\r
3465         }\r
3466         \r
3467         \r
3468         \r
3469         /*******************************************************************************\r
3470          * コンポーネント\r
3471          ******************************************************************************/\r
3472         \r
3473         /*\r
3474          * 特殊部品\r
3475          */\r
3476         \r
3477         /**\r
3478          * キーワード検索ウィンドウの内部クラス\r
3479          */\r
3480         private class VWKeywordDialog extends AbsKeywordDialog {\r
3481                 \r
3482                 private static final long serialVersionUID = 1L;\r
3483 \r
3484                 @Override\r
3485                 void preview(SearchKey search) {\r
3486                         previewKeywordSearch(search);\r
3487                 }\r
3488         }\r
3489 \r
3490         /**\r
3491          * 延長警告管理ウィンドウの内部クラス\r
3492          */\r
3493         private class VWExtensionDialog extends AbsExtensionDialog {\r
3494 \r
3495                 private static final long serialVersionUID = 1L;\r
3496 \r
3497                 @Override\r
3498                 void preview(SearchKey search) {\r
3499                         previewKeywordSearch(search);\r
3500                 }\r
3501         }\r
3502         \r
3503         /*\r
3504          * 部品\r
3505          */\r
3506         \r
3507         private JSplitPane getJSplitPane_view() {\r
3508                 if ( jSplitPane_view == null ) {\r
3509                         jSplitPane_view = new JSplitPane() {\r
3510 \r
3511                                 private static final long serialVersionUID = 1L;\r
3512 \r
3513                                 @Override\r
3514                                 public void setDividerLocation(int loc) {\r
3515                                         setDividerEnvs(loc);\r
3516                                         super.setDividerLocation(loc);\r
3517                                 }\r
3518                         };\r
3519                         \r
3520                         jSplitPane_view.setLeftComponent(getJPanel_tree());\r
3521                         jSplitPane_view.setRightComponent(getJScrollPane_listed());\r
3522                         setExpandTree();\r
3523                 }\r
3524                 return jSplitPane_view;\r
3525         }\r
3526         \r
3527         private JPanel getJPanel_tree() {\r
3528                 if (jPanel_tree == null) {\r
3529                         jPanel_tree = new JPanel();\r
3530                         \r
3531                         jPanel_tree.setLayout(new BorderLayout());\r
3532                         jPanel_tree.add(getJScrollPane_tree_top(), BorderLayout.PAGE_START);\r
3533                         jPanel_tree.add(getJScrollPane_tree(), BorderLayout.CENTER);\r
3534                 }\r
3535                 return jPanel_tree;\r
3536         }\r
3537         \r
3538         private JScrollPane getJScrollPane_tree_top() {\r
3539                 if (jScrollPane_tree_top == null) {\r
3540                         jScrollPane_tree_top = new JScrollPane();\r
3541                         jScrollPane_tree_top.setViewportView(getJLabel_tree());\r
3542                         jScrollPane_tree_top.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);\r
3543                         jScrollPane_tree_top.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);\r
3544                 }\r
3545                 return jScrollPane_tree_top;\r
3546         }\r
3547         \r
3548         private JTreeLabel getJLabel_tree() {\r
3549                 if (jLabel_tree == null) {\r
3550                         jLabel_tree = new JTreeLabel();\r
3551                         \r
3552                         Dimension d = jLabel_tree.getMaximumSize();\r
3553                         d.height = bounds.getBangumiColumnHeight();\r
3554                         jLabel_tree.setPreferredSize(d);\r
3555                         //jLabel_tree.setBorder(new LineBorder(Color.BLACK));\r
3556                         jLabel_tree.setOpaque(true);\r
3557                         jLabel_tree.setBackground(Color.WHITE);\r
3558                 }\r
3559                 return jLabel_tree;\r
3560         }\r
3561         \r
3562         private JScrollPane getJScrollPane_tree() {\r
3563                 if (jScrollPane_tree == null) {\r
3564                         jScrollPane_tree = new JScrollPane();\r
3565 \r
3566                         jScrollPane_tree.setViewportView(getJTree_tree());\r
3567                 }\r
3568                 return jScrollPane_tree;\r
3569         }\r
3570         \r
3571         private JDetailPanel getJTextPane_detail() {\r
3572                 if (jTextPane_detail == null) {\r
3573                         jTextPane_detail = new JDetailPanel();\r
3574                         jTextPane_detail.setRows(bounds.getDetailRows());\r
3575                         //Dimension d = jTextPane_detail.getMaximumSize();\r
3576                         //d.height = bounds.getDetailAreaHeight();\r
3577                         //jTextPane_detail.setPreferredSize(d);\r
3578                         //jTextPane_detail.setVerticalAlignment(JLabel.TOP);\r
3579                         //jTextPane_detail.setHorizontalAlignment(JLabel.LEFT);\r
3580                 }\r
3581                 return jTextPane_detail;\r
3582         }\r
3583         \r
3584         /**\r
3585          * ツリーの作成\r
3586          */\r
3587         private JTree getJTree_tree() {\r
3588                 if (jTree_tree == null) {\r
3589                         \r
3590                         // ツリーの作成\r
3591                         jTree_tree = new JTree();\r
3592                         jTree_tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);\r
3593                         jTree_tree.setRootVisible(env.getRootNodeVisible());\r
3594                         jTree_tree.setCellRenderer(new VWTreeCellRenderer());   // 検索結果が存在するノードの色を変える\r
3595                         \r
3596                         // ノードの作成\r
3597                         jTree_tree.setModel(new DefaultTreeModel(getTreeNodes()));\r
3598                         \r
3599                         // ツリーの展開状態の復帰\r
3600                         undoTreeExpansion();\r
3601                         \r
3602                         // ツリーの開閉時に状態を保存する\r
3603                         jTree_tree.addTreeExpansionListener(tel_nodeexpansion);\r
3604                         \r
3605                         // フルスクリーンの時に使う(新聞形式のツリーを自動的に隠す)\r
3606                         jTree_tree.addMouseListener(ml_treehide);\r
3607                 }\r
3608                 return jTree_tree;\r
3609         }\r
3610         \r
3611         /**\r
3612          * ツリーのノード作成\r
3613          */\r
3614         private DefaultMutableTreeNode getTreeNodes() {\r
3615                 \r
3616                 listRootNode = new VWListedTreeNode(JTreeLabel.Nodes.ROOT.getLabel());\r
3617 \r
3618                 searchedNode    = new VWListedTreeNode(JTreeLabel.Nodes.SEARCHHIST.getLabel());\r
3619                 startNode               = new VWListedTreeNode(JTreeLabel.Nodes.START.getLabel());\r
3620                 endNode                 = new VWListedTreeNode(JTreeLabel.Nodes.END.getLabel());\r
3621                 nowNode                 = new VWListedTreeNode(JTreeLabel.Nodes.NOW.getLabel());\r
3622                 syobocalNode    = new VWListedTreeNode(JTreeLabel.Nodes.SYOBOCAL.getLabel());\r
3623                 standbyNode             = new VWListedTreeNode(JTreeLabel.Nodes.STANDBY.getLabel());\r
3624                 traceNode               = new VWListedTreeNode(JTreeLabel.Nodes.TRACE.getLabel());\r
3625                 keywordNode             = new VWListedTreeNode(JTreeLabel.Nodes.KEYWORD.getLabel());\r
3626                 keywordGrpNode  = new VWListedTreeNode(JTreeLabel.Nodes.KEYWORDGROUP.getLabel());\r
3627                 genreNode               = new VWListedTreeNode(JTreeLabel.Nodes.GENRE.getLabel());\r
3628                 centerListNode  = new VWListedTreeNode(JTreeLabel.Nodes.BCASTLIST.getLabel());\r
3629                 extensionNode   = new VWListedTreeNode(JTreeLabel.Nodes.EXTENTION.getLabel());\r
3630 \r
3631                 // ★★★ でふぉるとのーど ★★★\r
3632                 defaultNode = nowNode;\r
3633 \r
3634                 listRootNode.add(searchedNode);\r
3635                 listRootNode.add(startNode);\r
3636                 listRootNode.add(endNode);\r
3637                 listRootNode.add(nowNode);\r
3638                 if ( env.getUseSyobocal() ) {\r
3639                         listRootNode.add(syobocalNode);\r
3640                 }\r
3641                 listRootNode.add(standbyNode);\r
3642                 listRootNode.add(traceNode);\r
3643                 listRootNode.add(keywordNode);\r
3644                 listRootNode.add(keywordGrpNode);\r
3645                 listRootNode.add(genreNode);\r
3646                 listRootNode.add(centerListNode);\r
3647                 listRootNode.add(extensionNode);\r
3648                 \r
3649                 // 子の描画\r
3650                 redrawTreeByGenre();\r
3651                 redrawTreeBySyobo();\r
3652                 redrawTreeByStandby();\r
3653                 redrawTreeByTrace();\r
3654                 redrawTreeByKeyword();\r
3655                 redrawTreeByKeywordGroup();\r
3656                 redrawTreeBySubGenre();\r
3657                 redrawTreeByCenter();\r
3658                 redrawTreeByExtension();\r
3659                 \r
3660                 return listRootNode;\r
3661         }\r
3662 \r
3663         private void undoTreeExpansion() {\r
3664                 \r
3665                 // 展開状態の復帰\r
3666                 stopTreeListener();\r
3667                 \r
3668                 // ツリーの展開状態の保存場所\r
3669                 ter = new TreeExpansionReg(jTree_tree, TreeExpRegFile_Listed);\r
3670                 try {\r
3671                         ter.load();\r
3672                 }\r
3673                 catch (Exception e) {\r
3674                         MWin.appendMessage(ERRID+"ツリー展開情報の解析で問題が発生しました");\r
3675                         e.printStackTrace();\r
3676                 }\r
3677                 \r
3678                 // 状態を復元する\r
3679                 ArrayList<TreePath> tpa = ter.get();\r
3680                 for ( TreePath path : tpa ) {\r
3681                         jTree_tree.expandPath(path);\r
3682                 }\r
3683                 \r
3684                 startTreeListener();\r
3685         }\r
3686         \r
3687         private JScrollPane getJScrollPane_listed() {\r
3688                 if (jScrollPane_listed == null) {\r
3689                         jScrollPane_listed = new JScrollPane();\r
3690                         jScrollPane_listed.setRowHeaderView(jTable_rowheader = new JTableRowHeader(rowData));\r
3691                         jScrollPane_listed.setViewportView(getNETable_listed());\r
3692                         \r
3693                         Dimension d = new Dimension(jTable_rowheader.getPreferredSize().width,0);\r
3694                         jScrollPane_listed.getRowHeader().setPreferredSize(d);\r
3695                         \r
3696                         setRowHeaderVisible(env.getRowHeaderVisible());\r
3697                 }\r
3698                 return jScrollPane_listed;\r
3699         }\r
3700         \r
3701         private JNETable getNETable_listed() {\r
3702                 if (jTable_listed == null) {\r
3703                         \r
3704                         // カラム名の初期化\r
3705                         ArrayList<String> cola = new ArrayList<String>();\r
3706                         for ( ListedColumn lc : ListedColumn.values() ) {\r
3707                                 if ( lc.getIniWidth() >= 0 ) {\r
3708                                         cola.add(lc.getName());\r
3709                                 }\r
3710                         }\r
3711                         final String[] colname = cola.toArray(new String[0]);\r
3712 \r
3713                         // テーブルの基本的な設定\r
3714                         tableModel_listed = new ListedTableModel(colname, 0);\r
3715                         \r
3716                         jTable_listed = new ListedTable(tableModel_listed, true);\r
3717                         jTable_listed.setAutoResizeMode(JNETable.AUTO_RESIZE_OFF);\r
3718                         //jTable_listed.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);\r
3719 \r
3720                         // ヘッダのモデル\r
3721                         rowheaderModel_listed = (DefaultTableModel) jTable_rowheader.getModel();\r
3722                 \r
3723                         // ソーターをつける\r
3724                         final TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(tableModel_listed);\r
3725                         jTable_listed.setRowSorter(sorter);\r
3726                         //sorter.toggleSortOrder(listedTableColumn_Sorter);\r
3727                         \r
3728                         sorter.addRowSorterListener(new RowSorterListener() {\r
3729                                 @Override\r
3730                                 public void sorterChanged(RowSorterEvent e) {\r
3731                                         if ( e.getType() == Type.SORTED ) {\r
3732                                                 if (rowData.size()>2) setOverlapMark();\r
3733                                         }\r
3734                                 }\r
3735                         });\r
3736                         \r
3737                         // 数値でソートする項目用の計算式(番組長とか)\r
3738                         final Comparator<String> numcomp = new Comparator<String>() {\r
3739                                 @Override\r
3740                                 public int compare(String o1, String o2) {\r
3741                                         int n1 = -1;\r
3742                                         int n2 = -1;\r
3743                                         if ( o1 != null ) {\r
3744                                                 Matcher ma = Pattern.compile("^(\\d+)").matcher(o1);\r
3745                                                 if ( ma.find() ) {\r
3746                                                         n1 = Integer.valueOf(ma.group(1));\r
3747                                                 }\r
3748                                         }\r
3749                                         if ( o2 != null ) {\r
3750                                                 Matcher ma = Pattern.compile("^(\\d+)").matcher(o2);\r
3751                                                 if ( ma.find() ) {\r
3752                                                         n2 = Integer.valueOf(ma.group(1));\r
3753                                                 }\r
3754                                         }\r
3755                                         return n1-n2;\r
3756                                 }\r
3757                         };\r
3758                         \r
3759                         // ソーターの効かない項目用の計算式(重複マーク)\r
3760                         final Comparator<String> noncomp = new Comparator<String>() {\r
3761                                 @Override\r
3762                                 public int compare(String o1, String o2) {\r
3763                                         return 0;\r
3764                                 }\r
3765                         };\r
3766                         \r
3767                         // 数値比較を行う列\r
3768                         sorter.setComparator(jTable_listed.getColumn(ListedColumn.LENGTH.getName()).getModelIndex(),numcomp);\r
3769                         sorter.setComparator(jTable_listed.getColumn(ListedColumn.SCORE.getName()).getModelIndex(),numcomp);\r
3770                         sorter.setComparator(jTable_listed.getColumn(ListedColumn.THRESHOLD.getName()).getModelIndex(),numcomp);\r
3771 \r
3772                         sorter.setComparator(jTable_listed.getColumn(ListedColumn.DUPMARK.getName()).getModelIndex(),noncomp);\r
3773 \r
3774                         // 予約済みマーク/重複マークはちょっとだけ表示の仕方が違う\r
3775                         VWColorCharCellRenderer renderer = new VWColorCharCellRenderer();\r
3776                         if ( CommonUtils.isMac() ) renderer.setMacMarkFont();\r
3777                         jTable_listed.getColumn(ListedColumn.RSVMARK.getName()).setCellRenderer(renderer);\r
3778                         jTable_listed.getColumn(ListedColumn.DUPMARK.getName()).setCellRenderer(renderer);\r
3779                         \r
3780                         // 強調色関連\r
3781                         titleCellRenderer = new VWColorCharCellRenderer2();\r
3782                         jTable_listed.getColumn(ListedColumn.OPTIONS.getName()).setCellRenderer(titleCellRenderer);\r
3783                         jTable_listed.getColumn(ListedColumn.TITLE.getName()).setCellRenderer(titleCellRenderer);\r
3784                         \r
3785                         this.setMatchedKeywordColor(env.getMatchedKeywordColor());\r
3786                         this.setRsvdLineColor((env.getRsvdLineEnhance())?(env.getRsvdLineColor()):(null));\r
3787                         this.setPickedLineColor((env.getRsvdLineEnhance())?(env.getPickedLineColor()):(null));\r
3788                         this.setCurrentLineColor((env.getCurrentLineEnhance())?(env.getCurrentLineColor()):(null));\r
3789 \r
3790                         // スコア・閾値はちょっとだけ表示の仕方が違う\r
3791                         DefaultTableCellRenderer renderer3 = new DefaultTableCellRenderer();\r
3792                         renderer3.setHorizontalAlignment(SwingConstants.RIGHT);\r
3793                         jTable_listed.getColumn(ListedColumn.SCORE.getName()).setCellRenderer(renderer3);\r
3794                         jTable_listed.getColumn(ListedColumn.THRESHOLD.getName()).setCellRenderer(renderer3);\r
3795                         \r
3796                         // 詳細表示はうんぬんかんぬん\r
3797                         VWDetailCellRenderer renderer4 = new VWDetailCellRenderer();\r
3798                         jTable_listed.getColumn(ListedColumn.DETAIL.getName()).setCellRenderer(renderer4);\r
3799 \r
3800                         // 各カラムの幅を設定する\r
3801                         DefaultTableColumnModel columnModel = (DefaultTableColumnModel)jTable_listed.getColumnModel();\r
3802                         TableColumn column = null;\r
3803                         for ( ListedColumn lc : ListedColumn.values() ) {\r
3804                                 if ( lc.getIniWidth() < 0 ) {\r
3805                                         continue;\r
3806                                 }\r
3807                                 column = columnModel.getColumn(lc.ordinal());\r
3808                                 column.setPreferredWidth(bounds.getListedColumnSize().get(lc.toString()));      // toString()!\r
3809                         }\r
3810                         \r
3811                         // マーク表示分離の有無\r
3812                         setMarkColumnVisible(env.getSplitMarkAndTitle());\r
3813                         \r
3814                         // 番組詳細の表示・非表示\r
3815                         setDetailColumnVisible(env.getShowDetailOnList());\r
3816                         \r
3817                         // 行を選択すると詳細が表示されるようにする\r
3818                         jTable_listed.getSelectionModel().addListSelectionListener(lsSelectListner);\r
3819                         \r
3820                         // マウスクリックでメニュー表示\r
3821                         jTable_listed.addMouseListener(lsClickAdapter);\r
3822                 }\r
3823                 return jTable_listed;\r
3824         }\r
3825         \r
3826         \r
3827         \r
3828         \r
3829         /*******************************************************************************\r
3830          * 独自部品\r
3831          ******************************************************************************/\r
3832         \r
3833         /**\r
3834          *  テーブルの行データの構造\r
3835          * @see ListedColumn\r
3836          */\r
3837         private class ListedItem extends RowItem implements Cloneable {\r
3838                 String rsvmark;\r
3839                 String dupmark;\r
3840                 String prefix;\r
3841                 String title;\r
3842                 String searchlabel;\r
3843                 String okiniiri;\r
3844                 String score;\r
3845                 String threshold;\r
3846                 \r
3847                 String hide_rsvmarkcolor;\r
3848 \r
3849                 ProgDetailList tvd;\r
3850 \r
3851                 @Override\r
3852                 protected void myrefresh(RowItem o) {\r
3853                         ListedItem c = (ListedItem) o;\r
3854                         c.addData(rsvmark);\r
3855                         c.addData(dupmark);\r
3856                         c.addData(tvd.center);\r
3857                         c.addData(prefix);\r
3858                         c.addData(title);               // "\0"+title or "\0"+titlebefore+"\0"+matchedkeyword+"\0"+titleafter みたいな感じで\r
3859                         c.addData(tvd.detail);\r
3860                         c.addData(tvd.start);\r
3861                         c.addData(tvd.end);\r
3862                         c.addData(tvd.recmin);\r
3863                         c.addData(tvd.genre.toString());\r
3864                         c.addData(searchlabel);\r
3865                         c.addData(okiniiri);\r
3866                         c.addData(score);\r
3867                         c.addData(threshold);\r
3868                 }\r
3869                 \r
3870                 public ListedItem clone() {\r
3871                         return (ListedItem) super.clone();\r
3872                 }\r
3873         }\r
3874         \r
3875         /**\r
3876          * {@link ListedItem}を使ったJTable拡張\r
3877          */\r
3878         private class ListedTable extends JNETable {\r
3879 \r
3880                 private static final long serialVersionUID = 1L;\r
3881 \r
3882                 private Color passedColor = new Color(180,180,180);\r
3883                 \r
3884                 // futuer use.\r
3885                 public void setPassedColor(Color c) { passedColor = c; }\r
3886 \r
3887                 private Color currentColorEven = new Color(240,120,120);\r
3888                 private Color currentColorOdd = new Color(248,128,128);\r
3889 \r
3890                 public void setCurrentColor(Color c) {\r
3891                         if ( c == null ) {\r
3892                                 currentColorEven = null;\r
3893                                 currentColorOdd = null;\r
3894                         }\r
3895                         else {\r
3896                                 currentColorOdd = c;\r
3897                                 currentColorEven = new Color(\r
3898                                                 ((c.getRed()>=247)?(255):(c.getRed()+8)),\r
3899                                                 ((c.getGreen()>=247)?(255):(c.getGreen()+8)),\r
3900                                                 ((c.getBlue()>=247)?(255):(c.getBlue()+8))\r
3901                                                 );\r
3902                         }\r
3903                 }\r
3904 \r
3905                 private Color nextweekFgColor = new Color(120,120,120);\r
3906                 \r
3907                 // futuer use.\r
3908                 public void setNextweekFgColor(Color c) { nextweekFgColor = c; }\r
3909 \r
3910                 private Color reservedColorEven = new Color(255,247,204);\r
3911                 private Color reservedColorOdd = new Color(255,255,212);\r
3912 \r
3913                 public void setReservedColor(Color c) {\r
3914                         if ( c == null ) {\r
3915                                 reservedColorEven = null;\r
3916                                 reservedColorOdd = null;\r
3917                         }\r
3918                         else {\r
3919                                 reservedColorOdd = c;\r
3920                                 reservedColorEven = new Color(\r
3921                                                 ((c.getRed()>=247)?(255):(c.getRed()+8)),\r
3922                                                 ((c.getGreen()>=247)?(255):(c.getGreen()+8)),\r
3923                                                 ((c.getBlue()>=247)?(255):(c.getBlue()+8))\r
3924                                                 );\r
3925                         }\r
3926                 }\r
3927                 \r
3928                 private Color pickedColorEven = new Color(51,255,0);\r
3929                 private Color pickedColorOdd = new Color(59,255,8);\r
3930 \r
3931                 public void setPickedColor(Color c) {\r
3932                         if ( c == null ) {\r
3933                                 pickedColorEven = null;\r
3934                                 pickedColorOdd = null;\r
3935                         }\r
3936                         else {\r
3937                                 pickedColorEven = c;\r
3938                                 pickedColorOdd = new Color(\r
3939                                                 ((c.getRed()>=247)?(255):(c.getRed()+8)),\r
3940                                                 ((c.getGreen()>=247)?(255):(c.getGreen()+8)),\r
3941                                                 ((c.getBlue()>=247)?(255):(c.getBlue()+8))\r
3942                                                 );\r
3943                         }\r
3944                 }\r
3945                 \r
3946                 private int prechkrow = -1;\r
3947                 private boolean prechkreserved = false;\r
3948                 private boolean prechkpicked = false;\r
3949                 private boolean prechkpassed = false;\r
3950                 private boolean prechkcurrent = false;\r
3951                 private boolean prechknextweek = false;\r
3952                 \r
3953                 @Override\r
3954                 public Component prepareRenderer(TableCellRenderer tcr, int row, int column) {\r
3955                         Component comp = super.prepareRenderer(tcr, row, column);\r
3956                         Color fgColor = null;\r
3957                         Color bgColor = null;\r
3958                         if(isRowSelected(row)) {\r
3959                                 fgColor = this.getSelectionForeground();\r
3960                                 bgColor = this.getSelectionBackground();\r
3961                         }\r
3962                         else {\r
3963                                 isRowPassed(row);\r
3964                                 \r
3965                                 fgColor = (prechknextweek)?(nextweekFgColor):(this.getForeground());\r
3966                                 \r
3967                                 if( prechkpassed && passedColor != null ) {\r
3968                                         bgColor = passedColor;\r
3969                                 }\r
3970                                 else if( prechkreserved && reservedColorEven != null ) {\r
3971                                         bgColor = (isSepRowColor && row%2 == 1)?(reservedColorEven):(reservedColorOdd);\r
3972                                 }\r
3973                                 else if( prechkpicked && pickedColorEven != null ) {\r
3974                                         bgColor = (isSepRowColor && row%2 == 1)?(pickedColorEven):(pickedColorOdd);\r
3975                                 }\r
3976                                 else if( prechkcurrent && currentColorEven != null ) {\r
3977                                         bgColor = (isSepRowColor && row%2 == 1)?(currentColorEven):(currentColorOdd);\r
3978                                 }\r
3979                                 else {\r
3980                                         bgColor = (isSepRowColor && row%2 == 1)?(evenColor):(super.getBackground());\r
3981                                 }\r
3982                         }\r
3983                         if ( tcr instanceof VWColorCharCellRenderer2 ) {\r
3984                                 ((VWColorCharCellRenderer2) tcr).setForeground(fgColor);\r
3985                         }\r
3986                         else if ( ! (tcr instanceof VWColorCharCellRenderer) && ! (tcr instanceof VWColorCellRenderer)) {\r
3987                                 // マーク類は除外\r
3988                                 comp.setForeground(fgColor);\r
3989                         }               \r
3990                         if ( ! (tcr instanceof VWColorCellRenderer)) {\r
3991                                 comp.setBackground(bgColor);\r
3992                         }\r
3993                         return comp;\r
3994                 }\r
3995                 \r
3996                 // 直接rowDataを見に行くようになったから、このisRowPassed()はもういらないんじゃ…\r
3997                 \r
3998                 // 連続して同じ行へのアクセスがあったら計算を行わず前回のままにする\r
3999                 private boolean isRowPassed(int prow) {\r
4000                         \r
4001                         if(prechkrow == prow) {\r
4002                                 return true;\r
4003                         }\r
4004 \r
4005                         int row = this.convertRowIndexToModel(prow);\r
4006                         ListedItem c = rowData.get(row);\r
4007 \r
4008                         prechkrow = prow;\r
4009                         \r
4010                         prechkreserved  = false;\r
4011                         prechkpicked = false;\r
4012                         prechkpassed = false;\r
4013                         prechkcurrent = false;\r
4014                         prechknextweek = false;\r
4015                         \r
4016                         {\r
4017                                 // 予約が入っているか否か\r
4018                                 if ( c.rsvmark == null || c.rsvmark.length() == 0 ) {\r
4019                                         //\r
4020                                 }\r
4021                                 else if ( c.rsvmark.equals(RSVMARK_NOEXEC)  ) {\r
4022                                         //\r
4023                                 }\r
4024                                 else if ( c.rsvmark.equals(RSVMARK_PICKUP) ) {\r
4025                                         prechkpicked = true;\r
4026                                 }\r
4027                                 else {\r
4028                                         prechkreserved = true;\r
4029                                 }\r
4030                         }\r
4031                         {\r
4032                                 // 終了済みの番組か否か\r
4033                                 String cDT = CommonUtils.getDateTime(0);\r
4034                                 prechkpassed = (cDT.compareTo(c.tvd.endDateTime) >= 0);\r
4035                                 if ( ! prechkpassed ) {\r
4036                                         // 現在放送中\r
4037                                         prechkcurrent = (cDT.compareTo(c.tvd.startDateTime) >= 0);\r
4038                                 }\r
4039                                 if ( ! prechkcurrent ) {\r
4040                                         // 来週かな\r
4041                                         String critDT = CommonUtils.getCritDateTime(7);\r
4042                                         prechknextweek = (critDT.compareTo(c.tvd.startDateTime) <= 0);\r
4043                                 }\r
4044                         }\r
4045                         \r
4046                         return true;\r
4047                 }\r
4048                 \r
4049                 //\r
4050                 @Override\r
4051                 public void tableChanged(TableModelEvent e) {\r
4052                         reset();\r
4053                         super.tableChanged(e);\r
4054                 }\r
4055                 \r
4056                 private void reset() {\r
4057                         prechkrow = -1;\r
4058                         prechkreserved = false;\r
4059                         prechkpicked = false;\r
4060                         prechkpassed = false;\r
4061                 }\r
4062                 \r
4063                 /*\r
4064                  * コンストラクタ\r
4065                  */\r
4066                 public ListedTable(boolean b) {\r
4067                         super(b);\r
4068                         reset();\r
4069                 }\r
4070                 public ListedTable(TableModel d, boolean b) {\r
4071                         super(d,b);\r
4072                         reset();\r
4073                 }\r
4074         }\r
4075         \r
4076         /**\r
4077          *  ソートが必要な場合はTableModelを作る。ただし、その場合Viewのrowがわからないので行の入れ替えが行えない\r
4078          * @see ListedTable\r
4079          */\r
4080         private class ListedTableModel extends DefaultTableModel {\r
4081                 \r
4082                 private static final long serialVersionUID = 1L;\r
4083 \r
4084                 @Override\r
4085                 public Object getValueAt(int row, int column) {\r
4086                         // 多少負荷があがるがこっちの方が見通しがいいだろう\r
4087                         ListedItem c = rowData.get(row);\r
4088                         if ( c.size()>column ) {\r
4089                                 // 特殊なカラム\r
4090                                 if ( column == ListedColumn.RSVMARK.getColumn() ) {\r
4091                                         if ( c.rsvmark.length() > 0 ) {\r
4092                                                 return c.rsvmark+"\0"+c.hide_rsvmarkcolor;\r
4093                                         }\r
4094                                         else {\r
4095                                                 return "";\r
4096                                         }\r
4097                                 }\r
4098                                 else if ( column == ListedColumn.DUPMARK.getColumn() ) {\r
4099                                         return c.dupmark+"\0"+DUPMARK_COLOR;\r
4100                                 }\r
4101                                 else if ( column == ListedColumn.START.getColumn() ) {\r
4102                                         return c.tvd.accurateDate+" "+c.tvd.start;\r
4103                                 }\r
4104                                 else if ( column == ListedColumn.LENGTH.getColumn() ) {\r
4105                                         return c.tvd.recmin+"m";\r
4106                                 }\r
4107                                 else if ( column == ListedColumn.GENRE.getColumn() ) {\r
4108                                         if ( c.tvd.subgenre != null ) {\r
4109                                                 return c.tvd.genre.toString()+" - "+c.tvd.subgenre.toString();\r
4110                                         }\r
4111                                         else {\r
4112                                                 // サブジャンルに非対応な番組表の場合\r
4113                                                 return c.tvd.genre.toString();\r
4114                                         }\r
4115                                 }\r
4116                                 else if ( column == ListedColumn.OPTIONS.getColumn() && ! env.getSplitMarkAndTitle() ) {\r
4117                                         // オプション分離がOFFです\r
4118                                         return "";\r
4119                                 }\r
4120                                 else if ( column == ListedColumn.TITLE.getColumn() && ! env.getSplitMarkAndTitle() ) {\r
4121                                         // オプション分離がOFFです\r
4122                                         return c.prefix+c.title;\r
4123                                 }\r
4124                                 return c.get(column);\r
4125                         }\r
4126                         return null;\r
4127                 }\r
4128                 \r
4129                 @Override\r
4130                 public int getRowCount() {\r
4131                         return rowData.size();\r
4132                 }\r
4133 \r
4134                 public ListedTableModel(String[] colname, int i) {\r
4135                         super(colname,i);\r
4136                 }\r
4137                 \r
4138         }\r
4139 \r
4140 }\r