OSDN Git Service

予約ダイアログに裏番組情報のグラフィカル表示を追加
[tainavi/TinyBannavi.git] / TinyBannavi / src / tainavi / Viewer.java
1 package tainavi;\r
2 \r
3 import java.awt.AWTException;\r
4 import java.awt.BorderLayout;\r
5 import java.awt.Color;\r
6 import java.awt.Component;\r
7 import java.awt.Container;\r
8 import java.awt.Desktop;\r
9 import java.awt.Dimension;\r
10 import java.awt.Font;\r
11 import java.awt.Frame;\r
12 import java.awt.Image;\r
13 import java.awt.Insets;\r
14 import java.awt.MenuItem;\r
15 import java.awt.Point;\r
16 import java.awt.PopupMenu;\r
17 import java.awt.Rectangle;\r
18 import java.awt.SystemTray;\r
19 import java.awt.Toolkit;\r
20 import java.awt.TrayIcon;\r
21 import java.awt.datatransfer.Clipboard;\r
22 import java.awt.datatransfer.StringSelection;\r
23 import java.awt.event.ActionEvent;\r
24 import java.awt.event.ActionListener;\r
25 import java.awt.event.ComponentAdapter;\r
26 import java.awt.event.ComponentEvent;\r
27 import java.awt.event.MouseAdapter;\r
28 import java.awt.event.MouseEvent;\r
29 import java.awt.event.WindowAdapter;\r
30 import java.awt.event.WindowEvent;\r
31 import java.io.File;\r
32 import java.io.IOException;\r
33 import java.io.UnsupportedEncodingException;\r
34 import java.lang.management.ManagementFactory;\r
35 import java.lang.management.MemoryMXBean;\r
36 import java.lang.management.MemoryUsage;\r
37 import java.lang.reflect.InvocationTargetException;\r
38 import java.net.URI;\r
39 import java.net.URISyntaxException;\r
40 import java.net.URLEncoder;\r
41 import java.security.NoSuchAlgorithmException;\r
42 import java.util.ArrayList;\r
43 import java.util.Arrays;\r
44 import java.util.Calendar;\r
45 import java.util.GregorianCalendar;\r
46 import java.util.HashMap;\r
47 import java.util.LinkedHashMap;\r
48 import java.util.ServiceLoader;\r
49 import java.util.regex.Matcher;\r
50 import java.util.regex.Pattern;\r
51 \r
52 import javax.imageio.ImageIO;\r
53 import javax.swing.ImageIcon;\r
54 import javax.swing.JComponent;\r
55 import javax.swing.JFrame;\r
56 import javax.swing.JLabel;\r
57 import javax.swing.JMenuItem;\r
58 import javax.swing.JOptionPane;\r
59 import javax.swing.JPopupMenu;\r
60 import javax.swing.SwingUtilities;\r
61 import javax.swing.ToolTipManager;\r
62 import javax.swing.UIManager;\r
63 import javax.swing.event.ChangeEvent;\r
64 import javax.swing.event.ChangeListener;\r
65 \r
66 import tainavi.HDDRecorder.RecType;\r
67 import tainavi.SearchKey.TargetId;\r
68 import tainavi.TVProgram.ProgFlags;\r
69 import tainavi.TVProgram.ProgGenre;\r
70 import tainavi.TVProgram.ProgOption;\r
71 import tainavi.TVProgram.ProgSubgenre;\r
72 import tainavi.TVProgram.ProgSubtype;\r
73 import tainavi.TVProgram.ProgType;\r
74 import tainavi.VWMainWindow.MWinTab;\r
75 import tainavi.VWUpdate.UpdateResult;\r
76 \r
77 \r
78 /**\r
79  * メインな感じ\r
80  */\r
81 public class Viewer extends JFrame implements ChangeListener,TickTimerListener,HDDRecorderListener {\r
82 \r
83         private static final long serialVersionUID = 1L;\r
84         \r
85         \r
86         /*\r
87          * メソッド的な\r
88          */\r
89         \r
90         private void StdAppendMessage(String message)   { System.out.println(message); }\r
91         private void StdAppendError(String message)             { System.err.println(message); }\r
92         // \r
93         private void MWinSetVisible(boolean b)                  { mwin.setVisible(b); }\r
94         // \r
95         private void StWinClear()                                               { stwin.clear(); }\r
96         private void StWinSetVisible(boolean b)                 { stwin.setVisible(b); }\r
97         private void StWinSetLocationCenter(Component frame) { CommonSwingUtils.setLocationCenter(frame, (VWStatusWindow)stwin); }\r
98         private void StWinSetLocationUnder(Component frame)  { CommonSwingUtils.setLocationUnder(frame, (VWStatusWindow)stwin); }\r
99         \r
100         private void ringBeep() { if (env!=null && ! env.getDisableBeep()) { Toolkit.getDefaultToolkit().beep(); if ( env.getDebug() ) CommonUtils.printStackTrace(); } }\r
101         \r
102         \r
103         /*\r
104          * オブジェクト的な\r
105          */\r
106         \r
107         // 設定値をいれるところ\r
108         private final Env env = new Env();                                                                                      // 主要な設定\r
109         private final Bounds bounds = new Bounds();                                                                     // ウィンドウサイズとか動的に変化するもの\r
110         private final ClipboardInfoList cbitems = new ClipboardInfoList();                      // クリップボード対応機能でどの項目をコピーするかとかの設定 \r
111         private final PaperColorsMap pColors = new PaperColorsMap();                            // 新聞形式のジャンル別背景色の設定\r
112         private final AVSetting avs = new AVSetting();                                                          // ジャンル別録画画質・音質等設定\r
113         private final CHAVSetting chavs = new CHAVSetting();                                            // CH別録画画質・音質等設定\r
114         private final ChannelSort chsort = new ChannelSort();                                           // CHソート設定\r
115         private final ChannelConvert chconv = new ChannelConvert();                                     // ChannelConvert.dat\r
116         private final MarkChar markchar = new MarkChar(env);                                            // タイトルにつけるマークを操作する\r
117         \r
118         private final MarkedProgramList mpList = new MarkedProgramList();                       // 検索結果のキャッシュ(表示高速化用)\r
119         private final TraceProgram trKeys = new TraceProgram();                                         // 番組追跡の設定\r
120         private final SearchProgram srKeys = new SearchProgram();                                       // キーワード検索の設定\r
121         private final SearchGroupList srGrps = new SearchGroupList();                           // キーワード検索グループの設定\r
122         private final ExtProgram extKeys = new ExtProgram();                                            // 延長警告管理の設定\r
123         \r
124         private final RecorderInfoList recInfoList = new RecorderInfoList();            // レコーダ一覧の設定\r
125         \r
126         private final HDDRecorderList recPlugins = new HDDRecorderList();                       // レコーダプラグイン(テンプレート)\r
127         private final HDDRecorderList recorders = new HDDRecorderList();                        // レコーダプラグイン(実際に利用するもの)\r
128         \r
129         private final TVProgramList progPlugins = new TVProgramList();                          // Web番組表プラグイン(テンプレート)\r
130         private final TVProgramList tvprograms = new TVProgramList();                           // Web番組表プラグイン(実際に利用するもの)\r
131         \r
132         private final TickTimer timer_now = new TickTimer();                                                    // 毎分00秒に起動して処理をキックするタイマー\r
133         \r
134         // 初期化的な\r
135         private boolean logging = true;                                                                                 // ログ出力する\r
136         private boolean runRecWakeup = false;                                                                           // 起動時にレコーダを起こす\r
137         private boolean runRecLoad = false;                                                                                     // 起動時にレコーダから予約一覧を取得する\r
138         private boolean enableWebAccess = true;                                                                         // 起動時のWeb番組表へのアクセスを禁止する\r
139         private boolean onlyLoadProgram = false;\r
140         private String pxaddr = null;                                                                                           // ProxyAddress指定\r
141         private String pxport = null;                                                                                           // ProxtPort指定\r
142         \r
143         \r
144         /*******************************************************************************\r
145          * 定数\r
146          ******************************************************************************/\r
147         \r
148         public static final String LOG_FILE = "log.txt";                                                        // ログファイル名\r
149         public static final String HISTORY_FILE = "05_history.txt";                             // 更新履歴だよ\r
150         \r
151         private static final String ICONFILE_SYSTRAY = "icon"+File.separator+"tainavi16.png";\r
152         private static final String ICONFILE_TAINAVI = "icon"+File.separator+"tainavi.png";\r
153         \r
154         public static final int TIMEBAR_START = 5;                                      // 新聞形式の開始時刻\r
155         private static final int OPENING_WIAT = 500;                            // まあ起動時しか使わないんですけども\r
156 \r
157         private static final String MSGID = "[鯛ナビ] ";\r
158 //      private static final String ERRID = "[ERROR]"+MSGID;\r
159         private static final String DBGID = "[DEBUG]"+MSGID;\r
160         \r
161         /*\r
162          * [メモ] enumのtoString()をoverrideすると、シリアライズの際とても困るのでやらないこと\r
163          */\r
164         \r
165         /**\r
166          * Web番組表のどれとどれを読めばいいのか\r
167          */\r
168         public static enum LoadFor {\r
169                 TERRA   ("地上波&BSのみ取得"),\r
170                 CS              ("CSのみ取得"),\r
171                 CSo1    ("CS[プライマリ]のみ取得"),\r
172                 CSo2    ("CS[セカンダリ]のみ取得"),\r
173                 CSwSD   ("CSのみ取得(取得後シャットダウン)"),\r
174                 RADIO   ("ラジオのみ取得"),\r
175                 SYOBO   ("しょぼかるのみ取得"),\r
176                 ALL             ("すべて取得");\r
177                 \r
178                 private String name;\r
179                 \r
180                 private LoadFor(String name) {\r
181                         this.name = name;\r
182                 }\r
183 \r
184                 public String getName() {\r
185                         return this.name;\r
186                 }\r
187                 \r
188                 public static LoadFor get(String s) {\r
189                         for ( LoadFor lf : LoadFor.values() ) {\r
190                                 if ( lf.name.equals(s) ) {\r
191                                         return lf;\r
192                                 }\r
193                         }\r
194                         return null;\r
195                 }\r
196         };\r
197 \r
198         /**\r
199          * レコーダ情報のどれとどれを読めばいいのか\r
200          */\r
201         public static enum LoadRsvedFor {\r
202 //              SETTING         ( "設定情報のみ取得(future use.)" ),\r
203                 DETAILS         ( "予約一覧+録画詳細のみ取得" ),\r
204                 RECORDED        ( "録画結果一覧のみ取得" ),\r
205                 AUTORESERVE     ( "自動予約一覧のみ取得" ),\r
206                 ;\r
207                 \r
208                 private String name;\r
209                 \r
210                 private LoadRsvedFor(String name) {\r
211                         this.name = name;\r
212                 }\r
213                 \r
214                 public String getName() {\r
215                         return name;\r
216                 }\r
217                 \r
218                 public static LoadRsvedFor get(String s) {\r
219                         for ( LoadRsvedFor lrf : LoadRsvedFor.values() ) {\r
220                                 if ( lrf.name.equals(s) ) {\r
221                                         return lrf;\r
222                                 }\r
223                         }\r
224                         return null;\r
225                 }\r
226         }\r
227         \r
228         /**\r
229          *  リスト形式のカラム定義\r
230          * @deprecated しっぱいした 半年くらいしたら削除する\r
231          */\r
232         @Deprecated\r
233         public static enum ListedColumn {\r
234                 RSVMARK         ("予約",                      35),\r
235                 DUPMARK         ("重複",                      35),\r
236                 CHNAME          ("チャンネル名",  100),\r
237                 TITLE           ("番組タイトル",  300),\r
238                 DETAIL          ("番組詳細",                200),\r
239                 START           ("開始時刻",                150),\r
240                 END                     ("終了",                      50),\r
241                 LENGTH          ("長さ",                      50),\r
242                 GENRE           ("ジャンル",                85),\r
243                 SITEM           ("検索アイテム名",       100),\r
244                 STAR            ("お気に入り度",  100),\r
245                 SCORE           ("スコア",                   35),\r
246                 THRESHOLD       ("閾値",                      35),\r
247                 HID_PRGID       ("PRGID",               -1),\r
248                 HID_STIME       ("STIME",               -1),\r
249                 HID_ETIME       ("ETIME",               -1),\r
250                 HID_EXFLG       ("EXFLG",               -1),\r
251                 HID_TITLE       ("TITLE",               -1),\r
252                 ;\r
253 \r
254                 @SuppressWarnings("unused")\r
255                 private String name;\r
256                 private int iniWidth;\r
257 \r
258                 private ListedColumn(String name, int iniWidth) {\r
259                         this.name = name;\r
260                         this.iniWidth = iniWidth;\r
261                 }\r
262 \r
263                 /* なんだかなー\r
264                 @Override\r
265                 public String toString() {\r
266                         return name;\r
267                 }\r
268                 */\r
269 \r
270                 public int getIniWidth() {\r
271                         return iniWidth;\r
272                 }\r
273                 \r
274                 public int getColumn() {\r
275                         return ordinal();\r
276                 }\r
277         };\r
278         \r
279         /**\r
280          *  本体予約一覧のカラム定義\r
281          * @deprecated しっぱいした 半年くらいしたら削除する\r
282          */\r
283         @Deprecated\r
284         public static enum RsvedColumn {\r
285                 PATTERN         ("パタン",                   110),\r
286                 DUPMARK         ("重複",                      35),\r
287                 EXEC            ("実行",                      35),\r
288                 TRACE           ("追跡",                      35),\r
289                 NEXTSTART       ("次回実行予定",  150),\r
290                 END                     ("終了",                      50),\r
291                 LENGTH          ("長さ",                      50),\r
292                 ENCODER         ("エンコーダ",          50),\r
293                 VRATE           ("画質",                      100),\r
294                 ARATE           ("音質",                      50),\r
295                 TITLE           ("番組タイトル",  300),\r
296                 CHNAME          ("チャンネル名",  150),\r
297                 RECORDER        ("レコーダ",                200),\r
298                 HID_INDEX       ("INDEX",               -1),\r
299                 HID_RSVID       ("RSVID",               -1),\r
300                 ;\r
301 \r
302                 @SuppressWarnings("unused")\r
303                 private String name;\r
304                 private int iniWidth;\r
305 \r
306                 private RsvedColumn(String name, int iniWidth) {\r
307                         this.name = name;\r
308                         this.iniWidth = iniWidth;\r
309                 }\r
310 \r
311                 /*\r
312                 @Override\r
313                 public String toString() {\r
314                         return name;\r
315                 }\r
316                 */\r
317 \r
318                 public int getIniWidth() {\r
319                         return iniWidth;\r
320                 }\r
321                 \r
322                 public int getColumn() {\r
323                         return ordinal();\r
324                 }\r
325         };\r
326         \r
327         \r
328         \r
329         /*\r
330          * コンポーネント\r
331          */\r
332         \r
333         // 起動時に固定で用意しておくもの\r
334         private final VWStatusWindow stwin = new VWStatusWindow();\r
335         private final VWStatusTextArea mwin = new VWStatusTextArea();\r
336         private final VWColorChooserDialog ccwin = new VWColorChooserDialog();\r
337         private final VWPaperColorsDialog pcwin = new VWPaperColorsDialog();\r
338         private final VWReserveDialog rdialog = new VWReserveDialog(0, 0);\r
339         \r
340         // 初期化処理の中で生成していくもの\r
341         private VWMainWindow mainWindow = null;\r
342         private VWToolBar toolBar = null;\r
343         private VWListedView listed = null;\r
344         private VWPaperView paper = null;\r
345         private VWReserveListView reserved = null;\r
346         private VWRecordedListView recorded = null;\r
347         private VWAutoReserveListView autores = null;\r
348         private VWSettingView setting = null;\r
349         private VWRecorderSettingView recsetting = null;\r
350         private VWChannelSettingView chsetting = null;\r
351         private VWChannelDatSettingView chdatsetting = null;\r
352         private VWChannelSortView chsortsetting = null;\r
353         private VWChannelConvertView chconvsetting = null;\r
354         private VWLookAndFeel vwlaf = null;\r
355         private VWFont vwfont = null;\r
356         \r
357         private TrayIcon trayicon = null;\r
358         \r
359         \r
360         \r
361         /*******************************************************************************\r
362          * タブやダイアログのインスタンス作成用クラス定義\r
363          ******************************************************************************/\r
364         \r
365         /***\r
366          * リスト形式の内部クラス\r
367          */\r
368         private class VWListedView extends AbsListedView {\r
369 \r
370                 private static final long serialVersionUID = 1L;\r
371 \r
372                 // 環境設定の入れ物を渡す\r
373                 @Override\r
374                 protected Env getEnv() { return env; }\r
375                 @Override\r
376                 protected Bounds getBoundsEnv() { return bounds; }\r
377                 @Override\r
378                 protected ChannelSort getChannelSort() { return chsort; }\r
379 \r
380                 @Override\r
381                 protected MarkedProgramList getMarkedProgramList() { return mpList; }\r
382                 @Override\r
383                 protected TraceProgram getTraceProgram() { return trKeys; }\r
384                 @Override\r
385                 protected SearchProgram getSearchProgram() { return srKeys; }\r
386                 @Override\r
387                 protected SearchGroupList getSearchGroupList() { return srGrps; }\r
388                 @Override\r
389                 protected ExtProgram getExtProgram() { return extKeys; }\r
390 \r
391                 @Override\r
392                 protected TVProgramList getTVProgramList() { return tvprograms; }\r
393                 @Override\r
394                 protected HDDRecorderList getRecorderList() { return recorders; }\r
395 \r
396                 // メッセージ出力関連\r
397                 @Override\r
398                 protected StatusWindow getStWin() { return stwin; }\r
399                 @Override\r
400                 protected StatusTextArea getMWin() { return mwin; }\r
401                 \r
402                 // コンポーネントを渡す\r
403                 @Override\r
404                 protected AbsReserveDialog getReserveDialog() { return rdialog; }\r
405                 @Override\r
406                 protected Component getParentComponent() { return Viewer.this; }\r
407 \r
408                 @Override\r
409                 protected void ringBeep() { Viewer.this.ringBeep(); }\r
410                 \r
411                 /*\r
412                  * AbsListedView内でのイベントから呼び出されるメソッド群\r
413                  */\r
414 \r
415                 @Override\r
416                 protected void onShown() {\r
417                         // キーワード登録ボタンはリスト形式のみ\r
418                         toolBar.setAddkeywordEnabled(true);\r
419                         // 一括予約はリスト形式のみ\r
420                         toolBar.setBatchReservationEnabled(true);\r
421                         // スナップショットを有効にする\r
422                         toolBar.setSnapShotEnabled(true);\r
423                 }\r
424 \r
425                 @Override\r
426                 protected void onHidden() {\r
427                         // キーワード登録ボタンはリスト形式のみ\r
428                         toolBar.setAddkeywordEnabled(false);\r
429                         // 一括予約はリスト形式のみ\r
430                         toolBar.setBatchReservationEnabled(false);\r
431                         // スナップショットを無効にする\r
432                         toolBar.setSnapShotEnabled(false);\r
433                 }\r
434 \r
435                 @Override\r
436                 protected void showPopupForTraceProgram(\r
437                                 final JComponent comp,\r
438                                 final ProgDetailList tvd, final String keyword, final int threshold,\r
439                                 final int x, final int y) {\r
440                         \r
441                         timer_now.pause();      // 停止\r
442                         \r
443                         Viewer.this.showPopupForTraceProgram(comp, tvd, keyword, threshold, x, y, null);\r
444                         \r
445                         timer_now.start();      // 再開\r
446                 }\r
447 \r
448                 @Override\r
449                 protected void updateReserveDisplay(String chname) {\r
450                         timer_now.pause();\r
451                         paper.updateReserveBorder(chname);\r
452                         reserved.redrawReservedList();\r
453                         timer_now.start();\r
454                 }\r
455 \r
456                 @Override\r
457                 protected void updateBangumiColumns() {\r
458                         timer_now.pause();\r
459                         paper.updateBangumiColumns();\r
460                         timer_now.start();\r
461                 }\r
462 \r
463                 @Override\r
464                 protected void clearPaper() {\r
465                         timer_now.pause();\r
466                         paper.clearPanel();\r
467                         timer_now.start();\r
468                 }\r
469 \r
470                 @Override\r
471                 protected void previewKeywordSearch(SearchKey search) {\r
472                         //timer_now.pause();\r
473                         if (search.alTarget.size() > 0) {\r
474                                 mainWindow.setSelectedTab(MWinTab.LISTED);\r
475                                 listed.redrawListByPreview(search);\r
476                         }\r
477                         //timer_now.start();\r
478                 }\r
479 \r
480                 @Override\r
481                 protected void jumpToPaper(String Center, String StartDateTime) {\r
482                         //timer_now.pause();\r
483                         paper.jumpToBangumi(Center,StartDateTime);\r
484                         //timer_now.start();\r
485                 }\r
486 \r
487                 @Override\r
488                 protected boolean addToPickup(ProgDetailList tvd) { return Viewer.this.addToPickup(tvd); }\r
489 \r
490                 @Override\r
491                 protected boolean isTabSelected(MWinTab tab) { return mainWindow.isTabSelected(tab); }\r
492                 @Override\r
493                 protected void setSelectedTab(MWinTab tab) { mainWindow.setSelectedTab(tab); }\r
494 \r
495                 @Override\r
496                 protected String getSelectedRecorderOnToolbar() { return toolBar.getSelectedRecorder(); }\r
497                 @Override\r
498                 protected boolean isFullScreen() { return toolBar.isFullScreen(); }\r
499                 @Override\r
500                 protected void setPagerEnabled(boolean b) { toolBar.setPagerEnabled(b); }\r
501                 @Override\r
502                 protected int getPagerCount() { return toolBar.getPagerCount(); }\r
503                 @Override\r
504                 protected int getSelectedPagerIndex() { return toolBar.getSelectedPagerIndex(); }\r
505 \r
506                 @Override\r
507                 protected void setDividerEnvs(int loc) {\r
508                         if ( ! toolBar.isFullScreen() && mainWindow.isTabSelected(MWinTab.LISTED) ) {\r
509                                 if (env.getSyncTreeWidth()) {\r
510                                         bounds.setTreeWidth(loc);\r
511                                         bounds.setTreeWidthPaper(loc);\r
512                                 }\r
513                                 else {\r
514                                         bounds.setTreeWidth(loc);\r
515                                 }\r
516                         }\r
517                 }\r
518         }\r
519         \r
520         \r
521         \r
522         /**\r
523          * 新聞形式の内部クラス\r
524          */\r
525         private class VWPaperView extends AbsPaperView {\r
526 \r
527                 private static final long serialVersionUID = 1L;\r
528 \r
529                 // 環境設定の入れ物を渡す\r
530                 @Override\r
531                 protected Env getEnv() { return env; }\r
532                 @Override\r
533                 protected Bounds getBoundsEnv() { return bounds; }\r
534                 @Override\r
535                 protected PaperColorsMap getPaperColorMap() { return pColors; }\r
536                 @Override\r
537                 protected ChannelSort getChannelSort() { return chsort; }\r
538                 \r
539                 @Override\r
540                 protected TVProgramList getTVProgramList() { return tvprograms; }\r
541                 @Override\r
542                 protected HDDRecorderList getRecorderList() { return recorders; }\r
543 \r
544                 // メッセージ出力関連\r
545                 @Override\r
546                 protected StatusWindow getStWin() { return stwin; }\r
547                 @Override\r
548                 protected StatusTextArea getMWin() { return mwin; }\r
549                 \r
550                 // コンポーネントを渡す\r
551                 @Override\r
552                 protected AbsReserveDialog getReserveDialog() { return rdialog; }\r
553                 @Override\r
554                 protected Component getParentComponent() { return Viewer.this; }\r
555 \r
556                 @Override\r
557                 protected void ringBeep() { Viewer.this.ringBeep(); }\r
558                 \r
559                 /*\r
560                  * AbsPaperView内でのイベントから呼び出されるメソッド群\r
561                  */\r
562 \r
563                 @Override\r
564                 protected void onShown() {\r
565                         // ページャーコンボボックスを有効にする(状況次第で有効にならない場合もある)(ツリーの選択次第で変わるのでもどし)\r
566                         //toolBar.setPagerEnabled(true);\r
567                         // スナップショットを有効にする\r
568                         toolBar.setSnapShotEnabled(true);\r
569                         // ジャンル別背景色を有効にする\r
570                         toolBar.setPaperColorDialogEnabled(true);\r
571                         // マッチ枠を有効にする\r
572                         toolBar.setBorderToggleEnabled(true);\r
573                 }\r
574 \r
575                 @Override\r
576                 protected void onHidden() {\r
577                         // 新聞形式以外ではページャーコンボボックスを無効にする(ツリーの選択次第で変わるのでもどし)\r
578                         //toolBar.setPagerEnabled(false);\r
579                         // 新聞形式以外ではスナップショットを無効にする\r
580                         toolBar.setSnapShotEnabled(false);\r
581                         // 新聞形式以外ではジャンル別背景色を無効にする\r
582                         toolBar.setPaperColorDialogEnabled(false);\r
583                         // 新聞形式以外ではマッチ枠を無効にする\r
584                         toolBar.setBorderToggleEnabled(false);\r
585                 }\r
586 \r
587                 @Override\r
588                 protected void showPopupForTraceProgram(\r
589                                 final JComponent comp,\r
590                                 final ProgDetailList tvd, final String keyword, final int threshold,\r
591                                 final int x, final int y, final String clickedDateTime) {\r
592                         \r
593                         timer_now.pause();      // 停止\r
594                         \r
595                         Viewer.this.showPopupForTraceProgram(comp, tvd, keyword, threshold, x, y, clickedDateTime);\r
596                         \r
597                         timer_now.start();      // 再開\r
598                 }\r
599 \r
600                 @Override\r
601                 protected void updateReserveDisplay() {\r
602                         timer_now.pause();\r
603                         listed.updateReserveMark();\r
604                         reserved.redrawReservedList();\r
605                         timer_now.start();\r
606                 }\r
607 \r
608                 @Override\r
609                 protected void addToPickup(ProgDetailList tvd) { Viewer.this.addToPickup(tvd); }\r
610 \r
611                 @Override\r
612                 protected boolean isTabSelected(MWinTab tab) { return mainWindow.isTabSelected(tab); }\r
613                 @Override\r
614                 protected void setSelectedTab(MWinTab tab) { mainWindow.setSelectedTab(tab); }\r
615 \r
616                 @Override\r
617                 protected boolean isFullScreen() { return toolBar.isFullScreen(); }\r
618                 @Override\r
619                 protected void setSelectedPagerIndex(int idx) {\r
620                         toolBar.setSelectedPagerIndex(idx);\r
621                 }\r
622                 @Override\r
623                 protected void setPagerEnabled(boolean b) { toolBar.setPagerEnabled(b); }\r
624                 @Override\r
625                 protected int getPagerCount() { return toolBar.getPagerCount(); }\r
626                 @Override\r
627                 protected int getSelectedPagerIndex() { return toolBar.getSelectedPagerIndex(); }\r
628                 @Override\r
629                 protected void setPagerItems(TVProgramIterator pli, int curindex) {\r
630                         toolBar.setPagerItems(pli,curindex);\r
631                 }\r
632 \r
633                 @Override\r
634                 protected String getExtensionMark(ProgDetailList tvd) { return markchar.getExtensionMark(tvd); }\r
635                 @Override\r
636                 protected String getOptionMark(ProgDetailList tvd) { return markchar.getOptionMark(tvd)+markchar.getNewLastMark(tvd); }\r
637                 @Override\r
638                 protected String getPostfixMark(ProgDetailList tvd) { return markchar.getPostfixMark(tvd); }\r
639 \r
640                 @Override\r
641                 protected void setDividerEnvs(int loc) {\r
642                         if ( ! toolBar.isFullScreen() && mainWindow.isTabSelected(MWinTab.PAPER) ) {\r
643                                 if (env.getSyncTreeWidth()) {\r
644                                         bounds.setTreeWidth(loc);\r
645                                         bounds.setTreeWidthPaper(loc);\r
646                                 }\r
647                                 else {\r
648                                         bounds.setTreeWidthPaper(loc);\r
649                                 }\r
650                         }\r
651                 }\r
652         }\r
653         \r
654         \r
655         \r
656         /**\r
657          * \r
658          * 本体予約一覧の内部クラス\r
659          * \r
660          */\r
661         private class VWReserveListView extends AbsReserveListView {\r
662 \r
663                 private static final long serialVersionUID = 1L;\r
664 \r
665                 // 環境設定の入れ物を渡す\r
666                 @Override\r
667                 protected Env getEnv() { return env; }\r
668                 @Override\r
669                 protected Bounds getBoundsEnv() { return bounds; }\r
670 \r
671                 @Override\r
672                 protected HDDRecorderList getRecorderList() { return recorders; }\r
673 \r
674                 // ログ関係はないのか\r
675                 \r
676                 // コンポーネントを渡す\r
677                 @Override\r
678                 protected AbsReserveDialog getReserveDialog() { return rdialog; }\r
679                 @Override\r
680                 protected Component getParentComponent() { return Viewer.this; }\r
681 \r
682                 @Override\r
683                 protected void ringBeep() { Viewer.this.ringBeep(); }\r
684 \r
685                 /*\r
686                  * AbsReserveListView内でのイベントから呼び出されるメソッド群\r
687                  */\r
688                 \r
689                 @Override\r
690                 protected void updateReserveDisplay(String chname) {\r
691                         timer_now.pause();\r
692                         listed.updateReserveMark();\r
693                         paper.updateReserveBorder(chname);\r
694                         timer_now.start();\r
695                 }\r
696 \r
697                 @Override\r
698                 protected boolean doExecOnOff(boolean fexec, String title, String chnam, String rsvId, String recId) {\r
699                         return Viewer.this.doExecOnOff(fexec, title, chnam, rsvId, recId);\r
700                 }\r
701                 \r
702                 @Override\r
703                 protected JMenuItem getExecOnOffMenuItem(boolean fexec,\r
704                                 String start, String title, String chnam, String rsvId, String recId) {\r
705 \r
706                         return Viewer.this.getExecOnOffMenuItem(fexec, start, title, chnam, rsvId, recId, 0);\r
707                 }\r
708 \r
709                 @Override\r
710                 protected JMenuItem getRemoveRsvMenuItem(\r
711                                 String start, String title, String chnam,       String rsvId, String recId) {\r
712                         \r
713                         return Viewer.this.getRemoveRsvMenuItem(start, title, chnam, rsvId, recId, 0);\r
714                 }\r
715 \r
716                 @Override\r
717                 protected JMenuItem getJumpMenuItem(String title, String chnam,\r
718                                 String startDT) {\r
719                         \r
720                         return Viewer.this.getJumpMenuItem(title, chnam, startDT);\r
721                 }\r
722 \r
723                 @Override\r
724                 protected JMenuItem getJumpToLastWeekMenuItem(String title,\r
725                                 String chnam, String startDT) {\r
726                         \r
727                         return Viewer.this.getJumpToLastWeekMenuItem(title, chnam, startDT);\r
728                 }\r
729 \r
730                 @Override\r
731                 protected String getSelectedRecorderOnToolbar() { return toolBar.getSelectedRecorder(); }\r
732         }\r
733         \r
734         \r
735         /**\r
736          * \r
737          * 録画結果一覧の内部クラス\r
738          * \r
739          */\r
740         private class VWRecordedListView extends AbsRecordedListView {\r
741 \r
742                 private static final long serialVersionUID = 1L;\r
743 \r
744                 // 環境設定の入れ物を渡す\r
745                 @Override\r
746                 protected Env getEnv() { return env; }\r
747                 @Override\r
748                 protected Bounds getBoundsEnv() { return bounds; }\r
749 \r
750                 @Override\r
751                 protected HDDRecorderList getRecorderList() { return recorders; }\r
752 \r
753                 // ログ関係はないのか\r
754                 \r
755                 // コンポーネントを渡す\r
756                 @Override\r
757                 protected Component getParentComponent() { return Viewer.this; }\r
758 \r
759                 @Override\r
760                 protected void ringBeep() { Viewer.this.ringBeep(); }\r
761 \r
762                 /*\r
763                  * AbsReserveListView内でのイベントから呼び出されるメソッド群\r
764                  */\r
765                 \r
766                 @Override\r
767                 protected String getSelectedRecorderOnToolbar() { return toolBar.getSelectedRecorder(); }\r
768         }\r
769         \r
770         \r
771         /**\r
772          * \r
773          * 録画結果一覧の内部クラス\r
774          * \r
775          */\r
776         private class VWAutoReserveListView extends AbsAutoReserveListView {\r
777 \r
778                 private static final long serialVersionUID = 1L;\r
779 \r
780                 // 環境設定の入れ物を渡す\r
781                 @Override\r
782                 protected Env getEnv() { return env; }\r
783                 @Override\r
784                 protected Bounds getBoundsEnv() { return bounds; }\r
785                 \r
786         }\r
787         \r
788         /***\r
789          * 各種設定の内部クラス\r
790          */\r
791         private class VWSettingView extends AbsSettingView {\r
792 \r
793                 private static final long serialVersionUID = 1L;\r
794 \r
795                 // 環境設定の入れ物を渡す\r
796                 @Override\r
797                 protected Env getEnv() { return env; }\r
798                 @Override\r
799                 protected ClipboardInfoList getCbItemEnv() { return cbitems; }\r
800                 @Override\r
801                 protected VWLookAndFeel getLAFEnv() { return vwlaf; }\r
802                 @Override\r
803                 protected VWFont getFontEnv() { return vwfont; }\r
804                 \r
805                 // メッセージ出力関連\r
806                 @Override\r
807                 protected StatusWindow getStWin() { return stwin; }\r
808                 @Override\r
809                 protected StatusTextArea getMWin() { return mwin; }\r
810                 \r
811                 // コンポーネントを渡す\r
812                 @Override\r
813                 protected Component getParentComponent() { return Viewer.this; }\r
814                 @Override\r
815                 protected VWColorChooserDialog getCcWin() { return ccwin; }\r
816 \r
817                 /*\r
818                  * AbsSettingView内でのイベントから呼び出されるメソッド群\r
819                  */\r
820                 \r
821                 @Override\r
822                 protected void lafChanged(String lafname) {\r
823                         vwlaf.update(lafname);\r
824                         Viewer.this.updateComponentTreeUI();\r
825                         StdAppendMessage("Set LookAndFeel="+lafname);\r
826                 }\r
827 \r
828                 @Override\r
829                 protected void fontChanged(String fn, int fontSize) {\r
830                         vwfont.update(fn, fontSize);\r
831                         Viewer.this.updateComponentTreeUI();\r
832                         StdAppendMessage("システムのフォントを変更しました: "+fn+", size="+fontSize);\r
833                 }\r
834 \r
835                 @Override\r
836                 protected void setEnv(final boolean reload_prog) {\r
837                         \r
838                         //listed.pauseTimer();\r
839                         timer_now.pause();\r
840                         \r
841                         Viewer.this.setEnv(reload_prog);\r
842                         \r
843                         timer_now.start();\r
844                 }\r
845         }\r
846         \r
847         /**\r
848          * レコーダ設定タブの内部クラス\r
849          * @see AbsRecorderSettingView\r
850          */\r
851         private class VWRecorderSettingView extends AbsRecorderSettingView {\r
852 \r
853                 private static final long serialVersionUID = 1L;\r
854 \r
855                 // 環境設定の入れ物を渡す\r
856                 @Override\r
857                 protected Env getEnv() { return env; }\r
858                 @Override\r
859                 protected RecorderInfoList getRecInfos() { return recInfoList; }\r
860                 @Override\r
861                 protected HDDRecorderList getRecPlugins() { return recPlugins; }\r
862 \r
863                 // ログ関連\r
864                 @Override\r
865                 protected VWStatusWindow getStWin() { return stwin; }\r
866                 @Override\r
867                 protected StatusTextArea getMWin() { return mwin; }\r
868 \r
869                 // コンポーネントを渡す\r
870                 @Override\r
871                 protected Component getParentComponent() { return Viewer.this; }\r
872                 @Override\r
873                 protected VWColorChooserDialog getCcWin() { return ccwin; }\r
874 \r
875                 @Override\r
876                 protected void ringBeep() { Viewer.this.ringBeep(); }\r
877 \r
878                 /*\r
879                  * AbsRecorderSettingView内でのイベントから呼び出されるメソッド群\r
880                  */\r
881                 \r
882                 @Override\r
883                 protected void setRecInfos() {\r
884                         \r
885                         timer_now.pause();\r
886                         \r
887                         // 設定を保存\r
888                         recInfoList.save();\r
889                         \r
890                         // レコーダプラグインのリフレッシュ\r
891                         initRecPluginAll();\r
892                         \r
893                         // レコーダ一覧をツールバーに設定\r
894                         toolBar.updateRecorderComboBox();\r
895                         \r
896                         // 予約一覧のリフレッシュ\r
897                         loadRdReservesAll(false, null);         // toolBarの内容がリセットされているので recId = null で\r
898                         \r
899                         // レコーダのエンコーダ表示の更新\r
900                         this.redrawRecorderEncoderEntry();\r
901 \r
902                         // レコーダ一覧をCHコード設定のコンボボックスに設定 \r
903                         chdatsetting.updateRecorderComboBox();\r
904                         \r
905                         // Web番組表の再構築(予約マークのリフレッシュ)\r
906                         paper.updateReserveBorder(null);\r
907                         listed.updateReserveMark();\r
908                         \r
909                         timer_now.start();\r
910                 }\r
911 \r
912         }\r
913 \r
914         \r
915         /***\r
916          * CH設定の内部クラス\r
917          */\r
918         private class VWChannelSettingView extends AbsChannelSettingView {\r
919 \r
920                 private static final long serialVersionUID = 1L;\r
921                 \r
922                 // 環境設定の入れ物を渡す\r
923                 @Override\r
924                 protected Env getEnv() { return Viewer.this.env; }\r
925                 @Override\r
926                 protected TVProgramList getProgPlugins() { return progPlugins; }\r
927 \r
928                 // ログ関連\r
929                 @Override\r
930                 protected StatusWindow getStWin() { return stwin; }\r
931                 @Override\r
932                 protected StatusTextArea getMWin() { return mwin; }\r
933 \r
934                 // コンポーネントを渡す\r
935                 @Override\r
936                 protected Component getParentComponent() { return Viewer.this; }\r
937                 @Override\r
938                 protected VWColorChooserDialog getCcWin() { return ccwin; }\r
939 \r
940                 @Override\r
941                 protected void ringBeep() {\r
942                         Viewer.this.ringBeep();\r
943                 }\r
944                 @Override\r
945                 protected void updateProgPlugin() {\r
946                         \r
947                         timer_now.pause();\r
948                         \r
949                         // 設定を保存(プラグイン内部の設定はChannelSettingPanel内で実施)\r
950                         env.save();\r
951                         \r
952                         // Web番組表プラグインのリフレッシュ\r
953                         setSelectedProgPlugin();\r
954                         initProgPluginAll();\r
955                         \r
956                         // CHソート設定に反映\r
957                         chsortsetting.updateChannelSortTable();\r
958                         \r
959                         // CHコンバート設定をリフレッシュ\r
960                         chconvsetting.updateChannelConvertTable();\r
961                         \r
962                         // CHコード設定にも反映\r
963                         chdatsetting.updateChannelDatTable();\r
964 \r
965                         // 番組情報の再取得\r
966                         loadTVProgram(false,LoadFor.ALL);       // 部品呼び出し\r
967                         \r
968                         // ツールバーに反映\r
969                         toolBar.setPagerItems();\r
970                         \r
971                         // 新聞描画枠のリセット\r
972                         paper.clearPanel();\r
973                         paper.buildMainViewByDate();\r
974                         \r
975                         // サイドツリーの再構築\r
976                         paper.redrawTreeByCenter();\r
977                         \r
978                         listed.redrawTreeByCenter();\r
979                         \r
980                         // 再構築\r
981                         paper.reselectTree();\r
982                         listed.reselectTree();\r
983                         \r
984                         timer_now.start();\r
985                 }\r
986                 \r
987         }\r
988         \r
989         /***\r
990          * CHコード設定の内部クラス\r
991          */\r
992         private class VWChannelDatSettingView extends AbsChannelDatSettingView {\r
993 \r
994                 private static final long serialVersionUID = 1L;\r
995 \r
996                 // 環境設定の入れ物を渡す\r
997                 @Override\r
998                 protected Env getEnv() { return Viewer.this.env; }\r
999                 @Override\r
1000                 protected TVProgramList getTVProgramList() { return tvprograms; }\r
1001                 @Override\r
1002                 protected ChannelSort getChannelSort() { return chsort; }\r
1003                 @Override\r
1004                 protected HDDRecorderList getHDDRecorderList() { return recorders; }\r
1005 \r
1006                 // ログ関連\r
1007                 @Override\r
1008                 protected StatusWindow getStWin() { return stwin; }\r
1009                 @Override\r
1010                 protected StatusTextArea getMWin() { return mwin; }\r
1011 \r
1012                 // コンポーネントを渡す\r
1013                 @Override\r
1014                 protected Component getParentComponent() { return Viewer.this; }\r
1015                 \r
1016                 @Override\r
1017                 protected void ringBeep() {\r
1018                         Viewer.this.ringBeep();\r
1019                 }\r
1020                 \r
1021         }\r
1022 \r
1023         /**\r
1024          * CHソート設定タブの内部クラス\r
1025          */\r
1026         private class VWChannelSortView extends AbsChannelSortView {\r
1027 \r
1028                 private static final long serialVersionUID = 1L;\r
1029 \r
1030                 @Override\r
1031                 protected Env getEnv() { return Viewer.this.env; }\r
1032                 @Override\r
1033                 protected TVProgramList getTVProgramList() { return tvprograms; }\r
1034                 @Override\r
1035                 protected ChannelSort getChannelSort() { return chsort; }\r
1036                 \r
1037                 // ログ関連\r
1038                 @Override\r
1039                 protected StatusTextArea getMWin() { return mwin; }\r
1040                 \r
1041                 @Override\r
1042                 protected void updProc() {\r
1043                         \r
1044                         timer_now.pause();\r
1045                         \r
1046                         env.save();\r
1047                         \r
1048                         toolBar.setPagerItems();\r
1049                         toolBar.setSelectedPagerIndex(toolBar.getSelectedPagerIndex());\r
1050                         \r
1051                         // 新聞描画枠のリセット\r
1052                         paper.clearPanel();\r
1053                         paper.buildMainViewByDate();\r
1054                         \r
1055                         // サイドツリーの再構築\r
1056                         paper.redrawTreeByCenter();\r
1057                         \r
1058                         listed.redrawTreeByCenter();\r
1059                         \r
1060                         // 再描画 \r
1061                         paper.reselectTree();\r
1062                         listed.reselectTree();\r
1063                         \r
1064                         timer_now.start();\r
1065                 }\r
1066         }\r
1067         \r
1068         /**\r
1069          * CHコンバート設定タブの内部クラス\r
1070          */\r
1071         private class VWChannelConvertView extends AbsChannelConvertView {\r
1072 \r
1073                 private static final long serialVersionUID = 1L;\r
1074 \r
1075                 // 環境設定の入れ物を渡す\r
1076                 @Override\r
1077                 protected Env getEnv() { return env; }\r
1078                 @Override\r
1079                 protected TVProgramList getProgPlugins() { return progPlugins; }\r
1080                 @Override\r
1081                 protected ChannelConvert getChannelConvert() { return chconv; }\r
1082                 \r
1083         }\r
1084         \r
1085         /***\r
1086          * 予約ウィンドウの内部クラス\r
1087          */\r
1088         private class VWReserveDialog extends AbsReserveDialog {\r
1089 \r
1090                 private static final long serialVersionUID = 1L;\r
1091 \r
1092                 // コンストラクタ\r
1093                 public VWReserveDialog(int x, int y) {\r
1094                         super(x, y);\r
1095                 }\r
1096 \r
1097                 // 環境設定の入れ物を渡す\r
1098                 @Override\r
1099                 protected Env getEnv() { return env; }\r
1100                 @Override\r
1101                 protected TVProgramList getTVProgramList() { return tvprograms; }\r
1102                 @Override\r
1103                 protected HDDRecorderList getRecorderList() { return recorders; }\r
1104                 @Override\r
1105                 protected AVSetting getAVSetting() { return avs; }\r
1106                 @Override\r
1107                 protected CHAVSetting getCHAVSetting() { return chavs; }\r
1108 \r
1109                 // ログ関連\r
1110                 @Override\r
1111                 protected StatusWindow getStWin() { return stwin; }\r
1112                 @Override\r
1113                 protected StatusTextArea getMWin() { return mwin; }\r
1114                 \r
1115                 // コンポーネントを渡す\r
1116                 @Override\r
1117                 protected Component getParentComponent() { return Viewer.this; }\r
1118 \r
1119                 @Override\r
1120                 protected void ringBeep() { Viewer.this.ringBeep(); }\r
1121 \r
1122                 /*\r
1123                  * ReserveDialog内でのイベントから呼び出されるメソッド群\r
1124                  */\r
1125                 \r
1126                 @Override\r
1127                 protected LikeReserveList findLikeReserves(ProgDetailList tvd, String keyword, int threshold) {\r
1128                         return Viewer.this.findLikeReserves(tvd, keyword, threshold);\r
1129                 }\r
1130         }\r
1131         \r
1132         /**\r
1133          * 新聞の表示形式を操作するダイアログ\r
1134          */\r
1135         private class VWPaperColorsDialog extends AbsPaperColorsDialog {\r
1136 \r
1137                 private static final long serialVersionUID = 1L;\r
1138 \r
1139                 @Override\r
1140                 protected Env getEnv() { return env; }\r
1141                 @Override\r
1142                 protected Bounds getBoundsEnv() { return bounds; }\r
1143                 @Override\r
1144                 protected PaperColorsMap getPaperColorMap() { return pColors; }\r
1145                 \r
1146                 @Override\r
1147                 protected VWColorChooserDialog getCCWin() { return ccwin; }\r
1148                 \r
1149                 /*\r
1150                  * PaperColorsDialog内でのイベントから呼び出されるメソッド群\r
1151                  */\r
1152                 \r
1153                 // 背景色設定の反映\r
1154                 @Override\r
1155                 protected void updatePaperColors(Env ec,PaperColorsMap pc) {\r
1156                         paper.updateColors(ec,pc);\r
1157                 }\r
1158 \r
1159                 // フォント設定の反映\r
1160                 @Override\r
1161                 protected void updatePaperFonts(Env ec) {\r
1162                         paper.updateFonts(ec);\r
1163                 }\r
1164 \r
1165                 // サイズ設定の反映\r
1166                 @Override\r
1167                 protected void updatePaperBounds(Env ec, Bounds bc) {\r
1168                         paper.updateBounds(ec,bc);\r
1169                 }\r
1170                 \r
1171                 // 再描画?\r
1172                 @Override\r
1173                 protected void updatePaperRepaint() {\r
1174                         paper.updateRepaint();\r
1175                 }\r
1176         }\r
1177         \r
1178         /**\r
1179          * キーワード検索ウィンドウの内部クラス\r
1180          */\r
1181         private class VWKeywordDialog extends AbsKeywordDialog {\r
1182 \r
1183                 private static final long serialVersionUID = 1L;\r
1184 \r
1185                 @Override\r
1186                 void preview(SearchKey search) {\r
1187                         // 検索実行\r
1188                         if (search.alTarget.size() > 0) {\r
1189                                 mainWindow.setSelectedTab(MWinTab.LISTED);\r
1190                                 listed.redrawListByPreview(search);\r
1191                         }\r
1192                 }\r
1193         }\r
1194 \r
1195         /**\r
1196          * 延長警告管理ウィンドウの内部クラス\r
1197          */\r
1198         private class VWExtensionDialog extends AbsExtensionDialog {\r
1199 \r
1200                 private static final long serialVersionUID = 1L;\r
1201 \r
1202                 @Override\r
1203                 void preview(SearchKey search) {\r
1204                         // 検索実行\r
1205                         if (search.alTarget.size() > 0) {\r
1206                                 mainWindow.setSelectedTab(MWinTab.LISTED);\r
1207                                 listed.redrawListByPreview(search);\r
1208                         }\r
1209                 }\r
1210         }\r
1211         \r
1212         /***\r
1213          * \r
1214          * ツールバーの内部クラス\r
1215          * \r
1216          */\r
1217         private class VWToolBar extends AbsToolBar {\r
1218 \r
1219                 private static final long serialVersionUID = 1L;\r
1220 \r
1221                 @Override\r
1222                 protected Env getEnv() { return env; }\r
1223                 @Override\r
1224                 protected Bounds getBoundsEnv() { return bounds; }\r
1225                 @Override\r
1226                 protected TVProgramList getTVPrograms() { return tvprograms; }\r
1227                 @Override\r
1228                 protected ChannelSort getChannelSort() { return chsort; }\r
1229                 @Override\r
1230                 protected HDDRecorderList getHDDRecorders() { return recorders; }\r
1231 \r
1232                 @Override\r
1233                 protected StatusWindow getStWin() { return stwin; }\r
1234                 @Override\r
1235                 protected StatusTextArea getMWin() { return mwin; }\r
1236                 @Override\r
1237                 protected Component getParentComponent() { return Viewer.this; }\r
1238 \r
1239                 @Override\r
1240                 protected void ringBeep() { Viewer.this.ringBeep(); }\r
1241 \r
1242                 @Override\r
1243                 protected boolean doKeywordSerach(SearchKey search, String kStr, String sStr, boolean doFilter) {\r
1244                         \r
1245                         timer_now.pause();\r
1246                         \r
1247                         if ( mainWindow.getSelectedTab() == MWinTab.RSVED ) {\r
1248                                 reserved.redrawListByKeywordFilter(search, kStr);\r
1249                         }\r
1250                         else if ( mainWindow.getSelectedTab() == MWinTab.RECED ) {\r
1251                                 recorded.redrawListByKeywordFilter(search, kStr);\r
1252                         }\r
1253                         else {\r
1254                                 if ( search != null ) {\r
1255                                         mainWindow.setSelectedTab(MWinTab.LISTED);\r
1256                                         if ( doFilter ) {\r
1257                                                 // 絞り込み検索\r
1258                                                 listed.clearSelection();\r
1259                                                 listed.redrawListByKeywordFilter(search, kStr);\r
1260                                         }\r
1261                                         else if (sStr != null) {\r
1262                                                 // 過去ログ検索\r
1263                                                 searchPassedProgram(search, sStr);\r
1264                                                 listed.clearSelection();\r
1265                                                 listed.redrawListBySearched(ProgType.PASSED, 0);\r
1266                                                 \r
1267                                                 listed.redrawTreeByHistory();\r
1268                                         }\r
1269                                         else {\r
1270                                                 // キーワード検索\r
1271                                                 listed.clearSelection();\r
1272                                                 listed.redrawListByKeywordDyn(search, kStr);\r
1273                                         }\r
1274                                 }\r
1275                         }\r
1276                         \r
1277                         timer_now.start();\r
1278                         \r
1279                         return true;\r
1280                 }\r
1281 \r
1282                 @Override\r
1283                 protected boolean doBatchReserve() {\r
1284                         timer_now.pause();\r
1285                         listed.doBatchReserve();\r
1286                         timer_now.start();\r
1287                         return true;\r
1288                 }\r
1289 \r
1290                 @Override\r
1291                 protected boolean jumpToNow() {\r
1292                         timer_now.pause();\r
1293                         if ( ! mainWindow.isTabSelected(MWinTab.PAPER) ) {\r
1294                                 mainWindow.setSelectedTab(MWinTab.PAPER);\r
1295                         }\r
1296                         paper.jumpToNow();\r
1297                         timer_now.start();\r
1298                         return true;\r
1299                 }\r
1300 \r
1301                 @Override\r
1302                 protected boolean jumpToPassed(String passed) {\r
1303                         timer_now.pause();\r
1304                         boolean b = paper.jumpToPassed(passed);\r
1305                         timer_now.start();\r
1306                         return b;\r
1307                 }\r
1308 \r
1309                 @Override\r
1310                 protected boolean redrawByPager() {\r
1311                         timer_now.pause();\r
1312                         boolean b = paper.redrawByPager();\r
1313                         timer_now.start();\r
1314                         return b;\r
1315                 }\r
1316 \r
1317                 @Override\r
1318                 protected void toggleMatchBorder() {\r
1319                         timer_now.pause();\r
1320                         paper.toggleMatchBorder();\r
1321                         timer_now.start();\r
1322                 }\r
1323 \r
1324                 @Override\r
1325                 protected void setPaperColorDialogVisible(boolean b) {\r
1326                         //paper.stopTimer(); xxxx\r
1327                         timer_now.pause();\r
1328                         CommonSwingUtils.setLocationCenter(Viewer.this,pcwin);\r
1329                         pcwin.setVisible(true);\r
1330                         timer_now.start();\r
1331                 }\r
1332 \r
1333                 @Override\r
1334                 protected void setPaperZoom(int n) {\r
1335                         timer_now.pause();\r
1336                         paper.setZoom(n);\r
1337                         timer_now.start();\r
1338                 }\r
1339 \r
1340                 @Override\r
1341                 protected boolean recorderSelectorChanged() {\r
1342                         \r
1343                         timer_now.pause();\r
1344                         \r
1345                         if (mainWindow.isTabSelected(MWinTab.LISTED)) {\r
1346                                 listed.updateReserveMark();\r
1347                                 listed.selectBatchTarget();\r
1348                         }\r
1349                         else if (mainWindow.isTabSelected(MWinTab.RSVED)) {\r
1350                                 reserved.redrawReservedList();\r
1351                         }\r
1352                         else if (mainWindow.isTabSelected(MWinTab.RECED)) {\r
1353                                 recorded.redrawRecordedList();\r
1354                         }\r
1355                         \r
1356                         /*\r
1357                         // 新聞形式の予約枠を書き換えるかもよ?\r
1358                         if (env.getEffectComboToPaper()) {\r
1359                                 paper.updateReserveBorder(null);\r
1360                         }\r
1361                         */\r
1362                         \r
1363                         timer_now.start();\r
1364                         \r
1365                         return true;\r
1366                 }\r
1367 \r
1368                 @Override\r
1369                 protected void takeSnapShot() {\r
1370                         \r
1371                         timer_now.pause();\r
1372                         \r
1373                         Viewer.this.getSnapshot(getSelectedPagerIndex(),getPagerCount());\r
1374                         \r
1375                         timer_now.start();\r
1376                 }\r
1377 \r
1378                 @Override\r
1379                 protected void setStatusVisible(boolean b) {\r
1380                         Viewer.this.setStatusVisible(b);\r
1381                 }\r
1382 \r
1383                 @Override\r
1384                 protected void setFullScreen(boolean b) {\r
1385                         Viewer.this.setFullScreen(b);\r
1386                 }\r
1387 \r
1388                 @Override\r
1389                 protected void toggleSettingTabVisible() {\r
1390                         mainWindow.toggleShowSettingTabs();\r
1391                 }\r
1392 \r
1393                 @Override\r
1394                 protected boolean isTabSelected(MWinTab tab) {\r
1395                         return mainWindow.isTabSelected(tab);\r
1396                 }\r
1397 \r
1398                 @Override\r
1399                 protected boolean addKeywordSearch(SearchKey search) {\r
1400                         \r
1401                         timer_now.pause();\r
1402                         \r
1403                         AbsKeywordDialog kD = new VWKeywordDialog();\r
1404                         CommonSwingUtils.setLocationCenter(Viewer.this,kD);\r
1405                         \r
1406                         kD.open(search.getLabel(), srKeys, srGrps, search);\r
1407                         kD.setVisible(true);\r
1408                         \r
1409                         if (kD.isRegistered()) {\r
1410                                 // 検索結果の再構築\r
1411                                 mpList.clear(env.getDisableFazzySearch(), env.getDisableFazzySearchReverse());\r
1412                                 mpList.build(tvprograms, trKeys.getTraceKeys(), srKeys.getSearchKeys());\r
1413                                 \r
1414                                 // ツリーに反映する\r
1415                                 listed.redrawTreeByKeyword();\r
1416                                 \r
1417                                 mainWindow.setSelectedTab(MWinTab.LISTED);\r
1418                         }\r
1419                         \r
1420                         timer_now.start();\r
1421                         \r
1422                         return true;\r
1423                 }\r
1424 \r
1425                 @Override\r
1426                 protected boolean doLoadTVProgram(String selected) {\r
1427                         timer_now.pause();\r
1428                         \r
1429                         LoadFor lf = (selected != null) ? LoadFor.get(selected) : LoadFor.ALL;\r
1430                         boolean b = Viewer.this.doLoadTVProgram(true, lf);\r
1431                         \r
1432                         if ( b && lf == LoadFor.CSwSD ) {\r
1433                                 // ロード後シャットダウン\r
1434                                 CommonUtils.executeCommand(env.getShutdownCmd());\r
1435                         }\r
1436 \r
1437                         Viewer.this.doRedrawTVProgram();        // か き な お し\r
1438 \r
1439                         timer_now.start();\r
1440                         return b;\r
1441                 }\r
1442 \r
1443                 @Override\r
1444                 protected boolean doLoadRdRecorder(String selected) {\r
1445                         timer_now.pause();\r
1446                         \r
1447                         LoadRsvedFor lrf = (selected != null) ? LoadRsvedFor.get(selected) : null;\r
1448                         boolean b = Viewer.this.doLoadRdRecorder(lrf);\r
1449                         \r
1450                         timer_now.start();\r
1451                         return b;\r
1452                 }\r
1453         }\r
1454         \r
1455         /*******************************************************************************\r
1456          * ハンドラ―メソッド\r
1457          ******************************************************************************/\r
1458 \r
1459         /**\r
1460          * なんかよくわからないもの\r
1461          */\r
1462         @Override\r
1463         public void stateChanged(ChangeEvent e){\r
1464                 StdAppendMessage("イベント発生");\r
1465         }\r
1466 \r
1467         /**\r
1468          * ツールバーでレコーダの選択イベントが発生\r
1469          */\r
1470         @Override\r
1471         public void valueChanged(HDDRecorderSelectionEvent e) {\r
1472                 // 選択中のレコーダ情報を保存する\r
1473                 src_recsel = (HDDRecorderSelectable) e.getSource();\r
1474         }\r
1475         \r
1476         private String getSelectedMySelf() {\r
1477                 return ( src_recsel!=null ? src_recsel.getSelectedMySelf() : null );\r
1478         }\r
1479         \r
1480         private HDDRecorderList getSelectedRecorderList() {\r
1481                 return ( src_recsel!=null ? src_recsel.getSelectedList() : null );\r
1482         }\r
1483         \r
1484         private HDDRecorderSelectable src_recsel;\r
1485 \r
1486         /**\r
1487          * レコーダ情報の変更イベントが発生\r
1488          */\r
1489         @Override\r
1490         public void stateChanged(HDDRecorderChangeEvent e) {\r
1491                 // 未実装\r
1492         }\r
1493         \r
1494         /**\r
1495          * タイマーイベントが発生\r
1496          */\r
1497         @Override\r
1498         public void timerRised(TickTimerRiseEvent e) {\r
1499                 if (env.getDebug()) System.out.println("Timer Rised: now="+CommonUtils.getDateTimeYMDx(e.getCalendar()));\r
1500                 setTitleBar();\r
1501         }\r
1502         \r
1503         \r
1504         /*******************************************************************************\r
1505          * 共通メソッド群\r
1506          ******************************************************************************/\r
1507         \r
1508         /**\r
1509          * 類似予約をさがす\r
1510          */\r
1511         private LikeReserveList findLikeReserves(ProgDetailList tvd, String keyword, int threshold) {\r
1512                 \r
1513                 String keywordVal = null;\r
1514                 int thresholdVal = 0;\r
1515                 \r
1516                 // 曖昧検索のための初期化\r
1517                 if ( ! env.getDisableFazzySearch() ) {\r
1518                         if ( threshold > 0 ) {\r
1519                                 // キーワード指定がある場合\r
1520                                 keywordVal = TraceProgram.replacePop(keyword);\r
1521                                 thresholdVal = threshold;\r
1522                         }\r
1523                         else {\r
1524                                 // キーワード指定がない場合\r
1525                                 keywordVal = tvd.titlePop;\r
1526                                 thresholdVal = env.getDefaultFazzyThreshold();\r
1527                         }\r
1528                 }\r
1529 \r
1530                 // 検索実行\r
1531                 return recorders.findLikeReserves(tvd, keywordVal, thresholdVal, env.getRangeLikeRsv(), ! env.getDisableFazzySearchReverse());\r
1532         }\r
1533         \r
1534         /***\r
1535          * \r
1536          * リスト・新聞形式共通\r
1537          * \r
1538          */\r
1539 \r
1540         /**\r
1541          *  番組追跡への追加とgoogle検索\r
1542          */\r
1543         public void showPopupForTraceProgram(\r
1544                         final JComponent comp,\r
1545                         final ProgDetailList tvd, final String keyword, final int threshold,\r
1546                         final int x, final int y, final String clickedDateTime)\r
1547         {\r
1548                 JPopupMenu pop = new JPopupMenu();\r
1549                 \r
1550                 String myself = toolBar.getSelectedRecorder();\r
1551         \r
1552                 // 類似予約検索\r
1553                 LikeReserveList likeRsvList;\r
1554                 if ( env.getDisableFazzySearch() ) {\r
1555                         likeRsvList = recorders.findLikeReserves(tvd, null, 0, env.getRangeLikeRsv(), false);\r
1556                 }\r
1557                 else {\r
1558                         likeRsvList = recorders.findLikeReserves(tvd, tvd.titlePop, env.getDefaultFazzyThreshold(), env.getRangeLikeRsv(), ! env.getDisableFazzySearchReverse());\r
1559                 }\r
1560                 \r
1561                 // 重複予約検索\r
1562                 LikeReserveList overlapRsvList = recorders.findOverlapReserves(tvd, null, true, env.getOverlapUp());\r
1563                 \r
1564                 // 類似と重複で被るものを重複から除外\r
1565                 for ( LikeReserveItem item : likeRsvList ) {\r
1566                         overlapRsvList.removeDup(item);\r
1567                 }\r
1568                 \r
1569                 // 予約する\r
1570                 if ( tvd.type == ProgType.PASSED ||\r
1571                                 (tvd.type == ProgType.PROG && tvd.subtype == ProgSubtype.RADIO) ||\r
1572                                 recorders.size() == 0 ) {\r
1573                         // 過去ログは処理対象外です\r
1574                 }\r
1575                 else {\r
1576                         String target;\r
1577                         LikeReserveItem item = likeRsvList.getClosest(myself);\r
1578                         if ( env.getGivePriorityToReserved() && item != null && item.isCandidate(env.getOverlapUp()) ) {\r
1579                                 target = "予約を編集する";\r
1580                         }\r
1581                         else {\r
1582                                 target = "新規予約を登録する";\r
1583                         }\r
1584                         \r
1585                         JMenuItem menuItem = new JMenuItem(String.format("%s【%s %s - %s(%s)】",target,tvd.accurateDate,tvd.start,tvd.title,tvd.center));\r
1586                         {\r
1587                                 menuItem.setForeground(Color.BLUE);\r
1588                                 Font f = menuItem.getFont();\r
1589                                 menuItem.setFont(f.deriveFont(f.getStyle()|Font.BOLD));\r
1590                         }\r
1591                         \r
1592                         menuItem.addActionListener(new ActionListener() {\r
1593                                 public void actionPerformed(ActionEvent e) {\r
1594 \r
1595                                         CommonSwingUtils.setLocationCenter(mainWindow,rdialog);\r
1596 \r
1597                                         if ( rdialog.open(tvd) ) {\r
1598                                                 rdialog.setVisible(true);\r
1599                                         }\r
1600                                         else {\r
1601                                                 rdialog.setVisible(false);\r
1602                                         }\r
1603                                         \r
1604                                         //\r
1605                                         if (rdialog.isSucceededReserve()) {\r
1606                                                 listed.updateReserveMark();\r
1607                                                 paper.updateReserveBorder(tvd.center);\r
1608                                                 reserved.redrawReservedList();\r
1609                                         }\r
1610                                 }\r
1611                         });\r
1612                         pop.add(menuItem);\r
1613                 }\r
1614                 \r
1615                 // 隣接予約を編集する\r
1616                 {\r
1617                         for ( final LikeReserveItem item : overlapRsvList ) {\r
1618                                 \r
1619                                 if ( ! item.getRec().Myself().equals(toolBar.getSelectedRecorder()) ) {\r
1620                                         continue;       // 選択中のレコーダ以外はスルーで\r
1621                                 }\r
1622                                 \r
1623                                 {\r
1624                                         ReserveList rsv = item.getRsv();\r
1625                                         String start = CommonUtils.getDateTimeW(CommonUtils.getCalendar(rsv.getStartDateTime()));\r
1626                                         JMenuItem menuItem = new JMenuItem(String.format("隣接予約を上書する【%s - %s(%s)】",start,rsv.getTitle(),rsv.getCh_name()));\r
1627                                         \r
1628                                         menuItem.addActionListener(new ActionListener() {\r
1629                                                 public void actionPerformed(ActionEvent e) {\r
1630 \r
1631                                                         CommonSwingUtils.setLocationCenter(mainWindow,rdialog);\r
1632 \r
1633                                                         if ( rdialog.open(tvd,item) ) {\r
1634                                                                 rdialog.setVisible(true);\r
1635                                                         }\r
1636                                                         else {\r
1637                                                                 rdialog.setVisible(false);\r
1638                                                         }\r
1639                                                         \r
1640                                                         //\r
1641                                                         if (rdialog.isSucceededReserve()) {\r
1642                                                                 listed.updateReserveMark();\r
1643                                                                 paper.updateReserveBorder(tvd.center);\r
1644                                                                 reserved.redrawReservedList();\r
1645                                                         }\r
1646                                                 }\r
1647                                         });\r
1648                                         pop.add(menuItem);\r
1649                                 }\r
1650                         }\r
1651                 }\r
1652                 pop.addSeparator();\r
1653                 \r
1654                 // 予約実行ON・OFF\r
1655                 if ( tvd.type != ProgType.PASSED )\r
1656                 {\r
1657                         for ( int n=0; n<2; n++ ) {\r
1658                                 \r
1659                                 LikeReserveList rsvList = null;\r
1660                                 if ( n == 0 ) {\r
1661                                         rsvList = likeRsvList;\r
1662                                 }\r
1663                                 else {\r
1664                                         rsvList = overlapRsvList;\r
1665                                 }\r
1666                                 \r
1667                                 for ( LikeReserveItem rsvItem : rsvList ) {\r
1668                                         \r
1669                                         final boolean fexec = rsvItem.getRsv().getExec();\r
1670                                         final String start = rsvItem.getRsv().getAhh()+":"+rsvItem.getRsv().getAmm();\r
1671                                         final String title = rsvItem.getRsv().getTitle();\r
1672                                         final String chnam = rsvItem.getRsv().getCh_name();\r
1673                                         final String rsvId = rsvItem.getRsv().getId();\r
1674                                         final String recId = rsvItem.getRec().Myself();\r
1675                                         \r
1676                                         pop.add(getExecOnOffMenuItem(fexec,start,title,chnam,rsvId,recId,n));\r
1677                                 }\r
1678                                 \r
1679                                 pop.addSeparator();\r
1680                         }\r
1681                 }\r
1682                 \r
1683                 pop.addSeparator();\r
1684                 \r
1685                 // 削除する\r
1686                 if ( tvd.type != ProgType.PASSED )      // 過去ログは処理対象外です\r
1687                 {\r
1688                         for ( int n=0; n<2; n++ ) {\r
1689                                 \r
1690                                 LikeReserveList rsvList = null;\r
1691                                 if ( n == 0 ) {\r
1692                                         rsvList = likeRsvList;\r
1693                                 }\r
1694                                 else {\r
1695                                         rsvList = overlapRsvList;\r
1696                                 }\r
1697                                 \r
1698                                 for ( LikeReserveItem rsvItem : rsvList ) {\r
1699                                         \r
1700                                         final String start = rsvItem.getRsv().getAhh()+":"+rsvItem.getRsv().getAmm();\r
1701                                         final String title = rsvItem.getRsv().getTitle();\r
1702                                         final String chnam = rsvItem.getRsv().getCh_name();\r
1703                                         final String rsvId = rsvItem.getRsv().getId();\r
1704                                         final String recId = rsvItem.getRec().Myself();\r
1705                                         \r
1706                                         pop.add(getRemoveRsvMenuItem(start, title,chnam,rsvId,recId,n));\r
1707                                 }\r
1708                                 \r
1709                                 pop.addSeparator();\r
1710                         }\r
1711                 }\r
1712                 else {\r
1713                         pop.addSeparator();\r
1714                         pop.addSeparator();\r
1715                 }\r
1716                 \r
1717                 // ジャンプする\r
1718                 {\r
1719                         if ( mainWindow.isTabSelected(MWinTab.LISTED) ) {\r
1720                                 pop.add(getJumpMenuItem(tvd.title,tvd.center,tvd.accurateDate+" "+tvd.start));\r
1721                         }\r
1722                         if ( mainWindow.isTabSelected(MWinTab.LISTED) || mainWindow.isTabSelected(MWinTab.PAPER) ) {\r
1723                                 JMenuItem mi = getJumpToLastWeekMenuItem(tvd.title,tvd.center,tvd.startDateTime);\r
1724                                 if ( mi != null ) {\r
1725                                         pop.add(mi);\r
1726                                 }\r
1727                         }\r
1728                 }\r
1729                 \r
1730                 pop.addSeparator();\r
1731                 \r
1732                 // 番組追跡へ追加する\r
1733                 {\r
1734                         final String label = TraceProgram.getNewLabel(tvd.title, tvd.center);\r
1735                         JMenuItem menuItem = new JMenuItem("番組追跡への追加【"+label+"】");\r
1736                         menuItem.addActionListener(new ActionListener() {\r
1737                                 public void actionPerformed(ActionEvent e) {\r
1738                                         //\r
1739                                         VWTraceKeyDialog tD = new VWTraceKeyDialog(0,0);\r
1740                                         CommonSwingUtils.setLocationCenter(mainWindow,tD);\r
1741                                         \r
1742                                         tD.open(trKeys, tvd, env.getDefaultFazzyThreshold());\r
1743                                         tD.setVisible(true);\r
1744                                         \r
1745                                         if (tD.isRegistered()) {\r
1746                                                 //\r
1747                                                 trKeys.save();\r
1748                                                 \r
1749                                                 // 検索結果の再構築\r
1750                                                 mpList.clear(env.getDisableFazzySearch(), env.getDisableFazzySearchReverse());\r
1751                                                 mpList.build(tvprograms, trKeys.getTraceKeys(), srKeys.getSearchKeys());\r
1752                                                 \r
1753                                                 // ツリーに反映する\r
1754                                                 listed.redrawTreeByTrace();\r
1755 \r
1756                                                 // 表示を更新する\r
1757                                                 paper.updateBangumiColumns();\r
1758                                                 listed.reselectTree();\r
1759                                                 \r
1760                                                 mwin.appendMessage("番組追跡へ追加しました【"+label+"】");\r
1761                                         }\r
1762                                         else {\r
1763                                                 trKeys.remove(label);\r
1764                                         }\r
1765                                 }\r
1766                         });\r
1767                         pop.add(menuItem);\r
1768                 }\r
1769                 \r
1770                 // キーワード検索へ追加する\r
1771                 {\r
1772                         final String label = tvd.title+" ("+tvd.center+")";\r
1773                         JMenuItem menuItem = new JMenuItem("キーワード検索への追加【"+label+"】");\r
1774                         menuItem.addActionListener(new ActionListener(){\r
1775                                 public void actionPerformed(ActionEvent e){\r
1776                                         \r
1777                                         // 「キーワード検索の設定」ウィンドウを開く\r
1778                                         \r
1779                                         AbsKeywordDialog kD = new VWKeywordDialog();\r
1780                                         CommonSwingUtils.setLocationCenter(mainWindow,kD);\r
1781                                         \r
1782                                         kD.open(srKeys, srGrps, tvd);\r
1783                                         kD.setVisible(true);\r
1784                                         \r
1785                                         if (kD.isRegistered()) {\r
1786                                                 // 検索結果の再構築\r
1787                                                 mpList.clear(env.getDisableFazzySearch(), env.getDisableFazzySearchReverse());\r
1788                                                 mpList.build(tvprograms, trKeys.getTraceKeys(), srKeys.getSearchKeys());\r
1789                                                 \r
1790                                                 // ツリーに反映する\r
1791                                                 listed.redrawTreeByKeyword();\r
1792 \r
1793                                                 // 表示を更新する\r
1794                                                 paper.updateBangumiColumns();\r
1795                                                 listed.reselectTree();\r
1796                                                 \r
1797                                                 mwin.appendMessage("キーワード検索へ追加しました【"+label+"】");\r
1798                                         }\r
1799                                 }\r
1800                         });\r
1801                         pop.add(menuItem);\r
1802                 }\r
1803                 \r
1804                 // ピックアップへ追加する\r
1805                 {\r
1806                         boolean isRemoveItem = false;\r
1807                         if ( mainWindow.isTabSelected(MWinTab.LISTED) && tvd.type == ProgType.PICKED ) {\r
1808                                 isRemoveItem = true;\r
1809                         }\r
1810                         else {\r
1811                                 PickedProgram tvp = tvprograms.getPickup();\r
1812                                 if ( tvp != null ) {\r
1813                                         isRemoveItem = tvp.remove(tvd, tvd.center, tvd.accurateDate, false);\r
1814                                 }\r
1815                         }\r
1816                         \r
1817                         if ( ! isRemoveItem )   // 過去ログは処理対象外です\r
1818                         {\r
1819                                 final String label = String.format("%s(%s)",tvd.title,tvd.center);\r
1820                                 JMenuItem menuItem = new JMenuItem(String.format("ピックアップへの追加【%s %s - %s】",tvd.accurateDate,tvd.start,label));\r
1821                                 menuItem.addActionListener(new ActionListener() {\r
1822                                         public void actionPerformed(ActionEvent e) {\r
1823                                                 //\r
1824                                                 PickedProgram tvp = tvprograms.getPickup();\r
1825                                                 if ( tvp != null ) {\r
1826                                                         tvp.refresh();\r
1827                                                         tvp.add(tvd);\r
1828                                                         tvp.save();\r
1829                                                         /*\r
1830                                                         if ( listed.isNodeSelected(ListedTreeNode.PICKUP) ) {\r
1831                                                                 // ピックアップノードが選択されていたらリストを更新する\r
1832                                                                 listed.reselectTree();\r
1833                                                         }\r
1834                                                         */\r
1835                                                         listed.updateReserveMark();\r
1836                                                         listed.refocus();\r
1837                                                         paper.updateReserveBorder(tvd.center);\r
1838                                                         mwin.appendMessage("【ピックアップ】追加しました: "+tvd.title+" ("+tvd.center+")");\r
1839                                                         return;\r
1840                                                 }\r
1841                                         }\r
1842                                 });\r
1843                                 pop.add(menuItem);\r
1844                         }\r
1845                         else {\r
1846                                 final String label = tvd.title+" ("+tvd.center+")";\r
1847                                 JMenuItem menuItem = new JMenuItem("ピックアップからの削除【"+label+"】");\r
1848                                 menuItem.setForeground(Color.RED);\r
1849                                 menuItem.addActionListener(new ActionListener() {\r
1850                                         public void actionPerformed(ActionEvent e) {\r
1851                                                 //\r
1852                                                 PickedProgram tvp = tvprograms.getPickup();\r
1853                                                 if ( tvp != null ) {\r
1854                                                         tvp.refresh();\r
1855                                                         tvp.remove(tvd, tvd.center, tvd.accurateDate, true);\r
1856                                                         tvp.save();\r
1857                                                         /*\r
1858                                                         if ( listed.isNodeSelected(ListedTreeNode.PICKUP) || listed.isNodeSelected(ListedTreeNode.STANDBY) ) {\r
1859                                                                 // ピックアップノードが選択されていたらリストを更新する\r
1860                                                                 listed.reselectTree();\r
1861                                                         }\r
1862                                                         */\r
1863                                                         listed.updateReserveMark();\r
1864                                                         paper.updateReserveBorder(tvd.center);\r
1865                                                         mwin.appendMessage("【ピックアップ】削除しました: "+tvd.title+" ("+tvd.center+")");\r
1866                                                         return;\r
1867                                                 }\r
1868                                         }\r
1869                                 });\r
1870                                 pop.add(menuItem);\r
1871                         }\r
1872                 }\r
1873 \r
1874                 pop.addSeparator();\r
1875                 \r
1876                 // googleで検索する\r
1877                 {\r
1878                         for (final TextValueSet tv : env.getTvCommand()) {\r
1879                                 JMenuItem menuItem = new JMenuItem(tv.getText());\r
1880                                 String escepedTitle = "";\r
1881                                 String escepedChName = "";\r
1882                                 String escepedDetail = "";\r
1883                                 try {\r
1884                                         escepedTitle = URLEncoder.encode(tvd.title,"UTF-8");\r
1885                                         escepedDetail = URLEncoder.encode(tvd.detail,"UTF-8");\r
1886                                         escepedChName = URLEncoder.encode(tvd.center,"UTF-8");\r
1887                                 } catch (UnsupportedEncodingException e2) {\r
1888                                         //\r
1889                                 }\r
1890                                 \r
1891                                 String cmd = tv.getValue();\r
1892                                 if ( cmd.matches(".*%DETAILURL%.*") ) {\r
1893                                         if ( tvd.link == null || tvd.link.length() == 0 ) {\r
1894                                                 // このメニューは利用できません!\r
1895                                                 menuItem.setEnabled(false);\r
1896                                                 menuItem.setForeground(Color.lightGray);\r
1897                                         }\r
1898                                 }\r
1899                                 cmd = cmd.replaceAll("%ENCTITLE%", escepedTitle);\r
1900                                 cmd = cmd.replaceAll("%ENCDETAIL%", escepedDetail);\r
1901                                 cmd = cmd.replaceAll("%ENCCHNAME%", escepedChName);\r
1902                                 cmd = cmd.replaceAll("%TITLE%", tvd.title);\r
1903                                 cmd = cmd.replaceAll("%DETAIL%", tvd.detail);\r
1904                                 cmd = cmd.replaceAll("%CHNAME%", tvd.center);\r
1905                                 cmd = cmd.replaceAll("%DATE%", tvd.accurateDate);\r
1906                                 cmd = cmd.replaceAll("%START%", tvd.start);\r
1907                                 cmd = cmd.replaceAll("%END%", tvd.end);\r
1908                                 cmd = cmd.replaceAll("%DETAILURL%", tvd.link); \r
1909                                 \r
1910                                 // CHAN-TORU対応\r
1911                                 if ( cmd.matches(".*%TVKAREACODE%.*") && cmd.matches(".*%TVKPID%.*") ) {\r
1912                                         Center cr = null;\r
1913                                         for ( TVProgram tvp : progPlugins ) {\r
1914                                                 if ( tvp.getTVProgramId().startsWith("Gガイド.テレビ王国") ) {\r
1915                                                         for ( Center tempcr : tvp.getCRlist() ) {\r
1916                                                                 // CH設定が完了している必要がある\r
1917                                                                 if ( tvp.getSubtype() == ProgSubtype.TERRA && tvp.getSelectedCode().equals(TVProgram.allCode) && ! tempcr.getAreaCode().equals(TVProgram.bsCode) ) {\r
1918                                                                         // 地域が全国の地デジの場合のみ、有効局かどうかを確認する必要がある\r
1919                                                                         if ( tempcr.getCenter().equals(tvd.center) && tempcr.getOrder() > 0 ) {\r
1920                                                                                 // このメニューは利用できます!\r
1921                                                                                 cr = tempcr;\r
1922                                                                                 break;\r
1923                                                                         }\r
1924                                                                 }\r
1925                                                                 else {\r
1926                                                                         if ( tempcr.getCenter().equals(tvd.center) ) {\r
1927                                                                                 // このメニューは利用できます!\r
1928                                                                                 cr = tempcr;\r
1929                                                                                 break;\r
1930                                                                         }\r
1931                                                                 }\r
1932                                                         }\r
1933                                                         \r
1934                                                         if ( cr != null ) {\r
1935                                                                 break;\r
1936                                                         }\r
1937                                                 }\r
1938                                         }\r
1939                                         if ( cr != null ) {\r
1940                                                 String areacode = null;\r
1941                                                 String centercode = cr.getLink();\r
1942                                                 String cat = cr.getLink().substring(0,1);\r
1943                                                 if ( cat.equals("1") ) {\r
1944                                                         areacode = cr.getAreaCode();\r
1945                                                 }\r
1946                                                 else {\r
1947                                                         if ( cat.equals("4") ) {\r
1948                                                                 cat = "5";\r
1949                                                         }\r
1950                                                         else if ( cat.equals("5") ) {\r
1951                                                                 cat = "4";\r
1952                                                         }\r
1953                                                         areacode = "10";\r
1954                                                 }\r
1955                                                 \r
1956                                                 cmd = cmd.replaceAll("%TVKAREACODE%", areacode);\r
1957                                                 cmd = cmd.replaceAll("%TVKCAT%", cat);\r
1958                                                 cmd = cmd.replaceAll("%TVKPID%", centercode+CommonUtils.getDateTimeYMD(CommonUtils.getCalendar(tvd.startDateTime)).replaceFirst("..$", ""));\r
1959                                                 System.out.println("[DEBUG] "+cmd);\r
1960                                                 \r
1961                                                 menuItem.setEnabled(true);\r
1962                                                 menuItem.setForeground(Color.BLACK);\r
1963                                         }\r
1964                                         else {\r
1965                                                 menuItem.setEnabled(false);\r
1966                                                 menuItem.setForeground(Color.lightGray);\r
1967                                         }\r
1968                                 }\r
1969                                 \r
1970                                 final String run = cmd;\r
1971                                 \r
1972                                 menuItem.addActionListener(new ActionListener() {\r
1973                                         @Override\r
1974                                         public void actionPerformed(ActionEvent e) {\r
1975                                                 try {\r
1976                                                         if (run.indexOf("http") == 0) {\r
1977                                                                 Desktop desktop = Desktop.getDesktop();\r
1978                                                                 desktop.browse(new URI(run));\r
1979                                                         }\r
1980                                                         else {\r
1981                                                                 CommonUtils.executeCommand(run);\r
1982                                                         }\r
1983                                                 } catch (IOException e1) {\r
1984                                                         e1.printStackTrace();\r
1985                                                 } catch (URISyntaxException e1) {\r
1986                                                         e1.printStackTrace();\r
1987                                                 }\r
1988                                         }\r
1989                                 });\r
1990 \r
1991                                 pop.add(menuItem);\r
1992                         }\r
1993                 }\r
1994                 \r
1995                 pop.addSeparator();\r
1996                 \r
1997                 // クリップボードへコピーする\r
1998                 {\r
1999                         JMenuItem menuItem = new JMenuItem("番組名をコピー【"+tvd.title+"】");\r
2000                         menuItem.addActionListener(new ActionListener() {\r
2001                                 public void actionPerformed(ActionEvent e) {\r
2002                                         String msg = tvd.title;\r
2003                                         Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();\r
2004                                         StringSelection s = new StringSelection(msg);\r
2005                                         cb.setContents(s, null);\r
2006                                 }\r
2007                         });\r
2008                         pop.add(menuItem);\r
2009                 }\r
2010                 {\r
2011                         JMenuItem menuItem = new JMenuItem("番組名と詳細をコピー【"+tvd.title+"】");\r
2012                         menuItem.addActionListener(new ActionListener() {\r
2013                                 public void actionPerformed(ActionEvent e) {\r
2014                                         String msg = tvd.title+System.getProperty("line.separator")+tvd.detail+"\0"+tvd.getAddedDetail();\r
2015                                         Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();\r
2016                                         StringSelection s = new StringSelection(msg);\r
2017                                         cb.setContents(s, null);\r
2018                                 }\r
2019                         });\r
2020                         pop.add(menuItem);\r
2021                 }\r
2022                 {\r
2023                         JMenuItem menuItem = new JMenuItem("番組情報をコピー【"+tvd.title+"】");\r
2024                         menuItem.addActionListener(new ActionListener() {\r
2025                                 public void actionPerformed(ActionEvent e) {\r
2026                                         String msg = "";\r
2027                                         int preId = 0;\r
2028                                         for (ClipboardInfo cb : cbitems) {\r
2029                                                 if (cb.getB()) {\r
2030                                                         switch (cb.getId()) {\r
2031                                                         case 1:\r
2032                                                                 msg += tvd.title+"\t";\r
2033                                                                 break;\r
2034                                                         case 2:\r
2035                                                                 msg += tvd.center+"\t";\r
2036                                                                 break;\r
2037                                                         case 3:\r
2038                                                                 msg += tvd.accurateDate+"\t";\r
2039                                                                 break;\r
2040                                                         case 4:\r
2041                                                                 msg += tvd.start+"\t";\r
2042                                                                 break;\r
2043                                                         case 5:\r
2044                                                                 if (preId == 4) {\r
2045                                                                         msg = msg.substring(0,msg.length()-1)+"-";\r
2046                                                                 }\r
2047                                                                 msg += tvd.end+"\t";\r
2048                                                                 break;\r
2049                                                         case 6:\r
2050                                                                 msg += tvd.genre+"\t";\r
2051                                                                 break;\r
2052                                                         case 7:\r
2053                                                                 msg += tvd.detail+"\0"+tvd.getAddedDetail()+"\t";\r
2054                                                                 break;\r
2055                                                         }\r
2056                                                 }\r
2057                                                 preId = cb.getId();\r
2058                                         }\r
2059                                         if (msg.length() > 0) {\r
2060                                                 msg = msg.substring(0,msg.length()-1);\r
2061                                         }\r
2062                                         Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();\r
2063                                         StringSelection s = new StringSelection(msg);\r
2064                                         cb.setContents(s, null);\r
2065                                 }\r
2066                         });\r
2067                         pop.add(menuItem);\r
2068                 }\r
2069 \r
2070                 pop.addSeparator();\r
2071                 \r
2072                 // 延長感染源へ追加する\r
2073                 if (\r
2074                                 tvd.type == ProgType.SYOBO ||\r
2075                                 tvd.type == ProgType.PASSED ||\r
2076                                 tvd.type == ProgType.PICKED ||\r
2077                                 (tvd.type == ProgType.PROG && tvd.subtype != ProgSubtype.RADIO) )       // ラジオは処理対象外です\r
2078                 {\r
2079                         JMenuItem menuItem = new JMenuItem("延長感染源にしない【"+tvd.title+" ("+tvd.center+")】");\r
2080                         menuItem.addActionListener(new ActionListener() {\r
2081                                 public void actionPerformed(ActionEvent e) {\r
2082                                         //\r
2083                                         mwin.appendMessage("延長感染源を隔離します【"+tvd.title+"("+tvd.center+")】");\r
2084                                         //\r
2085                                         AbsExtensionDialog eD = new VWExtensionDialog();\r
2086                                         CommonSwingUtils.setLocationCenter(mainWindow,eD);\r
2087                                         \r
2088                                         eD.open(tvd.title,tvd.center,false,extKeys);\r
2089                                         eD.setVisible(true);\r
2090                                         \r
2091                                         if (eD.isRegistered()) {\r
2092                                                 // 番組表の状態を更新する\r
2093                                                 for (TVProgram tvp : tvprograms) {\r
2094                                                         if (tvp.getType() == ProgType.PROG) {\r
2095                                                                 tvp.setExtension(null, null, false, extKeys.getSearchKeys());\r
2096                                                         }\r
2097                                                 }\r
2098                                                 \r
2099                                                 // ツリーに反映する\r
2100                                                 listed.redrawTreeByExtension();\r
2101                                                 \r
2102                                                 mainWindow.setSelectedTab(MWinTab.LISTED);\r
2103                                         }\r
2104                                 }\r
2105                         });\r
2106                         pop.add(menuItem);\r
2107                 }\r
2108                 if ( tvd.type == ProgType.PASSED || (tvd.type == ProgType.PROG && tvd.subtype != ProgSubtype.RADIO) )   // ラジオは処理対象外です\r
2109                 {\r
2110                         JMenuItem menuItem = new JMenuItem("延長感染源にする【"+tvd.title+" ("+tvd.center+")】");\r
2111                         menuItem.addActionListener(new ActionListener() {\r
2112                                 public void actionPerformed(ActionEvent e) {\r
2113                                         //\r
2114                                         AbsExtensionDialog eD = new VWExtensionDialog();\r
2115                                         CommonSwingUtils.setLocationCenter(mainWindow,eD);\r
2116                                         \r
2117                                         eD.open(tvd.title,tvd.center,true,extKeys);\r
2118                                         eD.setVisible(true);\r
2119                                         \r
2120                                         if (eD.isRegistered()) {\r
2121                                                 // 番組表の状態を更新する\r
2122                                                 for (TVProgram tvp : tvprograms) {\r
2123                                                         if (tvp.getType() == ProgType.PROG) {\r
2124                                                                 tvp.setExtension(null, null, false, extKeys.getSearchKeys());\r
2125                                                         }\r
2126                                                 }\r
2127                                                 \r
2128                                                 // ツリーに反映する\r
2129                                                 listed.redrawTreeByExtension();\r
2130                                                 \r
2131                                                 mainWindow.setSelectedTab(MWinTab.LISTED);\r
2132                                         }\r
2133                                 }\r
2134                         });\r
2135                         pop.add(menuItem);\r
2136                 }\r
2137                 \r
2138                 pop.addSeparator();\r
2139                 \r
2140                 // 視聴する\r
2141                 if ( tvd.type == ProgType.PROG && tvd.subtype != ProgSubtype.RADIO)     // ラジオは処理対象外です\r
2142                 {\r
2143                         for (HDDRecorder recorder : recorders ) {\r
2144                                 \r
2145                                 if (recorder.ChangeChannel(null) == false) {\r
2146                                         continue;\r
2147                                 }\r
2148                                 \r
2149                                 final String recorderName = recorder.Myself();\r
2150                                 JMenuItem menuItem = new JMenuItem("【"+recorderName+"】で【"+tvd.center+"】を視聴する");\r
2151                                 \r
2152                                 menuItem.addActionListener(new ActionListener() {\r
2153                                         public void actionPerformed(ActionEvent e) {\r
2154                                                 for (HDDRecorder recorder : recorders ) {\r
2155                                                         if (recorder.isMyself(recorderName)) {\r
2156                                                                 if (recorder.ChangeChannel(tvd.center) == false) {\r
2157                                                                         ringBeep();\r
2158                                                                         mwin.appendError("【警告】チャンネルを変更できませんでした:"+recorder.getErrmsg());\r
2159                                                                 }\r
2160                                                                 else if (recorder.getErrmsg() !=null && recorder.getErrmsg().length() > 0) {\r
2161                                                                         mwin.appendError("[追加情報] "+recorder.getErrmsg());\r
2162                                                                 }\r
2163                                                         }\r
2164                                                 }\r
2165                                         }\r
2166                                 });\r
2167                                 \r
2168                                 menuItem.setEnabled(recorder.getUseChChange());\r
2169                                 \r
2170                                 pop.add(menuItem);\r
2171                         }\r
2172                 }\r
2173                 \r
2174                 pop.show(comp, x, y);\r
2175         }\r
2176         \r
2177         // ピックアップへ追加する\r
2178         public boolean addToPickup(final ProgDetailList tvd) {\r
2179                 \r
2180                 if (tvd.start.equals("")) {\r
2181                         // 番組情報がありません\r
2182                         return false;\r
2183                 }\r
2184                 \r
2185                 PickedProgram tvp = tvprograms.getPickup();\r
2186                 if ( tvp == null ) {\r
2187                         // ピックアップ先がありません\r
2188                         return true;\r
2189                 }\r
2190                 \r
2191                 // 削除かな?\r
2192                 if ( tvp.remove(tvd, tvd.center, tvd.accurateDate, true) ) {\r
2193                         tvp.save();\r
2194                         if ( listed.isNodeSelected(JTreeLabel.Nodes.PICKUP) || listed.isNodeSelected(JTreeLabel.Nodes.STANDBY) ) {\r
2195                                 // ピックアップノードor予約待機ノードが選択されていたらリストを更新する\r
2196                                 listed.reselectTree();\r
2197                                 //listed.updateReserveMark();\r
2198                         }\r
2199                         else {\r
2200                                 // 予約マークだけ変えておけばいいよね\r
2201                                 listed.updateReserveMark();\r
2202                                 listed.refocus();\r
2203                         }\r
2204                         paper.updateReserveBorder(tvd.center);\r
2205                         mwin.appendMessage("【ピックアップ】削除しました: "+tvd.title+" ("+tvd.center+")");\r
2206                         return false;\r
2207                 }\r
2208                 \r
2209                 // 追加です\r
2210                 if ( tvd.endDateTime.compareTo(CommonUtils.getDateTime(0)) > 0 ) {\r
2211                         tvp.refresh();\r
2212                         tvp.add(tvd);\r
2213                         tvp.save();\r
2214                         if ( listed.isNodeSelected(JTreeLabel.Nodes.PICKUP) ) {\r
2215                                 // ピックアップノードが選択されていたらリストを更新する\r
2216                                 listed.reselectTree();\r
2217                                 //listed.updateReserveMark();\r
2218                         }\r
2219                         else {\r
2220                                 listed.updateReserveMark();\r
2221                                 listed.refocus();\r
2222                         }\r
2223                         paper.updateReserveBorder(tvd.center);\r
2224                         mwin.appendMessage("【ピックアップ】追加しました: "+tvd.title+" ("+tvd.center+")");\r
2225                         return true;\r
2226                 }\r
2227 \r
2228                 // 過去ログは登録できないよ\r
2229                 mwin.appendMessage("【ピックアップ】過去情報はピックアップできません.");\r
2230                 return false;\r
2231         }\r
2232         \r
2233         /**\r
2234          *  予約を削除するメニューアイテム\r
2235          */\r
2236         private JMenuItem getRemoveRsvMenuItem(final String start, final String title, final String chnam, final String rsvId, final String recId, int n) {\r
2237                 //\r
2238                 JMenuItem menuItem = new JMenuItem();\r
2239                 \r
2240                 String mode = "削除";\r
2241                 menuItem.setForeground(Color.RED);\r
2242                 \r
2243                 String target = ( n==0 ) ? "予約" : "隣接予約";\r
2244 \r
2245                 menuItem.setText(String.format("%sを%sする【%s - %s(%s)/%s】",target,mode,start,title,chnam,recId));\r
2246                 \r
2247                 if ( recId.equals(toolBar.getSelectedRecorder()) ) {\r
2248                         // 選択中のレコーダのものは太字に\r
2249                         Font f = menuItem.getFont();\r
2250                         menuItem.setFont(f.deriveFont(f.getStyle()|Font.BOLD));\r
2251                 }\r
2252                 \r
2253                 menuItem.addActionListener(new ActionListener() {\r
2254                         public void actionPerformed(ActionEvent e) {\r
2255                                 \r
2256                                 if (env.getShowWarnDialog()) {\r
2257                                         Container cp = getContentPane();\r
2258                                         int ret = JOptionPane.showConfirmDialog(cp, "削除しますか?【"+title+"("+chnam+")】("+recId+")", "確認", JOptionPane.YES_NO_OPTION);\r
2259                                         if (ret != JOptionPane.YES_OPTION) {\r
2260                                                 return;\r
2261                                         }\r
2262                                 }\r
2263                                 \r
2264                                 stwin.clear();\r
2265                                 \r
2266                                 // 削除本体\r
2267                                 new SwingBackgroundWorker(false) {\r
2268                                         \r
2269                                         @Override\r
2270                                         protected Object doWorks() throws Exception {\r
2271                                                 \r
2272                                                 for (HDDRecorder recorder : recorders) {\r
2273                                                         if (recorder.isMyself(recId)) { // IPAddr:PortNo:RecorderIdで比較\r
2274                                                                 \r
2275                                                                 String title = "";\r
2276                                                                 for (ReserveList r : recorder.getReserves()) {\r
2277                                                                         if (r.getId().equals(rsvId)) {\r
2278                                                                                 title = r.getTitle();\r
2279                                                                                 break;\r
2280                                                                         }\r
2281                                                                 }\r
2282                                                                 \r
2283                                                                 stwin.appendMessage("予約を削除します:"+title+"("+rsvId+")");\r
2284                                                                 //recorder.setProgressArea(stwin);\r
2285                                                                 ReserveList r = recorder.RemoveRdEntry(rsvId);  // Noで検索\r
2286                                                                 if (r != null) {\r
2287                                                                         mwin.appendMessage("正常に削除できました:"+r.getTitle()+"("+r.getCh_name()+")");\r
2288                                                                         \r
2289                                                                         if ( ! r.getTitle().equals(title) || ! r.getId().equals(rsvId)) {\r
2290                                                                                 mwin.appendError("【警告】削除結果が一致しません!:"+title+"/"+r.getTitle());\r
2291                                                                         }\r
2292                                                                         \r
2293                                                                         if ( recorder.getUseCalendar()) {\r
2294                                                                                 // カレンダーから削除する\r
2295                                                                                 for ( HDDRecorder calendar : recorders ) {\r
2296                                                                                         if (calendar.getType() == RecType.CALENDAR) {\r
2297                                                                                                 stwin.appendMessage("カレンダーから予約情報を削除します");\r
2298                                                                                                 //calendar.setProgressArea(stwin);\r
2299                                                                                                 if ( ! calendar.UpdateRdEntry(r, null)) {\r
2300                                                                                                         mwin.appendError("【カレンダー】"+calendar.getErrmsg());\r
2301                                                                                                         ringBeep();\r
2302                                                                                                 }\r
2303                                                                                         }\r
2304                                                                                 }\r
2305                                                                         }\r
2306                                                                         \r
2307                                                                         r = null;\r
2308                                                                 }\r
2309                                                                 else {\r
2310                                                                         mwin.appendError("削除に失敗しました:"+title);\r
2311                                                                 }\r
2312                                                                 \r
2313                                                                 //\r
2314                                                                 if ( ! recorder.getErrmsg().equals("")) {\r
2315                                                                         mwin.appendError("【追加情報】"+recorder.getErrmsg());\r
2316                                                                         ringBeep();\r
2317                                                                 }\r
2318                                                                 break;\r
2319                                                         }\r
2320                                                 }\r
2321                                                 return null;\r
2322                                         }\r
2323                                         \r
2324                                         @Override\r
2325                                         protected void doFinally() {\r
2326                                                 StWinSetVisible(false);\r
2327                                         }\r
2328                                 }.execute();\r
2329                                 \r
2330                                 CommonSwingUtils.setLocationCenter(Viewer.this, stwin);\r
2331                                 StWinSetVisible(true);\r
2332                                 \r
2333                                 // 予約状況を更新\r
2334                                 listed.updateReserveMark();\r
2335                                 paper.updateReserveBorder(chnam);\r
2336                                 reserved.redrawReservedList();\r
2337                         }\r
2338                 });\r
2339                 \r
2340                 return menuItem;\r
2341         }\r
2342         \r
2343         \r
2344         \r
2345         \r
2346         /*\r
2347          * 他のクラスに分離できなかったというか、しなかったというか、そんなメソッド群\r
2348          */\r
2349         \r
2350         /**\r
2351          * \r
2352          */\r
2353         private boolean doExecOnOff(final boolean fexec, final String title, final String chnam, final String rsvId, final String recId) {\r
2354                 \r
2355                 CommonSwingUtils.setLocationCenter(mainWindow,rdialog);\r
2356                 \r
2357                 String mode = (fexec ? "ON" : "OFF");\r
2358                 \r
2359                 // 予約ON・OFFのみ\r
2360                 if ( rdialog.open(recId,rsvId,fexec) ) {\r
2361                         \r
2362                         rdialog.doUpdate();\r
2363                         \r
2364                         if (rdialog.isSucceededReserve()) {\r
2365                                 // 予約状況を更新\r
2366                                 listed.updateReserveMark();\r
2367                                 paper.updateReserveBorder(chnam);\r
2368                                 reserved.redrawReservedList();\r
2369                                 \r
2370                                 {\r
2371                                         String msg = "予約を"+mode+"にしました【"+title+"("+chnam+")/"+recId+"】";\r
2372                                         //StdAppendMessage(msg);\r
2373                                         mwin.appendMessage(msg);\r
2374                                 }\r
2375                                 \r
2376                                 return true;\r
2377                         }\r
2378                 }\r
2379                 \r
2380                 return false;\r
2381         }\r
2382         \r
2383         /**\r
2384          *  予約実行をONOFFするメニューアイテム\r
2385          */\r
2386         private JMenuItem getExecOnOffMenuItem(final boolean fexec, final String start, final String title, final String chnam, final String rsvId, final String recId, int n) {\r
2387                 \r
2388                 JMenuItem menuItem = new JMenuItem();\r
2389                 \r
2390                 String mode;\r
2391                 if ( ! fexec ) {\r
2392                         mode = "ON";\r
2393                         menuItem.setForeground(Color.BLUE);\r
2394                 }\r
2395                 else {\r
2396                         mode = "OFF";\r
2397                         menuItem.setForeground(Color.BLACK);\r
2398                 }\r
2399 \r
2400                 String target = ( n==0 ) ? "予約" : "隣接予約";\r
2401 \r
2402                 menuItem.setText(String.format("%sを%sにする【%s - %s(%s)/%s】",target,mode,start,title,chnam,recId));\r
2403                 \r
2404                 if ( recId.equals(toolBar.getSelectedRecorder()) ) {\r
2405                         // 選択中のレコーダのものは太字に\r
2406                         Font f = menuItem.getFont();\r
2407                         menuItem.setFont(f.deriveFont(f.getStyle()|Font.BOLD));\r
2408                 }\r
2409 \r
2410                 final String xmode = mode;\r
2411                 menuItem.addActionListener(new ActionListener() {\r
2412                         public void actionPerformed(ActionEvent e) {\r
2413                                 \r
2414                                 CommonSwingUtils.setLocationCenter(mainWindow,rdialog);\r
2415                                 \r
2416                                 // 予約ON・OFFのみ\r
2417                                 if ( rdialog.open(recId,rsvId, ! fexec) ) {\r
2418                                         \r
2419                                         rdialog.doUpdate();\r
2420                                         \r
2421                                         if (rdialog.isSucceededReserve()) {\r
2422                                                 // 予約状況を更新\r
2423                                                 listed.updateReserveMark();\r
2424                                                 paper.updateReserveBorder(chnam);\r
2425                                                 reserved.redrawReservedList();\r
2426                                                 \r
2427                                                 {\r
2428                                                         String msg = "予約を"+xmode+"にしました【"+title+"("+chnam+")/"+recId+"】";\r
2429                                                         StdAppendMessage(msg);\r
2430                                                         mwin.appendMessage(msg);\r
2431                                                 }\r
2432                                         }\r
2433                                 }\r
2434                                 else {\r
2435                                         //rdialog.setVisible(false);\r
2436                                 }\r
2437                         }\r
2438                 });\r
2439                 \r
2440                 return menuItem;\r
2441         }\r
2442         \r
2443         /**\r
2444          *  新聞形式へジャンプするメニューアイテム\r
2445          */\r
2446         private JMenuItem getJumpMenuItem(final String title, final String chnam, final String startDT) {\r
2447                 JMenuItem menuItem = new JMenuItem(String.format("番組欄へジャンプする【%s - %s(%s)】",startDT,title,chnam));\r
2448                 menuItem.addActionListener(new ActionListener() {\r
2449                         public void actionPerformed(ActionEvent e) {\r
2450                                 paper.jumpToBangumi(chnam,startDT);\r
2451                         }\r
2452                 });\r
2453                 return menuItem;\r
2454         }\r
2455         private JMenuItem getJumpToLastWeekMenuItem( final String title, final String chnam, final String startDT) {\r
2456                 GregorianCalendar cal = CommonUtils.getCalendar(startDT);\r
2457                 \r
2458                 if ( cal != null ) {\r
2459                         cal.add(Calendar.DATE, -7);\r
2460                         final String lastdatetime = CommonUtils.getDateTimeW(cal);\r
2461                         \r
2462                         JMenuItem menuItem = new JMenuItem(String.format("先週の番組欄へジャンプする【%s - (%s)】",lastdatetime,chnam));\r
2463                         \r
2464                         menuItem.addActionListener(new ActionListener() {\r
2465                                 public void actionPerformed(ActionEvent e) {\r
2466                                         paper.jumpToBangumi(chnam,lastdatetime);\r
2467                                 }\r
2468                         });\r
2469                         return menuItem;\r
2470                 }\r
2471                 return null;\r
2472         }\r
2473         \r
2474                 \r
2475         /*******************************************************************************\r
2476          * レコーダの予約情報をDLする\r
2477          ******************************************************************************/\r
2478         \r
2479         /***************************************\r
2480          * ツールバートリガーによる\r
2481          **************************************/\r
2482 \r
2483         /**\r
2484          *  レコーダの予約情報をDLする\r
2485          */\r
2486         private boolean doLoadRdRecorder(LoadRsvedFor lrf) {\r
2487                 \r
2488                 if ( lrf == null ) {\r
2489                         return doLoadRdRecorderAll();\r
2490                 }\r
2491                 else {\r
2492                         switch (lrf) {\r
2493                         case DETAILS:\r
2494                                 return doLoadRdReserveDetails();\r
2495                         case RECORDED:\r
2496                                 return doLoadRdRecorded();\r
2497                         case AUTORESERVE:\r
2498                                 return doLoadRdAutoReserves();\r
2499                         default:\r
2500                                 break;\r
2501                         }\r
2502                 }\r
2503                 return false;\r
2504         }\r
2505         \r
2506         /**\r
2507          * レコーダの情報を全部DLする(ステータスウィンドウは自前で用意        する)\r
2508          */\r
2509         private boolean doLoadRdRecorderAll() {\r
2510                 \r
2511                 final String myself = getSelectedMySelf();\r
2512                 \r
2513                 //\r
2514                 StWinClear();\r
2515                 \r
2516                 new SwingBackgroundWorker(false) {\r
2517                         \r
2518                         @Override\r
2519                         protected Object doWorks() throws Exception {\r
2520                                 \r
2521                                 TatCount tc = new TatCount();\r
2522                                 \r
2523                                 // 読み出せ!\r
2524                                 _loadRdRecorderAll(true,myself);\r
2525                                 \r
2526                                 // エンコーダ情報が更新されるかもしれないので、一覧のエンコーダ表示にも反映する\r
2527                                 recsetting.redrawRecorderEncoderEntry();\r
2528                                 \r
2529                                 // 各タブに反映する\r
2530                                 paper.updateReserveBorder(null);\r
2531                                 listed.updateReserveMark();\r
2532                                 reserved.redrawReservedList();\r
2533                                 recorded.redrawRecordedList();\r
2534                                 \r
2535                                 mwin.appendMessage(String.format("【予約一覧の取得処理が完了しました】 所要時間: %.2f秒",tc.end()));\r
2536                                 return null;\r
2537                         }\r
2538                         \r
2539                         @Override\r
2540                         protected void doFinally() {\r
2541                                 StWinSetVisible(false);\r
2542                         }\r
2543                 }.execute();\r
2544                 \r
2545                 StWinSetLocationCenter(this);\r
2546                 StWinSetVisible(true);\r
2547                 \r
2548                 return true;\r
2549         }\r
2550         \r
2551         \r
2552         /**\r
2553          * 予約一覧+予約詳細をDLする\r
2554          */\r
2555         private boolean doLoadRdReserveDetails() {\r
2556                 \r
2557                 final String myself = getSelectedMySelf();\r
2558                 \r
2559                 //\r
2560                 StWinClear();\r
2561                 \r
2562                 new SwingBackgroundWorker(false) {\r
2563                         \r
2564                         @Override\r
2565                         protected Object doWorks() throws Exception {\r
2566                                 \r
2567                                 TatCount tc = new TatCount();\r
2568                         \r
2569                                 boolean succeeded = true;\r
2570                                 \r
2571                                 HDDRecorderList recs;\r
2572                                 if ( myself != null ) {\r
2573                                         recs = recorders.findInstance(myself);\r
2574                                 }\r
2575                                 else {\r
2576                                         recs = recorders;\r
2577                                 }\r
2578                                 for ( HDDRecorder recorder : recs ) {\r
2579                                         \r
2580                                         if ( ! recorder.isReserveListSupported() ) {\r
2581                                                 continue;\r
2582                                         }\r
2583                                         \r
2584                                         // 各種設定の取得\r
2585                                         if ( ! recorder.GetRdSettings(true) ) {\r
2586                                                 succeeded = false;\r
2587                                                 continue;\r
2588                                         }\r
2589                                         \r
2590                                         // 予約一覧の取得\r
2591                                         if ( ! recorder.GetRdReserve(true) ) {\r
2592                                                 succeeded = false;\r
2593                                                 continue;\r
2594                                         }\r
2595                                         \r
2596                                         // レコーダから取得したエンコーダ情報で、登録済みレコーダ一覧を更新する\r
2597                                         setEncoderInfo2RecorderList(recorder,true);\r
2598                                         \r
2599                                         // 予約詳細の取得\r
2600                                         if ( recorder.isThereAdditionalDetails() ) {\r
2601                                                 if ( ! recorder.GetRdReserveDetails() ) {\r
2602                                                         succeeded = false;\r
2603                                                         continue;\r
2604                                                 }\r
2605                                         }\r
2606                                         \r
2607                                         // レコーダの放送局名をWeb番組表の放送局名に置き換え\r
2608                                         checkChNameIsRight(recorder);\r
2609                                         \r
2610                                         // 録画結果一覧を予約一覧に反映\r
2611                                         if ( recorder.isRecordedListSupported() ) {\r
2612                                                 recorder.GetRdRecorded(false);\r
2613                                         }\r
2614                                 }\r
2615                                 \r
2616                                 if ( succeeded ) {\r
2617                                         reserved.redrawReservedList();\r
2618                                         recorded.redrawRecordedList();\r
2619                                         \r
2620                                         mwin.appendMessage(String.format("【予約詳細の取得処理が完了しました】 所要時間: %.2f秒",tc.end()));\r
2621                                 }\r
2622                                 else {\r
2623                                         ringBeep();\r
2624                                         mwin.appendMessage(String.format("【予約詳細の取得処理に失敗しました】 所要時間: %.2f秒",tc.end()));\r
2625                                 }\r
2626                                 return null;\r
2627                         }\r
2628                         \r
2629                         @Override\r
2630                         protected void doFinally() {\r
2631                                 StWinSetVisible(false);\r
2632                         }\r
2633                 }.execute();\r
2634                 \r
2635                 StWinSetLocationCenter(this);\r
2636                 StWinSetVisible(true);\r
2637                 \r
2638                 return true;\r
2639         }\r
2640         \r
2641         \r
2642         /**\r
2643          * 録画結果一覧をDLする\r
2644          */\r
2645         private boolean doLoadRdRecorded() {\r
2646                 \r
2647                 final String myself = getSelectedMySelf();\r
2648                 \r
2649                 //\r
2650                 StWinClear();\r
2651                 \r
2652                 new SwingBackgroundWorker(false) {\r
2653                         \r
2654                         @Override\r
2655                         protected Object doWorks() throws Exception {\r
2656                                 \r
2657                                 TatCount tc = new TatCount();\r
2658                         \r
2659                                 boolean succeeded = true;\r
2660                                 \r
2661                                 HDDRecorderList recs;\r
2662                                 if ( myself != null ) {\r
2663                                         recs = recorders.findInstance(myself);\r
2664                                 }\r
2665                                 else {\r
2666                                         recs = recorders;\r
2667                                 }\r
2668                                 for ( HDDRecorder recorder : recs ) {\r
2669                                         if ( ! recorder.isRecordedListSupported() ) {\r
2670                                                 succeeded = false;\r
2671                                                 continue;\r
2672                                         }\r
2673 \r
2674                                         if ( ! recorder.GetRdRecorded(true) ) {\r
2675                                                 succeeded = false;\r
2676                                         }\r
2677                                 }\r
2678                                 \r
2679                                 if ( succeeded ) {\r
2680                                         reserved.redrawReservedList();\r
2681                                         recorded.redrawRecordedList();\r
2682                                         \r
2683                                         mwin.appendMessage(String.format("【録画結果一覧の取得処理が完了しました】 所要時間: %.2f秒",tc.end()));\r
2684                                 }\r
2685                                 else {\r
2686                                         ringBeep();\r
2687                                         mwin.appendMessage(String.format("【録画結果一覧の取得処理に失敗しました】 所要時間: %.2f秒",tc.end()));\r
2688                                 }\r
2689                                 return null;\r
2690                         }\r
2691                         \r
2692                         @Override\r
2693                         protected void doFinally() {\r
2694                                 StWinSetVisible(false);\r
2695                         }\r
2696                 }.execute();\r
2697                 \r
2698                 StWinSetLocationCenter(this);\r
2699                 StWinSetVisible(true);\r
2700                 \r
2701                 return true;\r
2702         }\r
2703 \r
2704 \r
2705         /**\r
2706          * 録画結果一覧をDLする\r
2707          */\r
2708         private boolean doLoadRdAutoReserves() {\r
2709                 \r
2710                 final String myself = getSelectedMySelf();\r
2711                 \r
2712                 //\r
2713                 StWinClear();\r
2714                 \r
2715                 new SwingBackgroundWorker(false) {\r
2716                         \r
2717                         @Override\r
2718                         protected Object doWorks() throws Exception {\r
2719                                 \r
2720                                 TatCount tc = new TatCount();\r
2721                         \r
2722                                 boolean succeeded = true;\r
2723                                 \r
2724                                 HDDRecorderList recs;\r
2725                                 if ( myself != null ) {\r
2726                                         recs = recorders.findInstance(myself);\r
2727                                 }\r
2728                                 else {\r
2729                                         recs = recorders;\r
2730                                 }\r
2731                                 for ( HDDRecorder recorder : recs ) {\r
2732                                         if ( ! recorder.isEditAutoReserveSupported() ) {\r
2733                                                 succeeded = false;\r
2734                                                 continue;\r
2735                                         }\r
2736                                         \r
2737                                         if ( ! recorder.GetRdAutoReserve(true) ) {\r
2738                                                 succeeded = false;\r
2739                                         }\r
2740                                 }\r
2741                                 \r
2742                                 if ( succeeded ) {\r
2743                                         // 再描画はここじゃないよ\r
2744                                         mwin.appendMessage(String.format("【自動予約一覧の取得処理が完了しました】 所要時間: %.2f秒",tc.end()));\r
2745                                 }\r
2746                                 else {\r
2747                                         ringBeep();\r
2748                                         mwin.appendMessage(String.format("【自動予約一覧の取得処理に失敗しました】 所要時間: %.2f秒",tc.end()));\r
2749                                 }\r
2750                                 return null;\r
2751                         }\r
2752                         \r
2753                         @Override\r
2754                         protected void doFinally() {\r
2755                                 StWinSetVisible(false);\r
2756                         }\r
2757                 }.execute();\r
2758                 \r
2759                 StWinSetLocationCenter(this);\r
2760                 StWinSetVisible(true);\r
2761                 \r
2762                 return true;\r
2763         }\r
2764         \r
2765         /***************************************\r
2766          * 自クラス内呼び出しによる\r
2767          **************************************/\r
2768         \r
2769         /**\r
2770          * レコーダの情報を全部DLする(ステータスウィンドウは呼び出し元が準備する)\r
2771          */\r
2772         private void loadRdReservesAll(final boolean force, final String myself) {\r
2773 \r
2774                 new SwingBackgroundWorker(true) {\r
2775                         \r
2776                         @Override\r
2777                         protected Object doWorks() throws Exception {\r
2778                                 \r
2779                                 _loadRdRecorderAll(force,myself);\r
2780                                 \r
2781                                 return null;\r
2782                         }\r
2783                         \r
2784                         @Override\r
2785                         protected void doFinally() {\r
2786                         }\r
2787                 }.execute();\r
2788         }\r
2789         \r
2790         /***************************************\r
2791          * レコーダの情報を取得する部品群\r
2792          **************************************/\r
2793         \r
2794         private boolean _loadRdRecorderAll(final boolean force, final String myself) {\r
2795 \r
2796                 HDDRecorderList recs;\r
2797                 if ( myself != null ) {\r
2798                         recs = recorders.findInstance(myself);\r
2799                 }\r
2800                 else {\r
2801                         recs = recorders;\r
2802                 }\r
2803                 \r
2804                 boolean success = true;\r
2805                 \r
2806                 for ( HDDRecorder recorder : recs ) {\r
2807                         if ( recorder.isReserveListSupported() ) {\r
2808                                 success = success & _loadRdRecorder(recorder, force);\r
2809                         }\r
2810                 }\r
2811                 \r
2812                 return success;\r
2813         }\r
2814         \r
2815         private boolean _loadRdRecorder(HDDRecorder recorder, boolean force) {\r
2816                 \r
2817                 mwin.appendMessage("【レコーダ情報取得】情報を取得します: "+recorder.Myself());\r
2818                 if ( recorder.isThereAdditionalDetails() && env.getForceLoadReserveDetails() == 2 ) {\r
2819                         mwin.appendMessage("<<<注意!>>>このレコーダでは予約詳細の個別取得を実行しないと正確な情報を得られない場合があります。");\r
2820                 }\r
2821                 \r
2822                 try {\r
2823                         \r
2824                         // 各種設定の取得\r
2825                         if ( ! _loadRdSettings(recorder,force) ) {\r
2826                                 return false;\r
2827                         }\r
2828                         \r
2829                         // 予約一覧の取得\r
2830                         if ( ! _loadRdReserves(recorder,force) ) {\r
2831                                 return false;\r
2832                         }\r
2833                         \r
2834                         // レコーダから取得したエンコーダ情報で、登録済みレコーダ一覧を更新する\r
2835                         setEncoderInfo2RecorderList(recorder,force);\r
2836                         \r
2837                         // 予約詳細の取得(強制取得じゃなければ処理不要)\r
2838                         if ( force && ! _loadRdReserveDetails(recorder,force) ) {\r
2839                                 return false;\r
2840                         }\r
2841                         \r
2842                         // レコーダの放送局名をWeb番組表の放送局名に置き換え\r
2843                         checkChNameIsRight(recorder);\r
2844                         \r
2845                         // 自動予約一覧の取得\r
2846                         if ( ! _loadRdAutoReserves(recorder,force) ) {\r
2847                                 return false;\r
2848                         }\r
2849                         \r
2850                         // 録画結果一覧の取得\r
2851                         if ( ! _loadRdRecorded(recorder,force) ) {\r
2852                                 return false;\r
2853                         }\r
2854                 }\r
2855                 catch (Exception e) {\r
2856                         e.printStackTrace();\r
2857                         mwin.appendError("【致命的エラー】予約一覧の取得で例外が発生 "+recorder.getIPAddr()+":"+recorder.getPortNo()+":"+recorder.getRecorderId());\r
2858                         ringBeep();\r
2859                         return false;\r
2860                 }\r
2861                 return true;\r
2862         }\r
2863         \r
2864         \r
2865         /***************************************\r
2866          * レコーダの情報を取得する部品群\r
2867          **************************************/\r
2868         \r
2869         private boolean _loadRdSettings(HDDRecorder recorder, boolean force) {\r
2870                 if ( recorder.GetRdSettings(force) ) {\r
2871                         return true;\r
2872                 }\r
2873                 \r
2874                 mwin.appendError(recorder.getErrmsg()+" "+recorder.Myself());   // 取得に失敗\r
2875                 ringBeep();\r
2876                 return false;\r
2877         }\r
2878         \r
2879         private boolean _loadRdReserves(HDDRecorder recorder, boolean force) {\r
2880                 if ( recorder.GetRdReserve(force) ) {\r
2881                         return true;\r
2882                 }\r
2883                 \r
2884                 mwin.appendError(recorder.getErrmsg()+" "+recorder.Myself());   // 取得に失敗\r
2885                 ringBeep();\r
2886                 return false;\r
2887         }\r
2888         \r
2889         private boolean _loadRdReserveDetails(HDDRecorder recorder, boolean force) {\r
2890                 \r
2891                 if ( ! recorder.isThereAdditionalDetails() ) {\r
2892                         return true;    // 非対応レコーダ\r
2893                 }\r
2894                 \r
2895                 boolean skip = false;\r
2896                 if ( force && env.getForceLoadReserveDetails() == 2 ) {\r
2897                         skip = true;\r
2898                 }\r
2899                 else if ( force && env.getForceLoadReserveDetails() == 0 ) {\r
2900                         int ret = JOptOptionPane.showConfirmDialog(stwin, "<HTML>詳細情報を取得しますか?(時間がかかります)<BR><BR>"+recorder.Myself()+"</HTML>", "今回の選択を既定の動作とする", "※既定動作は各種設定で変更できます", "確認", JOptionPane.YES_NO_OPTION);\r
2901                         skip = (ret != JOptOptionPane.YES_OPTION);\r
2902                         \r
2903                         if ( JOptOptionPane.isSelected() ) {\r
2904                                 // 今回の選択を既定の動作とする\r
2905                                 env.setForceLoadReserveDetails(skip ? 2 : 1);\r
2906                                 env.save();\r
2907                                 if (setting!=null) setting.updateSelections();\r
2908                         }\r
2909                 }\r
2910                 if ( skip ) {\r
2911                         mwin.appendMessage("【!】予約詳細情報の取得はスキップされました");\r
2912                         return true;\r
2913                 }\r
2914                 \r
2915                 if ( recorder.GetRdReserveDetails()) {\r
2916                         return true;    // 取得成功\r
2917                 }\r
2918                 \r
2919                 mwin.appendError(recorder.getErrmsg()+" "+recorder.Myself());\r
2920                 ringBeep();\r
2921                 return false;           // 取得失敗\r
2922         }\r
2923 \r
2924         private boolean _loadRdAutoReserves(HDDRecorder recorder, boolean force) {\r
2925 \r
2926                 if ( ! recorder.isEditAutoReserveSupported() ) {\r
2927                         return true;\r
2928                 }\r
2929                 \r
2930                 boolean skip = false;\r
2931                 if ( force && env.getForceLoadAutoReserves() == 2 ) {\r
2932                         skip = true;\r
2933                 }\r
2934                 else if ( force && env.getForceLoadAutoReserves() == 0 ) {\r
2935                         int ret = JOptOptionPane.showConfirmDialog(stwin, "<HTML>自動予約一覧を取得しますか?(時間がかかります)<BR><BR>"+recorder.Myself()+"</HTML>", "今回の選択を既定の動作とする", "※既定動作は各種設定で変更できます", "確認", JOptionPane.YES_NO_OPTION);\r
2936                         skip = (ret != JOptOptionPane.YES_OPTION);\r
2937                         \r
2938                         if ( JOptOptionPane.isSelected() ) {\r
2939                                 // 今回の選択を既定の動作とする\r
2940                                 env.setForceLoadAutoReserves(skip ? 2 : 1);\r
2941                                 env.save();\r
2942                                 if (setting!=null) setting.updateSelections();\r
2943                         }\r
2944                 }\r
2945                 if ( skip ) {\r
2946                         mwin.appendMessage("【!】自動予約一覧の取得はスキップされました");\r
2947                         return true;\r
2948                 }\r
2949 \r
2950                 if ( recorder.GetRdAutoReserve(force) ) {\r
2951                         return true;\r
2952                 }\r
2953                 \r
2954                 mwin.appendError(recorder.getErrmsg()+" "+recorder.Myself());\r
2955                 ringBeep();\r
2956                 return false;\r
2957         }\r
2958         \r
2959         private boolean _loadRdRecorded(HDDRecorder recorder, boolean force) {\r
2960                 \r
2961                 if ( ! recorder.isRecordedListSupported() ) {\r
2962                         return true;\r
2963                 }\r
2964                 \r
2965                 boolean skip = false;\r
2966                 if ( force && env.getForceLoadRecorded() == 2 ) {\r
2967                         skip = true;\r
2968                 }\r
2969                 if ( force && env.getForceLoadRecorded() == 0 ) {\r
2970                         int ret = JOptOptionPane.showConfirmDialog(stwin, "<HTML>録画結果一覧を取得しますか?(時間がかかります)<BR><BR>"+recorder.Myself()+"</HTML>", "今回の選択を既定の動作とする", "※既定動作は各種設定で変更できます", "確認", JOptionPane.YES_NO_OPTION);\r
2971                         skip = (ret != JOptOptionPane.YES_OPTION);\r
2972                         \r
2973                         if ( JOptOptionPane.isSelected() ) {\r
2974                                 // 今回の選択を既定の動作とする\r
2975                                 env.setForceLoadRecorded(skip ? 2 : 1);\r
2976                                 env.save();\r
2977                                 if (setting!=null) setting.updateSelections();\r
2978                         }\r
2979                 }\r
2980                 if ( skip ) {\r
2981                         mwin.appendMessage("【!】録画結果一覧の取得はスキップされました");\r
2982                         return true;\r
2983                 }\r
2984                 \r
2985                 if ( recorder.GetRdRecorded(force) ) {\r
2986                         return true;\r
2987                 }\r
2988                 \r
2989                 mwin.appendError(recorder.getErrmsg()+" "+recorder.Myself());\r
2990                 ringBeep();\r
2991                 return false;\r
2992         }\r
2993 \r
2994         /**\r
2995          * レコーダから取得したエンコーダ情報で、登録済みレコーダ一覧を更新する\r
2996          * @param recorder\r
2997          */\r
2998         private void setEncoderInfo2RecorderList(HDDRecorder recorder, boolean force) {\r
2999                 for (RecorderInfo ri : recInfoList ) {\r
3000                         //if (rl.getRecorderEncoderList().size() == 0)\r
3001                         {\r
3002                                 //String mySelf = ri.getRecorderIPAddr()+":"+ri.getRecorderPortNo()+":"+ri.getRecorderId();\r
3003                                 //String myMail = "MAIL"+":"+ri.getRecorderMacAddr()+":"+ri.getRecorderId();\r
3004                                 //if (recorder.isMyself(mySelf) || recorder.isMyself(myMail)) {\r
3005                                 if ( recorder.isMyself(ri.MySelf()) ) {\r
3006                                         ri.clearEncoders();\r
3007                                         for (TextValueSet enc : recorder.getEncoderList()) {\r
3008                                                 ri.addEncoder(enc.getText());\r
3009                                         }\r
3010                                         \r
3011                                         if ( force ) {\r
3012                                                 recInfoList.save();\r
3013                                         }\r
3014                                         break;\r
3015                                 }\r
3016                         }\r
3017                 }\r
3018         }\r
3019         \r
3020         /**\r
3021          * 予約一覧の放送局名が正しい形式であるかどうかのチェック\r
3022          */\r
3023         private void checkChNameIsRight(HDDRecorder recorder) {\r
3024                 HashMap<String,String> misCN = new HashMap<String,String>();\r
3025                 for ( ReserveList r : recorder.getReserves() ) {\r
3026                         if ( r.getCh_name() == null ) {\r
3027                                 misCN.put(r.getChannel(),recorder.getRecorderId());\r
3028                         }\r
3029                 }\r
3030                 if ( misCN.size() > 0 ) {\r
3031                         for ( String cn : misCN.keySet() ) {\r
3032                                 String msg = "【警告(予約一覧)】 <"+misCN.get(cn)+"> \"レコーダの放送局名\"を\"Web番組表の放送局名\"に変換できません。CHコード設定に設定を追加してください:\"レコーダの放送局名\"="+cn;\r
3033                                 mwin.appendMessage(msg);\r
3034                         }\r
3035                         ringBeep();\r
3036                 }\r
3037         }\r
3038         \r
3039         /*******************************************************************************\r
3040          * Web番組表をDLする\r
3041          ******************************************************************************/\r
3042         \r
3043         /***************************************\r
3044          * ツールバートリガー(と、各種設定変更トリガー)による\r
3045          **************************************/\r
3046         \r
3047         /**\r
3048          * Web番組表をDL→再描画まで\r
3049          * <P>単体実行の場合はこちらを呼び出す\r
3050          * <P>部品実行の場合はこちらを呼び出す:{@link #loadTVProgram(boolean, LoadFor)}\r
3051          * @see #doRedrawTVProgram()\r
3052          */\r
3053         private boolean doLoadTVProgram(final boolean force, final LoadFor lf) {\r
3054                 //\r
3055                 StWinClear();\r
3056                 \r
3057                 new SwingBackgroundWorker(false) {\r
3058                         \r
3059                         @Override\r
3060                         protected Object doWorks() throws Exception {\r
3061                                 \r
3062                                 TatCount tc = new TatCount();\r
3063                                 \r
3064                                 loadTVProgram(force, lf);\r
3065                                 \r
3066                                 mwin.appendMessage(String.format("[Web番組表取得] 【完了しました】 所要時間: %.2f秒",tc.end()));\r
3067                                 return null;\r
3068                         }\r
3069                         \r
3070                         @Override\r
3071                         protected void doFinally() {\r
3072                                 StWinSetVisible(false);\r
3073                         }\r
3074                 }.execute();\r
3075                 \r
3076                 StWinSetLocationCenter(this);\r
3077                 StWinSetVisible(true);\r
3078                 \r
3079                 return true;\r
3080         }\r
3081 \r
3082         /**\r
3083          * \r
3084          * @see #doLoadTVProgram(boolean, LoadFor)\r
3085          */\r
3086         private void doRedrawTVProgram() {\r
3087                 \r
3088                 // 新聞描画枠のリセット\r
3089                 paper.clearPanel();\r
3090                 paper.buildMainViewByDate();\r
3091                 \r
3092                 // サイドツリーの再構築\r
3093                 paper.redrawTreeByDate();\r
3094                 paper.redrawTreeByPassed();\r
3095                 \r
3096                 listed.redrawTreeByHistory();\r
3097                 listed.redrawTreeByCenter();\r
3098                 \r
3099                 // 再描画\r
3100                 paper.reselectTree();\r
3101                 listed.reselectTree();\r
3102         }\r
3103         \r
3104         /***************************************\r
3105          * 自クラス内呼び出しによる\r
3106          **************************************/\r
3107         \r
3108         /**\r
3109          * Web番組表をDLする\r
3110          * <P>単体実行の場合はこちらを呼び出す:{@link #doLoadTVProgram(LoadFor)}\r
3111          * <P>部品実行の場合はこちらを呼び出す\r
3112          */\r
3113         private boolean loadTVProgram(final boolean force, final LoadFor lf) {\r
3114                 \r
3115                 final String FUNCID = "[Web番組表取得] ";\r
3116                 final String ERRID = "[ERROR]"+FUNCID;\r
3117                 \r
3118                 try {\r
3119                         String msg;\r
3120                         TVProgram tvp;\r
3121                         \r
3122                         tvp = tvprograms.getTvProgPlugin(null);\r
3123                         if ( tvp != null )\r
3124                         {\r
3125                                 String sType = "地上波&BS番組表";\r
3126                                 if (lf == LoadFor.ALL || lf == LoadFor.TERRA) {\r
3127                                         loadTVProgramOnce(tvp, sType, tvp.getSelectedArea(), false, force);\r
3128                                 }\r
3129                                 else {\r
3130                                         stwin.appendMessage(FUNCID+sType+"へのアクセスはスキップされました: "+tvp.getTVProgramId());\r
3131                                 }\r
3132                         }\r
3133                         \r
3134                         tvp = tvprograms.getCsProgPlugin(null);\r
3135                         if ( tvp != null )\r
3136                         {\r
3137                                 String sType = "CS番組表[プライマリ]";\r
3138                                 if (lf == LoadFor.ALL || lf == LoadFor.CS || lf == LoadFor.CSo1 || lf == LoadFor.CSwSD) {\r
3139                                         loadTVProgramOnce(tvp, sType, tvp.getSelectedArea(), false, force);\r
3140                                 }\r
3141                                 else {\r
3142                                         stwin.appendMessage(FUNCID+sType+"へのアクセスはスキップされました: "+tvp.getTVProgramId());\r
3143                                 }\r
3144                         }\r
3145                         \r
3146                         tvp = tvprograms.getCs2ProgPlugin(null);\r
3147                         if ( tvp != null )\r
3148                         {\r
3149                                 String sType = "CS番組表[セカンダリ]";\r
3150                                 if (lf == LoadFor.ALL || lf == LoadFor.CS || lf == LoadFor.CSo2 || lf == LoadFor.CSwSD) {\r
3151                                         loadTVProgramOnce(tvp, sType, tvp.getSelectedArea(), false, force);\r
3152                                 }\r
3153                                 else {\r
3154                                         stwin.appendMessage(FUNCID+sType+"へのアクセスはスキップされました: "+tvp.getTVProgramId());\r
3155                                 }\r
3156                         }\r
3157                         \r
3158                         tvp = tvprograms.getSyobo();\r
3159                         if ( tvp != null ) {\r
3160                                 String sType = "しょぼかる";\r
3161                                 if ( (lf == LoadFor.ALL || lf == LoadFor.SYOBO) && enableWebAccess && env.getUseSyobocal()) {\r
3162                                         tvp.loadCenter(tvp.getSelectedCode(), force);   // しょぼかるには放送局リストを取得するイベントが他にないので\r
3163                                         loadTVProgramOnce(tvp, sType, null, true, force);\r
3164                                 }\r
3165                                 else {\r
3166                                         stwin.appendMessage(FUNCID+sType+"へのアクセスはスキップされました.");\r
3167                                 }\r
3168                                 \r
3169                                 // しょぼかるの新番組マークを引き継ぐ\r
3170                                 attachSyoboNew();\r
3171                         }\r
3172                 \r
3173                         PickedProgram pickup = tvprograms.getPickup();\r
3174                         if ( tvp != null ) {\r
3175                                 pickup.refresh();\r
3176                                 //pickup.save();\r
3177                         }\r
3178                         \r
3179                         // 番組タイトルを整形する\r
3180                         fixTitle();\r
3181                         fixDetail();\r
3182                         \r
3183                         // 検索結果の再構築\r
3184                         stwin.appendMessage(FUNCID+"検索結果を生成します.");\r
3185                         mpList.clear(env.getDisableFazzySearch(), env.getDisableFazzySearchReverse());\r
3186                         mpList.build(tvprograms, trKeys.getTraceKeys(), srKeys.getSearchKeys());\r
3187                         \r
3188                         // 過去ローグ\r
3189                         if ( env.getUsePassedProgram() ) {\r
3190                                 TatCount tc = new TatCount();\r
3191                                 stwin.appendMessage(FUNCID+"過去ログを生成します.");\r
3192                                 if ( tvprograms.getPassed().save(tvprograms.getIterator(), chsort.getClst(), env.getPrepPassedProgramCount()) ) {\r
3193                                         msg = String.format(FUNCID+"過去ログを生成しました [%.2f秒].",tc.end());\r
3194                                         StdAppendMessage(msg);\r
3195                                 }\r
3196                                 //PassedProgramList.getDateList(env.getPassedLogLimit());\r
3197                         }\r
3198                         else {\r
3199                                 stwin.appendMessage(FUNCID+"過去ログは記録されません.");\r
3200                         }\r
3201                 }\r
3202                 catch (Exception e) {\r
3203                         e.printStackTrace();\r
3204                         mwin.appendError(ERRID+"番組情報の取得で例外が発生");\r
3205                         ringBeep();\r
3206                         return false;\r
3207                 }\r
3208                 \r
3209                 return true;\r
3210         }\r
3211         \r
3212         // 分割\r
3213         private void loadTVProgramOnce(TVProgram tvp, String sType, String aName, boolean loadonly, boolean force) {\r
3214                 \r
3215                 final String FUNCID = "[Web番組表取得] ";\r
3216 //              final String ERRID = "[ERROR]"+FUNCID;\r
3217                 \r
3218                 // ログ\r
3219                 String msg = FUNCID+sType+"を取得します: "+tvp.getTVProgramId();\r
3220                 stwin.appendMessage(msg);\r
3221                 if (aName!=null) stwin.appendMessage(FUNCID+"+選択されているエリア="+aName);\r
3222                 \r
3223                 // 読み込み\r
3224                 //tvp.setProgressArea(stwin);\r
3225                 tvp.loadProgram(tvp.getSelectedCode(), force);\r
3226                 \r
3227                 if (loadonly) {\r
3228                         return;\r
3229                 }\r
3230                 \r
3231                 // 延長警告\r
3232                 tvp.setExtension(null, null, false, extKeys.getSearchKeys());   // 最初の3引数は盲腸。ダミー\r
3233                 // NGワード\r
3234                 tvp.abon(env.getNgword());\r
3235                 // 抜けチェック\r
3236                 String errmsg = tvp.chkComplete(); \r
3237                 if (errmsg != null) {\r
3238                         stwin.appendError(FUNCID+"取得した情報が不正です:"+errmsg);\r
3239                         if (mainWindow!=null) mwin.appendMessage(msg);\r
3240                         ringBeep();\r
3241                 }\r
3242         }\r
3243         \r
3244         // しょぼかるの番組詳細を番組表に反映する\r
3245         private void attachSyoboNew() {\r
3246                 TVProgram syobo = tvprograms.getSyobo();\r
3247                 if (syobo == null) {\r
3248                         return;\r
3249                 }\r
3250                 \r
3251                 for ( TVProgram tvp : tvprograms ) {\r
3252                         \r
3253                         if ( tvp.getType() != ProgType.PROG ) {\r
3254                                 continue;\r
3255                         }\r
3256                         if ( ! (tvp.getSubtype() == ProgSubtype.TERRA || tvp.getSubtype() == ProgSubtype.CS || tvp.getSubtype() == ProgSubtype.CS2) ) {\r
3257                                 continue;\r
3258                         }\r
3259                         \r
3260                         for ( ProgList tvpl : tvp.getCenters() ) {\r
3261                                 if ( ! tvpl.enabled) {\r
3262                                         continue;\r
3263                                 }\r
3264                                 for ( ProgList svpl : syobo.getCenters() ) {\r
3265                                         if ( ! tvpl.Center.equals(svpl.Center)) {\r
3266                                                 continue;\r
3267                                         }\r
3268                                         for ( ProgDateList tvc : tvpl.pdate ) {\r
3269                                                 \r
3270                                                 ProgDateList mSvc = null;\r
3271                                                 for ( ProgDateList svc : svpl.pdate ) {\r
3272                                                         if (tvc.Date.equals(svc.Date) ) {\r
3273                                                                 mSvc = svc;\r
3274                                                                 break;\r
3275                                                         }\r
3276                                                 }\r
3277                                                 if (mSvc == null) {\r
3278                                                         // しょぼかる側に該当する日付自体ないので全部フラグを立てっぱなしでいい\r
3279                                                         for ( ProgDetailList tvd : tvc.pdetail ) {\r
3280                                                                 if ( tvd.isEqualsGenre(ProgGenre.ANIME, null) ) {\r
3281                                                                         tvd.addOption(ProgOption.NOSYOBO);\r
3282                                                                 }\r
3283                                                         }\r
3284                                                 }\r
3285                                                 else {\r
3286                                                         // しょぼかる側に該当する日付があるのでマッチング。アニメと映画と音楽\r
3287                                                         for ( ProgDetailList tvd : tvc.pdetail ) {\r
3288                                                                 \r
3289                                                                 // アニメはいったんフラグを立てる\r
3290                                                                 if ( tvd.isEqualsGenre(ProgGenre.ANIME, null) ) {\r
3291                                                                         tvd.addOption(ProgOption.NOSYOBO);\r
3292                                                                 }\r
3293                                                                 \r
3294                                                                 boolean isFind = false;\r
3295                                                                 for ( ProgDetailList svd : mSvc.pdetail ) {\r
3296                                                                         if ( tvd.start.equals(svd.start) ) {\r
3297                                                                                 \r
3298                                                                                 // 番組ID\r
3299                                                                                 {\r
3300                                                                                         //svd.progid = tvd.progid;\r
3301                                                                                         svd.setContentIdStr();\r
3302                                                                                 }\r
3303                                                                                 \r
3304                                                                                 boolean isAnime = tvd.isEqualsGenre(ProgGenre.ANIME, null);\r
3305                                                                                 if ( ! isAnime && ! tvd.isEqualsGenre(ProgGenre.MOVIE, null) && ! tvd.isEqualsGenre(ProgGenre.MUSIC, null) ) {\r
3306                                                                                         break;\r
3307                                                                                 }\r
3308                                                                                 \r
3309                                                                                 // みつけた\r
3310                                                                                 isFind = true;\r
3311                                                                                 \r
3312                                                                                 // しょぼかるとWeb番組表の両方に存在する\r
3313                                                                                 svd.nosyobo = true;\r
3314                         \r
3315                                                                                 // 各種フラグ\r
3316                                                                                 {\r
3317                                                                                         boolean isAttached = false;\r
3318                                                                                         \r
3319                                                                                         // 新番組フラグ\r
3320                                                                                         if ( svd.flag == ProgFlags.NEW && tvd.flag != ProgFlags.NEW ) {\r
3321                                                                                                 tvd.flag = ProgFlags.NEW;\r
3322                                                                                                 isAttached = true;\r
3323                                                                                         }\r
3324                                                                                         \r
3325                                                                                         // 最終回フラグ\r
3326                                                                                         if ( svd.flag == ProgFlags.LAST && tvd.flag != ProgFlags.LAST ) {\r
3327                                                                                                 tvd.flag = ProgFlags.LAST;\r
3328                                                                                                 isAttached = true;\r
3329                                                                                         }\r
3330                                                                                         \r
3331                                                                                         // ジャンル\r
3332                                                                                         if ( tvd.isEqualsGenre(ProgGenre.MOVIE, null) && ! tvd.isEqualsGenre(ProgGenre.MOVIE, ProgSubgenre.MOVIE_ANIME) ) {\r
3333                                                                                                 if ( tvd.genrelist == null ) {\r
3334                                                                                                         tvd.genrelist = new ArrayList<ProgGenre>();\r
3335                                                                                                         tvd.genrelist.add(tvd.genre);\r
3336                                                                                                         tvd.genrelist.add(ProgGenre.MOVIE);\r
3337                                                                                                         tvd.subgenrelist = new ArrayList<ProgSubgenre>();\r
3338                                                                                                         tvd.subgenrelist.add(tvd.subgenre);\r
3339                                                                                                         tvd.subgenrelist.add(ProgSubgenre.MOVIE_ANIME);\r
3340                                                                                                 }\r
3341                                                                                                 else {\r
3342                                                                                                         tvd.genrelist.add(ProgGenre.MOVIE);\r
3343                                                                                                         tvd.subgenrelist.add(ProgSubgenre.MOVIE_ANIME);\r
3344                                                                                                 }\r
3345                                                                                                 isAttached = true;\r
3346                                                                                         }\r
3347                                                                                         \r
3348                                                                                         // その他のフラグ\r
3349                                                                                         for ( ProgOption sopt : svd.getOption() ) {\r
3350                                                                                                 if ( tvd.addOption(sopt) && isAttached == false ) {\r
3351                                                                                                         isAttached = true;\r
3352                                                                                                 }\r
3353                                                                                         }\r
3354                                                                                         \r
3355                                                                                         // ログ\r
3356                                                                                         if (isAttached && env.getDebug()) {\r
3357                                                                                                 StdAppendMessage("しょぼかるのフラグを引き継ぎました: ("+tvpl.Center+") "+tvd.title);\r
3358                                                                                         }\r
3359                                                                                 }\r
3360                                                                                 \r
3361                                                                                 // 番組詳細\r
3362                                                                                 if ( tvd.detail.length() < svd.detail.length() ) {\r
3363                                                                                         tvd.detail = svd.detail;\r
3364                                                                                 }\r
3365                                                                                 else {\r
3366                                                                                         int idx = svd.detail.indexOf("<!");\r
3367                                                                                         if (idx != -1) {\r
3368                                                                                                 tvd.detail += svd.detail.substring(idx);\r
3369                                                                                         }\r
3370                                                                                 }\r
3371                                                                                 \r
3372                                                                                 // 「しょぼかるにのみ存在」フラグの上げ下げ(これはアニメ限定)\r
3373                                                                                 if ( isAnime ) {\r
3374                                                                                         if ( isFind ) {\r
3375                                                                                                 tvd.removeOption(ProgOption.NOSYOBO);   // NOSYOBOって…\r
3376                                                                                         }\r
3377                                                                                         else {\r
3378                                                                                                 //tvd.addOption(ProgOption.NOSYOBO);\r
3379                                                                                         }\r
3380                                                                                 }\r
3381                                                                                 \r
3382                                                                                 break;\r
3383                                                                         }\r
3384                                                                 }\r
3385                                                         }\r
3386                                                 }\r
3387                                         }\r
3388                                         break;\r
3389                                 }\r
3390                         }\r
3391                 }\r
3392         }\r
3393         \r
3394         // 番組タイトルを整形する\r
3395         private void fixTitle() {\r
3396                 //\r
3397                 if ( ! env.getFixTitle()) {\r
3398                         return;\r
3399                 }\r
3400                 //\r
3401                 for ( TVProgram tvp : tvprograms ) {\r
3402                         //if ( ! (tvp.getType() == ProgType.PROG && tvp.getSubtype() == ProgSubtype.TERRA) ) {\r
3403                         if ( tvp.getType() != ProgType.PROG ) {\r
3404                                 continue;\r
3405                         }\r
3406                         //\r
3407                         for ( ProgList pl : tvp.getCenters() ) {\r
3408                                 if ( ! pl.enabled ) {\r
3409                                         continue;\r
3410                                 }\r
3411 \r
3412                                 for ( ProgDateList pcl : pl.pdate ) {\r
3413                                         //\r
3414                                         for ( ProgDetailList tvd : pcl.pdetail ) {\r
3415                                                 if ( tvd.isEqualsGenre(ProgGenre.ANIME, null) ) {\r
3416                                                         if ( pl.Center.startsWith("NHK") || pl.Center.startsWith("NHK") ) {\r
3417                                                                 // NHK系で先頭が「アニメ 」ではじまるものから「アニメ 」を削除する\r
3418                                                                 tvd.title = tvd.title.replaceFirst("^アニメ[  ・]+","");\r
3419                                                                 tvd.titlePop = TraceProgram.replacePop(tvd.title);\r
3420                                                                 tvd.SearchStrKeys = TraceProgram.splitKeys(tvd.titlePop);\r
3421                                                         }\r
3422                                                         if ( tvd.title.contains("コメンタリ") || tvd.detail.contains("コメンタリ") ) {\r
3423                                                                 // "コメンタリ"の記述のあるものは「副音声」扱いにする(副音声でなくても)\r
3424                                                                 tvd.option.add(ProgOption.MULTIVOICE);\r
3425                                                         }\r
3426                                                         if ( (tvd.title.contains("劇場版") || (tvd.detail.contains("映画") && ! tvd.detail.contains("映画館"))) && ! tvd.isEqualsGenre(ProgGenre.MOVIE, ProgSubgenre.MOVIE_ANIME) ) {\r
3427                                                                 // ジャンル=アニメだがタイトルに「劇場版」が含まれるならジャンル=映画(アニメ映画)を追加する\r
3428                                                                 if ( tvd.genrelist == null ) {\r
3429                                                                         tvd.genrelist = new ArrayList<ProgGenre>();\r
3430                                                                         tvd.genrelist.add(tvd.genre);\r
3431                                                                         tvd.genrelist.add(ProgGenre.MOVIE);\r
3432                                                                         tvd.subgenrelist = new ArrayList<ProgSubgenre>();\r
3433                                                                         tvd.subgenrelist.add(tvd.subgenre);\r
3434                                                                         tvd.subgenrelist.add(ProgSubgenre.MOVIE_ANIME);\r
3435                                                                 }\r
3436                                                                 else {\r
3437                                                                         tvd.genrelist.add(ProgGenre.MOVIE);\r
3438                                                                         tvd.subgenrelist.add(ProgSubgenre.MOVIE_ANIME);\r
3439                                                                 }\r
3440                                                         }\r
3441                                                 }\r
3442                                                 else if ( tvd.isEqualsGenre(ProgGenre.MOVIE, ProgSubgenre.MOVIE_ANIME) && tvd.subgenre != ProgSubgenre.MOVIE_ANIME ) {\r
3443                                                         // ジャンル=映画でサブジャンルが複数ありアニメが優先されてないものはアニメを優先する\r
3444                                                         tvd.subgenre = ProgSubgenre.MOVIE_ANIME;\r
3445                                                 }\r
3446                                                 \r
3447                                                 // サブタイトルを番組追跡の対象から外す\r
3448                                                 if ( env.getTraceOnlyTitle() && tvd.title != tvd.splitted_title ) {\r
3449                                                         tvd.SearchStrKeys = TraceProgram.splitKeys(TraceProgram.replacePop(tvd.splitted_title));        // 番組追跡の検索用インデックスは、サブタイトルを削除したもので置き換える\r
3450                                                 }\r
3451                                         }\r
3452                                 }\r
3453                         }\r
3454                 }\r
3455         }\r
3456         \r
3457         /**\r
3458          * {@link ProgDetailList} の情報を整形する\r
3459          */\r
3460         private void fixDetail() {\r
3461                 for ( TVProgram tvp : tvprograms ) {\r
3462                         for ( ProgList pl : tvp.getCenters() ) {\r
3463                                 if ( ! pl.enabled ) {\r
3464                                         continue;\r
3465                                 }\r
3466                                 for ( ProgDateList pcl : pl.pdate ) {\r
3467                                         for ( ProgDetailList tvd : pcl.pdetail ) {\r
3468                                                 if ( tvd.start == null || tvd.start.length() == 0 ) {\r
3469                                                         continue;\r
3470                                                 }\r
3471                                                 \r
3472                                                 fixDetailSub(tvp, pl, tvd);\r
3473                                         }\r
3474                                 }\r
3475                         }\r
3476                 }\r
3477         }\r
3478         \r
3479         private void fixDetailSub(TVProgram tvp, ProgList pl, ProgDetailList tvd) {\r
3480                 tvd.type = tvp.getType();\r
3481                 tvd.subtype = tvp.getSubtype();\r
3482                 tvd.center = pl.Center;\r
3483                 \r
3484                 tvd.recmin = CommonUtils.getRecMinVal(tvd.startDateTime, tvd.endDateTime);\r
3485                 \r
3486                 tvd.extension_mark = markchar.getExtensionMark(tvd);\r
3487                 tvd.prefix_mark = markchar.getOptionMark(tvd);\r
3488                 tvd.newlast_mark = markchar.getNewLastMark(tvd);\r
3489                 tvd.postfix_mark = markchar.getPostfixMark(tvd);\r
3490                 \r
3491                 tvd.dontoverlapdown = (tvd.center.startsWith("NHK") || tvd.center.startsWith("NHK"));\r
3492         }\r
3493         \r
3494         \r
3495         /*******************************************************************************\r
3496          * 過去ログ検索\r
3497          ******************************************************************************/\r
3498         \r
3499         /**\r
3500          * <P>過去ログから検索キーワードにマッチする情報を取得する\r
3501          * <P>全部検索がヒットした結果がかえるのだから {@link ProgDetailList} ではなく {@link MarkedProgramList} を使うべきなのだが…\r
3502          */\r
3503         private boolean searchPassedProgram(final SearchKey sKey, final String target) {\r
3504                 \r
3505                 Matcher ma = Pattern.compile("^(\\d\\d\\d\\d/\\d\\d/\\d\\d)-(\\d\\d\\d\\d/\\d\\d/\\d\\d)$").matcher(target);\r
3506                 if ( ! ma.find() ) {\r
3507                         return false;\r
3508                 }\r
3509                 \r
3510                 final GregorianCalendar s = CommonUtils.getCalendar(ma.group(1));\r
3511                 final GregorianCalendar e = CommonUtils.getCalendar(ma.group(2));\r
3512                 final long dDays = (e.getTimeInMillis() - s.getTimeInMillis())/86400000 + 1;\r
3513 \r
3514                 final ArrayList<ProgDetailList> srchpdl = tvprograms.getSearched().getResultBuffer(sKey.getLabel()) ;\r
3515 \r
3516                 stwin.clear();\r
3517                 \r
3518                 // 検索実行(時間がかかるので状況表示する)\r
3519                 new SwingBackgroundWorker(false) {\r
3520                         \r
3521                         @Override\r
3522                         protected Object doWorks() throws Exception {\r
3523                                 \r
3524                                 TatCount tc = new TatCount();\r
3525                                 \r
3526                                 // 検索中\r
3527                                 int resultCnt = 0;\r
3528                                 for (int cnt=1; cnt<=dDays; cnt++) {\r
3529                                         \r
3530                                         String passdt = CommonUtils.getDate(e);\r
3531                                         stwin.appendMessage(String.format("[過去ログ検索] 検索中:(%d/%d) %s", cnt, dDays, passdt));\r
3532                                         \r
3533                                         PassedProgram tvp = new PassedProgram();\r
3534                                         if ( tvp.loadAllCenters(passdt) ) {\r
3535                                                 for ( ProgList pl : tvp.getCenters() ) {\r
3536                                                         if ( ! pl.enabled ) {\r
3537                                                                 continue;\r
3538                                                         }\r
3539                                                         \r
3540                                                         for ( ProgDateList pcl : pl.pdate ) {\r
3541                                                                 for ( ProgDetailList tvd : pcl.pdetail ) {\r
3542                                                                         if ( tvd.start == null || tvd.start.length() == 0 ) {\r
3543                                                                                 continue;\r
3544                                                                         }\r
3545                                                                         \r
3546                                                                         if ( SearchProgram.isMatchKeyword(sKey, pl.Center, tvd) ) {\r
3547                                                                                 tvd.dynKey = sKey;\r
3548                                                                                 tvd.dynMatched = SearchProgram.getMatchedString();\r
3549                                                                                 fixDetailSub(tvp, pl, tvd);\r
3550                                                                                 srchpdl.add(tvd);\r
3551                                                                                 if ( ++resultCnt >= env.getSearchResultMax() ) {\r
3552                                                                                         mwin.appendMessage(String.format("[過去ログ検索] 検索件数の上限に到達しました。所要時間: %.2f秒",tc.end()));\r
3553                                                                                         return null;\r
3554                                                                                 }\r
3555                                                                         }\r
3556                                                                 }\r
3557                                                         }\r
3558                                                 }\r
3559                                         }\r
3560                                         \r
3561                                         e.add(Calendar.DATE,-1);\r
3562                                 }\r
3563 \r
3564                                 mwin.appendMessage(String.format("[過去ログ検索] 検索完了。所要時間: %.2f秒",tc.end()));\r
3565                                 return null;\r
3566                         }\r
3567                         \r
3568                         @Override\r
3569                         protected void doFinally() {\r
3570                                 StWinSetVisible(false);\r
3571                         }\r
3572                 }.execute();\r
3573                 \r
3574                 StWinSetLocationCenter(this);\r
3575                 StWinSetVisible(true);\r
3576 \r
3577                 return true;\r
3578         }\r
3579 \r
3580         \r
3581         /*******************************************************************************\r
3582          * スナップ・ショット!\r
3583          ******************************************************************************/\r
3584         \r
3585         /**\r
3586          * 番組表のスナップショットをファイルに保存したり印刷したりする\r
3587          */\r
3588         private boolean getSnapshot(int currentpage, int numberofpages) {\r
3589                 \r
3590                 try {\r
3591                         String fname;\r
3592                         if ( mainWindow.isTabSelected(MWinTab.LISTED) ) {\r
3593                                 // リスト形式\r
3594                                 fname = String.format("snapshot.%s",env.getSnapshotFmt().getExtension());\r
3595                                 CommonSwingUtils.saveComponentAsJPEG(listed.getCurrentView(), listed.getTableHeader(), null, listed.getTableBody(), fname, env.getSnapshotFmt(), Viewer.this);\r
3596                         }\r
3597                         else if ( mainWindow.isTabSelected(MWinTab.PAPER) ){\r
3598                                 // 新聞形式\r
3599                                 if ( env.getDrawcacheEnable() || ! env.isPagerEnabled() ) {\r
3600                                         fname = String.format("snapshot.%s",env.getSnapshotFmt().getExtension());\r
3601                                 }\r
3602                                 else {\r
3603                                         if ( env.getAllPageSnapshot() ) {\r
3604                                                 for ( int i=0; i<numberofpages; i++ ) {\r
3605                                                         if ( i != currentpage ) {\r
3606                                                                 // カレントページは最後にスナップる(再描画を1回で済ませるため)\r
3607                                                                 toolBar.setSelectedPagerIndex(i);\r
3608                                                                 fname = String.format("snapshot%02d.%s",i+1,env.getSnapshotFmt().getExtension());\r
3609                                                                 CommonSwingUtils.saveComponentAsJPEG(paper.getCurrentView(), paper.getCenterPane(), paper.getTimebarPane(), paper.getCurrentPane(), fname, env.getSnapshotFmt(), Viewer.this);\r
3610                                                         }\r
3611                                                 }\r
3612                                         }\r
3613                                         fname = String.format("snapshot%02d.%s",currentpage+1,env.getSnapshotFmt().getExtension());\r
3614                                         toolBar.setSelectedPagerIndex(currentpage);\r
3615                                 }\r
3616                                 CommonSwingUtils.saveComponentAsJPEG(paper.getCurrentView(), paper.getCenterPane(), paper.getTimebarPane(), paper.getCurrentPane(), fname, env.getSnapshotFmt(), Viewer.this);\r
3617                         }\r
3618                         else {\r
3619                                 // 他のタブ\r
3620                                 return true;\r
3621                         }\r
3622                         \r
3623                         Desktop desktop = Desktop.getDesktop();\r
3624                         if (env.getPrintSnapshot()) {\r
3625                                 // 印刷\r
3626                                 desktop.print(new File(fname));\r
3627                         }\r
3628                         else {\r
3629                                 // ファイルに保存\r
3630                                 String emsg = CommonUtils.openFile(fname);\r
3631                                 if (emsg != null) {\r
3632                                         mwin.appendError(emsg);\r
3633                                         return false;\r
3634                                 }\r
3635                         }\r
3636                         \r
3637                         return true;\r
3638                         \r
3639                 } catch (IOException e) {\r
3640                         e.printStackTrace();\r
3641                 }\r
3642                 \r
3643                 return false;\r
3644         }\r
3645         \r
3646         \r
3647         /*******************************************************************************\r
3648          * ここからおおむね初期化処理にかかわるメソッド群\r
3649          ******************************************************************************/\r
3650 \r
3651         /**\r
3652          * 各種設定の変更の反映\r
3653          */\r
3654         private boolean setEnv(final boolean reload_prog) {\r
3655                 \r
3656                 bounds.save();\r
3657                 cbitems.save();\r
3658                 env.save();\r
3659 \r
3660                 // CommonUtilsの設定変更\r
3661                 CommonUtils.setAdjLateNight(env.getAdjLateNight());\r
3662                 CommonUtils.setExpandTo8(env.getExpandTo8());\r
3663                 CommonUtils.setUseRundll32(env.getUseRundll32());\r
3664                 CommonUtils.setDisplayPassedReserve(env.getDisplayPassedReserve());\r
3665                 CommonUtils.setDebug(env.getDebug());\r
3666                 \r
3667                 SwingBackgroundWorker.setDebug(env.getDebug());\r
3668 \r
3669                 // ほにゃらら\r
3670                 toolBar.setDebug(env.getDebug());\r
3671                 autores.setDebug(env.getDebug());\r
3672                 rdialog.setDebug(env.getDebug());\r
3673 \r
3674                 // PassedProgramListの設定変更\r
3675                 tvprograms.getPassed().setPassedDir(env.getPassedDir());\r
3676 \r
3677                 // レコーダプラグインの設定変更\r
3678                 for ( HDDRecorder rec : recorders ) {\r
3679                         // 拡張設定だけ\r
3680                         setSettingRecPluginExt(rec, env);\r
3681                 }\r
3682 \r
3683                 // Web番組表共通設定\r
3684                 setSettingProgPluginCommon(env);\r
3685                 \r
3686                 // web番組表のリフレッシュ\r
3687                 setSettingProgPluginAll(env);\r
3688                 \r
3689                 // リロードメニューの書き換え\r
3690                 toolBar.updateReloadReservedExtension();\r
3691                 toolBar.updateReloadProgramExtension();\r
3692                 \r
3693                 // ページャーコンボボックスの書き換え\r
3694                 toolBar.setPagerItems();\r
3695                 \r
3696                 // 列の表示・非表示\r
3697                 listed.setMarkColumnVisible(env.getSplitMarkAndTitle());\r
3698                 listed.setDetailColumnVisible(env.getShowDetailOnList());\r
3699                 listed.setRowHeaderVisible(env.getRowHeaderVisible());\r
3700                 reserved.setRowHeaderVisible(env.getRowHeaderVisible());\r
3701                 \r
3702                 // 強調色\r
3703                 listed.setMatchedKeywordColor(env.getMatchedKeywordColor());\r
3704                 listed.setRsvdLineColor((env.getRsvdLineEnhance())?(env.getRsvdLineColor()):(null));\r
3705                 listed.setPickedLineColor((env.getRsvdLineEnhance())?(env.getPickedLineColor()):(null));\r
3706                 listed.setCurrentLineColor((env.getCurrentLineEnhance())?(env.getCurrentLineColor()):(null));\r
3707                 \r
3708                 // システムトレイアイコン\r
3709                 setTrayIconVisible(env.getShowSysTray());\r
3710                 setXButtonAction(env.getShowSysTray() && env.getHideToTray());\r
3711                 \r
3712                 // 新聞形式のツールチップの表示時間を変更する\r
3713                 setTooltipDelay();\r
3714                 \r
3715                 // 番組情報の再取得\r
3716                 if ( reload_prog ) {\r
3717                         loadTVProgram(false, LoadFor.ALL);      // 部品呼び出し\r
3718                 }\r
3719                 \r
3720                 // Web番組表の再構築\r
3721                 mpList.setHistoryOnlyUpdateOnce(env.getHistoryOnlyUpdateOnce());\r
3722                 mpList.setShowOnlyNonrepeated(env.getShowOnlyNonrepeated());\r
3723                 \r
3724                 doRedrawTVProgram();    // か き な お し\r
3725 \r
3726                 return true;\r
3727         }\r
3728         \r
3729         // システムトレイ関係\r
3730         private void getTrayIcon() {\r
3731                 if ( trayicon != null ) {\r
3732                         return;\r
3733                 }\r
3734                 \r
3735                 try {\r
3736                         Image image = ImageIO.read(new File(ICONFILE_SYSTRAY));\r
3737                         trayicon = new TrayIcon(image,"Tainavi");\r
3738                         \r
3739                         final Viewer thisClass = this;\r
3740                         \r
3741                         // メニューの追加\r
3742                         PopupMenu popup = new PopupMenu();\r
3743                         {\r
3744                                 MenuItem item = new MenuItem("開く");\r
3745                                 item.addActionListener(new ActionListener() {\r
3746                                         @Override\r
3747                                         public void actionPerformed(ActionEvent e) {\r
3748                                                 thisClass.setVisible(true);\r
3749                                                 thisClass.setState(Frame.NORMAL);\r
3750                                         }\r
3751                                 });\r
3752                                 popup.add(item);\r
3753                         }\r
3754                         {\r
3755                                 MenuItem item = new MenuItem("終了する");\r
3756                                 item.addActionListener(new ActionListener() {\r
3757                                         @Override\r
3758                                         public void actionPerformed(ActionEvent e) {\r
3759                                                 ExitOnClose();\r
3760                                                 System.exit(0);\r
3761                                         }\r
3762                                 });\r
3763                                 popup.add(item);\r
3764                         }\r
3765                         trayicon.setPopupMenu(popup);\r
3766                         \r
3767                         // 左クリックで復帰\r
3768                         trayicon.addMouseListener(new MouseAdapter() {\r
3769                                 //\r
3770                                 public void mouseClicked(MouseEvent e) {\r
3771                                         if (e.getButton() == MouseEvent.BUTTON1) {\r
3772                                                 thisClass.setVisible(true);\r
3773                                                 thisClass.setState(Frame.NORMAL);\r
3774                                         }\r
3775                                 }\r
3776                         });\r
3777                 \r
3778                 } catch (IOException e) {\r
3779                         StdAppendError("アイコンファイルが読み込めませんでした: "+ICONFILE_SYSTRAY);\r
3780                         e.printStackTrace();\r
3781                 }\r
3782         }\r
3783         private void setTrayIconVisible(boolean b) {\r
3784                 \r
3785                 if ( ! SystemTray.isSupported() || trayicon == null ) {\r
3786                         return;\r
3787                 }\r
3788                 \r
3789                 try {\r
3790                         if ( b ) {\r
3791                                 // システムトレイに追加\r
3792                                 SystemTray.getSystemTray().remove(trayicon);\r
3793                                 SystemTray.getSystemTray().add(trayicon);\r
3794                         }\r
3795                         else {\r
3796                                 // システムトレイから削除\r
3797                                 SystemTray.getSystemTray().remove(trayicon);\r
3798                         }\r
3799                 } catch (AWTException e) {\r
3800                         e.printStackTrace();\r
3801                 }\r
3802         }\r
3803         private void HideToTray() {\r
3804                 if ( SystemTray.isSupported() && trayicon != null && (env.getShowSysTray() && env.getHideToTray()) ) {\r
3805                         this.setVisible(false);\r
3806                 }\r
3807         }\r
3808         private void setXButtonAction(boolean b) {\r
3809                 if ( b ) {\r
3810                         this.setDefaultCloseOperation(JFrame.ICONIFIED);\r
3811                 }\r
3812                 else {\r
3813                         this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);\r
3814                 }\r
3815         }\r
3816         \r
3817         // コマンドライン引数の処理\r
3818         private void procArgs(String[] args) {\r
3819                 int flag = 0;\r
3820                 for (String arg : args) {\r
3821                         switch (flag) {\r
3822                         case 0:\r
3823                                 if (arg.compareTo("-L") == 0) {\r
3824                                         // -l : ロギング\r
3825                                         //logging = false;\r
3826                                 }\r
3827                                 else if (arg.compareTo("-L") == 0) {\r
3828                                         // -L : ロギング不可\r
3829                                         logging = false;\r
3830                                 }\r
3831                                 else if (arg.compareTo("-w") == 0) {\r
3832                                         // -w : レコーダ起動\r
3833                                         runRecWakeup = true;\r
3834                                 }\r
3835                                 else if (arg.compareTo("-nowebaccess") == 0) {\r
3836                                         // -nowebaccess : 起動時のWeb番組表へのアクセス無効\r
3837                                         enableWebAccess = false;\r
3838                                 }\r
3839                                 else if (arg.compareTo("-proxy") == 0) {\r
3840                                         // -proxy : Web番組表へのアクセスにProxy経由を強制する\r
3841                                         flag = 1;\r
3842                                 }\r
3843                                 else if (arg.compareTo("-loadrec") == 0) {\r
3844                                         // -loadrec : 起動時にレコーダにアクセスする\r
3845                                         runRecLoad = true;\r
3846                                 }\r
3847                                 else if (arg.compareTo("-onlyLoadProgram") == 0) {\r
3848                                         // -onlyLoadProgram : 番組表の取得だけ行う\r
3849                                         onlyLoadProgram = true;\r
3850                                 }\r
3851                                 break;\r
3852                         case 1:\r
3853                                 String[] dat = arg.split(":");\r
3854                                 if (dat.length == 1 ) {\r
3855                                         pxaddr = dat[0];\r
3856                                         pxport = "8080";\r
3857                                 } if (dat.length >= 2 ) {\r
3858                                         pxaddr = dat[0];\r
3859                                         pxport = dat[1];\r
3860                                 }\r
3861                                 flag = 0;\r
3862                                 break;\r
3863                         }\r
3864                 }\r
3865         }\r
3866         \r
3867         // メインの環境設定ファイルを読みだす\r
3868         private void loadEnvfile() {\r
3869                 StdAppendMessage("【環境設定】環境設定ファイルを読み込みます.");\r
3870                 env.load();\r
3871         }\r
3872         \r
3873         // 引き続きその他の環境設定ファイルも読みだす\r
3874         private void procEnvs() {\r
3875                 \r
3876                 StdAppendMessage("【環境設定】環境設定ファイル類を読み込みます.");\r
3877 \r
3878                 // 各種設定\r
3879                 env.makeEnvDir();\r
3880                 \r
3881                 // レコーダ一覧\r
3882                 recInfoList.load();\r
3883 \r
3884                 // Proxyサーバ\r
3885                 if (pxaddr != null) {\r
3886                         env.setUseProxy(true);\r
3887                         env.setProxyAddr(pxaddr);\r
3888                         env.setProxyPort(pxport);\r
3889                 }\r
3890                 \r
3891                 // Cookieの処理を入れようとしたけど無理だった\r
3892                 /*\r
3893                 {\r
3894                         CookieManager manager = new CookieManager();\r
3895                         manager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);\r
3896                         CookieHandler.setDefault(manager);\r
3897                 }\r
3898                 */\r
3899                 \r
3900                 // ジャンル別背景色\r
3901                 pColors.load();\r
3902                 \r
3903                 // 深夜の帯予約の補正(一日前にずらす)\r
3904                 // 可能なら番組表を8日分取得する\r
3905                 // 【WIN】ファイルオープンにrundll32を使用する\r
3906                 CommonUtils.setAdjLateNight(env.getAdjLateNight());\r
3907                 CommonUtils.setExpandTo8(env.getExpandTo8());\r
3908                 CommonUtils.setUseRundll32(env.getUseRundll32());\r
3909                 CommonUtils.setDisplayPassedReserve(env.getDisplayPassedReserve());\r
3910                 CommonUtils.setDebug(env.getDebug());\r
3911                 \r
3912                 SwingBackgroundWorker.setDebug(env.getDebug());\r
3913                 \r
3914                 // クリップボードアイテム\r
3915                 cbitems.load();\r
3916                 \r
3917                 // サイズ・位置情報取得\r
3918                 bounds.setLoaded(bounds.load());\r
3919                 \r
3920                 // 番組追跡キーワード取得\r
3921                 trKeys.load();\r
3922                 \r
3923                 // 検索キーワード取得\r
3924                 srKeys.load();\r
3925                 \r
3926                 // 検索キーワードグループ取得\r
3927                 srGrps.load();\r
3928                 \r
3929                 // 延長警告源設定取得\r
3930                 extKeys.load();\r
3931                 \r
3932                 // デフォルトAV設定取得\r
3933                 avs.load();\r
3934                 chavs.load();\r
3935 \r
3936                 // スポーツ延長警告のデフォルト設定のコードはもういらないので削除(3.15.4β) \r
3937                 \r
3938                 // 簡易描画はもういらないので削除\r
3939                 \r
3940                 // ChannelConvert\r
3941                 chconv.load();\r
3942         }\r
3943         \r
3944         // 二重起動チェック\r
3945         private void chkDualBoot() {\r
3946                 if ( ! env.getOnlyOneInstance() ) {\r
3947                         return;\r
3948                 }\r
3949                 \r
3950                 if ( ! CommonUtils.getLock() ) {\r
3951                         // 既にロックされている\r
3952                         ringBeep();\r
3953                         System.exit(1);\r
3954                 }\r
3955                 \r
3956                 Runtime.getRuntime().addShutdownHook(new Thread() {\r
3957                         public void run() {\r
3958                                 // 鯛ナビ終了時にロックを解除する\r
3959                                 CommonUtils.getUnlock();\r
3960                         }\r
3961                 });\r
3962         }\r
3963         \r
3964         // アップデートの有無チェック\r
3965         private void chkVerUp() {\r
3966                 if ( ! enableWebAccess || onlyLoadProgram ) {\r
3967                         stwin.appendError("【オンラインアップデート】オンラインアップデートは無効です");\r
3968                         return;\r
3969                 }\r
3970                 \r
3971                 VWUpdate vu = new VWUpdate(stwin);\r
3972                 if ( ! vu.isExpired(env.getUpdateMethod()) ) {\r
3973                         // メッセージはVWUpdate内で出力されます\r
3974                         return;\r
3975                 }\r
3976                 if ( doVerUp(vu) ) {\r
3977                         System.exit(0);\r
3978                 }\r
3979         }\r
3980         \r
3981         private boolean doVerUp(VWUpdate vu) {\r
3982                 UpdateResult res = vu.checkUpdate(VersionInfo.getVersion());\r
3983                 switch ( res ) {\r
3984                 case DONE:\r
3985                         // 成功\r
3986                         // 履歴は更新しない(連続アップデートがあるかも知れないので)\r
3987                         LogViewer lv = new LogViewer(HISTORY_FILE);\r
3988                         lv.setModal(true);\r
3989                         lv.setCaretPosition(0);\r
3990                         lv.setVisible(true);\r
3991                         return true;\r
3992                 case PASS:\r
3993                         // キャンセル\r
3994                         // 履歴は更新しない(次回に持ち越し)\r
3995                         break;\r
3996                 case NOUPDATE:\r
3997                         // アップデートなし\r
3998                         vu.updateHistory();\r
3999                         break;\r
4000                 default:\r
4001                         // 失敗\r
4002                         // 履歴は更新しない(次回再挑戦)\r
4003                         break;\r
4004                 }\r
4005                 return false;\r
4006         }\r
4007         \r
4008         /**\r
4009          *  レコーダプラグインをすべて読み込みます。\r
4010          */\r
4011         private boolean loadRecPlugins() {\r
4012                 \r
4013                 stwin.appendMessage("【レコーダプラグイン】プラグインを読み込みます.");\r
4014                 \r
4015                 boolean isMailPluginEnabled = false;\r
4016                 try {\r
4017                         Class.forName("javax.mail.Session");\r
4018                         isMailPluginEnabled = true;\r
4019                 }\r
4020                 catch ( Exception e ) {\r
4021                         System.err.println("【レコーダプラグイン】メール系プラグイン用の外部ライブラリがみつかりません: "+e.toString());\r
4022                 }\r
4023 \r
4024                 boolean isCalendarPluginEnabled = false;\r
4025                 try {\r
4026                         Class.forName("com.google.gdata.client.calendar.CalendarService");\r
4027                         isCalendarPluginEnabled = true;\r
4028                 }\r
4029                 catch ( Exception e ) {\r
4030                         System.err.println("【レコーダプラグイン】カレンダー系プラグイン用の外部ライブラリがみつかりません: "+e.toString());\r
4031                 }\r
4032                 \r
4033                 //\r
4034                 ArrayList<String> recIda = new ArrayList<String>();\r
4035                 for ( File f : new File(CommonUtils.joinPath(new String[]{"bin","tainavi"})).listFiles() ) {\r
4036                         Matcher ma = Pattern.compile("^(PlugIn_Rec[^$]+)[^$]*\\.class$").matcher(f.getName());\r
4037                         if ( ma.find() ) {\r
4038                                 if ( ! isMailPluginEnabled && f.getName().toLowerCase().contains("mail") ) {\r
4039                                         System.out.println("【レコーダプラグイン】メール系プラグインは無効です: "+f.getName());\r
4040                                         continue;\r
4041                                 }\r
4042                                 if ( ! isCalendarPluginEnabled && f.getName().toLowerCase().contains("calendar") ) {\r
4043                                         System.out.println("【レコーダプラグイン】カレンダー系プラグインは無効です: "+f.getName());\r
4044                                         continue;\r
4045                                 }\r
4046                                 \r
4047                                 recIda.add(ma.group(1));\r
4048                         }\r
4049                 }\r
4050                 String[] recIdd = recIda.toArray(new String[0]);\r
4051                 Arrays.sort(recIdd);\r
4052                 \r
4053                 // servicesに追記\r
4054                 StringBuilder sb = new StringBuilder();\r
4055                 for ( String recId : recIdd ) {\r
4056                         sb.append("tainavi.");\r
4057                         sb.append(recId);\r
4058                         sb.append("\n");\r
4059                 }\r
4060                 if ( ! CommonUtils.write2file(CommonUtils.joinPath(new String[] {"bin","META-INF","services","tainavi.HDDRecorder"}), sb.toString()) ) {\r
4061                         stwin.appendError("【レコーダプラグイン】プラグインの読み込みに失敗しました: ");\r
4062                         return false;\r
4063                 }\r
4064 \r
4065                 // ここで例外が起きてもトラップできない、スレッドが落ちる\r
4066                 ServiceLoader<HDDRecorder> r = ServiceLoader.load(HDDRecorder.class);\r
4067                 \r
4068                 recPlugins.clear();\r
4069                 for ( HDDRecorder recorder : r ) {\r
4070                         if (env.getDebug()) {\r
4071                                 StdAppendMessage("+追加します: "+recorder.getRecorderId());\r
4072                         }\r
4073                         recPlugins.add(recorder.clone());\r
4074                         StdAppendMessage("+追加しました: "+recorder.getRecorderId());\r
4075                 }\r
4076                 \r
4077                 return true;\r
4078         }\r
4079         \r
4080         /**\r
4081          * レコーダ設定をもとにレコーダプラグインから実レコーダのインスタンスを生成します。\r
4082          */\r
4083         private void initRecPluginAll() {\r
4084                 //\r
4085                 recorders.clear();\r
4086                 for ( RecorderInfo ri : recInfoList ) {\r
4087                         ArrayList<HDDRecorder> rl = recPlugins.findPlugin(ri.getRecorderId());\r
4088                         if ( rl.size() == 0 ) {\r
4089                                 stwin.appendError("【レコーダプラグイン】プラグインがみつかりません: "+ri.getRecorderId()+"("+ri.getRecorderIPAddr()+":"+ri.getRecorderPortNo()+")");\r
4090                         }\r
4091                         else { \r
4092                                 stwin.appendMessage("【レコーダプラグイン】プラグインを初期化します: "+ri.getRecorderId()+"("+ri.getRecorderIPAddr()+":"+ri.getRecorderPortNo()+")");\r
4093                                 for ( HDDRecorder rPlugin : rl ) {\r
4094                                         initRecPlugin(rPlugin, ri);\r
4095                                 }\r
4096                         }\r
4097                 }\r
4098         }\r
4099         protected HDDRecorder initRecPlugin(HDDRecorder rPlugin, RecorderInfo ri) {\r
4100                 HDDRecorder rec = rPlugin.clone();\r
4101                 recorders.add(rec);\r
4102                 \r
4103                 rec.getChCode().load(true);     // true : ログ出力あり\r
4104                 setSettingRecPluginBase(rec, ri);\r
4105                 setSettingRecPluginExt(rec,env);\r
4106                 rec.setProgressArea(stwin);\r
4107                 return rec;\r
4108         }\r
4109         protected void setSettingRecPluginBase(HDDRecorder to, RecorderInfo from) {\r
4110                 to.setIPAddr(from.getRecorderIPAddr());\r
4111                 to.setPortNo(from.getRecorderPortNo());\r
4112                 to.setUser(from.getRecorderUser());\r
4113                 to.setPasswd(from.getRecorderPasswd());\r
4114                 to.setMacAddr(from.getRecorderMacAddr());\r
4115                 to.setBroadcast(from.getRecorderBroadcast());\r
4116                 to.setUseCalendar(from.getUseCalendar());\r
4117                 to.setUseChChange(from.getUseChChange());\r
4118                 to.setRecordedCheckScope(from.getRecordedCheckScope());\r
4119                 to.setTunerNum(from.getTunerNum());\r
4120                 to.setColor(from.getRecorderColor());\r
4121         }\r
4122         protected void setSettingRecPluginExt(HDDRecorder recorder, Env nEnv) {\r
4123                 recorder.setUserAgent(nEnv.getUserAgent());\r
4124                 recorder.setDebug(nEnv.getDebug());\r
4125                 recorder.setAdjNotRep(nEnv.getAdjoiningNotRepetition());\r
4126                 recorder.setRecordedSaveScope(nEnv.getRecordedSaveScope());\r
4127         }\r
4128         \r
4129         //\r
4130         protected void doRecWakeup() {\r
4131                 for ( HDDRecorder rec : recorders ) {\r
4132                         if ( ! rec.getMacAddr().equals("") && ! rec.getBroadcast().equals("") ) {\r
4133                                 rec.wakeup();\r
4134                         }\r
4135                 }\r
4136         }\r
4137         \r
4138         /**\r
4139          * 一時間は再実行させないんだ\r
4140          */\r
4141         private boolean isOLPExpired(int expire) {\r
4142                 String fname = "env"+File.separator+"olp.history";\r
4143                 if ( ! new File(fname).exists() || ! new File(fname).canWrite() ) {\r
4144                         stwin.appendError("【警告】実行履歴ファイルがないから実行させないよ!");\r
4145                         ringBeep();\r
4146                         return false;\r
4147                 }\r
4148                 String dat = CommonUtils.read4file(fname, true);\r
4149                 if ( dat == null ) {\r
4150                         stwin.appendError("【警告】実行履歴を取得できなかったから実行させないよ!");\r
4151                         ringBeep();\r
4152                         return false;\r
4153                 }\r
4154                 GregorianCalendar ca = null;\r
4155                 dat = EncryptPassword.dec(b64.dec(dat));\r
4156                 if ( dat != null ) {\r
4157                         ca = CommonUtils.getCalendar(dat);\r
4158                 }\r
4159                 if ( ca == null ) {\r
4160                         stwin.appendError("【警告】実行履歴の内容が不正だったから実行させないよ! "+dat);\r
4161                         ringBeep();\r
4162                         return false;\r
4163                 }\r
4164                 if ( CommonUtils.getCompareDateTime(ca, CommonUtils.getCalendar(-expire*3600)) >= 0 ) {\r
4165                         ca.add(Calendar.HOUR,expire);\r
4166                         stwin.appendError("【警告】"+expire+"時間以内の再実行は許さないよ!"+CommonUtils.getDateTime(ca)+"まで待って!");\r
4167                         ringBeep();\r
4168                         return false;\r
4169                 }\r
4170                 if ( ! CommonUtils.write2file(fname, b64.enc(EncryptPassword.enc(CommonUtils.getDateTime(0)))) ) {\r
4171                         stwin.appendError("【警告】実行履歴を保存できなかったから実行させないよ!");\r
4172                         ringBeep();\r
4173                         return false;\r
4174                 }\r
4175                 \r
4176                 return true;\r
4177         }\r
4178         \r
4179         /**\r
4180          *  Web番組表プラグインをすべて読み込みます。\r
4181          */\r
4182         private boolean loadProgPlugins() {\r
4183         \r
4184                 final String FUNCID = "[Web番組表プラグイン組込] ";\r
4185                 final String ERRID = "[ERROR]"+FUNCID;\r
4186                 \r
4187                 // Web番組表プラグインの処理\r
4188                 stwin.appendMessage(FUNCID+"プラグインを読み込みます.");\r
4189                 \r
4190                 // Web番組表共通設定\r
4191                 setSettingProgPluginCommon(env);\r
4192                 \r
4193                 /*\r
4194                  * 重要 - ここから\r
4195                  */\r
4196                 \r
4197                 // TVProgramListのインスタンスは別途初期化が必要\r
4198                 progPlugins.clear();\r
4199                 tvprograms.clear();\r
4200 \r
4201                 /*\r
4202                  * 重要 - ここまで\r
4203                  */\r
4204 \r
4205                 ArrayList<String> prgIda = new ArrayList<String>();\r
4206                 for ( File f : new File(CommonUtils.joinPath("bin","tainavi")).listFiles() ) {\r
4207                         Matcher ma = Pattern.compile("^(PlugIn_(TV|CS|RAD)P[^$]+)\\.class$").matcher(f.getName());\r
4208                         if (ma.find()) {\r
4209                                 prgIda.add(ma.group(1));\r
4210                         }\r
4211                 }\r
4212                 String[] prgIdd = prgIda.toArray(new String[0]);\r
4213                 Arrays.sort(prgIdd);\r
4214                 \r
4215                 // servicesに追記\r
4216                 StringBuilder sb = new StringBuilder();\r
4217                 for ( String prgId : prgIdd ) {\r
4218                         sb.append("tainavi.");\r
4219                         sb.append(prgId);\r
4220                         sb.append("\n");\r
4221                 }\r
4222                 if ( ! CommonUtils.write2file(CommonUtils.joinPath("bin","META-INF","services","tainavi.TVProgram"), sb.toString()) ) {\r
4223                         stwin.appendError(ERRID+"プラグインの読み込みに失敗しました: ");\r
4224                         return false;\r
4225                 }\r
4226                 \r
4227                 ServiceLoader<TVProgram> p = ServiceLoader.load(TVProgram.class);\r
4228 \r
4229                 // 実際必要ないのだが、プラグインのインスタンスはclone()して使う\r
4230                 for ( TVProgram pg : p ) {\r
4231                         TVProgram prog = pg.clone();\r
4232                         \r
4233                         stwin.appendMessage("+追加しました: "+prog.getTVProgramId());\r
4234                         \r
4235                         // CH設定タブではプラグイン側のインスタンスを使うので情報を追加してやる必要があるのであった\r
4236                         setSettingProgPlugin(prog, env);\r
4237                         \r
4238                         progPlugins.add(prog);\r
4239                 }\r
4240                 \r
4241                 p = null;\r
4242                 \r
4243                 return true;\r
4244         }\r
4245         \r
4246         /**\r
4247          *  設定にあわせてWeb番組表プラグインを絞り込みます。\r
4248          */\r
4249         private void setSelectedProgPlugin() {\r
4250                 \r
4251                 // この3つは保存しておく\r
4252                 Syobocal syobo = tvprograms.getSyobo();\r
4253                 PassedProgram passed = tvprograms.getPassed();\r
4254                 PickedProgram pickup = tvprograms.getPickup();\r
4255                 SearchResult searched = tvprograms.getSearched();\r
4256                 \r
4257                 tvprograms.clear();\r
4258                 \r
4259                 {\r
4260                         TVProgram tvp = progPlugins.getTvProgPlugin(env.getTVProgramSite());\r
4261                         if ( tvp == null ) {\r
4262                                 // デフォルトもなければ先頭にあるもの\r
4263                                 tvp = progPlugins.getTvProgPlugin(null);\r
4264                         }\r
4265                         if ( tvp == null ) {\r
4266                                 // てか一個もなくね?\r
4267                                 StdAppendError("【Web番組表選択】地上波&BS番組表が選択されていません: "+env.getTVProgramSite());\r
4268                         }\r
4269                         else {\r
4270                                 StdAppendMessage("【Web番組表選択】地上波&BS番組表が選択されました: "+tvp.getTVProgramId());\r
4271                                 tvprograms.add(tvp.clone());\r
4272                         }\r
4273                 }\r
4274                 {\r
4275                         TVProgram tvp = progPlugins.getCsProgPlugin(env.getCSProgramSite());\r
4276                         if ( tvp == null ) {\r
4277                                 tvp = progPlugins.getCsProgPlugin(null);\r
4278                         }\r
4279                         if ( tvp == null ) {\r
4280                                 StdAppendError("【Web番組表選択】CS番組表[プライマリ]が選択されていません: "+env.getCSProgramSite());\r
4281                         }\r
4282                         else {\r
4283                                 StdAppendMessage("【Web番組表選択】CS番組表[プライマリ]が選択されました: "+tvp.getTVProgramId());\r
4284                                 tvprograms.add(tvp.clone());\r
4285                         }\r
4286                 }\r
4287                 {\r
4288                         TVProgram tvp = progPlugins.getCs2ProgPlugin(env.getCS2ProgramSite());\r
4289                         if ( tvp == null ) {\r
4290                                 tvp = progPlugins.getCs2ProgPlugin(null);\r
4291                         }\r
4292                         if ( tvp == null ) {\r
4293                                 StdAppendError("【Web番組表選択】CS番組表[プライマリ]が選択されていません: "+env.getCS2ProgramSite());\r
4294                         }\r
4295                         else {\r
4296                                 StdAppendMessage("【Web番組表選択】CS番組表[プライマリ]が選択されました: "+tvp.getTVProgramId());\r
4297                                 tvprograms.add(tvp.clone());\r
4298                         }\r
4299                 }\r
4300                 /*\r
4301                 if ( progPlugins.getRadioProgPlugins().size() > 0 )\r
4302                 {\r
4303                         TVProgram tvp = progPlugins.getCsProgPlugin(env.getRadioProgramSite());\r
4304                         if ( tvp == null ) {\r
4305                                 tvp = progPlugins.getCsProgPlugin(null);\r
4306                         }\r
4307                         if ( tvp == null ) {\r
4308                                 StdAppendError("【Web番組表選択】ラジオ番組表が選択されていません: "+env.getRadioProgramSite());\r
4309                         }\r
4310                         else {\r
4311                                 StdAppendMessage("【Web番組表選択】ラジオ番組表が選択されました: "+tvp.getTVProgramId());\r
4312                                 tvprograms.add(tvp.clone());\r
4313                         }\r
4314                 }\r
4315                 */\r
4316                 \r
4317                 {\r
4318                         if ( syobo == null ) {\r
4319                                 syobo = new Syobocal();\r
4320                         }\r
4321                         tvprograms.add(syobo);\r
4322                 }\r
4323                 {\r
4324                         if ( passed == null ) {\r
4325                                 passed = new PassedProgram();\r
4326                         }\r
4327                         tvprograms.add(passed);\r
4328                 }\r
4329                 {\r
4330                         if ( pickup == null ) {\r
4331                                 pickup = new PickedProgram();\r
4332                                 pickup.loadProgram(null, false);\r
4333                         }\r
4334                         tvprograms.add(pickup);\r
4335                 }\r
4336                 {\r
4337                         if ( searched == null ) {\r
4338                                 searched = new SearchResult();\r
4339                         }\r
4340                         tvprograms.add(searched);\r
4341                 }\r
4342         }\r
4343         \r
4344         /**\r
4345          * Web番組表設定をもとにレコーダプラグインのインスタンスを生成します。\r
4346          */\r
4347         private void initProgPluginAll() {\r
4348 \r
4349                 final String FUNCID = "[Web番組表プラグイン初期化] ";\r
4350                 final LinkedHashMap<ArrayList<TVProgram>,String> map = new LinkedHashMap<ArrayList<TVProgram>, String>();\r
4351                 map.put(tvprograms.getTvProgPlugins(), "地上波&BS番組表");\r
4352                 map.put(tvprograms.getCsProgPlugins(), "CS番組表[プライマリ]");\r
4353                 map.put(tvprograms.getCs2ProgPlugins(), "CS番組表[セカンダリ]");\r
4354                 //map.put(progPlugins.getRadioProgPlugins(), "ラジオ番組表");\r
4355                 \r
4356                 new SwingBackgroundWorker(true) {\r
4357                         \r
4358                         @Override\r
4359                         protected Object doWorks() throws Exception {\r
4360 \r
4361                                 for ( ArrayList<TVProgram> tvpa : map.keySet() ) {\r
4362                                         stwin.appendMessage(FUNCID+map.get(tvpa)+"のベース情報(放送局リストなど)を取得します.");\r
4363                                         for ( TVProgram p : tvpa ) {\r
4364                                                 stwin.appendMessage(FUNCID+"プラグインを初期化します: "+p.getTVProgramId());\r
4365                                                 \r
4366                                                 try {\r
4367                                                         // 個別設定(2) …(1)と(2)の順番が逆だったので前に移動してきました(3.17.3β)\r
4368                                                         setSettingProgPlugin(p,env);                            // 他からも呼び出される部分だけ分離\r
4369                                                         \r
4370                                                         // 個別設定(1)\r
4371                                                         p.setOptString(null);                                           // フリーオプション初期化\r
4372                                                         p.loadAreaCode();                                                       // 放送エリア情報取得\r
4373                                                         p.loadCenter(p.getSelectedCode(),false);        // 放送局情報取得\r
4374                                                         p.setSortedCRlist();                                            // 有効放送局だけよりわける\r
4375                                                 }\r
4376                                                 catch (Exception e) {\r
4377                                                         stwin.appendError(FUNCID+"ベース情報の取得に失敗しました.");\r
4378                                                         e.printStackTrace();\r
4379                                                 }\r
4380                                         }\r
4381                                 }\r
4382                                 \r
4383                                 // 共通設定部分の一斉更新\r
4384                                 //setSettingProgPluginAll(env);\r
4385                                 \r
4386                                 if ( env.getUseSyobocal() ) {\r
4387                                         TVProgram syobo = tvprograms.getSyobo();\r
4388                                         if ( syobo != null ) {\r
4389                                                 stwin.appendMessage(FUNCID+"しょぼかるを初期化します.");\r
4390                                                 setSettingProgPlugin(syobo,env);                                // 他からも呼び出される部分だけ分離\r
4391                                                 syobo.setUserAgent("tainavi");\r
4392                                                 syobo.setOptString(null);                                               // フリーオプション初期化\r
4393                                                 syobo.loadCenter(syobo.getSelectedCode(), false);\r
4394                                         }\r
4395                                 }\r
4396                                 \r
4397                                 return null;\r
4398                         }\r
4399                         \r
4400                         @Override\r
4401                         protected void doFinally() {\r
4402                         }\r
4403                 }.execute();\r
4404         }\r
4405         protected void setSettingProgPluginAll(Env nEnv) {\r
4406                 // 通常\r
4407                 setSettingProgPlugin(tvprograms.getTvProgPlugin(null),nEnv);\r
4408                 setSettingProgPlugin(tvprograms.getCsProgPlugin(null),nEnv);\r
4409                 setSettingProgPlugin(tvprograms.getCs2ProgPlugin(null),nEnv);\r
4410                 //setSettingProgPlugin(tvprograms.getRadioProgPlugin(null),nEnv);\r
4411                 setSettingProgPlugin(tvprograms.getSyobo(),nEnv);\r
4412                 \r
4413                 // しょぼかるは特殊\r
4414                 tvprograms.getSyobo().setUserAgent("tainavi");\r
4415                 // 検索結果も特殊\r
4416                 tvprograms.getSearched().setResultBufferMax(nEnv.getSearchResultBufferMax());\r
4417         }\r
4418         protected void setSettingProgPlugin(TVProgram p, Env nEnv) {\r
4419                 if ( p == null ) {\r
4420                         return;\r
4421                 }               \r
4422                 p.setUserAgent(nEnv.getUserAgent());\r
4423                 p.setProgDir(nEnv.getProgDir());\r
4424                 p.setCacheExpired((enableWebAccess)?(nEnv.getCacheTimeLimit()):(0));\r
4425                 p.setContinueTomorrow(nEnv.getContinueTomorrow());\r
4426                 p.setExpandTo8(nEnv.getExpandTo8());\r
4427                 //p.setUseDetailCache(nEnv.getUseDetailCache());\r
4428                 p.setUseDetailCache(false);\r
4429                 p.setSplitEpno(nEnv.getSplitEpno());\r
4430         }\r
4431         \r
4432         /**\r
4433          * staticで持っている共通設定の更新\r
4434          */\r
4435         protected void setSettingProgPluginCommon(Env nEnv) {\r
4436                 \r
4437                 if ( nEnv.getUseProxy() && (nEnv.getProxyAddr().length() > 0 && nEnv.getProxyPort().length() > 0) ) {\r
4438                         stwin.appendMessage("+Web番組表へのアクセスにProxyが設定されています: "+nEnv.getProxyAddr()+":"+nEnv.getProxyPort());\r
4439                         TVProgramUtils.setProxy(nEnv.getProxyAddr(),nEnv.getProxyPort());\r
4440                 }\r
4441                 else {\r
4442                         TVProgramUtils.setProxy(null,null);\r
4443                 }\r
4444                 \r
4445                 TVProgramUtils.setProgressArea(stwin);\r
4446                 TVProgramUtils.setChConv(chconv);\r
4447         }\r
4448         \r
4449         //\r
4450         private void initMpList() {\r
4451                 //mpList = new MarkedProgramList();                     // 検索結果リスト\r
4452                 mpList.setHistoryOnlyUpdateOnce(env.getHistoryOnlyUpdateOnce());\r
4453                 mpList.setShowOnlyNonrepeated(env.getShowOnlyNonrepeated());\r
4454         }\r
4455         \r
4456         // L&FとFontを設定\r
4457         private void initLookAndFeelAndFont() {\r
4458 \r
4459                 try {\r
4460                         {\r
4461                                 vwlaf = new VWLookAndFeel();\r
4462                                 \r
4463                                 String lafname = vwlaf.update(env.getLookAndFeel());\r
4464                                 if ( lafname != null && ! lafname.equals(env.getLookAndFeel())) {\r
4465                                         env.setLookAndFeel(lafname);\r
4466                                 }\r
4467                                 \r
4468                                 if ( CommonUtils.isMac() ) {\r
4469                                         UIManager.getDefaults().put("Table.gridColor", new Color(128,128,128));\r
4470                                         //UIManager.getDefaults().put("Table.selectionBackground", new Color(182,207,229));\r
4471                                         //UIManager.getDefaults().put("Table.selectionForeground", new Color(0,0,0));\r
4472                                 }\r
4473                         }\r
4474                         \r
4475                         {\r
4476                                 vwfont = new VWFont();\r
4477                                 \r
4478                                 String fname = vwfont.update(env.getFontName(),env.getFontSize());\r
4479                                 if ( fname != null && ! fname.equals(env.getFontName())) {\r
4480                                         env.setFontName(fname);\r
4481                                 }\r
4482                         }\r
4483                 }\r
4484                 catch ( Exception e ) {\r
4485                         // 落ちられると困るからトラップしておこうぜ\r
4486                         e.printStackTrace();\r
4487                 }\r
4488         }\r
4489         \r
4490         // L&FやFontを変えたらコンポーネントに通知が必要\r
4491         protected void updateComponentTreeUI() {\r
4492                 try {\r
4493                         SwingUtilities.updateComponentTreeUI(this);\r
4494                         SwingUtilities.updateComponentTreeUI(stwin);\r
4495                         SwingUtilities.updateComponentTreeUI(mwin);\r
4496                         SwingUtilities.updateComponentTreeUI(pcwin);\r
4497                         SwingUtilities.updateComponentTreeUI(rdialog);\r
4498                         SwingUtilities.updateComponentTreeUI(ccwin);\r
4499                 }\r
4500                 catch ( Exception e ) {\r
4501                         // 落ちられると困るからトラップしておこうぜ\r
4502                         e.printStackTrace();\r
4503                 }\r
4504         }\r
4505 \r
4506         // ツールチップの表示遅延時間を設定する\r
4507         private void setTooltipDelay() {\r
4508                 ToolTipManager tp = ToolTipManager.sharedInstance();\r
4509                 tp.setInitialDelay(env.getTooltipInitialDelay()*100);\r
4510                 tp.setDismissDelay(env.getTooltipDismissDelay()*100);\r
4511         }\r
4512         \r
4513         /**\r
4514          * \r
4515          * @return true:前回終了時の設定がある場合\r
4516          */\r
4517         private boolean buildMainWindow() {\r
4518                 \r
4519                 // コンポーネント作成\r
4520                 {\r
4521                         // メインウィンドウの作成\r
4522                         mainWindow = new VWMainWindow();\r
4523                 \r
4524                         // 内部クラスのインスタンス生成\r
4525                         toolBar = new VWToolBar();\r
4526                         listed = new VWListedView();\r
4527                         paper = new VWPaperView();\r
4528                         reserved = new VWReserveListView();\r
4529                         recorded = new VWRecordedListView();\r
4530                         autores = new VWAutoReserveListView();\r
4531                         setting = new VWSettingView();\r
4532                         recsetting = new VWRecorderSettingView();\r
4533                         chsetting = new VWChannelSettingView();\r
4534                         chdatsetting = new VWChannelDatSettingView();\r
4535                         chsortsetting = new VWChannelSortView();\r
4536                         chconvsetting = new VWChannelConvertView();\r
4537                 }\r
4538                 \r
4539                 // 初期値\r
4540                 {\r
4541                         // 設定\r
4542                         toolBar.setDebug(env.getDebug());\r
4543                         autores.setDebug(env.getDebug());\r
4544                         rdialog.setDebug(env.getDebug());\r
4545         \r
4546                         // ページャーの設定\r
4547                         toolBar.setPagerItems();\r
4548                 }\r
4549                 \r
4550                 // コンポーネントの組み立て\r
4551                 {\r
4552                         // ツールバーなど\r
4553                         mainWindow.addToolBar(toolBar);\r
4554                         mainWindow.addStatusArea(mwin);\r
4555                         \r
4556                         // タブ群\r
4557                         mainWindow.addTab(listed, MWinTab.LISTED);\r
4558                         mainWindow.addTab(paper, MWinTab.PAPER);\r
4559                         mainWindow.addTab(reserved, MWinTab.RSVED);\r
4560                         mainWindow.addTab(recorded, MWinTab.RECED);\r
4561                         mainWindow.addTab(autores, MWinTab.AUTORES);\r
4562                         mainWindow.addTab(setting, MWinTab.SETTING);\r
4563                         mainWindow.addTab(recsetting, MWinTab.RECSET);\r
4564                         mainWindow.addTab(chsetting, MWinTab.CHSET);\r
4565                         mainWindow.addTab(chsortsetting, MWinTab.CHSORT);\r
4566                         mainWindow.addTab(chconvsetting, MWinTab.CHCONV);\r
4567                         mainWindow.addTab(chdatsetting, MWinTab.CHDAT);\r
4568                 }\r
4569                 \r
4570                 // ステータスエリアを開く\r
4571                 setStatusVisible(bounds.getShowStatus());\r
4572                 \r
4573                 //新聞描画枠のリセット\r
4574                 paper.clearPanel();\r
4575                 paper.buildMainViewByDate();\r
4576                 \r
4577                 return true;\r
4578         }\r
4579         \r
4580         private void ShowInitTab() {\r
4581                 \r
4582                 // いったん無選択状態にしてから\r
4583                 mainWindow.setSelectedTab(null);\r
4584                 \r
4585                 if ( recInfoList.size() <= 0 ) {\r
4586                         // 設定が存在しない場合\r
4587                         mainWindow.setSelectedTab(MWinTab.RECSET);\r
4588                 }\r
4589                 else {\r
4590                         // 設定が存在する場合\r
4591                         MWinTab tab = MWinTab.getAt(bounds.getSelectedTab());\r
4592                         mainWindow.setSelectedTab(tab);\r
4593                 }\r
4594         }\r
4595         \r
4596         //\r
4597         private void setInitBounds() {\r
4598                 // ウィンドウのサイズと表示位置を設定する\r
4599                 Rectangle window = bounds.getWinRectangle();\r
4600                 if (bounds.isLoaded()) {\r
4601                         // 設定ファイルを読み込んであったらそれを設定する\r
4602                         System.out.println(DBGID+"set bounds "+window);\r
4603                         this.setBounds(window.x, window.y, window.width, window.height);\r
4604                 }\r
4605                 else {\r
4606                         // 設定ファイルがなければ自動設定する\r
4607                         Rectangle screen = this.getGraphicsConfiguration().getBounds();\r
4608                         int x = 0;\r
4609                         int w = window.width;\r
4610                         if (window.width > screen.width) {\r
4611                                 x = 0;\r
4612                                 w = screen.width;\r
4613                         }\r
4614                         else {\r
4615                                 x = (screen.width - window.width)/2;\r
4616                         }\r
4617                         int y = 0;\r
4618                         int h = window.height;\r
4619                         if (window.height > screen.height) {\r
4620                                 y = 0;\r
4621                                 h = screen.height;\r
4622                         }\r
4623                         else {\r
4624                                 y = (screen.height - window.height)/2;\r
4625                         }\r
4626                         this.setBounds(x, y, w, h);\r
4627                 }\r
4628         }\r
4629 \r
4630         /**\r
4631          * <P>ステータスエリアを隠す\r
4632          * {@link VWMainWindow#setStatusVisible(boolean)}の置き換え\r
4633          */\r
4634         private void setStatusVisible(boolean b) {\r
4635                 \r
4636                 if (b) {\r
4637                         listed.setDetailVisible(true);\r
4638                         paper.setDetailVisible(true);\r
4639                         MWinSetVisible(true);\r
4640                 }\r
4641                 else {\r
4642                         listed.setDetailVisible(false);\r
4643                         paper.setDetailVisible(false);\r
4644                         MWinSetVisible(false);\r
4645                 }\r
4646         }\r
4647         \r
4648         // フルスクリーンモードをトグル切り替え\r
4649         private Dimension f_dim;\r
4650         private Point f_pnt;\r
4651         private int divloc_l = 0;\r
4652         private int divloc_p = 0;\r
4653         \r
4654         private void setFullScreen(boolean b) {\r
4655                 \r
4656                 if ( b == true ) {\r
4657                         // 枠の撤去\r
4658                         this.dispose();\r
4659                         this.setUndecorated(true);\r
4660                         this.setVisible(true);\r
4661                         \r
4662                         //全画面表示へ\r
4663                         Toolkit tk = getToolkit();\r
4664                         Insets in = tk.getScreenInsets(getGraphicsConfiguration());\r
4665                         Dimension d = tk.getScreenSize();\r
4666                         f_dim = this.getSize();\r
4667                         f_pnt = this.getLocation();\r
4668                         this.setBounds(in.left, in.top, d.width-(in.left+in.right), d.height-(in.top+in.bottom));\r
4669                         \r
4670                         divloc_l = bounds.getTreeWidth();\r
4671                         divloc_p = bounds.getTreeWidthPaper();\r
4672                         \r
4673                         // ツリーを閉じる\r
4674                         paper.setCollapseTree();\r
4675                         listed.setCollapseTree();\r
4676                 }\r
4677                 else {\r
4678                         if ( f_pnt != null && f_dim != null ) { // 起動直後などは値がないですしね\r
4679                                 \r
4680                                 // 枠の復帰\r
4681                                 this.dispose();\r
4682                                 this.setUndecorated(false);\r
4683                                 this.setVisible(true);\r
4684                                 \r
4685                                 //全画面表示終了\r
4686                                 this.setBounds(f_pnt.x, f_pnt.y, f_dim.width, f_dim.height);\r
4687                                 \r
4688                                 bounds.setTreeWidth(divloc_l);\r
4689                                 bounds.setTreeWidthPaper(divloc_p);\r
4690                                 \r
4691                                 // ツリーの幅を元に戻す\r
4692                                 paper.setExpandTree();\r
4693                                 listed.setExpandTree();\r
4694                         }\r
4695                 }\r
4696         }\r
4697         \r
4698         // タイトルバー\r
4699         private void setTitleBar() {\r
4700                 MemoryMXBean mbean = ManagementFactory.getMemoryMXBean();\r
4701                 MemoryUsage heapUsage = mbean.getHeapMemoryUsage();\r
4702                 \r
4703                 this.setTitle(\r
4704                                 String.format(\r
4705                                                 "%s - %s - Memory Usage Max:%dM Committed:%dM Used:%dM - FrameBuffer Status:%s",\r
4706                                                 VersionInfo.getVersion(),\r
4707                                                 CommonUtils.getDateTime(0),\r
4708                                                 heapUsage.getMax()/(1024*1024),\r
4709                                                 heapUsage.getCommitted()/(1024*1024),\r
4710                                                 heapUsage.getUsed()/(1024*1024),\r
4711                                                 (paper!=null)?(paper.getFrameBufferStatus()):("N/A")\r
4712                                 )\r
4713                 );\r
4714         }\r
4715         \r
4716         // 終了処理関連\r
4717         private void ExitOnClose() {\r
4718                 // 座標・サイズ\r
4719                 if ( ! this.toolBar.isFullScreen()) {\r
4720                         Rectangle r = this.getBounds();\r
4721                         bounds.setWinRectangle(r);\r
4722                 }\r
4723                 else {\r
4724                         Rectangle r = new Rectangle();\r
4725                         r.x = this.f_pnt.x;\r
4726                         r.y = this.f_pnt.y;\r
4727                         r.width = this.f_dim.width;\r
4728                         r.height = this.f_dim.height;\r
4729                         bounds.setWinRectangle(r);\r
4730                 }\r
4731                 listed.copyColumnWidth();\r
4732                 reserved.copyColumnWidth();\r
4733                 \r
4734                 bounds.setStatusRows(mwin.getRows());\r
4735 \r
4736                 // 動作状態\r
4737                 bounds.setSelectedTab(mainWindow.getSelectedTab().getIndex());\r
4738                 bounds.setShowSettingTabs(mainWindow.getShowSettingTabs());\r
4739                 bounds.setSelectedRecorderId(toolBar.getSelectedRecorder());\r
4740                 bounds.setShowStatus(toolBar.isStatusShown());\r
4741                 \r
4742                 // 保存する\r
4743                 bounds.save();\r
4744                 \r
4745                 // ツリーの展開状態の保存\r
4746                 listed.saveTreeExpansion();\r
4747                 paper.saveTreeExpansion();\r
4748         }\r
4749         \r
4750 \r
4751         /*******************************************************************************\r
4752          * main()\r
4753          ******************************************************************************/\r
4754         \r
4755         // 初期化が完了したら立てる\r
4756         private static boolean initialized = false;\r
4757         private static Viewer myClass = null;\r
4758         \r
4759         /**\r
4760          * めいーん\r
4761          * @param args\r
4762          * @throws NoSuchAlgorithmException\r
4763          * @version 今まで初期化を行ってからウィンドウを作成していたが<BR>\r
4764          * 途中で例外が起こるとダンマリの上にゾンビになってたりとヒドかったので<BR>\r
4765          * 先にウィンドウを作成してから初期化を行うように変えました\r
4766          * @throws InterruptedException \r
4767          * @throws InvocationTargetException \r
4768          */\r
4769         public static void main(final String[] args) throws NoSuchAlgorithmException, InvocationTargetException, InterruptedException {\r
4770                 \r
4771                 if ( myClass != null ) {\r
4772                         // 既に起動していたらフォアグラウンドにする\r
4773                         SwingUtilities.invokeAndWait(new Runnable() {\r
4774                                 @Override\r
4775                                 public void run() {\r
4776                                         // うーん、いいのかこのコード?\r
4777                                         myClass.setVisible(true);\r
4778                                         myClass.setState(Frame.NORMAL);\r
4779                                 }\r
4780                         });\r
4781                         return;\r
4782                 }\r
4783                 \r
4784                 SwingUtilities.invokeLater(new Runnable() {\r
4785                         public void run() {\r
4786                                 \r
4787                                 final Viewer thisClass = myClass = new Viewer(args);\r
4788                                 \r
4789                                 thisClass.addComponentListener(new ComponentAdapter() {\r
4790                                         @Override\r
4791                                         public void componentShown(ComponentEvent e) {\r
4792                                                 \r
4793                                                 // 一回実行したらもういらないよ\r
4794                                                 thisClass.removeComponentListener(this);\r
4795                                                 \r
4796                                                 // 初期化するよ\r
4797                                                 thisClass.initialize(args);\r
4798                                                 \r
4799                                         }\r
4800                                 });\r
4801                                 \r
4802                                 thisClass.setVisible(true);\r
4803                         }\r
4804                 });\r
4805         }\r
4806 \r
4807         \r
4808         \r
4809         /*******************************************************************************\r
4810          * コンストラクタ\r
4811          ******************************************************************************/\r
4812 \r
4813         /**\r
4814          * デフォルトコンストラクタ\r
4815          */\r
4816         public Viewer(final String[] args) {\r
4817                 \r
4818                 super();\r
4819                 \r
4820                 env.loadText();\r
4821                 bounds.loadText();\r
4822                 \r
4823                 \r
4824                 // 初期化が終わるまでは閉じられないよ → どうせステータスウィンドウにブロックされて操作できない\r
4825                 //setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);\r
4826                 //setResizable(false);\r
4827                 \r
4828                 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);\r
4829                 \r
4830                 setTitleBar();\r
4831                 \r
4832                 try {\r
4833                         Image image = ImageIO.read(new File(ICONFILE_TAINAVI));\r
4834                         setIconImage(image);\r
4835                 }\r
4836                 catch (IOException e) {\r
4837                         StdAppendError("[ERROR] アイコンが設定できない: "+e.toString());\r
4838                 }\r
4839                 \r
4840                 JLabel jLabel_splash_img = new JLabel(new ImageIcon("splash.gif"));\r
4841                 jLabel_splash_img.setPreferredSize(new Dimension(400,300));\r
4842                 //getContentPane().setLayout(new BorderLayout());\r
4843                 getContentPane().add(jLabel_splash_img, BorderLayout.CENTER);\r
4844                 pack();\r
4845                 \r
4846                 setLocationRelativeTo(null);    // 画面の真ん中に\r
4847                 \r
4848                 // SwingLocker共有設定\r
4849                 SwingLocker.setOwner(this);\r
4850                 \r
4851                 // とりあえずルックアンドフィールはリセットしておかないとだめっぽいよ\r
4852                 initLookAndFeelAndFont();\r
4853                 updateComponentTreeUI();\r
4854         }\r
4855         \r
4856         // 初期化をバックグラウンドで行う\r
4857         private void initialize(final String[] args) {\r
4858                 \r
4859                 StWinClear();\r
4860                 \r
4861                 // 初期化処理はバックグラウンドで行う\r
4862                 new SwingBackgroundWorker(false) {\r
4863                         \r
4864                         @Override\r
4865                         protected Object doWorks() throws Exception {\r
4866                                 \r
4867                                 TatCount tc = new TatCount();\r
4868                                 \r
4869                                 // 初期化処理\r
4870                                 _initialize(args);\r
4871                                 \r
4872                                 // 終わったら閉じられるようにするよ\r
4873                                 //setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);\r
4874                                 //setResizable(true);\r
4875 \r
4876                                 stwin.append("");\r
4877                                 stwin.appendMessage(String.format("【タイニー番組ナビゲータが起動しました】 所要時間: %.2f秒",tc.end()));\r
4878                                 return null;\r
4879                         }\r
4880                         \r
4881                         @Override\r
4882                         protected void doFinally() {\r
4883                                 if ( ! initialized ) System.err.println("[ERROR][鯛ナビ] 【致命的エラー】 初期化処理を行っていたスレッドが異常終了しました。");\r
4884                                 stwin.setClosingEnabled(false);\r
4885                                 CommonUtils.milSleep(OPENING_WIAT);\r
4886                                 StWinSetVisible(false);\r
4887                         }\r
4888                 }.execute();\r
4889                 \r
4890                 StWinSetLocationUnder(this);\r
4891                 StWinSetVisible(true);\r
4892         }\r
4893         \r
4894         // 初期化の本体\r
4895         private void _initialize(final String[] args) {\r
4896                 \r
4897                 // コマンドライン引数を処理する\r
4898                 procArgs(args);\r
4899                 \r
4900                 // ログ出力を設定する(Windowsの場合は文字コードをMS932にする) →DOS窓を殺したので終了\r
4901                 System.setOut(new DebugPrintStream(System.out,LOG_FILE,logging));\r
4902                 System.setErr(new DebugPrintStream(System.err,LOG_FILE,logging));\r
4903                 \r
4904                 // 起動メッセージ\r
4905                 StdAppendMessage("================================================================================");\r
4906                 StdAppendMessage("以下のメッセージは無視してください(原因調査中)");\r
4907                 StdAppendMessage("Exception occurred during event dispatching:");\r
4908                 StdAppendMessage("      java.lang.NullPointerException");\r
4909                 StdAppendMessage("              at javax.swing.plaf.basic.BasicScrollBarUI.layoutHScrollbar(Unknown Source)");\r
4910                 StdAppendMessage("              (以下略)");\r
4911                 StdAppendMessage("================================================================================");\r
4912                 stwin.appendMessage(CommonUtils.getDateTime(0));\r
4913                 stwin.appendMessage(String.format("タイニー番組ナビゲータが起動を開始しました(VersionInfo:%s on %s)",VersionInfo.getVersion(),VersionInfo.getEnvironment()));\r
4914                 \r
4915                 // 起動時にアップデートを確認する\r
4916                 chkVerUp();\r
4917                 \r
4918                 try {\r
4919                         // メインの環境設定ファイルを読み込む\r
4920                         loadEnvfile();\r
4921                         \r
4922                         // 二重起動防止\r
4923                         chkDualBoot();\r
4924                         \r
4925                         // その他の環境設定ファイルを読み込む\r
4926                         procEnvs();\r
4927                         \r
4928                         if ( onlyLoadProgram ) {\r
4929                                 if ( ! isOLPExpired(4) ) {\r
4930                                         CommonUtils.milSleep(3000);\r
4931                                         System.exit(1);\r
4932                                 }\r
4933                                 // プラグインのロード\r
4934                                 loadProgPlugins();\r
4935                                 // プラグインの初期化\r
4936                                 setSelectedProgPlugin();\r
4937                                 initProgPluginAll();\r
4938                                 // 検索結果リストの初期化(loadTVProgram()中で使うので)\r
4939                                 initMpList();\r
4940                                 // データのロード\r
4941                                 loadTVProgram(true,LoadFor.ALL);\r
4942                                 stwin.appendMessage("番組表を取得したので終了します");\r
4943                                 CommonUtils.milSleep(3000);\r
4944                                 System.exit(1);\r
4945                         }\r
4946                         \r
4947                         // プラグインのロード\r
4948                         loadProgPlugins();\r
4949                         loadRecPlugins();\r
4950 \r
4951                         // プラグインの初期化\r
4952                         setSelectedProgPlugin();\r
4953                         initProgPluginAll();\r
4954 \r
4955                         initRecPluginAll();\r
4956 \r
4957                         // WOL指定があったなら\r
4958                         if ( runRecWakeup ) {\r
4959                                 doRecWakeup();\r
4960                         }\r
4961 \r
4962                         // 検索結果リストの初期化(loadTVProgram()中で使うので)\r
4963                         initMpList();\r
4964                         \r
4965                         // データのロード\r
4966                         loadTVProgram(false,LoadFor.ALL);\r
4967                         \r
4968                         // 放送局の並び順もロード\r
4969                         chsort.load();\r
4970                         \r
4971                         loadRdReservesAll(runRecLoad, null);\r
4972                 }\r
4973                 catch ( Exception e ) {\r
4974                         System.err.println("【致命的エラー】設定の初期化に失敗しました");\r
4975                         e.printStackTrace();\r
4976                         System.exit(1);\r
4977                 }\r
4978                 \r
4979                 // 背景色設定ダイアログにフォント名の一覧を設定する\r
4980                 pcwin.setFontList(vwfont);\r
4981                 \r
4982                 // (新聞形式の)ツールチップの表示時間を変更する\r
4983                 setTooltipDelay();\r
4984 \r
4985                 // ウィンドウを構築\r
4986                 try {\r
4987                         buildMainWindow();\r
4988                 }\r
4989                 catch ( Exception e ) {\r
4990                         System.err.println("【致命的エラー】ウィンドウの構築に失敗しました");\r
4991                         e.printStackTrace();\r
4992                         System.exit(1);\r
4993                 }\r
4994                 \r
4995                 // ★★★★★★★★★★\r
4996                 //int x = 2/0;  // サブスレッドの突然死のトラップを確認するためのコード\r
4997                 // ★★★★★★★★★★\r
4998                 \r
4999                 // トレイアイコンを作る\r
5000                 getTrayIcon();\r
5001                 setTrayIconVisible(env.getShowSysTray());\r
5002                 \r
5003                 // ウィンドウを閉じたときの処理\r
5004                 setXButtonAction(env.getShowSysTray() && env.getHideToTray());\r
5005                 \r
5006                 // ウィンドウ操作のリスナー登録\r
5007                 this.addWindowListener(new WindowAdapter() {\r
5008                         // ウィンドウを最小化したときの処理\r
5009                         @Override\r
5010                         public void windowIconified(WindowEvent e) {\r
5011                                 HideToTray();\r
5012                         }\r
5013                 \r
5014                         // ウィンドウを閉じたときの処理\r
5015                         @Override\r
5016                         public void windowClosing(WindowEvent e) {\r
5017                                 ExitOnClose();\r
5018                         }\r
5019                 });\r
5020                 \r
5021                 // 初回起動時はレコーダの登録を促す\r
5022                 if ( recorders.size() == 0 ) {\r
5023                         Container cp = getContentPane();\r
5024                         JOptionPane.showMessageDialog(cp, "レコーダが登録されていません。\n最初に登録を行ってください。\n番組表だけを使いたい場合は、\nNULLプラグインを登録してください。");\r
5025                 }\r
5026                 \r
5027                 // ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
5028                 // イベントリスナーの登録 \r
5029                 // ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
5030                 \r
5031                 // [ツールバー/共通] レコーダ情報変更\r
5032                 toolBar.addHDDRecorderChangeListener(autores);\r
5033                 \r
5034                 // [ツールバー/レコーダ選択]\r
5035                 toolBar.addHDDRecorderSelectionListener(this);          // 新聞形式\r
5036                 toolBar.addHDDRecorderSelectionListener(paper);         // 新聞形式\r
5037                 toolBar.addHDDRecorderSelectionListener(autores);       // 自動予約一覧\r
5038                 toolBar.addHDDRecorderSelectionListener(rdialog);       // 予約ダイアログ\r
5039                 \r
5040                 // [タイマー] タイトルバー更新/リスト形式の現在時刻ノード/新聞形式の現在時刻ノード\r
5041                 timer_now.addTickTimerRiseListener(this);\r
5042                 timer_now.addTickTimerRiseListener(listed);\r
5043                 timer_now.addTickTimerRiseListener(paper);\r
5044 \r
5045                 // ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
5046                 // [Fire!] レコーダ選択\r
5047                 // ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
5048                 toolBar.setSelectedRecorder(bounds.getSelectedRecorderId());\r
5049                 \r
5050                 // ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
5051                 // [Fire!] サイドツリーのデフォルトを選択することで番組情報の描画を開始する\r
5052                 // ※ここ以前だとぬぽとかOOBとか出るかもよ!\r
5053                 // ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
5054                 paper.selectTreeDefault();\r
5055                 listed.selectTreeDefault();\r
5056                 \r
5057                 // ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
5058                 // メインウィンドウをスプラッシュからコンポーネントに入れ替える\r
5059                 // ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
5060                 this.setVisible(false);\r
5061                 this.setContentPane(mainWindow);\r
5062                 setInitBounds();\r
5063                 this.setVisible(true);\r
5064                 \r
5065                 setTitleBar();  // タイトルバー更新\r
5066                 \r
5067                 ShowInitTab();  // 前回開いていたタブを開く\r
5068                 \r
5069                 // ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
5070                 // タイマーを起動する\r
5071                 // ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
5072                 timer_now.start();\r
5073                 \r
5074                 // ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
5075                 // 初期化終了\r
5076                 // ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
5077                 mwin.appendMessage(String.format("タイニー番組ナビゲータが起動しました (VersionInfo:%s on %s)",VersionInfo.getVersion(),VersionInfo.getEnvironment()));\r
5078                 initialized = true;\r
5079         }\r
5080 }\r