View Javadoc

1   /*
2    * All Rights Reserved.
3    * Copyright (C) 1999-2005 Tsukuba Bunko.
4    *
5    * Licensed under the BSD License ("the License"); you may not use
6    * this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    *
9    *       http://www.tsukuba-bunko.org/licenses/LICENSE.txt
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   *
17   * $Id: TextCanvas.java,v 1.3 2005/07/23 17:57:02 ppoi Exp $
18   */
19  package tsukuba_bunko.peko.canvas.text;
20  
21  import	java.awt.AlphaComposite;
22  import	java.awt.Dimension;
23  import	java.awt.Graphics;
24  import	java.awt.Graphics2D;
25  import	java.awt.Insets;
26  import	java.awt.Point;
27  import	java.awt.RenderingHints;
28  
29  import	java.awt.font.FontRenderContext;
30  
31  import	java.util.List;
32  
33  import	javax.swing.BorderFactory;
34  import	javax.swing.JComponent;
35  
36  import	javax.swing.border.Border;
37  
38  import	tsukuba_bunko.peko.Logger;
39  
40  
41  /***
42   * テキストを表示するキャンバスです。
43   * @author	$Author: ppoi $
44   * @version	$Revision: 1.3 $
45   */
46  public class TextCanvas	extends JComponent	{
47  
48  	/***
49  	 * serial version UID
50  	 */
51  	private static final long	serialVersionUID	= 2600492357487531048L;
52  
53  
54  	/***
55  	 * Page
56  	 */
57  	private Page	_page = null;
58  
59  
60  	/***
61  	 * Lines
62  	 */
63  	private List	_lines = null;
64  
65  	/***
66  	 * alpha-composite
67  	 */
68  	private AlphaComposite	_alphaComposite = AlphaComposite.getInstance( AlphaComposite.DST_OVER, 0.5f );
69  
70  	/***
71  	 * page size
72  	 */
73  	private Dimension	_size = new Dimension();
74  
75  	/***
76  	 * location
77  	 */
78  	private Point	_location = new Point( 0, 0 );
79  
80  	/***
81  	 * padding
82  	 */
83  	private Insets	_padding = new Insets( 0, 0, 0, 0 );
84  
85  
86  	/***
87  	 * cached FontRenderContext
88  	 */
89  	private FontRenderContext	_frc = null;
90  
91  
92  	/***
93  	 * marker
94  	 */
95  	private Marker	_marker = null;
96  
97  
98  	/***
99  	 * <code>TextCanvas</code> のインスタンスを作成します。
100 	 */
101 	public TextCanvas()
102 	{
103 		super();
104 		initialize();
105 	}
106 
107 
108 	/***
109 	 * ページに文字を描画するのに使用する <code>FontRenderContext</code> を取得します。
110 	 * @return	ページに文字を描画するのに使用する <code>FontRenderContext</code>
111 	 */
112 	public FontRenderContext getFontRenderContext()
113 	{
114 		if( _frc == null )	{
115 			synchronized( this )	{
116 				if( _frc == null )	{
117 					try	{
118 						Logger.debug( "[canvas.text] waiting for create cached FontRenderContext." );
119 						wait();
120 						Logger.debug( "[canvas.text] creating cached FontRenderContext done." );
121 					}
122 					catch( InterruptedException ie )	{
123 						Logger.error( "[canvas.text] interrupted." );
124 					}
125 				}
126 			}
127 		}
128 		return _frc;
129 	}
130 
131 	/***
132 	 * 背景色を描画する際に使用する AlphaComposite を取得します。
133 	 * @return	背景色を描画する際に使用する AlphaComposite インスタンス
134 	 */
135 	public AlphaComposite getAlphaComposite()
136 	{
137 		return _alphaComposite;
138 	}
139 
140 	/***
141 	 * キャンバスを最新の状態に更新します。
142 	 */
143 	public void updateCanvas()
144 	{
145 		if( !isEnabled() )	{
146 			return;
147 		}
148 
149 		Logger.debug( "[canvas.text] update TextCanvas view" );
150 		_lines = null;
151 		_page.getSize( _size );
152 		_page.getLocation( _location );
153 		_page.getPadding( _padding );
154 		setForeground( _page.getForeground() );
155 		setBackground( _page.getBackground() );
156 		float	trans = _page.getTransparency();
157 		if( (_alphaComposite == null) || (_alphaComposite.getAlpha() != trans) )	{
158 			_alphaComposite = AlphaComposite.getInstance( AlphaComposite.SRC_OVER, trans );
159 		}
160 		_marker.setText( "▼", _page );
161 	}
162 
163 	/***
164 	 * キャンバスに描画するテキストを最新の状態に更新します。
165 	 */
166 	public void updateText()
167 	{
168 		if( !isEnabled() )	{
169 			return;
170 		}
171 
172 		Logger.debug( "[canvas.text] update texts." );
173 		_marker.setVisible( false );
174 
175 		List	lines = _page.getLines();
176 		int size = lines.size();
177 		for( int i = 0; i < size; ++i )	{
178 			((Line)lines.get(i)).prepare( _page );
179 		}
180 		_lines = lines;
181 
182 //		setVisible( true );
183 		tsukuba_bunko.peko.PekoSystem.getInstance().getCanvasManager().showTextCanvas();
184 		repaint();
185 
186 		try	{
187 			synchronized( this )	{
188 				wait( 100 );
189 			}
190 		}
191 		catch( Exception e )	{
192 		}
193 		_marker.setVisible( true );
194 	}
195 
196 
197 	/***
198 	 * このキャンバスで描画するページを設定します。
199 	 * @param	page	このキャンバスで描画するページ
200 	 */
201 	public void setPage( Page page )
202 	{
203 		_page = page;
204 		_page.setTextCanvas( this );
205 	}
206 
207 	/***
208 	 * 現在このキャンバスで描画中のページを取得します。
209 	 * @return	現在このキャンバスで描画中のページ
210 	 */
211 	public Page getPage()
212 	{
213 		return _page;
214 	}
215 
216 	public void paintPageBackground( Graphics g )
217 	{
218 		Dimension	size = _size;
219 		Point	location = _location;
220 
221 		Graphics2D	g2 = (Graphics2D)g.create( location.x, location.y, size.width, size.height );
222 		g2.setComposite( _alphaComposite );
223 		g2.setColor( getBackground() );
224 		g2.fillRect( 0, 0, size.width, size.height );
225 		g2.dispose();
226 	}
227 
228 	/***
229 	 * TextCanvas を初期化します。
230 	 */
231 	private void initialize()
232 	{
233 		setLayout( null );
234 		setDoubleBuffered( false );
235 		setBorder( BorderFactory.createEtchedBorder() );
236 
237 		_marker = new Marker();
238 		add( _marker );
239 		_marker.setLocation( 0, 0 );
240 		_marker.setVisible( false );
241 	}
242 
243 
244 //
245 //	JComponent の実装
246 //
247 	public void setVisible( boolean visibility )
248 	{
249 		Logger.debug( "[canvas.text] set visibility :" + visibility );
250 		if( visibility )	{
251 			_marker.start();
252 		}
253 		super.setVisible( visibility );
254 	}
255 
256 	public void addNotify()
257 	{
258 		super.addNotify();
259 		Logger.debug( "[canvas.text] added notify to TextCavas" );
260 		if( _frc == null )	{
261 			Logger.debug( "[canvas.text] try create new font render context." );
262 			synchronized( this )	{
263 				if( _frc == null )	{
264 					Graphics2D	g2 = (Graphics2D)getGraphics();
265 					g2.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
266 					_frc = g2.getFontRenderContext();
267 					Logger.debug( "[canvas] notify all thread waiting at TextCanvas" );
268 					notifyAll();
269 				}
270 			}
271 		}
272 	}
273 
274 	public void paint( Graphics g )
275 	{
276 		List	lines = _lines;
277 		if( (lines == null) || lines.isEmpty() )	{
278 			return;
279 		}
280 		else	{
281 			super.paint( g );
282 		}		
283 	}
284 
285 	public void paintBorder( Graphics g )
286 	{
287 		Border	border = getBorder();
288 		if( border != null )	{
289 			border.paintBorder( this, g, _location.x, _location.y, _size.width, _size.height );
290 		}
291 	}
292 
293 	public void paintComponent( Graphics g )
294 	{
295 		List	lines = _lines;
296 
297 		Point	location = _location;
298 		Insets	padding = _padding;
299 
300 //		paintPageBackground( g );
301 
302 		Graphics2D	g2 = (Graphics2D)g;
303 		float	x = (float)(location.x + padding.left);
304 		float	y = (float)(location.y + padding.top);
305 		float	tail = 0f;
306 		int	length = lines.size();
307 		Line	line = null;
308 		for( int i = 0; i < length; ++i )	{
309 			line = (Line)lines.get( i );
310 			y += line.getAscent();
311 			line.draw( g2, x, y );
312 			y += line.getDescent();
313 			tail = line.getAdavance();
314 		}
315 		_marker.setPosition( (int)(tail + 5f + x), (int)y );
316 	}
317 }