OSDN Git Service

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