OSDN Git Service

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