OSDN Git Service

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