OSDN Git Service

新聞形式の予約待機枠を、番組追跡とキーワード検索それぞれに個別の色を設定できるようにした。
[tainavi/TinyBannavi.git] / TinyBannavi / src / tainavi / AbsPaperView.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.Cursor;\r
8 import java.awt.Dimension;\r
9 import java.awt.Point;\r
10 import java.awt.Rectangle;\r
11 import java.awt.Robot;\r
12 import java.awt.event.ComponentAdapter;\r
13 import java.awt.event.ComponentEvent;\r
14 import java.awt.event.ComponentListener;\r
15 import java.awt.event.MouseAdapter;\r
16 import java.awt.event.MouseEvent;\r
17 import java.awt.event.MouseListener;\r
18 import java.io.File;\r
19 import java.util.ArrayList;\r
20 import java.util.Calendar;\r
21 import java.util.GregorianCalendar;\r
22 \r
23 import javax.swing.JComponent;\r
24 import javax.swing.JLabel;\r
25 import javax.swing.JLayeredPane;\r
26 import javax.swing.JPanel;\r
27 import javax.swing.JScrollPane;\r
28 import javax.swing.JSplitPane;\r
29 import javax.swing.JTree;\r
30 import javax.swing.JViewport;\r
31 import javax.swing.SpringLayout;\r
32 import javax.swing.border.LineBorder;\r
33 import javax.swing.event.MouseInputListener;\r
34 import javax.swing.event.TreeExpansionEvent;\r
35 import javax.swing.event.TreeExpansionListener;\r
36 import javax.swing.event.TreeSelectionEvent;\r
37 import javax.swing.event.TreeSelectionListener;\r
38 import javax.swing.tree.DefaultMutableTreeNode;\r
39 import javax.swing.tree.TreeNode;\r
40 import javax.swing.tree.TreePath;\r
41 import javax.swing.tree.TreeSelectionModel;\r
42 import javax.swing.tree.DefaultTreeModel;\r
43 \r
44 import tainavi.TVProgram.ProgType;\r
45 import tainavi.TVProgramIterator.IterationType;\r
46 import tainavi.VWMainWindow.MWinTab;\r
47 \r
48 \r
49 /**\r
50  * 新聞形式タブのクラス\r
51  * @since 3.15.4β {@link Viewer}から分離\r
52  */\r
53 public abstract class AbsPaperView extends JPanel implements TickTimerListener,HDDRecorderListener {\r
54 \r
55         private static final long serialVersionUID = 1L;\r
56 \r
57         public static String getViewName() { return "新聞形式"; }\r
58         \r
59         public void setDebug(boolean b) { debug = b; }\r
60         private static boolean debug = false;\r
61         \r
62         \r
63         /*******************************************************************************\r
64          * 抽象メソッド\r
65          ******************************************************************************/\r
66         \r
67         protected abstract Env getEnv();\r
68         protected abstract Bounds getBoundsEnv();\r
69         protected abstract PaperColorsMap getPaperColorMap();\r
70         protected abstract ChannelSort getChannelSort();\r
71         \r
72         protected abstract TVProgramList getTVProgramList();\r
73         protected abstract HDDRecorderList getRecorderList();\r
74         \r
75         protected abstract StatusWindow getStWin(); \r
76         protected abstract StatusTextArea getMWin();\r
77         \r
78         protected abstract AbsReserveDialog getReserveDialog();\r
79         protected abstract Component getParentComponent();\r
80         \r
81         protected abstract void ringBeep();\r
82         \r
83         // クラス内のイベントから呼び出されるもの\r
84         \r
85         /**\r
86          * タブが開いた\r
87          */\r
88         protected abstract void onShown();\r
89         /**\r
90          * タブが閉じた\r
91          */\r
92         protected abstract void onHidden();\r
93         \r
94         /**\r
95          * マウス右クリックメニューを表示する\r
96          */\r
97         protected abstract void showPopupForTraceProgram(\r
98                         final JComponent comp,\r
99                         final ProgDetailList tvd, final String keyword, final int threshold,\r
100                         final int x, final int y, final String clickedDateTime\r
101                         );\r
102 \r
103         /**\r
104          * 予約マーク・予約枠を更新してほしい\r
105          */\r
106         protected abstract void updateReserveDisplay();\r
107         \r
108         /**\r
109          * ピックアップに追加してほしい\r
110          */\r
111         protected abstract void addToPickup(final ProgDetailList tvd);\r
112         \r
113         protected abstract boolean isTabSelected(MWinTab tab);\r
114         protected abstract void setSelectedTab(MWinTab tab);\r
115 \r
116         protected abstract boolean isFullScreen();\r
117         /**\r
118          * ページャーコンボボックスを更新してほしい\r
119          */\r
120         protected abstract void setPagerEnabled(boolean b);\r
121         protected abstract int getPagerCount();\r
122         protected abstract int getSelectedPagerIndex();\r
123         protected abstract void setSelectedPagerIndex(int idx);\r
124         protected abstract void setPagerItems(TVProgramIterator pli, int curindex);\r
125 \r
126         protected abstract String getExtensionMark(ProgDetailList tvd);\r
127         protected abstract String getOptionMark(ProgDetailList tvd);\r
128         protected abstract String getPostfixMark(ProgDetailList tvd);\r
129 \r
130         /**\r
131          * ツリーペーンの幅の変更を保存してほしい\r
132          */\r
133         protected abstract void setDividerEnvs(int loc);\r
134         \r
135         \r
136         \r
137         /*******************************************************************************\r
138          * 呼び出し元から引き継いだもの\r
139          ******************************************************************************/\r
140         \r
141         // オブジェクト\r
142         private final Env env = getEnv();\r
143         private final Bounds bounds = getBoundsEnv();\r
144         private final PaperColorsMap pColors = getPaperColorMap();\r
145         private final ChannelSort chsort = getChannelSort();\r
146         \r
147         private final TVProgramList tvprograms = getTVProgramList();\r
148         private final HDDRecorderList recorders = getRecorderList();\r
149 \r
150         private final StatusWindow StWin = getStWin();                  // これは起動時に作成されたまま変更されないオブジェクト\r
151         private final StatusTextArea MWin = getMWin();                  // これは起動時に作成されたまま変更されないオブジェクト\r
152         private final AbsReserveDialog rD = getReserveDialog(); // これは起動時に作成されたまま変更されないオブジェクト\r
153         \r
154         private final Component parent = getParentComponent();  // これは起動時に作成されたまま変更されないオブジェクト\r
155 \r
156         // メソッド\r
157         private void StdAppendMessage(String message) { System.out.println(message); }\r
158         private void StdAppendError(String message) { System.err.println(message); }\r
159         //private void StWinSetVisible(boolean b) { StWin.setVisible(b); }\r
160         //private void StWinSetLocationCenter(Component frame) { CommonSwingUtils.setLocationCenter(frame, (VWStatusWindow)StWin); }\r
161 \r
162         \r
163         \r
164         /*******************************************************************************\r
165          * 定数\r
166          ******************************************************************************/\r
167 \r
168         private final String MSGID = "["+getViewName()+"] ";\r
169         private final String ERRID = "[ERROR]"+MSGID;\r
170         private final String DBGID = "[DEBUG]"+MSGID;\r
171 \r
172         private final int DASHBORDER_LENGTH = 6;        // ダッシュの長さ\r
173         private final int DASHBORDER_SPACE = 4;         // ダッシュの間隔\r
174         \r
175         private static final String TreeExpRegFile_Paper = "env"+File.separator+"tree_expand_paper.xml";\r
176         \r
177         private static final int TIMEBAR_START = Viewer.TIMEBAR_START;\r
178 \r
179         //\r
180         private static final String TUNERLABEL_PICKUP = "PICKUP";\r
181         \r
182         // 定数ではないが\r
183         \r
184         /**\r
185          * 現在時刻追従スクロールで日付がかわったかどうかを確認するための情報を保持する\r
186          */\r
187         private String prevDT4Now = CommonUtils.getDate529(0,true);\r
188         private String prevDT4Tree = prevDT4Now;\r
189         \r
190         /**\r
191          * 番組枠フレームバッファのサイズ\r
192          */\r
193         private int framebuffersize = 512;\r
194         \r
195         \r
196         /*******************************************************************************\r
197          * 部品\r
198          ******************************************************************************/\r
199         \r
200         // コンポーネント\r
201         \r
202         private JDetailPanel jTextPane_detail = null;\r
203         private JSplitPane jSplitPane_view = null;\r
204         private JPanel jPanel_tree = null;\r
205         private JScrollPane jScrollPane_tree_top = null;\r
206         private JTreeLabel jLabel_tree = null;\r
207         private JScrollPane jScrollPane_tree = null;\r
208         private JTree jTree_tree = null;\r
209         private JScrollPane jScrollPane_space_main = null;\r
210         private JLayeredPane jLayeredPane_space_main_view = null;\r
211         private ArrayList<JTaggedLayeredPane> jLayeredPane_space_main_view_byDate = null;\r
212         private JLayeredPane jLayeredPane_space_main_view_byMakeshift = null; \r
213         private JPanel jPanel_space_top_view = null;\r
214         private JPanel jPanel_space_side_view = null;\r
215         private JViewport vport = null;\r
216         \r
217         private final JTimeline jLabel_timeline = new JTimeline();\r
218         \r
219         private DefaultMutableTreeNode paperRootNode = null;    // 新聞形式のツリー\r
220         private DefaultMutableTreeNode dateNode = null;\r
221         private DefaultMutableTreeNode dgNode = null;\r
222         private DefaultMutableTreeNode bsNode = null;\r
223         private DefaultMutableTreeNode csNode = null;\r
224         private DefaultMutableTreeNode centerNode = null;\r
225         private DefaultMutableTreeNode passedNode = null;\r
226 \r
227         private DefaultMutableTreeNode defaultNode = null;\r
228 \r
229         // コンポーネント以外\r
230         \r
231         // 番組枠をしまっておくバッファ(newが遅いので一回作ったら捨てない)\r
232         private ArrayList<JTXTButton> frameUsed = new ArrayList<JTXTButton>();                  // 画面に表示されている番組枠\r
233         private ArrayList<JTXTButton> frameUnused = new ArrayList<JTXTButton>();                // 未使用の予備\r
234         private ArrayList<JTXTButton> frameUsedByDate = new ArrayList<JTXTButton>();    // 高速描画時の日付別ペーンに表示されている番組枠。高速描画時も、過去ログはframeUsedが使われる\r
235 \r
236         // 予約枠をしまっておくバッファ(検索用)\r
237         private ArrayList<JRMLabel> reserveBorders = new ArrayList<JRMLabel>();\r
238         \r
239         // ツリーの展開状態の保存場所\r
240         TreeExpansionReg ter = null;\r
241         \r
242         DefaultMutableTreeNode nowNode = null;\r
243         \r
244         // 現在放送中のタイマー\r
245         private boolean timer_now_enabled = false;\r
246         \r
247         private IterationType cur_tuner = null;\r
248         \r
249         \r
250         // 予約待機枠と番組枠\r
251         private final DashBorder dborder = new DashBorder(Color.RED,env.getMatchedBorderThickness(),DASHBORDER_LENGTH,DASHBORDER_SPACE);\r
252         private final DashBorder dborderK = new DashBorder(Color.MAGENTA,env.getMatchedBorderThickness(),DASHBORDER_LENGTH,DASHBORDER_SPACE);\r
253         private final LineBorder lborder = new ChippedBorder(Color.BLACK,1);\r
254         \r
255         private float paperHeightZoom = 1.0F;\r
256         \r
257         /**\r
258          * 現在時刻線のオブジェクト\r
259          */\r
260         private class JTimeline extends JLabel {\r
261                 \r
262                 private static final long serialVersionUID = 1L;\r
263                 \r
264                 private int minpos = 0;\r
265                 \r
266                 public int setMinpos(int x, int minpos, float multiplier) {\r
267                         if ( minpos >= 0 ) {\r
268                                 this.minpos = minpos;\r
269                         }\r
270                         \r
271                         int timeline = Math.round(this.minpos*multiplier);\r
272                         this.setLocation(x,timeline);\r
273                         \r
274                         return timeline;\r
275                 }\r
276         }\r
277         \r
278         /*******************************************************************************\r
279          * コンストラクタ\r
280          ******************************************************************************/\r
281         \r
282         public AbsPaperView() {\r
283                 \r
284                 super();\r
285                 \r
286                 this.setLayout(new BorderLayout());\r
287                 this.add(getJTextPane_detail(), BorderLayout.PAGE_START);\r
288                 this.add(getJSplitPane_view(), BorderLayout.CENTER);\r
289                 \r
290                 // タブが開いたり閉じたりしたときの処理\r
291                 this.addComponentListener(cl_shownhidden);\r
292         }\r
293         \r
294         \r
295         \r
296         /*******************************************************************************\r
297          * アクション\r
298          ******************************************************************************/\r
299         \r
300         // 主に他のクラスから呼び出されるメソッド\r
301         \r
302         public String getFrameBufferStatus() { return String.format("%d/%d",frameUsed.size(),framebuffersize); }\r
303 \r
304         /**\r
305          * 現在日時表示にリセット\r
306          */\r
307         public void jumpToNow() {\r
308                 if ( nowNode != null ) {\r
309                         TreePath tp = new TreePath(nowNode.getPath());\r
310                         jTree_tree.setSelectionPath(null);\r
311                         jTree_tree.setSelectionPath(tp);\r
312                 }\r
313         }\r
314         \r
315         /**\r
316          * ツールバーから過去ログへのジャンプ\r
317          */\r
318         public boolean jumpToPassed(String passed) {\r
319                 \r
320                 // ページャーは効くよ\r
321                 if ( env.isPagerEnabled() ) {\r
322                         setPagerEnabled(true);\r
323                 }\r
324                 \r
325                 // タイマーは止める\r
326                 stopTimer();\r
327                 \r
328                 GregorianCalendar c = CommonUtils.getCalendar(passed);\r
329                 String adate = CommonUtils.getDate(c);\r
330                 \r
331                 // 指定日付に移動して放送局の位置を確認する\r
332                 TVProgramIterator pli = redrawByDateWithCenter(null,adate);\r
333                 if ( pli == null ) {\r
334                         // どちらにもない\r
335                         MWin.appendError(ERRID+"ジャンプ先の日付がみつかりません: "+adate);\r
336                         ringBeep();\r
337                         return false;\r
338                 }\r
339                 \r
340                 // 新聞形式に移動\r
341                 if ( ! isTabSelected(MWinTab.PAPER) ) {\r
342                         setSelectedTab(MWinTab.PAPER);\r
343                 }\r
344                 \r
345                 return true;\r
346         }\r
347         \r
348         /**\r
349          * リスト形式・本体予約一覧からの目的の番組へジャンプ\r
350          */\r
351         public boolean jumpToBangumi(String center, String startdt) {\r
352                 \r
353                 // ページャーは効くよ\r
354                 if ( env.isPagerEnabled() ) {\r
355                         setPagerEnabled(true);\r
356                 }\r
357                 \r
358                 // タイマーは止める\r
359                 stopTimer();\r
360 \r
361                 // 日付群\r
362                 GregorianCalendar c = CommonUtils.getCalendar(startdt);\r
363                 int hour = c.get(Calendar.HOUR_OF_DAY);\r
364                 int min  = c.get(Calendar.MINUTE);\r
365                 \r
366                 String adate = CommonUtils.getDate(c);\r
367                 String adate529 = CommonUtils.getDate529(c,true);\r
368                 \r
369                 \r
370                 // 指定日付に移動して放送局の位置を確認する\r
371                 TVProgramIterator pli = redrawByDateWithCenter(center,adate529);\r
372                 if ( pli == null ) {\r
373                         // どちらにもない\r
374                         MWin.appendError(ERRID+"ジャンプ先の日付がみつかりません: "+adate529);\r
375                         ringBeep();\r
376                         return false;\r
377                 }\r
378                 \r
379                 // 新聞形式に移動\r
380                 if ( ! isTabSelected(MWinTab.PAPER) ) {\r
381                         setSelectedTab(MWinTab.PAPER);\r
382                 }\r
383                 \r
384                 /*\r
385                  * マウスカーソル移動\r
386                  */\r
387                 \r
388                 // 横の列\r
389                 int crindex = pli.getIndex(center);\r
390                 if ( crindex == -1 ) {\r
391                         MWin.appendError(ERRID+"「"+center+"」は有効な放送局ではありません");\r
392                         ringBeep();\r
393                         return false;\r
394                 }\r
395                 \r
396                 int x = 0;\r
397                 if ( env.isPagerEnabled() ) {\r
398                         int idx = env.getPageIndex(1+crindex);\r
399                         x = (crindex - idx*env.getCenterPerPage()) * bounds.getBangumiColumnWidth();\r
400                 }\r
401                 else {\r
402                         x = crindex * bounds.getBangumiColumnWidth();\r
403                 }\r
404                 \r
405                 // 縦の列\r
406                 int y = 0;\r
407                 if (adate529.equals(adate)) {\r
408                         if (hour < TIMEBAR_START) {\r
409                                 hour = TIMEBAR_START;\r
410                                 min = 0;\r
411                         }\r
412                 }\r
413                 else {\r
414                         hour += 24;\r
415                 }\r
416                 y = Math.round((float)((hour-TIMEBAR_START)*60+min)*bounds.getPaperHeightMultiplier()*paperHeightZoom);\r
417                 \r
418                 // 新聞面を移動する\r
419                 {\r
420                         // Viewのサイズ変更をJavaまかせにすると実際に表示されるまで変更されないので明示的に変更しておく\r
421                         Dimension dm = vport.getView().getPreferredSize();\r
422                         vport.setViewSize(dm);\r
423                         \r
424                         // 一旦位置情報をリセットする\r
425                         Point pos = new Point(0, 0);\r
426                         //vport.setViewPosition(pos);\r
427                         \r
428                         Rectangle ra = vport.getViewRect();\r
429                         pos.x = x + bounds.getBangumiColumnWidth()/2 - ra.width/2;\r
430                         pos.y = y - ra.height/4;\r
431                         \r
432                         // ViewのサイズがViewPortのサイズより小さい場合はsetViewPosition()が正しく動作しないので0にする\r
433                         if (pos.x < 0 || dm.width < ra.width) {\r
434                                 pos.x=0;\r
435                         }\r
436                         else if ((dm.width - ra.width) < pos.x) {\r
437                                 pos.x = dm.width - ra.width;\r
438                         }\r
439                         \r
440                         if (pos.y < 0 || dm.height < ra.height)  {\r
441                                 pos.y=0;\r
442                         }\r
443                         else if ((dm.height - ra.height) < pos.y) {\r
444                                 pos.y = dm.height - ra.height;\r
445                         }\r
446                         \r
447                         vport.setViewPosition(pos);\r
448                 }\r
449                 \r
450                 // マウスカーソルを移動する\r
451                 {\r
452                         Point sc = vport.getLocationOnScreen();\r
453                         Point pos = vport.getViewPosition();\r
454                         \r
455                         Point loc = new Point();\r
456                         loc.x = sc.x + (x + bounds.getBangumiColumnWidth()/2) - pos.x;\r
457                         loc.y = sc.y + (y + Math.round(5*bounds.getPaperHeightMultiplier()*paperHeightZoom)) - pos.y;\r
458                         \r
459                         try {\r
460                                 Robot robo = new Robot();\r
461                                 robo.mouseMove(loc.x,loc.y);\r
462                                 robo = null;\r
463                         } catch (AWTException e) {\r
464                                 e.printStackTrace();\r
465                         }\r
466                 }\r
467                 \r
468                 return true;\r
469         }\r
470         \r
471         /**\r
472          * ページャーによる再描画\r
473          */\r
474         public boolean redrawByPager() {\r
475                  \r
476                 //JTreeLabel.Nodes node = jLabel_tree.getNode();\r
477                 String value = jLabel_tree.getValue();\r
478 \r
479                 if ( value != null ) {\r
480                         if ( JTreeLabel.Nodes.NOW.getLabel().equals(value) ) {\r
481                                 redrawByNow(cur_tuner);\r
482                         }\r
483                         else {\r
484                                 redrawByDate(value, cur_tuner);\r
485                         }\r
486 \r
487                         return true;\r
488                 }\r
489                 \r
490                 return false;\r
491         }\r
492         \r
493         /**\r
494          * 予約待機赤枠の描画(全部)\r
495          * @see #putReserveBorder(String, String, int)\r
496          */\r
497         public void updateReserveBorder(String center) {\r
498                 \r
499                 // 予約の赤枠を表示する(上:日付別表示中、下:放送局別表示中)\r
500                 \r
501                 JTreeLabel.Nodes node = jLabel_tree.getNode();\r
502                 String value = jLabel_tree.getValue();\r
503                 \r
504                 switch ( node ) {\r
505                 case DATE:\r
506                 case TERRA:\r
507                 case BS:\r
508                 case CS:\r
509                         {\r
510                                 // 日付別は4種類ある\r
511                                 IterationType sTyp;\r
512                                 switch ( node ) {\r
513                                 case TERRA:\r
514                                         sTyp = IterationType.TERRA;\r
515                                         break;\r
516                                 case BS:\r
517                                         sTyp = IterationType.BS;\r
518                                         break;\r
519                                 case CS:\r
520                                         sTyp = IterationType.CS;\r
521                                         break;\r
522                                 default:\r
523                                         sTyp = IterationType.ALL;\r
524                                         break;\r
525                                 }\r
526                                 \r
527                                 // "現在日付"を現在日付にする\r
528                                 String dt = value;\r
529                                 if ( JTreeLabel.Nodes.NOW.getLabel().equals(dt) ) {\r
530                                         dt = CommonUtils.getDate529(0,true);\r
531                                 }\r
532                                 \r
533                                 TVProgramIterator pli = tvprograms.getIterator().build(chsort.getClst(), sTyp);\r
534                                 \r
535                                 // ページャーが有効なら表示すべきページ番号を取得する\r
536                                 int colmin = 0;\r
537                                 int colmax = pli.size();\r
538                                 int divider = 0;\r
539                                 if ( env.isPagerEnabled() ) {\r
540                                         int selectedpage = getSelectedPagerIndex();     // 予約枠の描画なのだから、ページ移動の必要はないはずだ\r
541                                         if ( selectedpage >= 0 ) {\r
542                                                 colmin = env.getCenterPerPage() * selectedpage;\r
543                                                 colmax = colmin + env.getCenterPerPage()-1;\r
544                                                 divider = env.getCenterPerPage();\r
545                                         }\r
546                                         else {\r
547                                                 StWin.appendError(ERRID+"ページャーコンボボックスが不正です: "+selectedpage);\r
548                                                 return;\r
549                                         }\r
550                                 }\r
551         \r
552                                 if ( center != null ) {\r
553                                         // 特定の放送局のみ更新\r
554                                         int cnt = pli.getIndex(center);\r
555                                         if ( colmin <= cnt && cnt <= colmax ) {\r
556                                                 int col = (divider==0) ? (cnt) : (cnt % divider);\r
557                                                 putReserveBorder(dt, center, col);\r
558                                         }\r
559                                 }\r
560                                 else {\r
561                                         // すべての放送局を更新\r
562                                         int cnt = -1;\r
563                                         for ( ProgList pl : pli ) {\r
564                                                 ++cnt;\r
565                                                 if ( cnt < colmin ) {\r
566                                                         continue;\r
567                                                 }\r
568                                                 else if ( cnt > colmax ) {\r
569                                                         break;\r
570                                                 }\r
571                                                 \r
572                                                 int col = (divider==0) ? (cnt) : (cnt % divider);\r
573                                                 \r
574                                                 putReserveBorder(dt, pl.Center, col);\r
575                                         }\r
576                                 }\r
577                         }\r
578                         break;\r
579                         \r
580                 case BCAST:\r
581                         {\r
582                                 \r
583                                 if (center != null && ! center.equals(value)) {\r
584                                         // 更新の必要はない\r
585                                         return;\r
586                                 }\r
587                                 if (center == null) {\r
588                                         // 選択中の放送局で更新する\r
589                                         center = value;\r
590                                 }\r
591                                 \r
592                                 TVProgramIterator pli = tvprograms.getIterator().build(chsort.getClst(), IterationType.ALL);\r
593                                 int cnt = tvprograms.getIterator().getIndex(center);\r
594                                 if ( cnt == -1 ) {\r
595                                         MWin.appendError(ERRID+"「"+center+"」は有効な放送局ではありません");\r
596                                 }\r
597                                 else {\r
598                                         ProgList pl = pli.getP();\r
599                                         for (int col=0; col<pl.pdate.size(); col++) {\r
600                                                 // 予約の赤枠を一週間分表示する\r
601                                                 putReserveBorder(pl.pdate.get(col).Date, center, col);\r
602                                         }\r
603                                 }\r
604                         }\r
605                         break;\r
606                 \r
607                 default:\r
608                         break;\r
609                 }\r
610         }\r
611         \r
612         /**\r
613          * \r
614          */\r
615         public void updateBangumiColumns() {\r
616                 for (JTXTButton b : frameUsed ) {\r
617                         ProgDetailList tvd = b.getInfo();\r
618                         if ( tvd.type == ProgType.PROG ) {\r
619                                 _updPBorder(bounds, b);\r
620                         }\r
621                 }\r
622         }\r
623         \r
624         /**\r
625          * 予約待機赤枠の描画(ツールバーからのトグル操作)\r
626          */\r
627         public boolean toggleMatchBorder() {\r
628                 \r
629                 // 状態を保存\r
630                 bounds.setShowMatchedBorder( ! bounds.getShowMatchedBorder());\r
631                 \r
632                 _updPBorderAll(env, bounds, frameUsed);\r
633                 \r
634                 if ( env.getDrawcacheEnable() ) {\r
635                         _updPBorderAll(env, bounds, frameUsedByDate);\r
636                 }\r
637                 \r
638                 return bounds.getShowMatchedBorder();\r
639         }\r
640 \r
641         \r
642         /**\r
643          * 新聞枠の拡縮(ツールバーからの操作)\r
644          */\r
645         public void setZoom(int n) {\r
646                 paperHeightZoom = n * 0.01F;\r
647                 updateBounds(env, bounds);\r
648                 updateRepaint();\r
649         }\r
650 \r
651         /**\r
652          * 新聞ペーンをクリアする。\r
653          */\r
654         public void clearPanel() {\r
655                 \r
656                 // 番組枠の初期化\r
657                 /* 移動しました */\r
658                 \r
659                 // 予約枠の初期化\r
660                 for ( JRMLabel b : reserveBorders) {\r
661                         jLayeredPane_space_main_view.remove(b);\r
662                 }\r
663                 reserveBorders.clear();\r
664                 \r
665                 // タイムラインの削除\r
666                 if (jLabel_timeline != null && jLayeredPane_space_main_view != null) {\r
667                         jLayeredPane_space_main_view.remove(jLabel_timeline);\r
668                 }\r
669                 \r
670                 // 時間枠・日付枠・放送局枠の初期化\r
671                 jPanel_space_top_view.removeAll();\r
672                 redrawTimebar(jPanel_space_side_view);\r
673                 \r
674                 // 選択してないことにする\r
675                 //paper.jLabel_tree.setText("");\r
676         }\r
677         \r
678         /**\r
679          * <P>新聞ペーンを選択する。\r
680          * <P>高速描画ONの場合は、主ペーンのほかに複数の日付別ペーンが作成されるのでどれを利用するか選択する。\r
681          * @param pane : nullの場合、主ペーンを選択する。過去ログは常にnullで。\r
682          * @see #jLayeredPane_space_main_view_byMakeshift 主ペーン\r
683          * @see #jLayeredPane_space_main_view_byDate 日付別ペーン\r
684          */\r
685         private void selectMainView(JLayeredPane pane) {\r
686                 \r
687                 // 表示開始位置を記憶する\r
688                 Point p = vport.getViewPosition();\r
689                 \r
690                 if (pane == null) {\r
691                         // 番組枠の初期化\r
692                         StdAppendMessage(MSGID+"番組枠描画バッファをリセット: "+frameUsed.size()+"/"+framebuffersize);\r
693                         for (int i=frameUsed.size()-1; i>=0; i--) {\r
694                                 JTXTButton b = frameUsed.remove(i);\r
695                                 b.setToolTipText(null);\r
696                                 b.clean();\r
697                                 frameUnused.add(b);\r
698                                 //jLayeredPane_space_main_view_byMakeshift.remove(b);   // 削除しちゃダメよ?\r
699                         }\r
700                         \r
701                         if (jLayeredPane_space_main_view == jLayeredPane_space_main_view_byMakeshift) {\r
702                                 return;\r
703                         }\r
704                         jScrollPane_space_main.setViewportView(jLayeredPane_space_main_view = jLayeredPane_space_main_view_byMakeshift);\r
705                 }\r
706                 else {\r
707                         if (jLayeredPane_space_main_view == pane) {\r
708                                 return;\r
709                         }\r
710                         jScrollPane_space_main.setViewportView(jLayeredPane_space_main_view = pane);\r
711                 }\r
712                 \r
713                 // 表示開始位置を戻す\r
714                 vport.setViewPosition(p);\r
715         }\r
716         \r
717         /**\r
718          * 現在時刻追従スクロールを開始する\r
719          */\r
720         private void startTimer() {\r
721                 timer_now_enabled = true;\r
722         }\r
723         \r
724         /**\r
725          * 現在時刻追従スクロールを停止する\r
726          */\r
727         private boolean stopTimer() {\r
728                 jLabel_timeline.setVisible(false);\r
729                 return (timer_now_enabled = false);\r
730         }\r
731         \r
732         /**\r
733          * サイドツリーの「現在日時」を選択する\r
734          */\r
735         public void selectTreeDefault() {\r
736                 if ( defaultNode != null ) jTree_tree.setSelectionPath(new TreePath(defaultNode.getPath()));\r
737         }\r
738         \r
739         /**\r
740          * サイドツリーの現在選択中のノードを再度選択して描画しなおす\r
741          */\r
742         public void reselectTree() {\r
743                 String[] names = new String[] { jLabel_tree.getNode().getLabel(), jLabel_tree.getValue() };\r
744                 TreeNode[] nodes = ter.getSelectedPath(paperRootNode, names, 0);\r
745                 if (nodes != null) {\r
746                         TreePath tp = new TreePath(nodes);\r
747                         if ( tp != null ) {\r
748                                 // 表示位置を記憶\r
749                                 Point vp = vport.getViewPosition(); //= SwingUtilities.convertPoint(vport,0,0,label);\r
750                                 // ツリー再選択\r
751                                 jTree_tree.setSelectionPath(null);\r
752                                 jTree_tree.setSelectionPath(tp);\r
753                                 // 表示位置を復帰\r
754                                 if (vp.x != 0 && vp.y != 0) {\r
755                                         jLayeredPane_space_main_view.scrollRectToVisible(new Rectangle(vp, vport.getSize()));\r
756                                 }\r
757                         }\r
758                 }\r
759         }\r
760         \r
761         /**\r
762          * サイドツリーを開く\r
763          */\r
764         public void setExpandTree() {\r
765                 jSplitPane_view.setDividerLocation(bounds.getTreeWidthPaper());\r
766                 jScrollPane_tree.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);\r
767                 jScrollPane_tree.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);\r
768         }\r
769         \r
770         /**\r
771          * サイドツリーを閉じる\r
772          */\r
773         public void setCollapseTree() {\r
774                 jSplitPane_view.setDividerLocation(bounds.getMinDivLoc());\r
775                 jScrollPane_tree.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);\r
776                 jScrollPane_tree.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);\r
777         }\r
778         \r
779         /**\r
780          * サイドツリーの展開状態を設定ファイルに保存(鯛ナビ終了時に呼び出される)\r
781          */\r
782         public void saveTreeExpansion() {\r
783                 ter.save();\r
784         }\r
785         \r
786         /**\r
787          * 画面上部の番組詳細領域の表示のON/OFF\r
788          */\r
789         public void setDetailVisible(boolean aFlag) {\r
790                 jTextPane_detail.setVisible(aFlag);\r
791         }\r
792         \r
793         /**\r
794          * スクリーンショット用\r
795          */\r
796         public Component getCenterPane() {\r
797                 return jPanel_space_top_view;\r
798         }\r
799         \r
800         /**\r
801          * スクリーンショット用\r
802          */\r
803         public Component getTimebarPane() {\r
804                 return jPanel_space_side_view;\r
805         }\r
806         \r
807         /**\r
808          * スクリーンショット用\r
809          */\r
810         public Component getCurrentPane() {\r
811                 return jLayeredPane_space_main_view;\r
812         }\r
813         \r
814         /**\r
815          * スクリーンショット用\r
816          */\r
817         public String getCurrentView() {\r
818                 return jLabel_tree.getView();\r
819         }\r
820         \r
821         /**\r
822          * 高速描画ONの場合に日付別ペーンを一気に全部描画する\r
823          */\r
824         public void buildMainViewByDate() {\r
825                 \r
826                 if (env.getDebug()) System.out.println(DBGID+"CALLED buildMainViewByDate()");\r
827                 \r
828                 if (jLayeredPane_space_main_view_byMakeshift == null) {\r
829                         jLayeredPane_space_main_view_byMakeshift = new JLayeredPane();\r
830                         for (int i=0; i<framebuffersize; i++) {\r
831                                 JTXTButton b2 = new JTXTButton();\r
832                                 b2.clean();\r
833                                 jLayeredPane_space_main_view_byMakeshift.add(b2);\r
834                                 jLayeredPane_space_main_view_byMakeshift.setLayer(b2, 0);\r
835                                 \r
836                                 // リスナーを設定する\r
837                                 b2.addMouseListener(ml_risepopup);\r
838                                 b2.addMouseMotionListener(ml_risepopup);\r
839                                 frameUnused.add(b2);\r
840                         }\r
841                         StdAppendMessage(MSGID+"番組枠描画バッファを初期化: "+framebuffersize);\r
842                 }\r
843                 \r
844                 // ページャー機能とは排他\r
845                 if (env.isPagerEnabled() || ! env.getDrawcacheEnable()) {\r
846                         jLayeredPane_space_main_view_byDate = null;\r
847                         return;\r
848                 }\r
849                 \r
850                 jLayeredPane_space_main_view_byDate = new ArrayList<JTaggedLayeredPane>();\r
851                 frameUsedByDate = new ArrayList<JTXTButton>();\r
852                 new SwingBackgroundWorker(true) {\r
853                         \r
854                         @Override\r
855                         protected Object doWorks() throws Exception {\r
856                                 //\r
857                                 int dogDays = (env.getExpandTo8())?(8):(7);\r
858                                 //\r
859                                 for ( int y=0; y < dogDays; y++ ) {\r
860                                         jLayeredPane_space_main_view_byDate.add(new JTaggedLayeredPane());\r
861                                 }\r
862                                 for ( int y=0; y < dogDays; y++ ) {\r
863                                         String day = CommonUtils.getDate529(y*86400,true);\r
864                                         \r
865                                         jLayeredPane_space_main_view_byDate.get(y).setTagstr(day);\r
866                                         \r
867                                         StWin.appendMessage(MSGID+"番組表を構築します:"+day);\r
868                                         redrawByDate(day,IterationType.ALL);\r
869                                 }\r
870                                 return null;\r
871                         }\r
872                         \r
873                         @Override\r
874                         protected void doFinally() {\r
875                         }\r
876                 }.execute();\r
877         }\r
878 \r
879         /**\r
880          * ツリーのリスナーを止める\r
881          */\r
882         private void stopTreeListener() {\r
883                 jTree_tree.removeTreeSelectionListener(tsl_nodeselected);\r
884         }\r
885         \r
886         /**\r
887          * ツリーのリスナーを動かす\r
888          */\r
889         private void startTreeListener() {\r
890                 jTree_tree.addTreeSelectionListener(tsl_nodeselected);\r
891         }\r
892         \r
893         /**\r
894          * 日付でサブノード作成\r
895          */\r
896         public  void redrawTreeByDate() {\r
897                 \r
898                 stopTreeListener();\r
899                 TreePath tp = jTree_tree.getSelectionPath();\r
900                 \r
901                 _redrawTreeByDate(dateNode);\r
902                 _redrawTreeByDate(dgNode);\r
903                 _redrawTreeByDate(bsNode);\r
904                 _redrawTreeByDate(csNode);\r
905                 \r
906                 jTree_tree.setSelectionPath(tp);\r
907                 jTree_tree.updateUI();\r
908                 startTreeListener();\r
909         }\r
910         \r
911         private void _redrawTreeByDate(DefaultMutableTreeNode parent) {\r
912                 \r
913                 // ★★★ でふぉるとのーど ★★★\r
914                 DefaultMutableTreeNode nNode = new DefaultMutableTreeNode(JTreeLabel.Nodes.NOW.getLabel());\r
915                 if ( parent == dateNode ) {\r
916                         nowNode = nNode;\r
917                         defaultNode = nNode;\r
918                 }\r
919                 \r
920                 parent.removeAllChildren();\r
921                 parent.add(nNode);\r
922                 int dogDays = (env.getExpandTo8())?(8):(7);\r
923                 for ( int i=0; i<dogDays; i++ ) {\r
924                         parent.add(new DefaultMutableTreeNode(CommonUtils.getDate529(i*86400, true)));\r
925                 }\r
926         }\r
927 \r
928         /**\r
929          * 放送局名でサブノード作成\r
930          */\r
931         public void redrawTreeByCenter() {\r
932 \r
933                 stopTreeListener();\r
934                 TreePath tp = jTree_tree.getSelectionPath();\r
935                 \r
936                 centerNode.removeAllChildren();\r
937                 TVProgramIterator pli = tvprograms.getIterator();\r
938                 pli.build(chsort.getClst(), IterationType.ALL);\r
939                 for ( ProgList pl : pli ) {\r
940                         centerNode.add(new DefaultMutableTreeNode(pl.Center));\r
941                 }\r
942                 \r
943                 jTree_tree.setSelectionPath(tp);\r
944                 jTree_tree.updateUI();\r
945                 startTreeListener();\r
946         }\r
947 \r
948         /**\r
949          * 過去ログ日付でサブノード作成\r
950          */\r
951         public void redrawTreeByPassed() {\r
952 \r
953                 stopTreeListener();\r
954                 TreePath tp = jTree_tree.getSelectionPath();\r
955                 \r
956                 passedNode.removeAllChildren();\r
957                 if ( env.getUsePassedProgram() ) {\r
958                         String[] dd = new PassedProgram().getDateList(env.getPassedLogLimit());\r
959                         for ( int i=1; i<dd.length && i<=env.getPassedLogLimit(); i++ ) {\r
960                                 passedNode.add(new DefaultMutableTreeNode(dd[i]));\r
961                         }\r
962                 }\r
963                 \r
964                 jTree_tree.setSelectionPath(tp);\r
965                 jTree_tree.updateUI();\r
966                 startTreeListener();\r
967         }\r
968 \r
969         /**\r
970          *  時刻の列を生成\r
971          */\r
972         private void redrawTimebar(JPanel jp)\r
973         {\r
974                 jp.removeAll();\r
975                 \r
976                 float phm60 = 60.0F * bounds.getPaperHeightMultiplier() * paperHeightZoom;\r
977                 \r
978                 for (int row=0; row<24; row++) {\r
979                         \r
980                         int hour = row+TIMEBAR_START;\r
981                         \r
982                         JTimebarLabel b0 = new JTimebarLabel(Integer.toString(hour));\r
983                         \r
984                         if ( hour >=6 && hour <= 11 ) {\r
985                                 b0.setBackground(env.getTimebarColor());\r
986                         }\r
987                         else if ( hour >=12 && hour <= 17 ) {\r
988                                 b0.setBackground(env.getTimebarColor2());\r
989                         }\r
990                         else if ( hour >=18 && hour <= 23 ) {\r
991                                 b0.setBackground(env.getTimebarColor3());\r
992                         }\r
993                         else {\r
994                                 b0.setBackground(env.getTimebarColor4());\r
995                         }\r
996                         b0.setOpaque(true);\r
997                         b0.setBorder(lborder);\r
998                         b0.setHorizontalAlignment(JLabel.CENTER);\r
999                         \r
1000                         b0.setBounds(\r
1001                                         0,\r
1002                                         (int) Math.ceil((float)row*phm60),\r
1003                                         bounds.getTimebarColumnWidth(),\r
1004                                         (int) Math.ceil(phm60));\r
1005                         \r
1006                         jp.add(b0);\r
1007                 }\r
1008                 \r
1009                 Dimension d = jp.getMaximumSize();\r
1010                 d.width = bounds.getTimebarColumnWidth();\r
1011                 d.height = (int) Math.ceil(24*phm60);\r
1012                 jp.setPreferredSize(d);\r
1013                 jp.updateUI();\r
1014         }\r
1015         \r
1016 \r
1017         /**\r
1018          * 現在日時に移動する\r
1019          * @see #redrawByDate(String, IterationType)\r
1020          */\r
1021         private void redrawByNow(final IterationType tuner) {\r
1022                 \r
1023                 // 古いタイマーの削除\r
1024                 stopTimer();\r
1025                 \r
1026                 // 移動汁!!\r
1027                 redrawByDate(CommonUtils.getDate529(0,true),tuner);\r
1028                 \r
1029                 // 時間線をひく\r
1030                 jLabel_timeline.setVisible(true);\r
1031                 Dimension dm = jLayeredPane_space_main_view.getPreferredSize();\r
1032                 //dm.height = Math.round(1*bounds.getPaperHeightMultiplier()*paperHeightZoom);\r
1033                 dm.height = 3;\r
1034                 jLabel_timeline.setBorder(new LineBorder(Color.RED,2));\r
1035                 jLabel_timeline.setBackground(Color.RED);\r
1036                 jLabel_timeline.setOpaque(true);\r
1037                 jLabel_timeline.setBounds(0, 0, dm.width, dm.height);\r
1038                 jLayeredPane_space_main_view.add(jLabel_timeline);\r
1039                 jLayeredPane_space_main_view.setLayer(jLabel_timeline, 2);\r
1040                 \r
1041                 // 現在時刻線のリセット\r
1042                 setTimelinePos(true);\r
1043                 \r
1044                 // 新しいタイマーの作成(1分ごとに線を移動する)\r
1045                 startTimer();\r
1046         }\r
1047         \r
1048         /**\r
1049          * 日付別に表を作成する\r
1050          * @see #_redrawByDateWithCenter(String, String, IterationType)\r
1051          */\r
1052         private TVProgramIterator redrawByDate(String date, IterationType tuner) {\r
1053                 return _redrawByDateWithCenter(null,date,tuner);\r
1054         }\r
1055         \r
1056         /**\r
1057          * 日付別に表を作成する(ページャーが有効な場合は指定の放送局のあるページを開く)\r
1058          * @see #_redrawByDateWithCenter(String, String, IterationType)\r
1059          */\r
1060         private TVProgramIterator redrawByDateWithCenter(String center, String date) {\r
1061                 \r
1062                 // 今日は?\r
1063                 String ndate529 = CommonUtils.getDate529(0, true);\r
1064                 \r
1065                 // 過去ログかどうか\r
1066                 IterationType tuner;\r
1067                 JTreeLabel.Nodes node;\r
1068                 if ( ndate529.compareTo(date) > 0 ) {\r
1069                         tuner = IterationType.PASSED;\r
1070                         node = JTreeLabel.Nodes.PASSED;\r
1071                 }\r
1072                 else {\r
1073                         tuner = IterationType.ALL;\r
1074                         node = JTreeLabel.Nodes.DATE;\r
1075                 }\r
1076                 \r
1077                 if ( tuner == IterationType.PASSED ) {\r
1078                         // 過去ログの取得\r
1079                         PassedProgram passed = tvprograms.getPassed();\r
1080                         if ( ! passed.loadAllCenters(date) ) {\r
1081                                 System.err.println(ERRID+"過去ログの取得に失敗しました: "+date);\r
1082                                 return null;\r
1083                         }\r
1084                 }\r
1085                 \r
1086                 // 番組枠描画\r
1087                 TVProgramIterator pli = _redrawByDateWithCenter(center, date, tuner);\r
1088                 \r
1089                 getJTree_tree().getSelectionModel().setSelectionPath(null); // 選択は解除する\r
1090                 \r
1091                 jLabel_tree.setView(node, date);\r
1092                 \r
1093                 return pli;\r
1094         }\r
1095         \r
1096         /**\r
1097          * 日付別に表を作成する、の本体\r
1098          * @see #redrawByDate(String, IterationType)\r
1099          * @see #redrawByDateWithCenter(String, String)\r
1100          */\r
1101         private TVProgramIterator _redrawByDateWithCenter(String center, String date, IterationType tuner) {\r
1102                 \r
1103                 if (env.getDebug()) System.out.println(DBGID+"CALLED redrawByDate() date="+date+" IterationType="+tuner);\r
1104                 \r
1105                 // 古いタイマーの削除\r
1106                 stopTimer();\r
1107                 \r
1108                 cur_tuner = tuner;\r
1109                 \r
1110                 if (date == null) {\r
1111                         return null;\r
1112                 }\r
1113 \r
1114                 // イテレータ-\r
1115                 TVProgramIterator pli = tvprograms.getIterator().build(chsort.getClst(),tuner);\r
1116                 \r
1117                 // パネルの初期化\r
1118                 clearPanel();\r
1119                 \r
1120                 // 新聞ペーンの選択\r
1121                 boolean drawPrograms = true;\r
1122                 if ( tuner != IterationType.ALL || env.isPagerEnabled() || ! env.getDrawcacheEnable() ) {\r
1123                         selectMainView(null);\r
1124                 }\r
1125                 else {\r
1126                         // 描画速度優先の場合\r
1127                         boolean nopane = true;\r
1128                         for ( JTaggedLayeredPane tlp : jLayeredPane_space_main_view_byDate ) {\r
1129                                 if ( tlp.getTagstr().equals(date) ) {\r
1130                                         selectMainView(tlp);\r
1131                                         if ( tlp.getComponentCountInLayer(0) > 0 ) {\r
1132                                                 // 描画済みなら再度の描画は不要\r
1133                                                 drawPrograms = false;\r
1134                                         }\r
1135                                         nopane = false;\r
1136                                         break;\r
1137                                 }\r
1138                         }\r
1139                         if ( nopane ) {\r
1140                                 // 該当日付のPaneがない場合\r
1141                                 selectMainView(null);\r
1142                         }\r
1143                 }\r
1144                 \r
1145                 // ページ制御\r
1146                 int colmin = 0;\r
1147                 int colmax = pli.size();\r
1148                 int divider = 0;\r
1149                 if ( env.isPagerEnabled() ) {\r
1150                         \r
1151                         int selectedpage = getSelectedPagerIndex();\r
1152                         \r
1153                         if ( center == null ) {\r
1154                                 // とび先の指定がないのでもともと選択されていたページを再度選択したい\r
1155                                 if ( selectedpage == -1 ) {\r
1156                                         // なんか、選択されてないよ?\r
1157                                         selectedpage = 0;\r
1158                                 }\r
1159                                 else {\r
1160                                         int maxindex = env.getPageIndex(pli.size());\r
1161                                         if ( selectedpage > maxindex ) {\r
1162                                                 // ページ数かわったら、インデックスがはみだしちゃった\r
1163                                                 selectedpage = 0;\r
1164                                         }\r
1165                                 }\r
1166                         }\r
1167                         else {\r
1168                                 // 特定の日付の特定の放送局を表示したい\r
1169                                 int crindex = pli.getIndex(center);\r
1170                                 if ( crindex ==  -1 ) {\r
1171                                         // ここに入ったらバグ\r
1172                                         MWin.appendError(ERRID+"「"+center+"」は有効な放送局ではありません");\r
1173                                         ringBeep();\r
1174                                         crindex = 0;\r
1175                                 }\r
1176                                 selectedpage = env.getPageIndex(1+crindex);\r
1177                         }\r
1178 \r
1179                         // 開始位置・終了位置・局数\r
1180                         colmin = env.getCenterPerPage() * selectedpage;\r
1181                         colmax = colmin + (env.getCenterPerPage()-1);\r
1182                         divider = env.getCenterPerPage();\r
1183                         \r
1184                         // ページャーコンボボックスの書き換え\r
1185                         setPagerItems(pli,env.getPageIndex(1+colmin));\r
1186                         pli.rewind();\r
1187                         \r
1188                         // ページャーは有効だよ\r
1189                         //setPagerEnabled(true);\r
1190                 }\r
1191                 \r
1192                 if (env.getDebug()) System.out.println(DBGID+"[描画開始] ch_start="+colmin+" ch_end="+colmax+" ch_size="+pli.size());\r
1193                 \r
1194                 // 番組の枠表示用\r
1195                 dborder.setDashColor(env.getMatchedBorderColor());\r
1196                 dborder.setThickness(env.getMatchedBorderThickness());\r
1197                 dborderK.setDashColor(env.getMatchedKeywordBorderColor());\r
1198                 dborderK.setThickness(env.getMatchedBorderThickness());\r
1199 \r
1200                 // 番組表時の共通設定\r
1201                 updateFonts(env);\r
1202                 \r
1203                 // 局列・番組表を作成\r
1204                 jPanel_space_top_view.setLayout(null);\r
1205                 int cnt = -1;\r
1206                 int col = -1;\r
1207                 for ( ProgList pl : pli ) {\r
1208 \r
1209                         ++cnt;\r
1210                         \r
1211                         if ( cnt < colmin ) {\r
1212                                 continue;\r
1213                         }\r
1214                         else if ( cnt > colmax ) {\r
1215                                 break;\r
1216                         }\r
1217                         \r
1218                         col = (divider==0) ? (cnt) : (cnt % divider);\r
1219                         \r
1220                         //TVProgram tvp = tvprograms.get(pli.getSiteId());\r
1221                         \r
1222                         //if (env.getDebug()) System.out.println(DBGID+"[描画中] "+pl.Center+" min="+colmin+" max="+colmax+" cnt="+cnt+" col="+col+" siteid="+siteid);\r
1223                         \r
1224                         // 局列\r
1225                         JLabel b1 = new JLabel(pl.Center);\r
1226                         b1.setOpaque(true);\r
1227                         b1.setBackground(pl.BgColor);\r
1228                         b1.setBorder(lborder);\r
1229                         b1.setHorizontalAlignment(JLabel.CENTER);\r
1230                         b1.setBounds(bounds.getBangumiColumnWidth()*col, 0, bounds.getBangumiColumnWidth(), bounds.getBangumiColumnHeight());\r
1231                         b1.addMouseListener(cnMouseAdapter);\r
1232                         jPanel_space_top_view.add(b1);\r
1233                         \r
1234                         // 予約の赤枠を表示する\r
1235                         if (tuner != IterationType.PASSED) {\r
1236                                 putReserveBorder(date, pl.Center, col);\r
1237                         }\r
1238 \r
1239                         // 番組表\r
1240                         if (drawPrograms == true) {\r
1241                                 putBangumiColumns(pl, col, date);\r
1242                         }\r
1243                 }\r
1244                 \r
1245                 ++col; // 描画後にパネルサイズの変更にも使う\r
1246                 \r
1247                 if ( ! env.getDrawcacheEnable()) {\r
1248                         // 番組枠描画バッファサイズの上限を確認する\r
1249                         if (framebuffersize < frameUsed.size()) {\r
1250                                 framebuffersize = frameUsed.size();\r
1251                                 StdAppendMessage(MSGID+"番組枠描画バッファの上限を変更: "+frameUsed.size()+"/"+framebuffersize);\r
1252                         }\r
1253                 }\r
1254                 \r
1255                 // ページサイズを変更する\r
1256                 //jPanel_space_top_view.setPreferredSize(new Dimension(bounds.getTimebarColumnWidth()+cnt*bounds.getBangumiColumnWidth(),bounds.getBangumiColumnHeight()));\r
1257                 jPanel_space_top_view.setPreferredSize(new Dimension(col*bounds.getBangumiColumnWidth(),bounds.getBangumiColumnHeight()));\r
1258                 jPanel_space_top_view.updateUI();\r
1259                 \r
1260                 jLayeredPane_space_main_view.setPreferredSize(new Dimension(bounds.getBangumiColumnWidth()*col,Math.round(24*60*bounds.getPaperHeightMultiplier()*paperHeightZoom)));\r
1261                 \r
1262                 if (env.getDebug()) System.out.println(DBGID+"END redrawByDate() date="+date+" IterationType="+tuner);\r
1263                 \r
1264                 pli.rewind();\r
1265                 return pli;\r
1266         }\r
1267 \r
1268         /**\r
1269          * 放送局別に表を作成する\r
1270          */\r
1271         private void redrawByCenter(String center)\r
1272         {\r
1273                 // 古いタイマーの削除\r
1274                 stopTimer();\r
1275                 \r
1276                 // ページャーは効かないよ\r
1277                 if ( env.isPagerEnabled() ) {\r
1278                         setPagerEnabled(false);\r
1279                 }\r
1280                 \r
1281                 // パネルの初期化\r
1282                 clearPanel();\r
1283                 selectMainView(null);\r
1284                 \r
1285                 jPanel_space_top_view.setLayout(null);\r
1286                 \r
1287                 for (int a=0; a<tvprograms.size(); a++) {\r
1288                         //\r
1289                         TVProgram tvp = tvprograms.get(a);\r
1290                         //\r
1291                         if (tvp.getType() != ProgType.PROG) {\r
1292                                 continue;\r
1293                         }\r
1294                         //\r
1295                         for (ProgList pl : tvp.getCenters()) {\r
1296                                 if (pl.enabled == true && pl.Center.equals(center)) {\r
1297                                         // 日付ヘッダを描画する\r
1298                                         for (int centerid=0; centerid<pl.pdate.size(); centerid++)\r
1299                                         {\r
1300                                                 ProgDateList pcl = pl.pdate.get(centerid);\r
1301                                                 \r
1302                                                 JTXTLabel b1 = new JTXTLabel();\r
1303                                                 GregorianCalendar c = CommonUtils.getCalendar(pcl.Date);\r
1304                                                 if ( c != null ) {\r
1305                                                         String date = CommonUtils.getDate(c);\r
1306                                                         b1.setValue(date);\r
1307                                                         b1.setText(date.substring(5));\r
1308                                                         b1.setOpaque(true);\r
1309                                                         if ( c.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY ) {\r
1310                                                                 b1.setBackground(new Color(90,90,255));\r
1311                                                         }\r
1312                                                         else if ( c.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY ) {\r
1313                                                                 b1.setBackground(new Color(255,90,90));\r
1314                                                         }\r
1315                                                         else {\r
1316                                                                 b1.setBackground(new Color(180,180,180));\r
1317                                                         }\r
1318                                                 }\r
1319                                                 b1.setBorder(lborder);\r
1320                                                 b1.setHorizontalAlignment(JLabel.CENTER);\r
1321                                                 b1.setBounds(bounds.getBangumiColumnWidth()*centerid, 0, bounds.getBangumiColumnWidth(), bounds.getBangumiColumnHeight());\r
1322                                                 b1.addMouseListener(tbMouseAdapter);\r
1323                                                 jPanel_space_top_view.add(b1);\r
1324                                         }\r
1325                                         //jPanel_space_top_view.setPreferredSize(new Dimension(bounds.getTimebarColumnWidth()+bounds.getBangumiColumnWidth()*tvprogram.getPlist().get(x).pcenter.size(),bounds.getBangumiColumnHeight()));\r
1326                                         jPanel_space_top_view.setPreferredSize(new Dimension(bounds.getBangumiColumnWidth()*pl.pdate.size(),bounds.getBangumiColumnHeight()));\r
1327                                         jPanel_space_top_view.updateUI();\r
1328                                         \r
1329 \r
1330                                         // 番組枠の表示\r
1331                                         {\r
1332                                                 putBangumiColumns(pl, -1, null);\r
1333                                         }\r
1334                                         \r
1335                                         // 予約枠の表示\r
1336                                         for (int progid=0; progid<pl.pdate.size(); progid++) {\r
1337                                                 putReserveBorder(pl.pdate.get(progid).Date, pl.Center, progid);\r
1338                                         }\r
1339                                         \r
1340                                         //\r
1341                                         jLayeredPane_space_main_view.setPreferredSize(new Dimension(tvp.getCenters().get(0).pdate.size()*bounds.getBangumiColumnWidth(),Math.round(24*60*bounds.getPaperHeightMultiplier()*paperHeightZoom)));\r
1342                                         //jScrollPane_space_main.updateUI();\r
1343 \r
1344                                         break;\r
1345                                 }\r
1346                         }\r
1347                 }\r
1348                 \r
1349                 // 番組枠描画バッファサイズの上限を確認する\r
1350                 if (framebuffersize < frameUsed.size()) {\r
1351                         framebuffersize = frameUsed.size();\r
1352                         StdAppendMessage(MSGID+"番組枠描画バッファの上限を変更: "+frameUsed.size()+"/"+framebuffersize);\r
1353                 }\r
1354         }\r
1355         \r
1356         \r
1357         /**\r
1358          * 予約待機赤枠の描画(個々の枠)\r
1359          * @see #updateReserveBorder(String)\r
1360          */\r
1361         private void putReserveBorder(String date, String Center, int q) {\r
1362                 \r
1363                 // 古いマークの削除(一見取りこぼしがあるように見えるが無問題)\r
1364                 for (int i=reserveBorders.size()-1; i>=0; i--) {\r
1365                         JRMLabel rb = reserveBorders.get(i);\r
1366                         if ( rb.getDate().equals(date) && rb.getCenter().equals(Center) ) {\r
1367                                 rb.setVisible(false);\r
1368                                 jLayeredPane_space_main_view.remove(rb);\r
1369                                 reserveBorders.remove(i);\r
1370                         }\r
1371                 }\r
1372                 \r
1373                 // 座標系\r
1374                 JRMLabel.setColumnWidth(bounds.getBangumiColumnWidth());\r
1375                 JRMLabel.setHeightMultiplier(bounds.getPaperHeightMultiplier() * paperHeightZoom);\r
1376                 \r
1377                 // 表示範囲\r
1378                 GregorianCalendar cal = CommonUtils.getCritCalendar(date);\r
1379                 String topDateTime = CommonUtils.getDateTime(cal);\r
1380                 cal.add(Calendar.DATE, 1);\r
1381                 String bottomDateTime = CommonUtils.getDateTime(cal);\r
1382                 \r
1383                 // \r
1384                 String passedCritDateTime = CommonUtils.getCritDateTime(env.getDisplayPassedReserve());\r
1385                 \r
1386                 // ツールバーで選択されている実レコーダ\r
1387                 String myself = ( env.getEffectComboToPaper() ) ? (getSelectedMySelf()) : (null);\r
1388                 \r
1389                 // 予約枠の描画\r
1390                 drawReserveBorders(date, Center, q, topDateTime, bottomDateTime, passedCritDateTime, myself);\r
1391                 \r
1392                 // ピックアップ枠の描画\r
1393                 drawPickupBorders(date, Center, q, topDateTime, bottomDateTime, passedCritDateTime, TUNERLABEL_PICKUP);\r
1394         }\r
1395         private void drawReserveBorders(String date, String Center, int q, String topDateTime, String bottomDateTime, String passedCritDateTime, String myself) {\r
1396                 if ( myself == HDDRecorder.SELECTED_PICKUP ) {\r
1397                         return;\r
1398                 }\r
1399                 for ( HDDRecorder recorder : getSelectedRecorderList() ) {\r
1400                         for ( ReserveList r : recorder.getReserves()) {\r
1401                                 \r
1402                                 // 「実行のみ表示」で無効な予約は表示しない\r
1403                                 if ( env.getDisplayOnlyExecOnEntry() && ! r.getExec() ) {\r
1404                                         continue;\r
1405                                 }\r
1406                                 \r
1407                                 // 放送局名の確認\r
1408                                 if ( r.getCh_name() == null ) {\r
1409                                         if ( r.getChannel() == null ) {\r
1410                                                 // CHコードすらないのはバグだろう\r
1411                                                 System.err.println(ERRID+"予約情報にCHコードが設定されていません。バグの可能性があります。 recid="+recorder.Myself()+" chname="+r.getCh_name());\r
1412                                         }\r
1413                                         continue;\r
1414                                 }\r
1415                                 \r
1416                                 // 描画本体\r
1417                                 if (r.getCh_name().equals(Center)) {\r
1418                                         \r
1419                                         // 開始終了日時リストを生成する\r
1420                                         ArrayList<String> starts = new ArrayList<String>();\r
1421                                         ArrayList<String> ends = new ArrayList<String>();\r
1422                                         CommonUtils.getStartEndList(starts, ends, r);\r
1423                                         \r
1424                                         // 予約枠を描画する\r
1425                                         for ( int j=0; j<starts.size(); j++ ) {\r
1426                                                 if ( passedCritDateTime.compareTo(ends.get(j)) > 0 ) {\r
1427                                                         // 過去情報の表示が制限されている場合\r
1428                                                         continue;\r
1429                                                 }\r
1430                                                 \r
1431                                                 drawBorder(date,Center,topDateTime,bottomDateTime,starts.get(j),ends.get(j),r.getRec_min(),r.getTuner(),recorder.getColor(r.getTuner()),r.getExec(),q);\r
1432                                         }\r
1433                                 }\r
1434                         }\r
1435                 }\r
1436         }\r
1437         private void drawPickupBorders(String date, String Center, int q, String topDateTime, String bottomDateTime, String passedCritDateTime, String tuner) {\r
1438                 for ( ProgList pl : tvprograms.getPickup().getCenters() ) {\r
1439                         if ( ! pl.Center.equals(Center) ) {\r
1440                                 continue;\r
1441                         }\r
1442                         for ( ProgDateList pcl : pl.pdate ) {\r
1443                                 for ( ProgDetailList tvd : pcl.pdetail ) {\r
1444                                         if ( passedCritDateTime.compareTo(tvd.endDateTime) > 0 ) {\r
1445                                                 // 過去情報の表示が制限されている場合\r
1446                                                 continue;\r
1447                                         }\r
1448                                         \r
1449                                         drawBorder(date,Center,topDateTime,bottomDateTime,tvd.startDateTime,tvd.endDateTime,tvd.length,tuner,env.getPickedColor(),false,q);\r
1450                                 }\r
1451                         }\r
1452                 }\r
1453         }\r
1454         private void drawBorder(String date, String Center, String topDateTime, String bottomDateTime, String startDateTime, String endDateTime, String recmin, String tuner, String bordercol, boolean exec, int col) {\r
1455                 drawBorder(date, Center, topDateTime, bottomDateTime, startDateTime, endDateTime, Integer.valueOf(recmin), tuner, CommonUtils.str2color(bordercol), exec, col);\r
1456         }\r
1457         private void drawBorder(String date, String Center, String topDateTime, String bottomDateTime, String startDateTime, String endDateTime, int recmin, String tuner, Color bordercol, boolean exec, int col) {\r
1458                 \r
1459                 GregorianCalendar ca = CommonUtils.getCalendar(startDateTime);\r
1460                 int ahh = ca.get(Calendar.HOUR_OF_DAY);\r
1461                 int amm = ca.get(Calendar.MINUTE);\r
1462                 \r
1463                 int row = 0;\r
1464                 int length = 0;\r
1465                 if (topDateTime.compareTo(startDateTime) <= 0 && startDateTime.compareTo(bottomDateTime) < 0) {\r
1466                         // 開始時刻が表示範囲内にある\r
1467                         row = ahh - TIMEBAR_START;\r
1468                         if (row < 0) {\r
1469                                 row += 24;\r
1470                         }\r
1471                         row = row*60 + amm;\r
1472                         length = recmin;\r
1473                 }\r
1474                 else if (startDateTime.compareTo(topDateTime) < 0 && topDateTime.compareTo(endDateTime) < 0) {\r
1475                         // 表示開始位置が番組の途中にある\r
1476                         row = 0;\r
1477                         length = recmin - (TIMEBAR_START*60 - ahh*60 - amm);\r
1478                 }\r
1479                 else {\r
1480                         return;\r
1481                 }\r
1482                 \r
1483                 {\r
1484                         // 重複予約の場合のエンコーダマーク表示位置の調整\r
1485                         int rc = 0;\r
1486                         //int rw = 0;\r
1487                         for (int k=0; k<reserveBorders.size(); k++) {\r
1488                                 JRMLabel rb = reserveBorders.get(k);\r
1489                                 if ( rb.getDate().equals(date) && rb.getCenter().equals(Center) ) {\r
1490                                         int drow = rb.getVRow() - row;\r
1491                                         int dlen = rb.getVHeight() - length;\r
1492                                         if ( rb.getVColumn() == col && ((drow == 0 && dlen == 0) || ((drow == 1 || drow == -1) && (dlen == 0 || dlen == -1 || dlen == 1))) ) {\r
1493                                                 rc++;\r
1494                                         }\r
1495                                 }\r
1496                         }\r
1497                         \r
1498                         // 予約マーク追加\r
1499                         JRMLabel rb = new JRMLabel();\r
1500                         \r
1501                         if (rc == 0) {\r
1502                                 rb.setVerticalAlignment(JLabel.BOTTOM);\r
1503                                 rb.setHorizontalAlignment(JLabel.RIGHT);\r
1504                         }\r
1505                         else if (rc == 1) {\r
1506                                 rb.setVerticalAlignment(JLabel.BOTTOM);\r
1507                                 rb.setHorizontalAlignment(JLabel.LEFT);\r
1508                         }\r
1509                         else {\r
1510                                 rb.setVerticalAlignment(JLabel.TOP);\r
1511                                 rb.setHorizontalAlignment(JLabel.RIGHT);\r
1512                         }\r
1513                         \r
1514                         // エンコーダの区別がないものは"■"を表示する\r
1515                         rb.setEncBackground(bordercol);\r
1516                         rb.setBorder(new LineBorder(bordercol,4));\r
1517                         if ( tuner != null && tuner.equals(TUNERLABEL_PICKUP) ) {\r
1518                                 rb.setEncForeground(env.getPickedFontColor());\r
1519                         }\r
1520                         else if ( exec ) {\r
1521                                 rb.setEncForeground(env.getExecOnFontColor());\r
1522                         }\r
1523                         else {\r
1524                                 rb.setEncForeground(env.getExecOffFontColor());\r
1525                         }\r
1526                         if (tuner == null || tuner.equals("")) {\r
1527                                 rb.setEncoder("■");\r
1528                         }\r
1529                         else {\r
1530                                 rb.setEncoder(tuner);\r
1531                         }\r
1532 \r
1533                         // 検索用情報\r
1534                         rb.setDate(date);\r
1535                         rb.setCenter(Center);\r
1536                         rb.setExec(exec);\r
1537                         \r
1538                         jLayeredPane_space_main_view.add(rb);\r
1539                         jLayeredPane_space_main_view.setLayer(rb,1);\r
1540                         rb.setVBounds(col, row, 1, length);\r
1541                         rb.setVisible(true);\r
1542                         \r
1543                         reserveBorders.add(rb);\r
1544                 }\r
1545         }\r
1546         \r
1547         /**\r
1548          * 番組枠の表示\r
1549          * @param cnt -1:放送局別表示、>=0:日付表示\r
1550          */\r
1551         private void putBangumiColumns(ProgList pl, int cnt, String date) {\r
1552                 int ymax = pl.pdate.size();\r
1553                 int col = -1;\r
1554                 for ( int dateid=0; dateid < ymax; dateid++ ) {\r
1555                         ProgDateList pcl = pl.pdate.get(dateid);\r
1556                         \r
1557                         if ( cnt >= 0 ) {\r
1558                                 if ( ! pcl.Date.equals(date) ) {\r
1559                                         // 日付表示の場合は1列のみ描画\r
1560                                         continue;\r
1561                                 }\r
1562                                 \r
1563                                 col = cnt;\r
1564                         }\r
1565                         else if ( cnt == -1 ) {\r
1566                                 col++;\r
1567                         }\r
1568                         \r
1569                         int row = 0;\r
1570                         int pEnd = 0;\r
1571                         int zmax = pcl.pdetail.size();\r
1572                         for ( int progid=0; progid<zmax; progid++ ) {\r
1573                                 ProgDetailList tvd = pcl.pdetail.get(progid);\r
1574                                 if ( progid != 0 ) {\r
1575                                         // 2つめ以降は開始時刻から計算\r
1576                                         String[] st = tvd.start.split(":",2);\r
1577                                         if ( st.length == 2 ) {\r
1578                                                 int ahh = Integer.valueOf(st[0]);\r
1579                                                 int amm = Integer.valueOf(st[1]);\r
1580                                                 if ( CommonUtils.isLateNight(ahh) ) {\r
1581                                                         ahh += 24;\r
1582                                                 }\r
1583                                                 row = (ahh-TIMEBAR_START)*60+amm;\r
1584                                         }\r
1585                                         else {\r
1586                                                 // 「番組情報がありません」は前の番組枠のお尻に\r
1587                                                 row = pEnd;\r
1588                                         }\r
1589                                 }\r
1590                                 else {\r
1591                                         // その日の最初のエントリは5:00以前の場合もあるので強制0スタート\r
1592                                         row = 0;\r
1593                                 }\r
1594                                 \r
1595                                 // 番組枠描画\r
1596                                 putBangumiColumnSub(tvd, row, col);\r
1597                                 \r
1598                                 // 「番組情報がありません」用に保存\r
1599                                 pEnd = row + tvd.length;\r
1600                         }\r
1601                 }\r
1602         }\r
1603         private void putBangumiColumnSub(ProgDetailList tvd, int row, int col) {\r
1604                 \r
1605                 // 新規生成か既存流用かを決める\r
1606                 JTXTButton b2 = null;\r
1607                 if (jLayeredPane_space_main_view == jLayeredPane_space_main_view_byMakeshift && ! frameUnused.isEmpty()) {\r
1608                         b2 = frameUnused.remove(frameUnused.size()-1);\r
1609                         //b2.setVisible(true);  // JTXTButton.clear()内でsetVisible(false)しているので\r
1610                 }\r
1611                 else {\r
1612                         // 生成する\r
1613                         b2 = new JTXTButton();\r
1614                         jLayeredPane_space_main_view.add(b2);\r
1615                         jLayeredPane_space_main_view.setLayer(b2, 0);\r
1616                         \r
1617                         // リスナーを設定する\r
1618                         b2.addMouseListener(ml_risepopup);\r
1619                         b2.addMouseMotionListener(ml_risepopup);\r
1620                 }\r
1621                 if (jLayeredPane_space_main_view == jLayeredPane_space_main_view_byMakeshift) {\r
1622                         frameUsed.add(b2);\r
1623                 }\r
1624                 else {\r
1625                         // 裏描画は十分遅いのでb2をUnusedキャッシュには入れず都度生成で構わない\r
1626                         frameUsedByDate.add(b2);\r
1627                 }\r
1628                 \r
1629                 // 情報設定\r
1630                 b2.setInfo(tvd);\r
1631                 \r
1632                 JTXTButton.setColumnWidth(bounds.getBangumiColumnWidth());\r
1633                 JTXTButton.setHeightMultiplier(bounds.getPaperHeightMultiplier() * paperHeightZoom);\r
1634                 \r
1635                 b2.setBackground(pColors.get(tvd.genre));\r
1636                 _updPBorder(bounds, b2);\r
1637 \r
1638                 // 配置を決定する\r
1639                 b2.setVBounds(col,row,1,tvd.length);\r
1640                 \r
1641                 // ツールチップを付加する\r
1642                 if ( env.getTooltipEnable() == true && ! tvd.title.equals("") && ! tvd.start.equals("") ) {\r
1643                         String t = "";\r
1644                         int tlen = bounds.getTooltipWidth();\r
1645                         for (int i=0; i<tvd.title.length(); i+=tlen) {\r
1646                                 t += tvd.title.substring(i, (i+tlen<tvd.title.length())?(i+tlen):(tvd.title.length()))+"<BR>";\r
1647                         }\r
1648                         String d = "";\r
1649                         int dlen = tlen+2;\r
1650                         for (int i=0; i<tvd.detail.length(); i+=dlen) {\r
1651                                 d += "&nbsp;&nbsp;&nbsp;&nbsp;"+tvd.detail.substring(i, (i+dlen<tvd.detail.length())?(i+dlen):(tvd.detail.length()))+"<BR>";\r
1652                         }\r
1653                         String e = getExtensionMark(tvd);\r
1654                         b2.setToolTipText(("<html>"+tvd.start+"&nbsp;<FONT COLOR=RED><EM>"+e+"</EM></FONT><BR>&nbsp;<FONT COLOR=BLUE><STRONG><U>"+t+"</U></STRONG></FONT>"+d+"</html>"));\r
1655                 }\r
1656         }\r
1657         \r
1658         /**\r
1659          * 現在時刻線の位置を変える\r
1660          * @param minpos : MINPOS.RESET=初回、MINPOS.UPDATE=自動更新時\r
1661          */\r
1662         private int setTimelinePos(boolean reset) {\r
1663                 if ( vport != null && jLabel_timeline != null && jLabel_timeline.isVisible() ) {\r
1664                         \r
1665                         int correct = 0; // 24:00-28:59迄は前日の日付になる\r
1666                         GregorianCalendar c = CommonUtils.getCalendar(0);\r
1667                         if ( CommonUtils.isLateNight(c) ) {\r
1668                                 c.add(Calendar.DATE, -1);\r
1669                                 correct += 24;\r
1670                         }\r
1671                         \r
1672                         Point vp = vport.getViewPosition();\r
1673                         Point tp = jLabel_timeline.getLocation();\r
1674                         \r
1675                         // ビュー上の位置\r
1676                         int minpos_new = (c.get(Calendar.HOUR_OF_DAY)-TIMEBAR_START+correct)*60+c.get(Calendar.MINUTE);\r
1677                         int timeline_vpos = jLabel_timeline.setMinpos(0, minpos_new, bounds.getPaperHeightMultiplier()*paperHeightZoom);\r
1678                         \r
1679                         // ビューポートの位置\r
1680                         if ( reset ) {\r
1681                                 // 初回描画\r
1682                                 Rectangle ra = vport.getViewRect();\r
1683                                 if ( minpos_new >= 30 ) {\r
1684                                         // 05:30以降\r
1685                                         ra.y =  Math.round(timeline_vpos - (float)bounds.getTimelinePosition() * bounds.getPaperHeightMultiplier() * paperHeightZoom);\r
1686                                         vport.setViewPosition(new Point(ra.x, ra.y));\r
1687                                 }\r
1688                                 else {\r
1689                                         // 05:30より前\r
1690                                         if ( ra.y >= 30 ) {\r
1691                                                 vport.setViewPosition(new Point(ra.x, 0));\r
1692                                         }\r
1693                                 }\r
1694                         }\r
1695                         else {\r
1696                                 if ( env.getTimerbarScrollEnable() && minpos_new >= 30 ) {\r
1697                                         // 自動更新(05:30まではスクロールしないよ)\r
1698                                         vp.y += (timeline_vpos - tp.y);\r
1699                                         vport.setViewPosition(vp);\r
1700                                 }\r
1701                         }\r
1702                         \r
1703                         jLabel_timeline.updateUI();\r
1704                         \r
1705                         return minpos_new;\r
1706                 }\r
1707                 \r
1708                 return -1;\r
1709         }\r
1710         \r
1711         /**\r
1712          * 番組枠のクリック位置を日時に変換する\r
1713          */\r
1714         private String getClickedDateTime(ProgDetailList tvd, int clikedY) {\r
1715                 \r
1716                 String clickedDateTime = null;\r
1717                 \r
1718                 if ( clikedY >= 0 && tvd.start.length() != 0 ) {\r
1719                         // 新聞形式ならクリック位置の日時を算出する\r
1720                         GregorianCalendar cala = CommonUtils.getCalendar(tvd.startDateTime);\r
1721                         cala.add(Calendar.MINUTE, Math.round(((float)clikedY)/(bounds.getPaperHeightMultiplier()*paperHeightZoom)));\r
1722                         clickedDateTime = CommonUtils.getDateTime(cala);\r
1723                 }\r
1724                 \r
1725                 return clickedDateTime;\r
1726         }\r
1727         \r
1728         \r
1729         /*******************************************************************************\r
1730          * ハンドラ―メソッド\r
1731          ******************************************************************************/\r
1732         \r
1733         /**\r
1734          * ツールバーでレコーダの選択イベントが発生\r
1735          */\r
1736         @Override\r
1737         public void valueChanged(HDDRecorderSelectionEvent e) {\r
1738                 if (debug) System.out.println(DBGID+"recorder selection rised");\r
1739                 \r
1740                 // 選択中のレコーダ情報を保存する\r
1741                 src_recsel = (HDDRecorderSelectable) e.getSource();\r
1742                 \r
1743                 // 予約枠を書き換える\r
1744                 updateReserveBorder(null);\r
1745         }\r
1746         \r
1747         private String getSelectedMySelf() {\r
1748                 return ( src_recsel!=null ? src_recsel.getSelectedMySelf() : null );\r
1749         }\r
1750         \r
1751         private HDDRecorderList getSelectedRecorderList() {\r
1752                 return ( src_recsel!=null ? src_recsel.getSelectedList() : null );\r
1753         }\r
1754         \r
1755         private HDDRecorderSelectable src_recsel;\r
1756         \r
1757         \r
1758         /**\r
1759          * レコーダ情報の変更イベントが発生\r
1760          */\r
1761         @Override\r
1762         public void stateChanged(HDDRecorderChangeEvent e) {\r
1763                 // テーブルをリフレッシュする処理\r
1764                 \r
1765         }\r
1766         \r
1767         \r
1768 \r
1769         /*******************************************************************************\r
1770          * リスナー\r
1771          ******************************************************************************/\r
1772 \r
1773         /**\r
1774          * 現在時刻追従スクロール\r
1775          */\r
1776         @Override\r
1777         public void timerRised(TickTimerRiseEvent e) {\r
1778                 \r
1779                 String curDT = CommonUtils.getDate529(0,true);\r
1780                 \r
1781                 if ( prevDT4Tree != null && ! prevDT4Tree.equals(curDT) ) {\r
1782                         // 日付が変わったらツリーを書き換える\r
1783                         redrawTreeByDate();\r
1784                         redrawTreeByPassed();\r
1785                         \r
1786                         // 前回実行日\r
1787                         prevDT4Tree = curDT;\r
1788                 }\r
1789                 \r
1790                 if ( timer_now_enabled ) {\r
1791 \r
1792                         if (prevDT4Now != null && ! prevDT4Now.equals(curDT)) {\r
1793                                 // 日付切り替え\r
1794                                 StdAppendError(MSGID+"日付が変わったので番組表を切り替えます("+CommonUtils.getDateTime(0)+")");\r
1795                                 redrawByNow(cur_tuner);\r
1796                         }\r
1797                         else {\r
1798                                 // 現在時刻線の移動\r
1799                                 setTimelinePos(false);\r
1800                         }\r
1801                         \r
1802                         // 前回実行日\r
1803                         prevDT4Now = curDT;\r
1804                 }\r
1805         }\r
1806         \r
1807         /**\r
1808          * タブを開いたり閉じたりしたときに動くリスナー\r
1809          */\r
1810         private ComponentListener cl_shownhidden = new ComponentAdapter() {\r
1811                 @Override\r
1812                 public void componentShown(ComponentEvent e) {\r
1813                         \r
1814                         // 前日以前の番組情報を削除する\r
1815                         for ( TVProgram tvp : tvprograms ) {\r
1816                                 tvp.refresh();\r
1817                         }\r
1818                         \r
1819                         // 終了した予約を整理する\r
1820                         for ( HDDRecorder recorder : recorders ) {\r
1821                                 recorder.removePassedReserves();\r
1822                         }\r
1823                         \r
1824                         // 他のコンポーネントと連動\r
1825                         onShown();\r
1826                         \r
1827                         setPagerEnabled(true);\r
1828                 }\r
1829                 \r
1830                 @Override\r
1831                 public void componentHidden(ComponentEvent e) {\r
1832                         \r
1833                         onHidden();\r
1834                         \r
1835                         setPagerEnabled(false);\r
1836                 }\r
1837         };\r
1838         \r
1839         /**\r
1840          * 番組枠につけるマウス操作のリスナー\r
1841          */\r
1842         private final MouseInputListener ml_risepopup = new MouseInputListener() {\r
1843                 //\r
1844                 private final Cursor defCursor = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);\r
1845                 private final Cursor hndCursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);\r
1846                 private final Point pp = new Point();\r
1847                 \r
1848                 private Color bgcolor = null;\r
1849 \r
1850                 @Override\r
1851                 public void mouseClicked(MouseEvent e) {\r
1852                         \r
1853                         // ポインタの位置\r
1854                         Point p = e.getPoint();\r
1855                         \r
1856                         // ポインタの乗っている番組\r
1857                         JTXTButton b = (JTXTButton) e.getSource();\r
1858                         ProgDetailList tvd = b.getInfo();\r
1859                         \r
1860                         if (e.getButton() == MouseEvent.BUTTON3) {\r
1861                                 if (e.getClickCount() == 1) {\r
1862                                         // 右シングルクリックでメニューの表示\r
1863                                         String clicked = getClickedDateTime(tvd, e.getY());\r
1864                                         showPopupForTraceProgram(b, tvd, tvd.title, TraceKey.noFazzyThreshold, p.x, p.y, clicked);\r
1865                                 }\r
1866                         }\r
1867                         else if (e.getButton() == MouseEvent.BUTTON1) {\r
1868                                 // 過去ログは閲覧のみ\r
1869                                 if (tvd.type == ProgType.PASSED) {\r
1870                                         if (e.getClickCount() == 2) {\r
1871                                                 MWin.appendMessage(MSGID+"過去ログでダブルクリックは利用できません");\r
1872                                                 ringBeep();\r
1873                                         }\r
1874                                         \r
1875                                         return;\r
1876                                 }\r
1877                                 \r
1878                                 if (e.getClickCount() == 2) {\r
1879                                         // 左ダブルクリックで予約ウィンドウを開く\r
1880                                         openReserveDialog(tvd);                                 \r
1881                                 }\r
1882                         }\r
1883                         else if (e.getButton() == MouseEvent.BUTTON2) {\r
1884                                 // ピックアップに追加\r
1885                                 addToPickup(tvd);\r
1886                         }\r
1887                 }\r
1888                 \r
1889                 private void openReserveDialog(ProgDetailList tvd) {\r
1890                         \r
1891                         // レコーダが登録されていない場合はなにもしない\r
1892                         if (recorders.size() == 0) {\r
1893                                 return;\r
1894                         }\r
1895 \r
1896                         // ダイアログの位置指定\r
1897                         CommonSwingUtils.setLocationCenter(parent,rD);\r
1898                         \r
1899                         // サブタイトルを番組追跡の対象から外す\r
1900                         boolean succeeded = false;\r
1901                         if ( ! env.getSplitEpno() && env.getTraceOnlyTitle() ) {\r
1902                                 succeeded = rD.open(tvd,tvd.title,TraceKey.defaultFazzyThreshold);\r
1903                         }\r
1904                         else {\r
1905                                 succeeded = rD.open(tvd);\r
1906                         }\r
1907                         \r
1908                         if (succeeded) {\r
1909                                 rD.setVisible(true);\r
1910                         }\r
1911                         else {\r
1912                                 rD.dispose();\r
1913                         }\r
1914                         \r
1915                         if (rD.isSucceededReserve()) {\r
1916                                 updateReserveDisplay();\r
1917                                 updateReserveBorder(tvd.center);\r
1918                         }\r
1919                 }\r
1920 \r
1921                 /**\r
1922                  * 詳細情報の自動表示\r
1923                  */\r
1924                 @Override\r
1925                 public void mouseEntered(MouseEvent e) {\r
1926                         \r
1927                         JTXTButton b = (JTXTButton) e.getSource();\r
1928                         ProgDetailList tvd = b.getInfo();\r
1929                         \r
1930                         if ( env.getEnableHighlight() ) {\r
1931                                 bgcolor = ((JTXTButton)e.getSource()).getBackground();\r
1932                                 ((JTXTButton)e.getSource()).setBackground(env.getHighlightColor());\r
1933                         }\r
1934                         jTextPane_detail.setLabel(tvd.start,tvd.end,tvd.title);\r
1935                         jTextPane_detail.setText(tvd.detail+"\n"+tvd.getAddedDetail());\r
1936                 }\r
1937 \r
1938                 @Override\r
1939                 public void mouseExited(MouseEvent e) {\r
1940                         if ( env.getEnableHighlight() ) {\r
1941                                 ((JTXTButton)e.getSource()).setBackground(bgcolor);\r
1942                         }\r
1943                 }\r
1944 \r
1945                 @Override\r
1946                 public void mouseDragged(final MouseEvent e) {\r
1947                         Point cp = e.getLocationOnScreen();\r
1948                         Point vp = vport.getViewPosition(); //= SwingUtilities.convertPoint(vport,0,0,label);\r
1949                         vp.translate(pp.x-cp.x, pp.y-cp.y);\r
1950                         jLayeredPane_space_main_view.scrollRectToVisible(new Rectangle(vp, vport.getSize()));\r
1951                         pp.setLocation(cp);\r
1952                 }\r
1953 \r
1954                 @Override\r
1955                 public void mousePressed(MouseEvent e) {\r
1956                         pp.setLocation(e.getLocationOnScreen());\r
1957                         jLayeredPane_space_main_view.setCursor(hndCursor);\r
1958                 }\r
1959 \r
1960                 @Override\r
1961                 public void mouseReleased(MouseEvent e) {\r
1962                         jLayeredPane_space_main_view.setCursor(defCursor);\r
1963                 }\r
1964 \r
1965                 @Override\r
1966                 public void mouseMoved(MouseEvent e) {\r
1967                 }\r
1968         };\r
1969         \r
1970         /**\r
1971          * サイドツリーにつけるリスナー(ツリーの展開状態を記憶する)\r
1972          */\r
1973         private final TreeExpansionListener tel_nodeexpansion = new TreeExpansionListener() {\r
1974                 \r
1975                 @Override\r
1976                 public void treeExpanded(TreeExpansionEvent event) {\r
1977                         ter.reg();\r
1978                 }\r
1979                 \r
1980                 @Override\r
1981                 public void treeCollapsed(TreeExpansionEvent event) {\r
1982                         ter.reg();\r
1983                 }\r
1984         };\r
1985 \r
1986         /**\r
1987          * サイドツリーにつけるリスナー(クリックで描画実行)\r
1988          */\r
1989         private final TreeSelectionListener tsl_nodeselected = new TreeSelectionListener() {\r
1990                 @Override\r
1991                 public void valueChanged(TreeSelectionEvent e){\r
1992                         \r
1993                         TreePath path = jTree_tree.getSelectionPath();\r
1994 \r
1995                         if ( path != null && path.getPathCount() == 2 ) {\r
1996                                 // 親ノードとか触られても…\r
1997                                 return;\r
1998                         }\r
1999                         \r
2000                         if ( path != null && path.getPathCount() == 3 ) {\r
2001                                 \r
2002                                 if (env.getDebug()) System.out.println(DBGID+"SELECTED treeSelListner "+path);\r
2003 \r
2004                                 stopTimer();\r
2005 \r
2006                                 JTreeLabel.Nodes node = JTreeLabel.Nodes.getNode(path.getPathComponent(1).toString());\r
2007                                 String value = path.getLastPathComponent().toString();\r
2008                         \r
2009                                 switch ( node ) {\r
2010                                 case DATE:\r
2011                                         if ( JTreeLabel.Nodes.NOW.getLabel().equals(value) ) {\r
2012                                                 // 現在日時に移動する\r
2013                                                 redrawByNow(IterationType.ALL);\r
2014                                         }\r
2015                                         else {\r
2016                                                 redrawByDate(value,IterationType.ALL);\r
2017                                         }\r
2018                                         if ( env.isPagerEnabled() ) {\r
2019                                                 setPagerEnabled(true);\r
2020                                         }\r
2021                                         break;\r
2022                                 case TERRA:\r
2023                                         if ( JTreeLabel.Nodes.NOW.getLabel().equals(value) ) {\r
2024                                                 redrawByNow(IterationType.TERRA);\r
2025                                         }\r
2026                                         else {\r
2027                                                 redrawByDate(value,IterationType.TERRA);\r
2028                                         }\r
2029                                         if ( env.isPagerEnabled() ) {\r
2030                                                 setPagerEnabled(true);\r
2031                                         }\r
2032                                         break;\r
2033                                 case BS:\r
2034                                         if ( JTreeLabel.Nodes.NOW.getLabel().equals(value) ) {\r
2035                                                 redrawByNow(IterationType.BS);\r
2036                                         }\r
2037                                         else {\r
2038                                                 redrawByDate(path.getLastPathComponent().toString(),IterationType.BS);\r
2039                                         }\r
2040                                         if ( env.isPagerEnabled() ) {\r
2041                                                 setPagerEnabled(true);\r
2042                                         }\r
2043                                         break;\r
2044                                 case CS:\r
2045                                         if ( JTreeLabel.Nodes.NOW.getLabel().equals(value) ) {\r
2046                                                 redrawByNow(IterationType.CS);\r
2047                                         }\r
2048                                         else {\r
2049                                                 redrawByDate(path.getLastPathComponent().toString(),IterationType.CS);\r
2050                                         }\r
2051                                         if ( env.isPagerEnabled() ) {\r
2052                                                 setPagerEnabled(true);\r
2053                                         }\r
2054                                         break;\r
2055                                 case BCAST:\r
2056                                         redrawByCenter(value);\r
2057                                         if ( env.isPagerEnabled() ) {\r
2058                                                 setPagerEnabled(false);\r
2059                                         }\r
2060                                         break;\r
2061                                 case PASSED:\r
2062                                         PassedProgram passed = tvprograms.getPassed();\r
2063                                         if ( passed.loadAllCenters(value) ) {\r
2064                                                 redrawByDate(value, IterationType.PASSED);\r
2065                                         }\r
2066                                         else {\r
2067                                                 MWin.appendError(ERRID+"過去ログが存在しません: "+value);\r
2068                                                 ringBeep();\r
2069                                         }\r
2070                                         if ( env.isPagerEnabled() ) {\r
2071                                                 setPagerEnabled(true);\r
2072                                         }\r
2073                                         break;\r
2074                                 default:\r
2075                                         break;\r
2076                                 }\r
2077                                 \r
2078                                 jLabel_tree.setView(node, value);\r
2079                                 return;\r
2080                         }\r
2081                         \r
2082                         // なんかおかしいのでデフォルト選択にまわす\r
2083                         CommonUtils.printStackTrace();\r
2084                         MWin.appendError(ERRID+"バグの可能性あり");\r
2085                         //redrawByNow(IterationType.ALL);\r
2086                         //jLabel_tree.setView(JTreeLabel.Nodes.DATE, JTreeLabel.Nodes.NOW.getLabel());\r
2087                 }\r
2088         };\r
2089         \r
2090         /**\r
2091          * フルスクリーン時にツリーを隠したりするの\r
2092          */\r
2093         private final MouseListener ml_treehide = new MouseAdapter() {\r
2094                 public void mouseEntered(MouseEvent e) {\r
2095                         if (isFullScreen()) {\r
2096                                 setExpandTree();\r
2097                                 //StdAppendMessage("Show tree (N)");\r
2098                         }\r
2099                 }\r
2100                 public void mouseExited(MouseEvent e) {\r
2101                         if (isFullScreen()) {\r
2102                                 setCollapseTree();\r
2103                                 //StdAppendMessage("Hide tree (N)");\r
2104                         }\r
2105                 }\r
2106         };\r
2107         \r
2108         /**\r
2109          * 放送局名につけるリスナー(ダブルクリックで一週間表示にジャンプ)\r
2110          */\r
2111         private final MouseAdapter cnMouseAdapter = new MouseAdapter() {\r
2112                 \r
2113                 private Color bgcolor = null;\r
2114                 \r
2115                 public void mouseExited(MouseEvent e) {\r
2116                         ((JLabel)e.getSource()).setBackground(bgcolor);\r
2117                 }\r
2118                 public void mouseEntered(MouseEvent e) {\r
2119                         bgcolor = ((JLabel)e.getSource()).getBackground();\r
2120                         ((JLabel)e.getSource()).setBackground(new Color(180,180,255));\r
2121                 }\r
2122                 \r
2123                 public void mouseClicked(MouseEvent e) {\r
2124                         if (e.getButton() == MouseEvent.BUTTON1) {\r
2125                                 if (e.getClickCount() == 2) {\r
2126                                         if ( cur_tuner == IterationType.PASSED ) {\r
2127                                                 MWin.appendMessage(MSGID+"過去ログでは一局表示に切り替えられません");\r
2128                                                 return;\r
2129                                         }\r
2130                                         \r
2131                                         // 右ダブルクリックで局表示に切り替え\r
2132                                         String center = ((JLabel)e.getSource()).getText();\r
2133                                         StdAppendMessage(MSGID+"一局表示に切り替え:"+center);\r
2134                                         //redrawByCenter(center);\r
2135                                         jLabel_tree.setView(JTreeLabel.Nodes.BCAST, center);\r
2136                                         reselectTree();\r
2137                                 }\r
2138                         }\r
2139                 }\r
2140         };\r
2141         \r
2142         /**\r
2143          * 日付枠につけるリスナー(ダブルクリックで放送局別表示にジャンプ)\r
2144          */\r
2145         private final MouseAdapter tbMouseAdapter = new MouseAdapter() {\r
2146                 private Color bgcolor = null;\r
2147                 //\r
2148                 public void mouseExited(MouseEvent e) {\r
2149                         ((JTXTLabel)e.getSource()).setBackground(bgcolor);\r
2150                 }\r
2151                 public void mouseEntered(MouseEvent e) {\r
2152                         bgcolor = ((JTXTLabel)e.getSource()).getBackground();\r
2153                         ((JTXTLabel)e.getSource()).setBackground(new Color(180,180,255));\r
2154                 }\r
2155                 \r
2156                 //\r
2157                 public void mouseClicked(MouseEvent e) {\r
2158                         if (e.getButton() == MouseEvent.BUTTON1) {\r
2159                                 if (e.getClickCount() == 2) {\r
2160                                         // 右ダブルクリックで日付表示に切り替え\r
2161                                         String date = ((JTXTLabel)e.getSource()).getValue();\r
2162                                         StdAppendMessage(MSGID+"日付表示に切り替え:"+date);\r
2163                                         //redrawByDate(date, -1);\r
2164                                         jLabel_tree.setView(JTreeLabel.Nodes.DATE, date);\r
2165                                         reselectTree();\r
2166                                 }\r
2167                         }\r
2168                 }\r
2169         };\r
2170         \r
2171         \r
2172         \r
2173         /*******************************************************************************\r
2174          * コンポーネント\r
2175          ******************************************************************************/\r
2176 \r
2177         private JDetailPanel getJTextPane_detail() {\r
2178                 if (jTextPane_detail == null) {\r
2179                         jTextPane_detail = new JDetailPanel();\r
2180                         jTextPane_detail.setRows(bounds.getDetailRows());\r
2181                         //Dimension d = jTextPane_detail.getMaximumSize();\r
2182                         //d.height = bounds.getDetailAreaHeight();\r
2183                         //jTextPane_detail.setPreferredSize(d);\r
2184                         //jTextPane_detail.setVerticalAlignment(JLabel.TOP);\r
2185                         //jTextPane_detail.setHorizontalAlignment(JLabel.LEFT);\r
2186                 }\r
2187                 return jTextPane_detail;\r
2188         }\r
2189         \r
2190         private JSplitPane getJSplitPane_view() {\r
2191                 if ( jSplitPane_view == null ) {\r
2192                         \r
2193                         jSplitPane_view = new JSplitPane() {\r
2194 \r
2195                                 private static final long serialVersionUID = 1L;\r
2196 \r
2197                                 @Override\r
2198                                 public void setDividerLocation(int loc) {\r
2199                                         setDividerEnvs(loc);\r
2200                                         super.setDividerLocation(loc);\r
2201                                 }\r
2202                         };\r
2203                         \r
2204                         jSplitPane_view.setLeftComponent(getJPanel_tree());\r
2205                         jSplitPane_view.setRightComponent(getJScrollPane_space_main());\r
2206                         setExpandTree();\r
2207                 }\r
2208                 return jSplitPane_view;\r
2209         }\r
2210 \r
2211         private JPanel getJPanel_tree() {\r
2212                 if (jPanel_tree == null) {\r
2213                         jPanel_tree = new JPanel();\r
2214 \r
2215                         jPanel_tree.setLayout(new BorderLayout());\r
2216                         jPanel_tree.add(getJScrollPane_tree_top(), BorderLayout.PAGE_START);\r
2217                         jPanel_tree.add(getJScrollPane_tree(), BorderLayout.CENTER);\r
2218                 }\r
2219                 return jPanel_tree;\r
2220         }\r
2221         \r
2222         //\r
2223         private JScrollPane getJScrollPane_tree_top() {\r
2224                 if (jScrollPane_tree_top == null) {\r
2225                         jScrollPane_tree_top = new JScrollPane();\r
2226                         jScrollPane_tree_top.setViewportView(getJLabel_tree());\r
2227                         jScrollPane_tree_top.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);\r
2228                         jScrollPane_tree_top.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);\r
2229                 }\r
2230                 return jScrollPane_tree_top;\r
2231         }\r
2232         private JTreeLabel getJLabel_tree() {\r
2233                 if (jLabel_tree == null) {\r
2234                         jLabel_tree = new JTreeLabel();\r
2235                         \r
2236                         Dimension d = jLabel_tree.getMaximumSize();\r
2237                         d.height = bounds.getBangumiColumnHeight();\r
2238                         jLabel_tree.setPreferredSize(d);\r
2239                         jLabel_tree.setOpaque(true);\r
2240                         jLabel_tree.setBackground(Color.WHITE);\r
2241                 }\r
2242                 return jLabel_tree;\r
2243         }\r
2244         \r
2245         private JScrollPane getJScrollPane_tree() {\r
2246                 if (jScrollPane_tree == null) {\r
2247                         jScrollPane_tree = new JScrollPane();\r
2248 \r
2249                         jScrollPane_tree.setViewportView(getJTree_tree());\r
2250                 }\r
2251                 return jScrollPane_tree;\r
2252         }\r
2253         \r
2254         /**\r
2255          * ツリーの作成\r
2256          */\r
2257         private JTree getJTree_tree() {\r
2258                 if (jTree_tree == null) {\r
2259 \r
2260                         // ツリーの作成\r
2261                         jTree_tree = new JTree();\r
2262                         jTree_tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);\r
2263                         jTree_tree.setRootVisible(env.getRootNodeVisible());\r
2264                         \r
2265                         // ノードの作成\r
2266                         jTree_tree.setModel(new DefaultTreeModel(getTreeNodes()));\r
2267                         \r
2268                         // ツリーの展開状態の復帰\r
2269                         undoTreeExpansion();\r
2270                         \r
2271                         // ツリーの開閉時に状態を保存する\r
2272                         jTree_tree.addTreeExpansionListener(tel_nodeexpansion);\r
2273                         \r
2274                         // フルスクリーンの時に使う(新聞形式のツリーを自動的に隠す)\r
2275                         jTree_tree.addMouseListener(ml_treehide);\r
2276                 }\r
2277                 return jTree_tree;\r
2278         }\r
2279 \r
2280         /**\r
2281          * ツリーのノード作成\r
2282          */\r
2283         private DefaultMutableTreeNode getTreeNodes() {\r
2284                 \r
2285                 paperRootNode = new DefaultMutableTreeNode(JTreeLabel.Nodes.ROOT.getLabel());\r
2286                 \r
2287                 dateNode        = new DefaultMutableTreeNode(JTreeLabel.Nodes.DATE.getLabel());\r
2288                 dgNode          = new DefaultMutableTreeNode(JTreeLabel.Nodes.TERRA.getLabel());\r
2289                 bsNode          = new DefaultMutableTreeNode(JTreeLabel.Nodes.BS.getLabel());\r
2290                 csNode          = new DefaultMutableTreeNode(JTreeLabel.Nodes.CS.getLabel());\r
2291                 centerNode      = new DefaultMutableTreeNode(JTreeLabel.Nodes.BCAST.getLabel());\r
2292                 passedNode      = new DefaultMutableTreeNode(JTreeLabel.Nodes.PASSED.getLabel());\r
2293                 \r
2294                 paperRootNode.add(dateNode);\r
2295                 paperRootNode.add(dgNode);\r
2296                 paperRootNode.add(bsNode);\r
2297                 paperRootNode.add(csNode);\r
2298                 paperRootNode.add(centerNode);\r
2299                 paperRootNode.add(passedNode);\r
2300 \r
2301                 // 子の描画\r
2302                 redrawTreeByDate();\r
2303                 redrawTreeByCenter();\r
2304                 redrawTreeByPassed();\r
2305                 \r
2306                 return paperRootNode;\r
2307         }\r
2308         \r
2309         private void undoTreeExpansion() {\r
2310                         \r
2311                 // 展開状態の復帰\r
2312                 stopTreeListener();\r
2313                 \r
2314                 // 展開状態の記憶域の初期化\r
2315                 ter = new TreeExpansionReg(jTree_tree, TreeExpRegFile_Paper);\r
2316                 try {\r
2317                         ter.load();\r
2318                 }\r
2319                 catch (Exception e) {\r
2320                         MWin.appendMessage(ERRID+"ツリー展開情報の解析で問題が発生しました");\r
2321                         e.printStackTrace();\r
2322                 }\r
2323 \r
2324                 // 状態を復元する\r
2325                 ArrayList<TreePath> tpa = ter.get();\r
2326                 for ( TreePath path : tpa ) {\r
2327                         jTree_tree.expandPath(path);\r
2328                 }\r
2329                 \r
2330                 startTreeListener();\r
2331         }\r
2332 \r
2333         private JScrollPane getJScrollPane_space_main() {\r
2334                 if (jScrollPane_space_main == null) {\r
2335                         jScrollPane_space_main = new JScrollPane(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);\r
2336                         jScrollPane_space_main.getVerticalScrollBar().setUnitIncrement(bounds.getBangumiColumnHeight());\r
2337                         jScrollPane_space_main.getHorizontalScrollBar().setUnitIncrement(bounds.getBangumiColumnWidth());\r
2338                         \r
2339                         //jScrollPane_space_main.setViewportView(getJLayeredPane_space_main_view());\r
2340                         jScrollPane_space_main.setColumnHeaderView(getJPanel_space_top_view());\r
2341                         jScrollPane_space_main.setRowHeaderView(getJPanel_space_side_view());\r
2342                         \r
2343                         vport = jScrollPane_space_main.getViewport();\r
2344                 }\r
2345                 return jScrollPane_space_main;\r
2346         }\r
2347         \r
2348         private JPanel getJPanel_space_top_view() {\r
2349                 if (jPanel_space_top_view == null) {\r
2350                         jPanel_space_top_view = new JPanel();\r
2351                         jPanel_space_top_view.setLayout(new SpringLayout());\r
2352                 }\r
2353                 return jPanel_space_top_view;\r
2354         }\r
2355         \r
2356         private JPanel getJPanel_space_side_view() {\r
2357                 if (jPanel_space_side_view == null) {\r
2358                         jPanel_space_side_view = new JPanel();\r
2359                         jPanel_space_side_view.setLayout(null);\r
2360                 }\r
2361                 return jPanel_space_side_view;\r
2362         }\r
2363         \r
2364         \r
2365         /*\r
2366          * 以下は、pcwinから呼び出されるメソッドをまとめたもの \r
2367          */\r
2368         \r
2369         // 時間枠のコンポーネント\r
2370         public Component[] getTimebarComponents() {\r
2371                 return jPanel_space_side_view.getComponents();\r
2372         }\r
2373 \r
2374         // 背景色ほかの変更\r
2375         public void updateColors(Env ec,PaperColorsMap pc) {\r
2376                 _updPColors(ec, pc, frameUsed);\r
2377                 \r
2378                 if ( env.getDrawcacheEnable() ) {\r
2379                         _updPColors(ec, pc, frameUsedByDate);\r
2380                 }\r
2381                 \r
2382                 // マウスオーバー時のハイライト\r
2383                 /* no proc. */\r
2384                 \r
2385                 // タイムバーの色\r
2386                 for ( Component c : getTimebarComponents() ) {\r
2387                         if ( c instanceof JTimebarLabel ) {\r
2388                                 int j = Integer.valueOf(((JTimebarLabel) c).getTs());\r
2389                                 if ( j >=6 && j <= 11 ) {\r
2390                                         c.setBackground(ec.getTimebarColor());\r
2391                                 }\r
2392                                 else if ( j >=12 && j <= 17 ) {\r
2393                                         c.setBackground(ec.getTimebarColor2());\r
2394                                 }\r
2395                                 else if ( j >=18 && j <= 23 ) {\r
2396                                         c.setBackground(ec.getTimebarColor3());\r
2397                                 }\r
2398                                 else {\r
2399                                         c.setBackground(ec.getTimebarColor4());\r
2400                                 }\r
2401                         }\r
2402                 }\r
2403         }\r
2404         \r
2405         // サイズの変更\r
2406         public void updateBounds(Env ec, Bounds bc) {\r
2407                 \r
2408                 int maxCol = jPanel_space_top_view.getComponentCount();\r
2409                 float maxRow = 24*60;\r
2410                 \r
2411                 float phm = bc.getPaperHeightMultiplier() * paperHeightZoom ;\r
2412 \r
2413                 int vieww = maxCol * bc.getBangumiColumnWidth();\r
2414                 int viewh = (int) Math.ceil(maxRow * phm);\r
2415 \r
2416                 // 変更前のビューの位置\r
2417                 Point vp = vport.getViewPosition();\r
2418                 float vh = vport.getView().getPreferredSize().height;\r
2419                 \r
2420                 // タイムバーのサイズ変更\r
2421                 {\r
2422                         int h = (int) Math.ceil(60.0F*phm);\r
2423                         int row = 0;\r
2424                         for ( Component b0 : jPanel_space_side_view.getComponents() ) {\r
2425                                 b0.setBounds(0,(int) Math.ceil((float)row*phm),bc.getTimebarColumnWidth(),h);\r
2426                                 row += 60;\r
2427                         }\r
2428                         \r
2429                         Dimension d = jPanel_space_side_view.getPreferredSize();\r
2430                         d.height = viewh;\r
2431                         jPanel_space_side_view.setPreferredSize(d);\r
2432                 }\r
2433                 \r
2434                 // 放送局名(or日付)のサイズ変更\r
2435                 {\r
2436                         for ( int col=0; col<jPanel_space_top_view.getComponentCount(); col++ ) {\r
2437                                 Component b1 = jPanel_space_top_view.getComponent(col);\r
2438                                 b1.setBounds(\r
2439                                                 bc.getBangumiColumnWidth() * col,\r
2440                                                 0,\r
2441                                                 bc.getBangumiColumnWidth(),\r
2442                                                 bc.getBangumiColumnHeight());\r
2443                         }\r
2444                         Dimension d = jPanel_space_top_view.getPreferredSize();\r
2445                         d.width = vieww;\r
2446                         jPanel_space_top_view.setPreferredSize(d);\r
2447                 }\r
2448                 \r
2449                 // 各番組枠のサイズ変更・検索マッチ枠の表示変更\r
2450                 {\r
2451                         {\r
2452                                 _updPBounds(bc, frameUsed);\r
2453                                 _updPBorderAll(ec, bc, frameUsed);\r
2454                                 \r
2455                                 Dimension d = jLayeredPane_space_main_view.getPreferredSize();\r
2456                                 d.width = vieww;\r
2457                                 d.height = viewh;\r
2458                                 jLayeredPane_space_main_view.setPreferredSize(d);\r
2459                         }\r
2460                         \r
2461                         if ( ec.getDrawcacheEnable() ) {\r
2462                                 _updPBounds(bc, frameUsedByDate);\r
2463                                 _updPBorderAll(ec, bc, frameUsedByDate);\r
2464                                 \r
2465                                 for ( JLayeredPane pane : jLayeredPane_space_main_view_byDate ) {\r
2466                                         Dimension d = pane.getPreferredSize();\r
2467                                         d.width = vieww;\r
2468                                         d.height = viewh;\r
2469                                         pane.setPreferredSize(d);\r
2470                                 }\r
2471                         }\r
2472                 }\r
2473                 \r
2474                 // 予約枠・ピックアップ枠のサイズ変更&色変更\r
2475                 {\r
2476                         JRMLabel.setColumnWidth(bc.getBangumiColumnWidth());\r
2477                         JRMLabel.setHeightMultiplier(phm);\r
2478                         \r
2479                         for ( JRMLabel rb : reserveBorders ) {\r
2480                                 \r
2481                                 rb.reVBounds();\r
2482                                 \r
2483                                 if ( rb.getEncoder().equals(TUNERLABEL_PICKUP) ) {\r
2484                                         rb.setEncBackground(ec.getPickedColor());\r
2485                                         rb.setEncForeground(ec.getPickedFontColor());\r
2486                                         rb.setBorder(new LineBorder(ec.getPickedColor(),4));\r
2487                                 }\r
2488                                 else if ( rb.getExec() ) {\r
2489                                         rb.setEncForeground(ec.getExecOnFontColor());\r
2490                                 }\r
2491                                 else {\r
2492                                         rb.setEncForeground(ec.getExecOffFontColor());\r
2493                                 }\r
2494                                 rb.repaint();\r
2495                         }\r
2496                 }\r
2497                 \r
2498                 // 現在時刻線の位置変更\r
2499                 setTimelinePos(false);\r
2500                 \r
2501                 // 枠のサイズを更新したのでupdateUI()\r
2502                 jScrollPane_space_main.updateUI();\r
2503                 \r
2504                 // ビューの位置調整\r
2505                 vp.y = (int)Math.ceil(maxRow * (float)vp.y * phm / vh);\r
2506                 vport.setViewPosition(vp);\r
2507                 \r
2508         }\r
2509         \r
2510         // フォントの変更\r
2511         public void updateFonts(Env ec) {\r
2512                 JTXTButton.setShowStart(ec.getShowStart());\r
2513                 JTXTButton.setSplitEpno(ec.getSplitEpno());\r
2514                 JTXTButton.setShowDetail(ec.getShowDetail());\r
2515                 JTXTButton.setDetailTab(ec.getDetailTab());\r
2516                 \r
2517                 JTXTButton.setTitleFont(ec.getTitleFont());\r
2518                 JTXTButton.setTitleFontStyle(ec.getTitleFontStyle());\r
2519                 JTXTButton.setDetailFont(ec.getDetailFont());\r
2520                 JTXTButton.setDetailFontStyle(ec.getDetailFontStyle());\r
2521                 JTXTButton.setTitleFontSize(ec.getTitleFontSize());\r
2522                 JTXTButton.setTitleFontColor(ec.getTitleFontColor());\r
2523                 JTXTButton.setDetailFontSize(ec.getDetailFontSize());\r
2524                 JTXTButton.setDetailFontColor(ec.getDetailFontColor());\r
2525                 JTXTButton.setAAHint(ec.getPaperAAMode().getHint());\r
2526         }\r
2527         \r
2528         // 再描画?\r
2529         public void updateRepaint() {\r
2530                 _updPRepaint(frameUsed);\r
2531                 \r
2532                 if ( env.getDrawcacheEnable() ) {\r
2533                         _updPRepaint(frameUsedByDate);\r
2534                 }\r
2535         }\r
2536         \r
2537         // 以下共通部品\r
2538         \r
2539         private void _updPColors(Env ec, PaperColorsMap pc, ArrayList<JTXTButton> fa) {\r
2540                 for ( JTXTButton b2 : fa ) {\r
2541                         b2.setBackground(pc.get(b2.getInfo().genre));\r
2542                 }\r
2543         }\r
2544 \r
2545         private void _updPBounds(Bounds bc, ArrayList<JTXTButton> fa) {\r
2546                 \r
2547                 JTXTButton.setColumnWidth(bc.getBangumiColumnWidth());\r
2548                 JTXTButton.setHeightMultiplier(bc.getPaperHeightMultiplier() * paperHeightZoom);\r
2549                 \r
2550                 for ( JTXTButton b2 :  fa ) {\r
2551                         b2.reVBounds();\r
2552                 }\r
2553         }\r
2554         \r
2555         private void _updPBorderAll(Env ec, Bounds bc, ArrayList<JTXTButton> fa) {\r
2556                 dborder.setDashColor(ec.getMatchedBorderColor());\r
2557                 dborder.setThickness(ec.getMatchedBorderThickness());\r
2558                 dborderK.setDashColor(ec.getMatchedKeywordBorderColor());\r
2559                 dborderK.setThickness(ec.getMatchedBorderThickness());\r
2560                 for ( JTXTButton b2 :  fa ) {\r
2561                         _updPBorder(bc, b2);\r
2562                 }\r
2563         }\r
2564 \r
2565         private void _updPBorder(Bounds bc, JTXTButton b) {\r
2566                 if ( bc.getShowMatchedBorder() && b.isStandby() ) {\r
2567                         if ( b.isStandbyByTrace() ) {\r
2568                                 if ( b.getBorder() != dborder )\r
2569                                         b.setBorder(dborder);\r
2570                         }\r
2571                         else {\r
2572                                 // 番組追跡はキーワード検索に優先する\r
2573                                 if ( b.getBorder() != dborder && b.getBorder() != dborderK )\r
2574                                         b.setBorder(dborderK);\r
2575                         }\r
2576                 }\r
2577                 else {\r
2578                         if ( b.getBorder() != lborder )\r
2579                                 b.setBorder(lborder);\r
2580                 }\r
2581         }\r
2582 \r
2583         private void _updPRepaint(ArrayList<JTXTButton> fa) {\r
2584                 for ( JTXTButton b2 :  fa ) {\r
2585                         b2.forceRepaint();\r
2586                 }\r
2587         }\r
2588 \r
2589 }\r