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